ck_swlock: We shouldn't decrement n_readers when

ck_swlock_read_latchlocks observers a writer if the unlatch
operation sets n_readers to 0.

The unlatch operation now just unsets the latch bit, we can safely
decrement n_readers in ck_swlock_read_latchlocks().

+ Fixes to validation tests & ELIDE coverage.
ck_pring
Jaidev Sridhar 11 years ago
parent 9732e2bdb3
commit 1f03809acb

@ -139,7 +139,13 @@ CK_CC_INLINE static void
ck_swlock_write_unlatch(ck_swlock_t *rw)
{
ck_pr_store_32(&rw->n_readers, 0);
uint32_t snapshot = ck_pr_load_32(&rw->n_readers);
uint32_t delta = snapshot & CK_SWLOCK_READER_BITS;
while (ck_pr_cas_32_value(&rw->n_readers, snapshot, delta, &snapshot) == false) {
delta = snapshot & CK_SWLOCK_READER_BITS;
ck_pr_stall();
}
ck_swlock_write_unlock(rw);
@ -209,14 +215,15 @@ ck_swlock_read_lock(ck_swlock_t *rw)
CK_CC_INLINE static void
ck_swlock_read_latchlock(ck_swlock_t *rw)
{
uint32_t n, w;
for (;;) {
while (ck_pr_load_32(&rw->writer) != 0)
ck_pr_fence_atomic_load();
while ((w = ck_pr_load_32(&rw->writer)) != 0) {
ck_pr_stall();
}
if (ck_pr_faa_32(&rw->n_readers, 1) & CK_SWLOCK_LATCH_BIT) {
/* Writer has latched, stall the reader */
if ((n = ck_pr_faa_32(&rw->n_readers, 1)) & CK_SWLOCK_LATCH_BIT) {
ck_pr_dec_32(&rw->n_readers);
continue;
}
@ -278,7 +285,7 @@ ck_swlock_recursive_write_lock(ck_swlock_recursive_t *rw)
ck_pr_fence_atomic_load();
while (ck_pr_load_32(&rw->rw.n_readers) != 0)
while (ck_pr_load_32(&rw->rw.n_readers) & CK_SWLOCK_READER_BITS != 0)
ck_pr_stall();
rw->wc++;
@ -307,7 +314,7 @@ ck_swlock_recursive_write_trylock(ck_swlock_recursive_t *rw)
ck_pr_fence_atomic_load();
if (ck_pr_load_32(&rw->rw.n_readers) != 0) {
if (ck_pr_load_32(&rw->rw.n_readers) & CK_SWLOCK_READER_BITS != 0) {
ck_pr_store_32(&rw->rw.writer, 0);
return false;
}
@ -331,7 +338,13 @@ ck_swlock_recursive_write_unlock(ck_swlock_recursive_t *rw)
CK_CC_INLINE static void
ck_swlock_recursive_write_unlatch(ck_swlock_recursive_t *rw)
{
ck_pr_store_32(&rw->rw.n_readers, 0);
uint32_t snapshot = ck_pr_load_32(&rw->rw.n_readers);
uint32_t delta = snapshot & CK_SWLOCK_READER_BITS;
while (ck_pr_cas_32_value(&rw->rw.n_readers, snapshot, delta, &snapshot) == false) {
delta = snapshot & CK_SWLOCK_READER_BITS;
ck_pr_stall();
}
ck_swlock_recursive_write_unlock(rw);

@ -14,4 +14,4 @@ clean:
rm -rf *.dSYM *.exe *~ *.o $(OBJECTS)
include ../../../build/regressions.build
CFLAGS+=$(PTHREAD_CFLAGS) -D_GNU_SOURCE -O0
CFLAGS+=$(PTHREAD_CFLAGS) -D_GNU_SOURCE -O0 -g

@ -125,13 +125,222 @@ thread_recursive(void *arg)
return (NULL);
}
#ifdef CK_F_PR_RTM
static void *
thread_rtm_adaptive(void *null CK_CC_UNUSED)
{
unsigned int i = ITERATE;
unsigned int l;
struct ck_elide_config config = CK_ELIDE_CONFIG_DEFAULT_INITIALIZER;
struct ck_elide_stat st = CK_ELIDE_STAT_INITIALIZER;
if (aff_iterate(&a)) {
perror("ERROR: Could not affine thread");
exit(EXIT_FAILURE);
}
while (i--) {
CK_ELIDE_LOCK_ADAPTIVE(ck_swlock_write, &st, &config, &lock);
{
l = ck_pr_load_uint(&locked);
if (l != 0) {
ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l);
}
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
l = ck_pr_load_uint(&locked);
if (l != 8) {
ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l);
}
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
l = ck_pr_load_uint(&locked);
if (l != 0) {
ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l);
}
}
CK_ELIDE_UNLOCK_ADAPTIVE(ck_swlock_write, &st, &lock);
CK_ELIDE_LOCK(ck_swlock_read, &lock);
{
l = ck_pr_load_uint(&locked);
if (l != 0) {
ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l);
}
}
CK_ELIDE_UNLOCK(ck_swlock_read, &lock);
}
return NULL;
}
static void *
thread_rtm_mix(void *null CK_CC_UNUSED)
{
unsigned int i = ITERATE;
unsigned int l;
if (aff_iterate(&a)) {
perror("ERROR: Could not affine thread");
exit(EXIT_FAILURE);
}
while (i--) {
if (i & 1) {
CK_ELIDE_LOCK(ck_swlock_write, &lock);
} else {
ck_swlock_write_lock(&lock);
}
{
l = ck_pr_load_uint(&locked);
if (l != 0) {
ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l);
}
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
l = ck_pr_load_uint(&locked);
if (l != 8) {
ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l);
}
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
l = ck_pr_load_uint(&locked);
if (l != 0) {
ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l);
}
}
if (i & 1) {
CK_ELIDE_UNLOCK(ck_swlock_write, &lock);
} else {
ck_swlock_write_unlock(&lock);
}
if (i & 1) {
CK_ELIDE_LOCK(ck_swlock_read, &lock);
} else {
ck_swlock_read_lock(&lock);
}
{
l = ck_pr_load_uint(&locked);
if (l != 0) {
ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l);
}
}
if (i & 1) {
CK_ELIDE_UNLOCK(ck_swlock_read, &lock);
} else {
ck_swlock_read_unlock(&lock);
}
}
return (NULL);
}
static void *
thread_rtm(void *null CK_CC_UNUSED)
{
unsigned int i = ITERATE;
unsigned int l;
if (aff_iterate(&a)) {
perror("ERROR: Could not affine thread");
exit(EXIT_FAILURE);
}
while (i--) {
CK_ELIDE_LOCK(ck_swlock_write, &lock);
{
l = ck_pr_load_uint(&locked);
if (l != 0) {
ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l);
}
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
ck_pr_inc_uint(&locked);
l = ck_pr_load_uint(&locked);
if (l != 8) {
ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l);
}
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
ck_pr_dec_uint(&locked);
l = ck_pr_load_uint(&locked);
if (l != 0) {
ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l);
}
}
CK_ELIDE_UNLOCK(ck_swlock_write, &lock);
CK_ELIDE_LOCK(ck_swlock_read, &lock);
{
l = ck_pr_load_uint(&locked);
if (l != 0) {
ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l);
}
}
CK_ELIDE_UNLOCK(ck_swlock_read, &lock);
}
return (NULL);
}
#endif /* CK_F_PR_RTM */
static void *
thread(void *arg)
{
unsigned int i = ITERATE;
unsigned int l;
int tid = *(int *) arg;
int tid = ck_pr_load_int(arg);
if (aff_iterate(&a)) {
perror("ERROR: Could not affine thread");
@ -141,6 +350,7 @@ thread(void *arg)
while (i--) {
if (tid == 0) {
/* Writer */
fflush(stdin);
ck_swlock_write_latch(&lock);
{
l = ck_pr_load_uint(&locked);
@ -195,11 +405,12 @@ thread(void *arg)
static void
swlock_test(pthread_t *threads, void *(*f)(void *), const char *test)
{
int i;
int i, tid[nthr];
fprintf(stderr, "Creating threads (%s)...", test);
for (i = 0; i < nthr; i++) {
if (pthread_create(&threads[i], NULL, f, &i)) {
ck_pr_store_int(&tid[i], i);
if (pthread_create(&threads[i], NULL, f, &tid[i])) {
ck_error("ERROR: Could not create thread %d\n", i);
}
}
@ -233,6 +444,12 @@ main(int argc, char *argv[])
a.delta = atoi(argv[2]);
swlock_test(threads, thread, "regular");
#ifdef CK_F_PR_RTM
swlock_test(threads, thread_rtm, "rtm");
swlock_test(threads, thread_rtm_mix, "rtm-mix");
swlock_test(threads, thread_rtm_adaptive, "rtm-adaptive");
#endif
swlock_test(threads, thread_recursive, "recursive");
return 0;
}

Loading…
Cancel
Save