Commit 754576bb authored by Bradley C. Kuszmaul's avatar Bradley C. Kuszmaul Committed by Yoni Fogel

Merge changes from tokudb.2826. Fixes #2826. close[t:2826]

git-svn-id: file:///svn/toku/tokudb@22664 c7de825b-a66e-492c-adef-691d508d4ae1
parent 736342d5
# -*- Mode: Makefile -*- # -*- Mode: Makefile -*-
CPPFLAGS = -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE CPPFLAGS = -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
CPPFLAGS += -I../../toku_include -I.. -I. CPPFLAGS += -I../../toku_include -I.. -I.
CFLAGS = -Wall -Werror -g -O0 -std=c99 OPTFLAGS = -O0
CFLAGS = -W -Wall -Werror -g $(OPTFLAGS) -std=c99
ifeq ($(GCCVERSION),4.4.2) ifeq ($(GCCVERSION),4.4.2)
CFLAGS += -Wno-deprecated CFLAGS += -Wno-deprecated
else ifeq ($(GCCVERSION),4.4.1) else ifeq ($(GCCVERSION),4.4.1)
...@@ -38,6 +39,9 @@ all: $(TARGETS) ...@@ -38,6 +39,9 @@ all: $(TARGETS)
build: $(TARGETS) build: $(TARGETS)
check: $(TARGETS) $(RUNTARGETS); check: $(TARGETS) $(RUNTARGETS);
test-rwlock: OPTFLAGS=-O3
test-rwlock: ../toku_pthread.h
# pwrite4g needs an argument to tell it which directory to write temporary files # pwrite4g needs an argument to tell it which directory to write temporary files
test-pwrite4g.tdbrun: TEST_EXTRA_ARGS=. test-pwrite4g.tdbrun: TEST_EXTRA_ARGS=.
%.tdbrun: % %.tdbrun: %
......
This diff is collapsed.
...@@ -168,6 +168,22 @@ toku_pthread_setspecific(toku_pthread_key_t key, void *data) { ...@@ -168,6 +168,22 @@ toku_pthread_setspecific(toku_pthread_key_t key, void *data) {
return pthread_setspecific(key, data); return pthread_setspecific(key, data);
} }
// Fair readers/writer locks. These are fair (meaning first-come first-served. No reader starvation, and no writer starvation). And they are
// probably faster than the linux readers/writer locks (pthread_rwlock_t).
struct toku_fair_rwlock_waiter_state; // this structure is used internally.
typedef struct toku_fair_rwlock_s {
toku_pthread_mutex_t mutex;
int state; // 0 means no locks, + is number of readers locked, -1 is a writer
struct toku_fair_rwlock_waiter_state *waiters_head, *waiters_tail;
} toku_fair_rwlock_t;
int toku_fair_rwlock_init (toku_fair_rwlock_t *rwlock);
int toku_fair_rwlock_destroy (toku_fair_rwlock_t *rwlock);
int toku_fair_rwlock_rdlock (toku_fair_rwlock_t *rwlock);
int toku_fair_rwlock_wrlock (toku_fair_rwlock_t *rwlock);
int toku_fair_rwlock_unlock (toku_fair_rwlock_t *rwlock);
#if defined(__cplusplus) || defined(__cilkplusplus) #if defined(__cplusplus) || defined(__cilkplusplus)
}; };
#endif #endif
......
/* -*- mode: C; c-basic-offset: 4 -*- */
#ident "$Id$"
#ident "Copyright (c) 2010 Tokutek Inc. All rights reserved."
#include <pthread.h>
#include <toku_assert.h>
#include "toku_pthread.h"
struct toku_fair_rwlock_waiter_state {
char is_read;
struct toku_fair_rwlock_waiter_state *next;
pthread_cond_t cond;
};
static __thread struct toku_fair_rwlock_waiter_state waitstate = {0, NULL, PTHREAD_COND_INITIALIZER };
int toku_fair_rwlock_init (toku_fair_rwlock_t *rwlock) {
rwlock->state=0;
rwlock->waiters_head = NULL;
rwlock->waiters_tail = NULL;
return toku_pthread_mutex_init(&rwlock->mutex, NULL);
}
int toku_fair_rwlock_destroy (toku_fair_rwlock_t *rwlock) {
return toku_pthread_mutex_destroy(&rwlock->mutex);
}
int toku_fair_rwlock_rdlock (toku_fair_rwlock_t *rwlock) {
int r = toku_pthread_mutex_lock(&rwlock->mutex);
assert(r==0);
if (rwlock->waiters_head!=NULL || rwlock->state<0) {
// Someone is ahead of me in the queue, or someone has a lock.
// We use per-thread-state for the condition variable. A thread cannot get control and try to reuse the waiter state for something else.
if (rwlock->waiters_tail) {
rwlock->waiters_tail->next = &waitstate;
} else {
rwlock->waiters_head = &waitstate;
}
rwlock->waiters_tail = &waitstate;
waitstate.next = NULL;
waitstate.is_read = 1;
do {
r = toku_pthread_cond_wait(&waitstate.cond, &rwlock->mutex);
assert(r==0);
} while (rwlock->waiters_head!=&waitstate || rwlock->state<0);
rwlock->state++;
rwlock->waiters_head=waitstate.next;
if (waitstate.next==NULL) rwlock->waiters_tail=NULL;
if (rwlock->waiters_head && rwlock->waiters_head->is_read) {
r = toku_pthread_cond_signal(&rwlock->waiters_head->cond);
assert(r==0);
}
} else {
// No one is waiting, and any holders are readers.
rwlock->state++;
}
r = toku_pthread_mutex_unlock(&rwlock->mutex);
assert(r==0);
return 0;
}
int toku_fair_rwlock_wrlock (toku_fair_rwlock_t *rwlock) {
int r = toku_pthread_mutex_lock(&rwlock->mutex);
assert(r==0);
if (rwlock->waiters_head!=NULL || rwlock->state!=0) {
// Someone else is ahead of me, or someone has a lock the lock, so we must wait our turn.
if (rwlock->waiters_tail) {
rwlock->waiters_tail->next = &waitstate;
} else {
rwlock->waiters_head = &waitstate;
}
rwlock->waiters_tail = &waitstate;
waitstate.next = NULL;
waitstate.is_read = 0;
do {
r = toku_pthread_cond_wait(&waitstate.cond, &rwlock->mutex);
assert(r==0);
} while (rwlock->waiters_head!=&waitstate || rwlock->state!=0);
rwlock->waiters_head = waitstate.next;
if (waitstate.next==NULL) rwlock->waiters_tail=NULL;
}
rwlock->state = -1;
r = toku_pthread_mutex_unlock(&rwlock->mutex);
assert(r==0);
return 0;
}
int toku_fair_rwlock_unlock (toku_fair_rwlock_t *rwlock) {
int r = toku_pthread_mutex_lock(&rwlock->mutex);
assert(r==0);
assert(rwlock->state!=0);
if (rwlock->state>0) {
rwlock->state--;
} else {
rwlock->state=0;
}
if (rwlock->state==0 && rwlock->waiters_head) {
r = toku_pthread_cond_signal(&rwlock->waiters_head->cond);
assert(r==0);
} else {
// printf(" No one to wake\n");
}
r = toku_pthread_mutex_unlock(&rwlock->mutex);
assert(r==0);
return 0;
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
int test_main(int argc, char *const argv[]) { int test_main(int argc __attribute__((__unused__)), char *const argv[] __attribute__((__unused__))) {
int r; int r;
toku_pthread_rwlock_t rwlock; toku_pthread_rwlock_t rwlock;
......
...@@ -15,7 +15,7 @@ static void *f(void *arg) { ...@@ -15,7 +15,7 @@ static void *f(void *arg) {
return arg; return arg;
} }
int test_main(int argc, char *const argv[]) { int test_main(int argc __attribute__((__unused__)), char *const argv[] __attribute__((__unused__))) {
int r; int r;
toku_pthread_rwlock_t rwlock; toku_pthread_rwlock_t rwlock;
toku_pthread_t tid; toku_pthread_t tid;
......
...@@ -37,7 +37,7 @@ check_snprintf(int i) { ...@@ -37,7 +37,7 @@ check_snprintf(int i) {
} }
int test_main(int argc, char *const argv[]) { int test_main(int argc __attribute__((__unused__)), char *const argv[] __attribute__((__unused__))) {
int i; int i;
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
check_snprintf(i); check_snprintf(i);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment