diff options
author | unknown <Kristofer.Pettersson@naruto.> | 2007-02-15 14:08:21 +0100 |
---|---|---|
committer | unknown <Kristofer.Pettersson@naruto.> | 2007-02-15 14:08:21 +0100 |
commit | 448f6003f922e0bfc7010bb2733421f76bbd8808 (patch) | |
tree | 3fbd3df81d06cd08059979b9f86ba560b85a843e /mysys/my_wincond.c | |
parent | e5c1656e978894d3c021ce4e702c9e03ef0fe7ca (diff) | |
download | mariadb-git-448f6003f922e0bfc7010bb2733421f76bbd8808.tar.gz |
Bug#25042 OPTIMIZE TABLE cause race condition in IO CACHE SHARE
- The condition variable implementation "lost" a signal to
WaitOnSingleObject when a semaphore was released.
- The signal could be consumed by a new call to pthread_cond_wait
before all waiting threads had awoken.
- The new implementation of pthread_cond_* uses events
instead of semaphores. It also uses an extra lock to protect entry
into new cond wait before the broadcast has finished.
include/my_pthread.h:
- New implementatin of pthread_cond_init. This version uses events
instead of semaphores
mysys/my_wincond.c:
- New implementatin of pthread_cond_init. This version uses events
instead of semaphores
Diffstat (limited to 'mysys/my_wincond.c')
-rw-r--r-- | mysys/my_wincond.c | 149 |
1 files changed, 111 insertions, 38 deletions
diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c index ed8b715cb85..353b2fced4e 100644 --- a/mysys/my_wincond.c +++ b/mysys/my_wincond.c @@ -27,27 +27,48 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) { - cond->waiting=0; - cond->semaphore=CreateSemaphore(NULL,0,0x7FFFFFFF,NullS); - if (!cond->semaphore) + cond->waiting= 0; + InitializeCriticalSection(&cond->lock_waiting); + + cond->events[SIGNAL]= CreateEvent(NULL, /* no security */ + FALSE, /* auto-reset event */ + FALSE, /* non-signaled initially */ + NULL); /* unnamed */ + + /* Create a manual-reset event. */ + cond->events[BROADCAST]= CreateEvent(NULL, /* no security */ + TRUE, /* manual-reset */ + FALSE, /* non-signaled initially */ + NULL); /* unnamed */ + + + cond->broadcast_block_event= CreateEvent(NULL, /* no security */ + TRUE, /* manual-reset */ + TRUE, /* signaled initially */ + NULL); /* unnamed */ + + if( cond->events[SIGNAL] == NULL || + cond->events[BROADCAST] == NULL || + cond->broadcast_block_event == NULL ) return ENOMEM; return 0; } int pthread_cond_destroy(pthread_cond_t *cond) { - return CloseHandle(cond->semaphore) ? 0 : EINVAL; + DeleteCriticalSection(&cond->lock_waiting); + + if (CloseHandle(cond->events[SIGNAL]) == 0 || + CloseHandle(cond->events[BROADCAST]) == 0 || + CloseHandle(cond->broadcast_block_event) == 0) + return EINVAL; + return 0; } int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { - InterlockedIncrement(&cond->waiting); - LeaveCriticalSection(mutex); - WaitForSingleObject(cond->semaphore,INFINITE); - InterlockedDecrement(&cond->waiting); - EnterCriticalSection(mutex); - return 0 ; + return pthread_cond_timedwait(cond,mutex,NULL); } @@ -57,52 +78,104 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, int result; long timeout; union ft64 now; - - GetSystemTimeAsFileTime(&now.ft); - /* - Calculate time left to abstime - - subtract start time from current time(values are in 100ns units) - - convert to millisec by dividing with 10000 - */ - timeout= (long)((abstime->tv.i64 - now.i64) / 10000); - - /* Don't allow the timeout to be negative */ - if (timeout < 0) - timeout= 0L; + if( abstime != NULL ) + { + GetSystemTimeAsFileTime(&now.ft); + + /* + Calculate time left to abstime + - subtract start time from current time(values are in 100ns units) + - convert to millisec by dividing with 10000 + */ + timeout= (long)((abstime->tv.i64 - now.i64) / 10000); + + /* Don't allow the timeout to be negative */ + if (timeout < 0) + timeout= 0L; + + /* + Make sure the calucated timeout does not exceed original timeout + value which could cause "wait for ever" if system time changes + */ + if (timeout > abstime->max_timeout_msec) + timeout= abstime->max_timeout_msec; - /* - Make sure the calucated timeout does not exceed original timeout - value which could cause "wait for ever" if system time changes + } + else + { + /* No time specified; don't expire */ + timeout= INFINITE; + } + + /* + Block access if previous broadcast hasn't finished. + This is just for safety and should normally not + affect the total time spent in this function. */ - if (timeout > abstime->max_timeout_msec) - timeout= abstime->max_timeout_msec; + WaitForSingleObject(cond->broadcast_block_event, INFINITE); + + EnterCriticalSection(&cond->lock_waiting); + cond->waiting++; + LeaveCriticalSection(&cond->lock_waiting); - InterlockedIncrement(&cond->waiting); LeaveCriticalSection(mutex); - result= WaitForSingleObject(cond->semaphore,timeout); - InterlockedDecrement(&cond->waiting); + + result= WaitForMultipleObjects(2, cond->events, FALSE, timeout); + + EnterCriticalSection(&cond->lock_waiting); + cond->waiting--; + + if (cond->waiting == 0 && result == (WAIT_OBJECT_0+BROADCAST)) + { + /* + We're the last waiter to be notified or to stop waiting, so + reset the manual event. + */ + /* Close broadcast gate */ + ResetEvent(cond->events[BROADCAST]); + /* Open block gate */ + SetEvent(cond->broadcast_block_event); + } + LeaveCriticalSection(&cond->lock_waiting); + EnterCriticalSection(mutex); return result == WAIT_TIMEOUT ? ETIMEDOUT : 0; } - int pthread_cond_signal(pthread_cond_t *cond) { - long prev_count; - if (cond->waiting) - ReleaseSemaphore(cond->semaphore,1,&prev_count); + EnterCriticalSection(&cond->lock_waiting); + + if(cond->waiting > 0) + SetEvent(cond->events[SIGNAL]); + + LeaveCriticalSection(&cond->lock_waiting); + return 0; } int pthread_cond_broadcast(pthread_cond_t *cond) { - long prev_count; - if (cond->waiting) - ReleaseSemaphore(cond->semaphore,cond->waiting,&prev_count); - return 0 ; + EnterCriticalSection(&cond->lock_waiting); + /* + The mutex protect us from broadcasting if + there isn't any thread waiting to open the + block gate after this call has closed it. + */ + if(cond->waiting > 0) + { + /* Close block gate */ + ResetEvent(cond->broadcast_block_event); + /* Open broadcast gate */ + SetEvent(cond->events[BROADCAST]); + } + + LeaveCriticalSection(&cond->lock_waiting); + + return 0; } |