pike.git / src / threads.c

version» Context lines:

pike.git/src/threads.c:2606:    push_text("Thread.MutexKey(/* Unlocked */)");    }   }      /*! @endclass    */      enum rwmux_kind    {    RWMUX_NONE = 0, +  RWMUX_TRY_READ = RWMUX_NONE,    RWMUX_READ,    RWMUX_DOWNGRADED, -  +  RWMUX_TRY_WRITE = RWMUX_DOWNGRADED,    RWMUX_WRITE,    };      struct rwmutex_key_storage   {    struct rwmutex_storage *rwmutex;    struct object *rwmutex_obj;    struct thread_state *owner;    struct object *owner_obj;    struct rwmutex_key_storage *prev;
pike.git/src/threads.c:2666:      /*! @decl RWKey read_lock()    *!    *! Obtain a lock for reading (shared lock).    *!    *! @throws    *! Throws an error if the current thread already has    *! a lock (read or write).    *!    *! @seealso -  *! @[write_lock()] +  *! @[try_read_lock()], @[write_lock()]    */   static void f_rwmutex_read_lock(INT32 args)   {    ref_push_object_inherit(Pike_fp->current_object,    Pike_fp->context -    Pike_fp->current_object->prog->inherits);    push_int(RWMUX_READ);    push_object(clone_object(rwmutex_key_program, 2));   }    -  + /*! @decl RWKey try_read_lock() +  *! +  *! Attempt to obtain a lock for reading (shared lock). +  *! +  *! @throws +  *! Throws an error if the current thread already has +  *! a lock (read or write). +  *! +  *! @seealso +  *! @[read_lock()], @[write_lock()] +  */ + static void f_rwmutex_try_read_lock(INT32 args) + { +  ref_push_object_inherit(Pike_fp->current_object, +  Pike_fp->context - +  Pike_fp->current_object->prog->inherits); +  push_int(RWMUX_TRY_READ); +  push_object(clone_object(rwmutex_key_program, 2)); + } +    /*! @decl RWKey write_lock()    *!    *! Obtain a lock for writing (exclusive lock).    *!    *! @throws    *! Throws an error if the current thread already has    *! a lock (read or write).    *!    *! @seealso -  *! @[read_lock()], @[try_read_lock()] +  *! @[read_lock()], @[try_read_lock()], @[try_write_lock()]    */   static void f_rwmutex_write_lock(INT32 args)   {    ref_push_object_inherit(Pike_fp->current_object,    Pike_fp->context -    Pike_fp->current_object->prog->inherits);    push_int(RWMUX_WRITE);    push_object(clone_object(rwmutex_key_program, 2));   }    -  + /*! @decl RWKey try_write_lock() +  *! +  *! Attempt to obtain a lock for writing (exclusive lock). +  *! +  *! @throws +  *! Throws an error if the current thread already has +  *! a lock (read or write). +  *! +  *! @seealso +  *! @[read_lock()], @[try_read_lock()], @[write_lock()] +  */ + static void f_rwmutex_try_write_lock(INT32 args) + { +  ref_push_object_inherit(Pike_fp->current_object, +  Pike_fp->context - +  Pike_fp->current_object->prog->inherits); +  push_int(RWMUX_TRY_WRITE); +  push_object(clone_object(rwmutex_key_program, 2)); + } +    /*! @decl string _sprintf(int c)    *!    *! Describes the mutex including the thread(s) that currently hold    *! locks (if any).    */   static void f_rwmutex__sprintf(INT32 args)   {    struct rwmutex_storage *m = THIS_RWMUTEX;    int c = 0;    struct rwmutex_key_storage *key;
pike.git/src/threads.c:2878:    /* Link */    THIS_RWKEY->prev = NULL;    if ((THIS_RWKEY->next = rwmutex->key)) {    rwmutex->key->prev = THIS_RWKEY;    }    rwmutex->key = THIS_RWKEY;       THIS_RWKEY->kind = RWMUX_NONE; /* No lock taken (yet). */       switch(kind) { +  case RWMUX_TRY_READ: +  if (rwmutex->writers > 0) { +  /* There's a write lock. -- Attempt in try mode failed. */ +  destruct_object(Pike_fp->current_object, DESTRUCT_EXPLICIT); +  break; +  } +  +  rwmutex->readers++; +  THIS_RWKEY->kind = RWMUX_READ; +  break; +     case RWMUX_READ:    /* States:    *    * readers writers self_count Action    * - <=0 - Add reader.    * (No active writers.)    * 0 1 0 Wait for writers to go to 0.    * (Some other thread is attempting to    * take a write lock.)    * >0 1 >0 Add reader.
pike.git/src/threads.c:2908:    SWAP_OUT_CURRENT_THREAD();    while(rwmutex->writers > 0) {    co_wait_interpreter(&rwmutex->condition);    }    SWAP_IN_CURRENT_THREAD();       rwmutex->readers++;    THIS_RWKEY->kind = RWMUX_READ;    break;    +  case RWMUX_TRY_WRITE: +  if (rwmutex->writers || rwmutex->readers) { +  /* There's a (degraded) write lock or a read lock. +  * -- Attempt in try mode failed. +  */ +  destruct_object(Pike_fp->current_object, DESTRUCT_EXPLICIT); +  break; +  } +  +  rwmutex->writers = 2; +  THIS_RWKEY->kind = RWMUX_WRITE; +  break; +     case RWMUX_WRITE:    /* States:    *    * readers writers self_count Action    * - 0 - Set writers to 1, wait for readers    * to go to 0, Set writers to 2.    * (No write lock active.)    * - -1 0 Wait for writers to go to 0, then as above.    * (Some other thread has a degraded write    * lock.)
pike.git/src/threads.c:2998:    *!    *! This is a no-op on keys that already are write-locks.    *!    *! For a downgraded write-lock, this operation will block    *! until all concurrent read-locks are released.    *!    *! @throws    *! Throws an error for keys that didn't start out as write-locks.    *!    *! @seealso -  *! @[downgrade()] +  *! @[try_upgrade()], @[downgrade()]    */   static void f_rwmutex_key_upgrade(INT32 args)   {    struct rwmutex_storage *rwmutex = NULL;       if (THIS_RWKEY->kind < RWMUX_DOWNGRADED) {    Pike_error("Unsupported operation -- not a (degraded) write lock.\n");    }    if (THIS_RWKEY->kind == RWMUX_WRITE) {    /* Already upgraded. */
pike.git/src/threads.c:3028:    SWAP_OUT_CURRENT_THREAD();    while(rwmutex->readers) {    co_wait_interpreter(&rwmutex->condition);    }    SWAP_IN_CURRENT_THREAD();       rwmutex->writers = 2;    THIS_RWKEY->kind = RWMUX_WRITE;   }    + /*! @decl int(0..1) try_upgrade() +  *! +  *! Attempt to upgrade this key back into a write-lock. +  *! +  *! This operation is only allowed on keys that have started +  *! out as write-locks. +  *! +  *! This is a no-op on keys that already are write-locks, in which +  *! case @expr{1@} will be returned. +  *! +  *! For a downgraded write-lock, this operation will upgrade the +  *! key into a write-lock if there are no active read locks. +  *! +  *! @throws +  *! Throws an error for keys that didn't start out as write-locks. +  *! +  *! @returns +  *! Returns @expr{1@} if the key is now a write-lock, and +  *! @expr{0@} (zero) if it is (still) a read-lock. +  *! +  *! @seealso +  *! @[upgrade()], @[downgrade()] +  */ + static void f_rwmutex_key_try_upgrade(INT32 args) + { +  struct rwmutex_storage *rwmutex = NULL; +  +  if (THIS_RWKEY->kind < RWMUX_DOWNGRADED) { +  Pike_error("Unsupported operation -- not a (degraded) write lock.\n"); +  } +  if (THIS_RWKEY->kind == RWMUX_DOWNGRADED) { +  rwmutex = THIS_RWKEY->rwmutex; +  +  if (rwmutex->readers != 1) { +  /* There are other readers active. */ +  push_int(0); +  return; +  } +  +  rwmutex->readers = 0; +  rwmutex->writers = 2; +  +  THIS_RWKEY->kind = RWMUX_WRITE; +  } +  push_int(1); + } +    static void f_rwmutex_key__sprintf(INT32 args)   {    int c = 0;    get_all_args("_sprintf", args, "%d", &c);    if (c != 'O') {    push_undefined();    return;    }    if (THIS_RWKEY->rwmutex_obj) {    push_text("Thread.RWKey(/* %O, %s */)");
pike.git/src/threads.c:4075:    set_init_callback(init_rwmutex_key_obj);    set_exit_callback(exit_rwmutex_key_obj);    ADD_FUNCTION("create", f_rwmutex_key_create,    tFunc(tOr(tObjIs_THREAD_RWMUTEX, tVoid)    tOr(tInt02, tVoid), tVoid),    ID_PROTECTED);    ADD_FUNCTION("downgrade", f_rwmutex_key_downgrade,    tFunc(tNone, tVoid), 0);    ADD_FUNCTION("upgrade", f_rwmutex_key_upgrade,    tFunc(tNone, tVoid), 0); +  ADD_FUNCTION("try_upgrade", f_rwmutex_key_try_upgrade, +  tFunc(tNone, tInt01), 0);    ADD_FUNCTION("_sprintf", f_rwmutex_key__sprintf,    tFunc(tOr(tInt, tVoid), tStr), ID_PROTECTED);    rwmutex_key_program = Pike_compiler->new_program;    add_ref(rwmutex_key_program);    end_class("RWKey", 0);    rwmutex_key_program->flags |= PROGRAM_DESTRUCT_IMMEDIATE;       START_NEW_PROGRAM_ID(THREAD_RWMUTEX);    ADD_STORAGE(struct rwmutex_storage);    ADD_FUNCTION("read_lock", f_rwmutex_read_lock,    tFunc(tNone, tObjIs_THREAD_RWMUTEX_KEY), 0); -  +  ADD_FUNCTION("try_read_lock", f_rwmutex_try_read_lock, +  tFunc(tNone, tObjIs_THREAD_RWMUTEX_KEY), 0);    ADD_FUNCTION("write_lock", f_rwmutex_write_lock,    tFunc(tNone, tObjIs_THREAD_RWMUTEX_KEY), 0); -  +  ADD_FUNCTION("try_write_lock", f_rwmutex_try_write_lock, +  tFunc(tNone, tObjIs_THREAD_RWMUTEX_KEY), 0);    ADD_FUNCTION("_sprintf", f_rwmutex__sprintf,    tFunc(tOr(tInt, tVoid), tStr), ID_PROTECTED);    set_init_callback(init_rwmutex_obj);    set_exit_callback(exit_rwmutex_obj);    rwmutex_program = Pike_compiler->new_program;    add_ref(rwmutex_program);    end_class("RWMutex", 0);       START_NEW_PROGRAM_ID(THREAD_CONDITION);    ADD_STORAGE(struct pike_cond);