+++ /dev/null
-/*
-
- silcwin32thread.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2001 - 2007 Pekka Riikonen
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
-*/
-/* $Id$ */
-
-#include "silc.h"
-
-/**************************** SILC Thread API *******************************/
-
-#ifdef SILC_THREADS
-
-/* Thread structure for WIN32 */
-typedef struct {
- HANDLE thread;
- SilcThreadStart start_func;
- void *context;
- SilcBool waitable;
-} *SilcWin32Thread;
-
-/* Actual routine that is called by WIN32 when the thread is created.
- We will call the start_func from here. When this returns the thread
- is destroyed. */
-
-unsigned __stdcall silc_thread_win32_start(void *context)
-{
- SilcWin32Thread thread = (SilcWin32Thread)context;
- SilcTls tls;
-
- tls = silc_thread_tls_init();
- if (tls)
- tls->platform_context = thread;
-
- silc_thread_exit(thread->start_func(thread->context));
-
- silc_free(tls);
-
- return 0;
-}
-#endif
-
-SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
- SilcBool waitable)
-{
-#ifdef SILC_THREADS
- SilcWin32Thread thread;
- unsigned id;
-
- SILC_LOG_DEBUG(("Creating new thread"));
-
- thread = silc_calloc(1, sizeof(*thread));
- if (!thread)
- return NULL;
- thread->start_func = start_func;
- thread->context = context;
- thread->waitable = waitable;
- thread->thread =
- _beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE)silc_thread_win32_start,
- (void *)thread, 0, &id);
-
- if (!thread->thread) {
- SILC_LOG_ERROR(("Could not create new thread"));
- silc_set_errno_reason(SILC_ERR, "Could not create new thread");
- silc_free(thread);
- return NULL;
- }
-
- return (SilcThread)thread;
-#else
- /* Call thread callback immediately */
- (*start_func)(context);
- return NULL;
-#endif
-}
-
-void silc_thread_exit(void *exit_value)
-{
-#ifdef SILC_THREADS
- SilcTls tls = silc_thread_get_tls();
- SilcWin32Thread thread = tls->platform_context;
-
- if (thread) {
- /* If the thread is waitable the memory is freed only in silc_thread_wait
- by another thread. If not waitable, free it now. */
- if (!thread->waitable)
- silc_free(thread);
- }
-
- _endthreadex(0);
-#endif
-}
-
-SilcThread silc_thread_self(void)
-{
-#ifdef SILC_THREADS
- SilcTls tls = silc_thread_get_tls();
- SilcWin32Thread self = tls->platform_context;
-
- if (!self) {
- /* This should only happen for the main thread. */
- HANDLE handle = GetCurrentThread ();
- HANDLE process = GetCurrentProcess ();
- self = silc_calloc(1, sizeof(*self));
- if (self) {
- DuplicateHandle(process, handle, process,
- &self->thread, 0, FALSE,
- DUPLICATE_SAME_ACCESS);
- tls->platform_context = self;
- }
- }
-
- return (SilcThread)self;
-#else
- return NULL;
-#endif
-}
-
-SilcBool silc_thread_wait(SilcThread thread, void **exit_value)
-{
-#ifdef SILC_THREADS
- SilcWin32Thread self = (SilcWin32Thread)thread;
-
- SILC_LOG_DEBUG(("Waiting for thread %p", self));
-
- if (!self->waitable)
- return FALSE;
-
- /* The thread is waitable thus we will free all memory after the
- WaitForSingleObject returns, the thread is destroyed after that. */
- WaitForSingleObject(self->thread, INFINITE);
- CloseHandle(self->thread);
-
- if (exit_value)
- *exit_value = NULL;
-
- return TRUE;
-#else
- return FALSE;
-#endif
-}
-
-void silc_thread_yield(void)
-{
-#ifdef SILC_THREADS
- SleepEx (0,0);
-#endif /* SILC_THREADS */
-}
-
-
-/***************************** SILC Mutex API *******************************/
-
-/* SILC Mutex structure */
-struct SilcMutexStruct {
-#ifdef SILC_THREADS
- CRITICAL_SECTION mutex;
-#endif /* SILC_THREADS */
- unsigned int locked : 1;
-};
-
-SilcBool silc_mutex_alloc(SilcMutex *mutex)
-{
-#ifdef SILC_THREADS
- *mutex = silc_calloc(1, sizeof(**mutex));
- if (!(*mutex))
- return FALSE;
- InitializeCriticalSection(&((*mutex)->mutex));
- return TRUE;
-#else
- return FALSE;
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_free(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- DeleteCriticalSection(&mutex->mutex);
- silc_free(mutex);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_lock(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- EnterCriticalSection(&mutex->mutex);
- SILC_ASSERT(mutex->locked == FALSE);
- mutex->locked = TRUE;
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_unlock(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- SILC_ASSERT(mutex->locked == TRUE);
- mutex->locked = FALSE;
- LeaveCriticalSection(&mutex->mutex);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_assert_locked(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex)
- SILC_ASSERT(mutex->locked);
-#endif /* SILC_THREADS */
-}
-
-
-/***************************** SILC Rwlock API ******************************/
-
-/* SILC read/write lock structure */
-struct SilcRwLockStruct {
-#ifdef SILC_THREADS
- SilcMutex mutex;
- SilcCond cond;
-#endif /* SILC_THREADS */
- unsigned int readers : 31;
- unsigned int locked : 1;
-};
-
-SilcBool silc_rwlock_alloc(SilcRwLock *rwlock)
-{
-#ifdef SILC_THREADS
- *rwlock = silc_calloc(1, sizeof(**rwlock));
- if (!(*rwlock))
- return FALSE;
- if (!silc_mutex_alloc(&(*rwlock)->mutex)) {
- silc_free(*rwlock);
- return FALSE;
- }
- if (!silc_cond_alloc(&(*rwlock)->cond)) {
- silc_mutex_free((*rwlock)->mutex);
- silc_free(*rwlock);
- return FALSE;
- }
- return TRUE;
-#else
- return FALSE;
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_free(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock) {
- silc_mutex_free(rwlock->mutex);
- silc_cond_free(rwlock->cond);
- silc_free(rwlock);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_rdlock(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock) {
- silc_mutex_lock(rwlock->mutex);
- rwlock->readers++;
- silc_mutex_unlock(rwlock->mutex);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_wrlock(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock) {
- silc_mutex_lock(rwlock->mutex);
- while (rwlock->readers > 0)
- silc_cond_wait(rwlock->cond, rwlock->mutex);
- rwlock->locked = TRUE;
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_unlock(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock) {
- if (rwlock->locked) {
- /* Unlock writer */
- rwlock->locked = FALSE;
- silc_mutex_unlock(rwlock->mutex);
- return;
- }
-
- /* Unlock reader */
- silc_mutex_lock(rwlock->mutex);
- rwlock->readers--;
- silc_cond_broadcast(rwlock->cond);
- silc_mutex_unlock(rwlock->mutex);
- }
-#endif /* SILC_THREADS */
-}
-
-
-/**************************** SILC Cond API ******************************/
-
-/* SILC Conditional Variable context */
-struct SilcCondStruct {
-#ifdef SILC_THREADS
- HANDLE event;
-#endif /* SILC_THREADS*/
- unsigned int waiters : 23;
- unsigned int signal : 1;
-};
-
-SilcBool silc_cond_alloc(SilcCond *cond)
-{
-#ifdef SILC_THREADS
- *cond = silc_calloc(1, sizeof(**cond));
- if (*cond == NULL)
- return FALSE;
- (*cond)->event = CreateEvent(NULL, TRUE, FALSE, NULL);
- return TRUE;
-#else
- return FALSE;
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_free(SilcCond cond)
-{
-#ifdef SILC_THREADS
- CloseHandle(cond->event);
- silc_free(cond);
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_signal(SilcCond cond)
-{
-#ifdef SILC_THREADS
- cond->signal = TRUE;
- SetEvent(cond->event);
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_broadcast(SilcCond cond)
-{
-#ifdef SILC_THREADS
- cond->signal = TRUE;
- SetEvent(cond->event);
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_wait(SilcCond cond, SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- silc_cond_timedwait(cond, mutex, 0);
-#endif /* SILC_THREADS*/
-}
-
-SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex,
- int timeout)
-{
-#ifdef SILC_THREADS
- DWORD ret, t = INFINITE;
-
- if (timeout)
- t = timeout;
-
- while (TRUE) {
- cond->waiters++;
- silc_mutex_unlock(mutex);
-
- ret = WaitForSingleObject(cond->event, t);
-
- silc_mutex_lock(mutex);
- cond->waiters--;
-
- if (ret != WAIT_OBJECT_0)
- return FALSE;
-
- if (cond->signal) {
- cond->signal = FALSE;
- ResetEvent(cond->event);
- break;
- }
- }
-#endif /* SILC_THREADS*/
- return TRUE;
-}
-
-/************************** Thread-local Storage ****************************/
-
-#ifdef SILC_THREADS
-
-static DWORD silc_tls;
-SilcBool silc_tls_set = FALSE;
-
-SilcTls silc_thread_tls_init(void)
-{
- SilcTls tls;
-
- if (!silc_tls_set) {
- silc_tls = TlsAlloc();
- if (silc_tls == TLS_OUT_OF_INDEXES) {
- SILC_LOG_ERROR(("Error creating Thread-local storage"));
- return NULL;
- }
-
- silc_tls_set = TRUE;
- }
-
- if (silc_thread_get_tls())
- return silc_thread_get_tls();
-
- /* Allocate Tls for the thread */
- tls = silc_calloc(1, sizeof(*tls));
- if (!tls) {
- SILC_LOG_ERROR(("Error allocating Thread-local storage"));
- return NULL;
- }
-
- TlsSetValue(silc_tls, tls);
- return tls;
-}
-
-SilcTls silc_thread_get_tls(void)
-{
- return (SilcTls)TlsGetValue(silc_tls);
-}
-
-#else
-
-SilcTlsStruct tls;
-SilcTls tls_ptr = NULL;
-
-SilcTls silc_thread_tls_init(void)
-{
- if (silc_thread_get_tls())
- return silc_thread_get_tls();
-
- tls_ptr = &tls;
- memset(tls_ptr, 0, sizeof(*tls_ptr));
- return tls_ptr;
-}
-
-SilcTls silc_thread_get_tls(void)
-{
- return tls_ptr;
-}
-
-#endif /* SILC_THREADS */