/* * Unlock write lock * Start any waiting writers in preference to waiting readers */ int devlock::writeunlock() { devlock *rwl = this; int status, status2; if (rwl->valid != DEVLOCK_VALID) { return EINVAL; } if ((status = pthread_mutex_lock(&rwl->mutex)) != 0) { return status; } if (rwl->w_active <= 0) { pthread_mutex_unlock(&rwl->mutex); Jmsg0(NULL, M_ABORT, 0, _("writeunlock called too many times.\n")); } rwl->w_active--; if (!pthread_equal(pthread_self(), rwl->writer_id)) { pthread_mutex_unlock(&rwl->mutex); Jmsg0(NULL, M_ABORT, 0, _("writeunlock by non-owner.\n")); } if (rwl->w_active > 0) { status = 0; /* writers still active */ } else { lmgr_do_unlock(rwl); /* No more writers, awaken someone */ if (rwl->r_wait > 0) { /* if readers waiting */ status = pthread_cond_broadcast(&rwl->read); } else if (rwl->w_wait > 0) { status = pthread_cond_broadcast(&rwl->write); } } status2 = pthread_mutex_unlock(&rwl->mutex); return (status == 0 ? status2 : status); }
/* * Lock for write access, wait until locked (or error). * Multiple nested write locking is permitted. */ int devlock::writelock(int areason, bool acan_take) { devlock *rwl = this; int status; if (rwl->valid != DEVLOCK_VALID) { return EINVAL; } if ((status = pthread_mutex_lock(&rwl->mutex)) != 0) { return status; } if (rwl->w_active && pthread_equal(rwl->writer_id, pthread_self())) { rwl->w_active++; pthread_mutex_unlock(&rwl->mutex); return 0; } lmgr_pre_lock(rwl, rwl->priority, __FILE__, __LINE__); if (rwl->w_active || rwl->r_active > 0) { rwl->w_wait++; /* indicate that we are waiting */ pthread_cleanup_push(devlock_write_release, (void *)rwl); while (rwl->w_active || rwl->r_active > 0) { if ((status = pthread_cond_wait(&rwl->write, &rwl->mutex)) != 0) { lmgr_do_unlock(rwl); break; /* error, bail out */ } } pthread_cleanup_pop(0); rwl->w_wait--; /* we are no longer waiting */ } if (status == 0) { rwl->w_active++; /* we are running */ rwl->writer_id = pthread_self(); /* save writer thread's id */ lmgr_post_lock(); } rwl->reason = areason; rwl->can_take = acan_take; pthread_mutex_unlock(&rwl->mutex); return status; }
/* * Lock for write access, wait until locked (or error). * Multiple nested write locking is permitted. */ int rwl_writelock_p(brwlock_t *rwl, const char *file, int line) { int stat; if (rwl->valid != RWLOCK_VALID) { return EINVAL; } if ((stat = pthread_mutex_lock(&rwl->mutex)) != 0) { return stat; } if (rwl->w_active && pthread_equal(rwl->writer_id, pthread_self())) { rwl->w_active++; pthread_mutex_unlock(&rwl->mutex); return 0; } lmgr_pre_lock(rwl, rwl->priority, file, line); if (rwl->w_active || rwl->r_active > 0) { rwl->w_wait++; /* indicate that we are waiting */ pthread_cleanup_push(rwl_write_release, (void *)rwl); while (rwl->w_active || rwl->r_active > 0) { if ((stat = pthread_cond_wait(&rwl->write, &rwl->mutex)) != 0) { lmgr_do_unlock(rwl); break; /* error, bail out */ } } pthread_cleanup_pop(0); rwl->w_wait--; /* we are no longer waiting */ } if (stat == 0) { rwl->w_active++; /* we are running */ rwl->writer_id = pthread_self(); /* save writer thread's id */ lmgr_post_lock(); } pthread_mutex_unlock(&rwl->mutex); return stat; }