From 1bdcfd92033d85d747ddc6fe85f986edba3f43b3 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sun, 1 Jul 2007 16:22:45 +0000 Subject: [PATCH] r13570@catbus: nickm | 2007-06-30 20:41:05 -0400 Implement conditions in compat.c; switch windows to use "critical sections" instead of mutexes. Apparently, mutexes are for IPC and critical sections are for multithreaded. svn:r10716 --- src/common/compat.c | 174 +++++++++++++++++++++++++++++++++++++++++++- src/common/compat.h | 10 +++ 2 files changed, 183 insertions(+), 1 deletion(-) diff --git a/src/common/compat.c b/src/common/compat.c index 49ea1d6b66..62749a4e5f 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -1439,7 +1439,7 @@ tor_gmtime_r(const time_t *timep, struct tm *result) #endif #endif -#ifdef USE_WIN32_THREADS +#if defined(USE_WIN32_THREADS) && 0 /** A generic lock structure for multithreaded builds. */ struct tor_mutex_t { HANDLE handle; @@ -1489,6 +1489,42 @@ tor_get_thread_id(void) { return (unsigned long)GetCurrentThreadId(); } +#elif defined(USE_WIN32_THREADS) +/** A generic lock structure for multithreaded builds. */ +struct tor_mutex_t { + CRITICAL_SECTION mutex; +}; +tor_mutex_t * +tor_mutex_new(void) +{ + void *r + m = tor_malloc_zero(sizeof(tor_mutex_t)); + r = InitializeCriticalSection(&m->mutex); + tor_assert(r != NULL); + return m; +} +void +tor_mutex_free(tor_mutex_t *m) +{ + DeleteCriticalSection(&m->mutex); + tor_free(m); +} +void +tor_mutex_acquire(tor_mutex_t *m) +{ + tor_assert(m); + EnterCriticalSection(&m->mutex); +} +void +tor_mutex_release(tor_mutex_t *m) +{ + LeaveCriticalSection(&m->mutex); +} +unsigned long +tor_get_thread_id(void) +{ + return (unsigned long)GetCurrentThreadId(); +} #elif defined(USE_PTHREADS) /** A generic lock structure for multithreaded builds. */ struct tor_mutex_t { @@ -1562,6 +1598,142 @@ struct tor_mutex_t { }; #endif +/* Condition stuff. DOCDOC */ +#ifdef USE_PTHREADS +struct tor_cond_t { + pthread_cond_t cond; +}; +tor_cond_t * +tor_cond_new(void) +{ + tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t)); + if (pthread_cond_init(&cond->cond, NULL)) { + tor_free(cond); + return NULL; + } + return cond; +} +void +tor_conf_free(tor_cond_t *cond) +{ + tor_assert(cond); + if (pthread_cond_destroy(&cond->cond)) { + log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno)); + return; + } + tor_free(cond); +} +int +tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex) +{ + return pthread_cond_wait(&cond->cond, &mutex->mutex) ? -1 : 0; +} +void +tor_cond_signal_one(tor_cond_t *cond) +{ + pthread_cond_signal(&cond->cond); +} +void +tor_cond_signal_all(tor_cond_t *cond) +{ + pthread_cond_broadcast(&cond->cond); +} +void +tor_threads_init(void) +{ +} +#elif defined(USE_WIN32_THREADS) +static DWORD cond_event_tls_index; +struct tor_cond_t { + CRITICAL_SECTION mutex; + smartlist_t *events; +}; +tor_cond_t * +tor_cond_new(void) +{ + tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t)); + if (!InitializeCriticalSection(&cond->mutex)) { + tor_free(cond); + return NULL; + } + cond->events = smartlist_create(); + return cond; +} +void +tor_cond_free(tor_cond_t *cond) +{ + tor_assert(cond); + DeleteCriticalSection(&cond->mutex); + /* XXXX020 notify? */ + smartlist_free(cond->events); + tor_free(cond); +} +void +tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex) +{ + HANDLE event; + int r; + tor_assert(cond); + tor_assert(mutex); + event = TlsGetValue(cond_event_tls_index); + if (!event) { + event = CreateEvent(0, FALSE, FALSE, NULL); + TlsSetValue(cond_event_tls_index, event); + } + EnterCriticalSection(&cond->mutex); + + tor_assert(WaitForSingleObject(event, 0) == WAIT_TIMEOUT); + tor_assert(!smartlist_isin(cond->events, event)); + smartlist_add(cond->events, event); + + LeaveCriticalSection(&cond->mutex); + + tor_mutex_release(mutex); + r = WaitForSingleObject(event, INFINITE); + tor_mutex_acquire(mutex); + + switch (r) { + case WAIT_OBJECT_0: /* we got the mutex normally. */ + break; + case WAIT_ABANDONED: /* holding thread exited. */ + case WAIT_TIMEOUT: /* Should never happen. */ + tor_assert(0); + break; + case WAIT_FAILED: + log_warn(LD_GENERAL, "Failed to acquire mutex: %d",(int) GetLastError()); + } +} +void +tor_cond_signal_one(tor_cond_t *cond) +{ + HANDLE event; + tor_assert(cond); + + EnterCriticalSection(&cond->mutex); + + if ((event = smartlist_pop_last(cond->events)) + SetEvent(event); + + LeaveCriticalSection(&cond->mutex); +} +void +tor_cond_signal_all(tor_cond_t *cond) +{ + tor_assert(cond); + + EnterCriticalSection(&cond->mutex); + SMARTLIST_FOREACH(cond->events, HANDLE, event, SetEvent(event)); + smartlist_clear(cond->events); + LeaveCriticalSection(&cond->mutex); +} +void +tor_threads_init(void) +{ + cond_event_tls_index = TlsAlloc(); +} +#endif + + /** * On Windows, WSAEWOULDBLOCK is not always correct: when you see it, * you need to ask the socket for its actual errno. Also, you need to diff --git a/src/common/compat.h b/src/common/compat.h index fe07d3254b..121683fcdb 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -360,6 +360,16 @@ unsigned long tor_get_thread_id(void); #define tor_get_thread_id() (1UL) #endif +#ifdef TOR_IS_MULTITHREADED +typedef struct tor_cond_t tor_cond_t; +tor_cond_t *tor_cond_new(void); +void tor_conf_free(tor_cond_t *cond); +int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex); +void tor_cond_signal_one(tor_cond_t *cond); +void tor_cond_signal_all(tor_cond_t *cond); +void tor_threads_init(void); +#endif + /* Platform-specific helpers. */ #ifdef MS_WINDOWS char *format_win32_error(DWORD err);