pike.git / src / threads.c

version» Context lines:

pike.git/src/threads.c:2327:    *! @value 1    *! Sleep until the mutex is unlocked. Useful if some    *! other thread will unlock it.    *! @value 2    *! Return zero. This allows recursion within a locked region of    *! code, but in conjunction with other locks it easily leads    *! to unspecified locking order and therefore a risk for deadlocks.    *! @endint    *!    *! @note +  *! Note that if the current thread already holds a shared key, +  *! a new will be created without waiting, and regardless of +  *! the value of @[type]. +  *! +  *! @note    *! If the mutex is destructed while it's locked or while threads are    *! waiting on it, it will continue to exist internally until the last    *! thread has stopped waiting and the last @[MutexKey] has    *! disappeared, but further calls to the functions in this class will    *! fail as is usual for destructed objects.    *! -  *! @note -  *! A thread may hold several shared locks concurrently. -  *! +     *! @seealso    *! @[lock()], @[trylock()], @[try_shared_lock()]    */   void f_mutex_shared_lock(INT32 args)   {    struct mutex_storage *m; -  struct key_storage *key; -  struct object *o; -  INT_TYPE type; +  struct key_storage *key, *prev = NULL; +  struct object *o, *prev_o = NULL; +  INT_TYPE type = 0;       DEBUG_CHECK_THREAD();       m=THIS_MUTEX; -  if(!args) -  type=0; -  else -  get_all_args(NULL, args, "%i", &type); +  get_all_args(NULL, args, ".%i", &type);    -  switch(type) -  { -  default: +  if ((type < 0) || (type > 2)) {    bad_arg_error("shared_lock", args, 2, "int(0..2)", Pike_sp+1-args, -  "Unknown mutex locking style: %"PRINTPIKEINT"d\n",type); +  "Unknown mutex locking style: %"PRINTPIKEINT"d\n", type); +  }    -  -  case 0: -  case 2: -  if (m->key && (m->key->kind >= KEY_PENDING)) { -  /* There are active or waiting exclusive locks. */ +     for (key = m->key; key; key = key->next) { -  if(key->owner == Pike_interpreter.thread_state) -  { +  if (key->owner == Pike_interpreter.thread_state) {    THREADS_FPRINTF(0,    "Recursive LOCK k:%p, m:%p(%p), t:%p\n",    key, m, key->mut,    Pike_interpreter.thread_state);    -  if(type==0) { +  if (key->kind >= KEY_PENDING) { +  /* This thread already has an exclusive lock. */ +  switch(type) { +  case 0:    Pike_error("Recursive mutex locks!\n"); -  } -  +  break; +  case 1: +  continue; +  case 2:    pop_n_elems(args);    push_int(0);    return;    }    } -  } -  case 1: +  +  prev = key; +  prev_o = prev->self; +  add_ref(prev_o);    break;    } -  +  }       /* Needs to be cloned here, since create()    * might use threads.    */    o=fast_clone_object(mutex_key);       DEBUG_CHECK_THREAD();    -  +  if (prev_o && !prev_o->prog) { +  /* Paranoia: prev got destructed during the clone above. +  * +  * NB: We rely on this thread not having added a new key +  * during the clone above. +  * +  * NB: We also rely on prev not getting unlinked for any other +  * reason than getting destructed. +  */ +  prev = NULL; +  free_object(prev_o); +  prev_o = NULL; +  for (key = m->key; key; key = key->next) { +  if (key->kind >= KEY_PENDING) continue; +  if (key->owner == Pike_interpreter.thread_state) { +  prev = key; +  prev_o = prev->self; +  add_ref(prev_o); +  break; +  } +  } +  } +  +  if (!prev) {    while (m->key && (m->key->kind >= KEY_PENDING)) {    if(threads_disabled)    {    free_object(o);    Pike_error("Cannot wait for mutexes when threads are disabled!\n");    }       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--;    } -  +  }      #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);    }    Pike_error ("Mutex was destructed while waiting for lock.\n");    }   #endif    -  /* Two cases here: +  /* Three cases here:    * -  * mut->key == NULL -  * mut->key && mut->key->kind == KEY_READ +  * prev != NULL +  * prev == NULL && m->key == NULL +  * prev == NULL && m->key && m->key->kind == KEY_READ    */    key = OB2KEY(o);    key->mut = m;    add_ref (key->mutex_obj = Pike_fp->current_object); -  +  if (prev) { +  /* Add key after prev in the list. */ +  key->prev = prev; +  if ((key->next = prev->next)) { +  prev->next->prev = key; +  } +  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:2536:    *! This function performs the same operation as @[shared_lock()],    *! but if the mutex is already locked exclusively, it will return    *! zero instead of sleeping until it's unlocked.    *!    *! @seealso    *! @[shared_lock()], @[lock()], @[trylock()]    */   void f_mutex_try_shared_lock(INT32 args)   {    struct mutex_storage *m; -  struct key_storage *key; +  struct key_storage *key, *prev = NULL;    struct object *o; -  INT_TYPE type; +  INT_TYPE type = 0;    int i=0;       /* No reason to release the interpreter lock here    * since we aren't calling any functions that take time.    */       m=THIS_MUTEX;    -  if(!args) -  type=0; -  else -  get_all_args(NULL, args, "%i", &type); +  get_all_args(NULL, args, ".%i", &type);    -  switch(type) -  { -  default: +  if ((type < 0) || (type > 2)) {    bad_arg_error("try_shared_lock", args, 2, "int(0..2)", Pike_sp+1-args,    "Unknown mutex locking style: %"PRINTPIKEINT"d\n",type); -  +  }    -  case 0: +  o = clone_object(mutex_key, 0); +     for (key = m->key; key; key = key->next) {    if(key->owner == Pike_interpreter.thread_state)    { -  +  if (key->kind >= KEY_PENDING) { +  if (type == 0) { +  free_object(o);    Pike_error("Recursive mutex locks!\n");    } -  +  continue;    } -  -  case 2: -  case 1: +  prev = key;    break;    } -  +  }    -  o=clone_object(mutex_key,0); +     key = OB2KEY(o);    -  if (!m->key || (m->key->kind < KEY_PENDING)) -  { +  if (prev) {    key->mut = m;    add_ref (key->mutex_obj = Pike_fp->current_object); -  +  key->prev = prev; +  if ((key->next = prev)) { +  prev->next->prev = key; +  } +  prev->next = key; +  key->kind = KEY_SHARED; +  i=1; +  } else if (!m->key || (m->key->kind < KEY_PENDING)) { +  key->mut = m; +  add_ref (key->mutex_obj = Pike_fp->current_object);    if ((key->next = m->key)) {    key->next->prev = key;    }    m->key = key;    key->prev = NULL;    key->kind = KEY_SHARED;    i=1;    }       pop_n_elems(args);