pike.git / src / threads.c

version» Context lines:

pike.git/src/threads.c:2127:    struct key_storage *key;    int num_waiting;   };      enum key_kind   {    KEY_UNINITIALIZED = 0,    KEY_INITIALIZED,    KEY_NONE = KEY_INITIALIZED,    KEY_SHARED, +  KEY_DOWNGRADED,    KEY_PENDING,    KEY_EXCLUSIVE,   };      struct key_storage   {    struct object *self; /* NOT reference-counted! */    struct mutex_storage *mut;    struct object *mutex_obj;    struct thread_state *owner;
pike.git/src/threads.c:2432:    m->num_waiting++;       THREADS_FPRINTF(1, "WAITING TO SHARE LOCK m:%p\n", m);    SWAP_OUT_CURRENT_THREAD();    co_wait_interpreter(& m->condition);    SWAP_IN_CURRENT_THREAD();    check_threads_etc();       m->num_waiting--;    } +  +  if (m->key && (m->key->kind == KEY_DOWNGRADED)) { +  /* Link new read keys after the downgraded key (if any). */ +  prev = m->key; +  prev_o = prev->self; +  add_ref(prev_o);    } -  +  }      #ifdef PICKY_MUTEX    if (!Pike_fp->current_object->prog) {    /* The mutex has been destructed during our wait. */    destruct(o);    free_object (o);    if (!m->num_waiting) {    co_destroy (&m->condition);    } -  +  if (prev_o) free_object(prev_o);    Pike_error ("Mutex was destructed while waiting for lock.\n");    }   #endif       /* Three cases here:    *    * prev != NULL    * prev == NULL && m->key == NULL    * prev == NULL && m->key && m->key->kind == KEY_READ    */
pike.git/src/threads.c:2471:    prev->next = key;    free_object(prev_o);    } else {    /* Add key first in the list. */    key->prev = NULL;    if ((key->next = m->key)) {    m->key->prev = key;    }    m->key = key;    } +     key->kind = KEY_SHARED;       DEBUG_CHECK_THREAD();       THREADS_FPRINTF(1, "SHARED_LOCK k:%p, m:%p(%p), t:%p\n",    key, m, key->mut,    Pike_interpreter.thread_state);    pop_n_elems(args);    push_object(o);   }
pike.git/src/threads.c:2601:    free_object(o);    Pike_error("Recursive mutex locks!\n");    }    continue;    }    prev = key;    break;    }    }    +  if (m->key && (m->key->kind == KEY_DOWNGRADED) && !prev) { +  /* Keep the downgraded key first. */ +  prev = m->key; +  } +     key = OB2KEY(o);       if (prev) {    /* Link after prev. */    key->mut = m;    add_ref (key->mutex_obj = Pike_fp->current_object);    key->prev = prev;    if ((key->next = prev->next)) {    prev->next->prev = key;    }
pike.git/src/threads.c:2956:    }    if (THIS_KEY->mutex_obj) {    push_text("Thread.MutexKey(/* %O */)");    ref_push_object(THIS_KEY->mutex_obj);    f_sprintf(2);    } else {    push_text("Thread.MutexKey(/* Unlocked */)");    }   }    + static void f_mutex_key_downgrade(INT32 args) + { +  struct key_storage *key = THIS_KEY; +  +  if (key->kind < KEY_PENDING) return; +  +  if (key->kind == KEY_PENDING) { +  Pike_error("It is not possible to downgrade a key that is waiting.\n"); +  } +  +  key->kind = KEY_DOWNGRADED; +  +  co_broadcast(&key->mut->condition); + } +  + static void f_mutex_key_upgrade(INT32 args) + { +  struct key_storage *key = THIS_KEY; +  struct mutex_storage *m = key->mut; +  +  if (key->kind >= KEY_PENDING) return; +  +  if (key->kind != KEY_DOWNGRADED) { +  Pike_error("Upgrade is not allowed for non-degraded mutex keys.\n"); +  } +  +  if(key->next) +  { +  if(threads_disabled) +  { +  /* Restore the key state. */ +  Pike_error("Cannot wait for mutexes when threads are disabled!\n"); +  } +  +  key->kind = KEY_PENDING; +  +  m->num_waiting++; +  do +  { +  THREADS_FPRINTF(1, "WAITING TO LOCK m:%p\n", m); +  SWAP_OUT_CURRENT_THREAD(); +  co_wait_interpreter(& m->condition); +  SWAP_IN_CURRENT_THREAD(); +  check_threads_etc(); +  } while (key->next); +  m->num_waiting--; +  } +  +  key->kind = KEY_EXCLUSIVE; + } +  + static void f_mutex_key_try_upgrade(INT32 args) + { +  struct key_storage *key = THIS_KEY; +  +  if (key->kind >= KEY_PENDING) { +  push_int(1); +  return; +  } +  +  if (key->kind != KEY_DOWNGRADED) { +  Pike_error("Upgrade is not allowed for non-degraded mutex keys.\n"); +  } +  +  if (key->next) { +  push_int(0); +  return; +  } +  +  key->kind = KEY_EXCLUSIVE; +  +  push_int(1); + } +    /*! @endclass    */      enum rwmux_kind    {    RWMUX_NONE = 0,    RWMUX_TRY_READ = RWMUX_NONE,    RWMUX_READ,    RWMUX_DOWNGRADED,    RWMUX_TRY_WRITE = RWMUX_DOWNGRADED,
pike.git/src/threads.c:4519:    mutex_key_offset = ADD_STORAGE(struct key_storage);    /* This is needed to allow the gc to find the possible circular reference.    * It also allows a thread to take over ownership of a key.    */    PIKE_MAP_VARIABLE("_owner",    mutex_key_offset + OFFSETOF(key_storage, owner_obj),    tObjIs_THREAD_ID, T_OBJECT, 0);    PIKE_MAP_VARIABLE("_mutex", mutex_key_offset + OFFSETOF(key_storage, mutex_obj),    tObjIs_THREAD_MUTEX, T_OBJECT, ID_PROTECTED|ID_PRIVATE);    ADD_FUNCTION("_sprintf",f_mutex_key__sprintf,tFunc(tInt,tStr),ID_PROTECTED); +  ADD_FUNCTION("downgrade", f_mutex_key_downgrade, tFunc(tNone,tVoid), 0); +  ADD_FUNCTION("upgrade", f_mutex_key_upgrade, tFunc(tNone,tVoid), 0); +  ADD_FUNCTION("try_upgrade", f_mutex_key_try_upgrade, tFunc(tNone,tInt01), 0);    set_init_callback(init_mutex_key_obj);    set_exit_callback(exit_mutex_key_obj);    mutex_key=Pike_compiler->new_program;    add_ref(mutex_key);    end_class("mutex_key", 0);    mutex_key->flags|=PROGRAM_DESTRUCT_IMMEDIATE;       START_NEW_PROGRAM_ID(THREAD_MUTEX);    ADD_STORAGE(struct mutex_storage);    ADD_FUNCTION("lock",f_mutex_lock,