X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Funix%2Fsilcunixthread.c;h=1f13f6190035fb21786fd543a7e5c1fb695993ea;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=7f52de901daca7baafd9d1c1bca4aaf949e52ad3;hpb=9905799a86c606304fd7df2cd401de1740a272a1;p=silc.git diff --git a/lib/silcutil/unix/silcunixthread.c b/lib/silcutil/unix/silcunixthread.c index 7f52de90..1f13f619 100644 --- a/lib/silcutil/unix/silcunixthread.c +++ b/lib/silcutil/unix/silcunixthread.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2006 Pekka Riikonen + 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 @@ -22,10 +22,29 @@ /**************************** SILC Thread API *******************************/ +typedef struct { + SilcThreadStart start_func; + void *context; +} *SilcThreadStartContext; + +static void *silc_thread_start(void *context) +{ + SilcThreadStartContext c = context; + SilcThreadStart start_func = c->start_func; + void *start_context = c->context; + + silc_free(c); + + silc_thread_tls_init(); + + return start_func(start_context); +} + SilcThread silc_thread_create(SilcThreadStart start_func, void *context, SilcBool waitable) { #ifdef SILC_THREADS + SilcThreadStartContext c; pthread_attr_t attr; pthread_t thread; int ret; @@ -35,24 +54,35 @@ SilcThread silc_thread_create(SilcThreadStart start_func, void *context, if (!start_func) return NULL; + c = silc_calloc(1, sizeof(*c)); + if (!c) + return NULL; + c->start_func = start_func; + c->context = context; + if (pthread_attr_init(&attr)) { - SILC_LOG_ERROR(("Thread error: %s", strerror(errno))); + silc_set_errno_posix(errno); + SILC_LOG_ERROR(("Thread error: %s", silc_errno_string(silc_errno))); + silc_free(c); return NULL; } if (pthread_attr_setdetachstate(&attr, waitable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED)) { - SILC_LOG_ERROR(("Thread error: %s", strerror(errno))); + silc_set_errno_posix(errno); + SILC_LOG_ERROR(("Thread error: %s", silc_errno_string(silc_errno))); pthread_attr_destroy(&attr); + silc_free(c); return NULL; } - ret = pthread_create(&thread, &attr, (void * (*)(void *))start_func, - context); + ret = pthread_create(&thread, &attr, silc_thread_start, c); if (ret) { - SILC_LOG_ERROR(("Thread error: %s", strerror(errno))); + silc_set_errno_posix(errno); + SILC_LOG_ERROR(("Thread error: %s", silc_errno_string(silc_errno))); pthread_attr_destroy(&attr); + silc_free(c); return NULL; } @@ -97,6 +127,14 @@ SilcBool silc_thread_wait(SilcThread thread, void **exit_value) #endif } +void silc_thread_yield(void) +{ +#ifdef SILC_THREADS +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif /* HAVE_SCHED_YIELD */ +#endif /* SILC_THREADS */ +} /***************************** SILC Mutex API *******************************/ @@ -114,7 +152,11 @@ SilcBool silc_mutex_alloc(SilcMutex *mutex) *mutex = silc_calloc(1, sizeof(**mutex)); if (*mutex == NULL) return FALSE; - pthread_mutex_init(&(*mutex)->mutex, NULL); + if (pthread_mutex_init(&(*mutex)->mutex, NULL)) { + silc_set_errno_posix(errno); + silc_free(*mutex); + return FALSE; + } (*mutex)->locked = FALSE; return TRUE; #else @@ -136,8 +178,7 @@ void silc_mutex_lock(SilcMutex mutex) { #ifdef SILC_THREADS if (mutex) { - if (pthread_mutex_lock(&mutex->mutex)) - SILC_ASSERT(FALSE); + SILC_VERIFY(pthread_mutex_lock(&mutex->mutex) == 0); mutex->locked = TRUE; } #endif /* SILC_THREADS */ @@ -147,9 +188,8 @@ void silc_mutex_unlock(SilcMutex mutex) { #ifdef SILC_THREADS if (mutex) { - if (pthread_mutex_unlock(&mutex->mutex)) - SILC_ASSERT(FALSE); mutex->locked = FALSE; + SILC_VERIFY(pthread_mutex_unlock(&mutex->mutex) == 0); } #endif /* SILC_THREADS */ } @@ -158,10 +198,71 @@ void silc_mutex_assert_locked(SilcMutex mutex) { #ifdef SILC_THREADS if (mutex) - SILC_ASSERT(mutex->locked); + SILC_VERIFY(mutex->locked); +#endif /* SILC_THREADS */ +} + +/***************************** SILC Rwlock API ******************************/ + +/* SILC read/write lock structure */ +struct SilcRwLockStruct { +#ifdef SILC_THREADS + pthread_rwlock_t rwlock; +#else + void *tmp; +#endif /* SILC_THREADS */ +}; + +SilcBool silc_rwlock_alloc(SilcRwLock *rwlock) +{ +#ifdef SILC_THREADS + *rwlock = silc_calloc(1, sizeof(**rwlock)); + if (*rwlock == NULL) + return FALSE; + if (pthread_rwlock_init(&(*rwlock)->rwlock, NULL)) { + silc_set_errno_posix(errno); + silc_free(*rwlock); + return FALSE; + } + return TRUE; +#else + return FALSE; +#endif /* SILC_THREADS */ +} + +void silc_rwlock_free(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) { + pthread_rwlock_destroy(&rwlock->rwlock); + silc_free(rwlock); + } +#endif /* SILC_THREADS */ +} + +void silc_rwlock_rdlock(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) + pthread_rwlock_rdlock(&rwlock->rwlock); #endif /* SILC_THREADS */ } +void silc_rwlock_wrlock(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) + SILC_VERIFY(pthread_rwlock_wrlock(&rwlock->rwlock) == 0); +#endif /* SILC_THREADS */ +} + +void silc_rwlock_unlock(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) + SILC_VERIFY(pthread_rwlock_unlock(&rwlock->rwlock) == 0); +#endif /* SILC_THREADS */ +} /****************************** SILC Cond API *******************************/ @@ -180,7 +281,11 @@ SilcBool silc_cond_alloc(SilcCond *cond) *cond = silc_calloc(1, sizeof(**cond)); if (*cond == NULL) return FALSE; - pthread_cond_init(&(*cond)->cond, NULL); + if (pthread_cond_init(&(*cond)->cond, NULL)) { + silc_set_errno_posix(errno); + silc_free(*cond); + return FALSE; + } return TRUE; #else return FALSE; @@ -232,3 +337,69 @@ SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex, return FALSE; #endif /* SILC_THREADS*/ } + +/************************** Thread-local Storage ****************************/ + +#if (defined(SILC_THREADS) && defined(HAVE_PTHREAD_KEY_CREATE) && \ + defined(HAVE_PTHREAD_ONCE)) + +static pthread_key_t key; +static pthread_once_t key_once = PTHREAD_ONCE_INIT; + +static void silc_thread_tls_destructor(void *context) +{ + silc_free(context); +} + +static void silc_thread_tls_alloc(void) +{ + if (pthread_key_create(&key, silc_thread_tls_destructor)) + SILC_LOG_ERROR(("Error creating Thread-local storage")); +} + +SilcTls silc_thread_tls_init(void) +{ + SilcTls tls; + + pthread_once(&key_once, silc_thread_tls_alloc); + + 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; + } + + pthread_setspecific(key, tls); + return tls; +} + +SilcTls silc_thread_get_tls(void) +{ + return pthread_getspecific(key); +} + +#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