2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-25 03:27:18 +00:00
bind/lib/isc/rwlock.c

223 lines
5.1 KiB
C
Raw Normal View History

1998-11-12 02:02:52 +00:00
1998-11-12 23:30:46 +00:00
#include <stdio.h>
1998-11-12 02:02:52 +00:00
#include <isc/assertions.h>
#include <isc/unexpect.h>
#include <isc/boolean.h>
#include <isc/rwlock.h>
#define LOCK(lp) \
INSIST(isc_mutex_lock((lp)) == ISC_R_SUCCESS);
#define UNLOCK(lp) \
INSIST(isc_mutex_unlock((lp)) == ISC_R_SUCCESS);
#define BROADCAST(cvp) \
INSIST(isc_condition_broadcast((cvp)) == ISC_R_SUCCESS);
#define SIGNAL(cvp) \
INSIST(isc_condition_signal((cvp)) == ISC_R_SUCCESS);
#define WAIT(cvp, lp) \
INSIST(isc_condition_wait((cvp), (lp)) == ISC_R_SUCCESS);
1998-11-12 23:30:46 +00:00
#define RWLOCK_MAGIC 0x52574C6BU /* RWLk. */
#define VALID_RWLOCK(rwl) ((rwl) != NULL && \
(rwl)->magic == RWLOCK_MAGIC)
1998-11-12 02:02:52 +00:00
1998-11-12 23:30:46 +00:00
#ifdef ISC_RWLOCK_TRACE
1998-11-12 02:02:52 +00:00
static void
print_lock(char *operation, isc_rwlock_t *rwl, isc_rwlocktype_t type) {
printf("%s(%s): ", operation,
(type == isc_rwlocktype_read ? "read" : "write"));
1998-11-12 23:30:46 +00:00
printf("%s, %u active, %u granted",
1998-11-12 02:02:52 +00:00
(rwl->type == isc_rwlocktype_read ? "reading" : "writing"),
1998-11-12 23:30:46 +00:00
rwl->active, rwl->granted);
1998-11-12 02:02:52 +00:00
printf(", %u rwaiting, %u wwaiting\n",
rwl->readers_waiting,
rwl->writers_waiting);
}
1998-11-12 23:30:46 +00:00
#endif
1998-11-12 02:02:52 +00:00
isc_result_t
1998-11-12 22:27:30 +00:00
isc_rwlock_init(isc_rwlock_t *rwl,
unsigned int read_quota,
unsigned int write_quota)
{
1998-11-12 02:02:52 +00:00
isc_result_t result;
REQUIRE(rwl != NULL);
1998-11-12 23:30:46 +00:00
/*
* In case there's trouble initializing, we zero magic now. If all
* goes well, we'll set it to RWLOCK_MAGIC.
*/
rwl->magic = 0;
1998-11-12 02:02:52 +00:00
rwl->type = isc_rwlocktype_read;
rwl->active = 0;
rwl->granted = 0;
rwl->readers_waiting = 0;
rwl->writers_waiting = 0;
1998-11-12 22:27:30 +00:00
if (read_quota == 0)
read_quota = 4;
rwl->read_quota = read_quota;
if (write_quota == 0)
write_quota = 4;
rwl->write_quota = write_quota;
1998-11-12 02:02:52 +00:00
result = isc_mutex_init(&rwl->lock);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_mutex_init() failed: %s",
isc_result_totext(result));
return (ISC_R_UNEXPECTED);
}
result = isc_condition_init(&rwl->readable);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_condition_init(readable) failed: %s",
isc_result_totext(result));
return (ISC_R_UNEXPECTED);
}
result = isc_condition_init(&rwl->writeable);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_condition_init(writeable) failed: %s",
isc_result_totext(result));
return (ISC_R_UNEXPECTED);
}
1998-11-12 23:30:46 +00:00
rwl->magic = RWLOCK_MAGIC;
1998-11-12 02:02:52 +00:00
return (ISC_R_SUCCESS);
}
isc_result_t
isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
isc_boolean_t skip = ISC_FALSE;
isc_boolean_t done = ISC_FALSE;
1998-11-12 23:30:46 +00:00
REQUIRE(VALID_RWLOCK(rwl));
1998-11-12 02:02:52 +00:00
LOCK(&rwl->lock);
1998-11-12 23:30:46 +00:00
#ifdef ISC_RWLOCK_TRACE
1998-11-12 02:02:52 +00:00
print_lock("prelock", rwl, type);
#endif
if (type == isc_rwlocktype_read) {
if (rwl->readers_waiting != 0)
skip = ISC_TRUE;
while (!done) {
if (!skip &&
((rwl->active == 0 ||
(rwl->type == isc_rwlocktype_read &&
rwl->granted < rwl->read_quota)))) {
rwl->type = isc_rwlocktype_read;
rwl->active++;
rwl->granted++;
done = ISC_TRUE;
} else {
skip = ISC_FALSE;
rwl->readers_waiting++;
WAIT(&rwl->readable, &rwl->lock);
rwl->readers_waiting--;
}
}
} else {
if (rwl->writers_waiting != 0)
skip = ISC_TRUE;
while (!done) {
if (!skip && rwl->active == 0) {
rwl->type = isc_rwlocktype_write;
rwl->active = 1;
1998-11-12 22:27:30 +00:00
rwl->granted++;
1998-11-12 02:02:52 +00:00
done = ISC_TRUE;
} else {
skip = ISC_FALSE;
rwl->writers_waiting++;
WAIT(&rwl->writeable, &rwl->lock);
rwl->writers_waiting--;
}
}
}
1998-11-12 23:30:46 +00:00
#ifdef ISC_RWLOCK_TRACE
1998-11-12 02:02:52 +00:00
print_lock("postlock", rwl, type);
#endif
UNLOCK(&rwl->lock);
return (ISC_R_SUCCESS);
}
isc_result_t
isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
1998-11-12 23:30:46 +00:00
REQUIRE(VALID_RWLOCK(rwl));
1998-11-12 02:02:52 +00:00
LOCK(&rwl->lock);
REQUIRE(rwl->type == type);
1998-11-12 23:30:46 +00:00
#ifdef ISC_RWLOCK_TRACE
1998-11-12 02:02:52 +00:00
print_lock("preunlock", rwl, type);
#endif
rwl->active--;
if (rwl->active == 0) {
if (rwl->type == isc_rwlocktype_read) {
1998-11-12 22:27:30 +00:00
rwl->granted = 0;
1998-11-12 02:02:52 +00:00
if (rwl->writers_waiting > 0) {
rwl->type = isc_rwlocktype_write;
SIGNAL(&rwl->writeable);
} else if (rwl->readers_waiting > 0) {
1998-11-12 22:27:30 +00:00
/* Does this case ever happen? */
1998-11-12 02:02:52 +00:00
BROADCAST(&rwl->readable);
}
} else {
if (rwl->readers_waiting > 0) {
1998-11-12 22:27:30 +00:00
if (rwl->writers_waiting > 0 &&
rwl->granted < rwl->write_quota) {
SIGNAL(&rwl->writeable);
} else {
rwl->granted = 0;
rwl->type = isc_rwlocktype_read;
BROADCAST(&rwl->readable);
}
1998-11-12 02:02:52 +00:00
} else if (rwl->writers_waiting > 0) {
1998-11-12 22:27:30 +00:00
rwl->granted = 0;
1998-11-12 02:02:52 +00:00
SIGNAL(&rwl->writeable);
1998-11-12 23:30:46 +00:00
} else {
rwl->granted = 0;
1998-11-12 02:02:52 +00:00
}
}
} else {
if (rwl->type == isc_rwlocktype_read &&
rwl->writers_waiting == 0 &&
rwl->readers_waiting > 0) {
INSIST(rwl->granted > 0);
rwl->granted--;
SIGNAL(&rwl->readable);
}
}
1998-11-12 23:30:46 +00:00
#ifdef ISC_RWLOCK_TRACE
1998-11-12 02:02:52 +00:00
print_lock("postunlock", rwl, type);
#endif
UNLOCK(&rwl->lock);
return (ISC_R_SUCCESS);
}
void
isc_rwlock_destroy(isc_rwlock_t *rwl) {
1998-11-12 23:30:46 +00:00
REQUIRE(VALID_RWLOCK(rwl));
1998-11-12 02:02:52 +00:00
LOCK(&rwl->lock);
REQUIRE(rwl->active == 0 &&
rwl->readers_waiting == 0 &&
rwl->writers_waiting == 0);
UNLOCK(&rwl->lock);
1998-11-12 23:30:46 +00:00
rwl->magic = 0;
1998-11-12 02:02:52 +00:00
(void)isc_condition_destroy(&rwl->readable);
(void)isc_condition_destroy(&rwl->writeable);
(void)isc_mutex_destroy(&rwl->lock);
}