X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsymbian%2Fsilcsymbianthread.cpp;h=4d08efaf1a1c71d639bddbfe0fcf6d7fd15a2048;hb=b4dc1a71c928fdc0ec885ed5745b0d17b094ff7e;hp=7e134e527d13281ec9880ca8fd69b7595f36e9be;hpb=89e862e5385cdd697feaec6c008e30b599890e4d;p=runtime.git diff --git a/lib/silcutil/symbian/silcsymbianthread.cpp b/lib/silcutil/symbian/silcsymbianthread.cpp index 7e134e52..4d08efaf 100644 --- a/lib/silcutil/symbian/silcsymbianthread.cpp +++ b/lib/silcutil/symbian/silcsymbianthread.cpp @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2006 - 2007 Pekka Riikonen + Copyright (C) 2006 - 2008 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 @@ -17,39 +17,62 @@ */ -#include "silc.h" +#include "silcruntime.h" +#include #include +/************************ Static utility functions **************************/ + +static SilcTls silc_thread_tls_init_shared(SilcTls other); + /**************************** SILC Thread API *******************************/ +extern "C" { + /* Thread structure for Symbian */ -typedef struct { +struct SilcSymbianThread { #ifdef SILC_THREADS SilcThreadStart start_func; void *context; SilcBool waitable; -#else - void *tmp; #endif -} *SilcSymbianThread; + SilcTls tls; +}; /* The actual thread function */ static TInt silc_thread_start(TAny *context) { #ifdef SILC_THREADS - SilcSymbianThread tc = (SilcSymbianThread)context; + SilcSymbianThread *tc = (SilcSymbianThread *)context; SilcThreadStart start_func = tc->start_func; - void *context = tc->context; + void *user_context = tc->context; SilcBool waitable = tc->waitable; + SilcTls tls, other = tc->tls; + void *ret = NULL; silc_free(tc); - /* Call the thread function */ - if (waitable) - silc_thread_exit(start_func(context)); - else - start_func(context); + tls = silc_thread_tls_init_shared(other); + + CTrapCleanup *cs = CTrapCleanup::New(); + if (cs) { + CActiveScheduler *s = new CActiveScheduler; + if(s) { + CActiveScheduler::Install(s); + + /* Call the thread function */ + TRAPD(ret_val, ret = start_func(user_context)); + + delete s; + } + delete cs; + } + + if (tls->tls_variables) + silc_hash_table_free(tls->tls_variables); + silc_free(tls); + silc_thread_exit(ret); #endif return KErrNone; @@ -58,17 +81,18 @@ static TInt silc_thread_start(TAny *context) /* Executed new thread */ SilcThread silc_thread_create(SilcThreadStart start_func, void *context, - bool waitable) + SilcBool waitable) { #ifdef SILC_THREADS - SilcSymbianThread tc; + SilcSymbianThread *tc; RThread *thread; TInt ret; - TBuf<32> name; + char tmp[24]; + SilcUInt16 wname[24]; SILC_LOG_DEBUG(("Creating new thread")); - tc = (SilcSymbianThread)silc_calloc(1, sizeof(*thread)); + tc = (SilcSymbianThread *)silc_calloc(1, sizeof(*tc)); if (!tc) return NULL; tc->start_func = start_func; @@ -76,18 +100,21 @@ SilcThread silc_thread_create(SilcThreadStart start_func, void *context, tc->waitable = waitable; /* Allocate thread */ - thread = new RThread(); + thread = new RThread; if (!thread) { silc_free(tc); return NULL; } /* Create the thread */ - name = (TText *)silc_time_string(0); - ret = thread->Create(name, silc_thread_start, 8192, 4096, 1024 * 1024, - (TAny *)tc); + silc_snprintf(tmp, sizeof(tmp), "thread-%p", tc); + silc_utf8_c2w((const unsigned char *)tmp, strlen(tmp), wname, + sizeof(wname) / sizeof(wname[0])); + TBuf<24> name((unsigned short *)wname); + name.PtrZ(); + ret = thread->Create(name, silc_thread_start, 8192, NULL, tc); if (ret != KErrNone) { - SILC_LOG_ERROR(("Could not create new thread")); + SILC_LOG_ERROR(("Could not create new thread, error %d", ret)); delete thread; silc_free(tc); return NULL; @@ -112,7 +139,7 @@ SilcThread silc_thread_create(SilcThreadStart start_func, void *context, void silc_thread_exit(void *exit_value) { #ifdef SILC_THREADS - RThread().Kill((Tint)exit_value); + RThread().Kill((TInt)exit_value); #endif } @@ -121,7 +148,8 @@ void silc_thread_exit(void *exit_value) SilcThread silc_thread_self(void) { #ifdef SILC_THREADS - return (SilcThread)&RThread(); + RThread thread = RThread(); + return (SilcThread)&thread; #else return NULL; #endif @@ -142,6 +170,15 @@ SilcBool silc_thread_wait(SilcThread thread, void **exit_value) #endif } +/* Yield processor */ + +void silc_thread_yield(void) +{ +#ifdef SILC_THREADS + User::After(1); +#endif /* SILC_THREADS */ +} + /***************************** SILC Mutex API *******************************/ /* SILC Mutex structure */ @@ -200,8 +237,8 @@ void silc_mutex_unlock(SilcMutex mutex) { #ifdef SILC_THREADS if (mutex) { - mutex->mutex->Signal(); mutex->locked = FALSE; + mutex->mutex->Signal(); } #endif /* SILC_THREADS */ } @@ -214,6 +251,92 @@ void silc_mutex_assert_locked(SilcMutex mutex) #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 = (SilcRwLock)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 *******************************/ @@ -282,11 +405,84 @@ SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex, int timeout) { #ifdef SILC_THREADS - if (timeout) - return (cond->cond->TimedWait(*mutex->mutex, (TInt)timeout * 1000) == - KErrNone); + TInt ret; + if (timeout) { + ret = cond->cond->TimedWait(*mutex->mutex, (TInt)timeout * 1000); + if (ret != KErrNone) + SILC_LOG_DEBUG(("TimedWait returned %d", ret)); + return ret != KErrTimedOut; + } return (cond->cond->Wait(*mutex->mutex) == KErrNone); #else return FALSE; #endif /* SILC_THREADS*/ } + +/************************** Thread-local Storage ****************************/ + +SilcTls silc_thread_tls_init(void) +{ + SilcTls tls; + + if (silc_thread_get_tls()) + return silc_thread_get_tls(); + + /* Allocate Tls for the thread */ + tls = (SilcTls)silc_calloc(1, sizeof(*tls)); + if (!tls) + return NULL; + + Dll::SetTls(tls); + + /* Allocate global lock */ + silc_mutex_alloc(&tls->lock); + + return tls; +} + +static SilcTls silc_thread_tls_init_shared(SilcTls other) +{ + SilcTls tls; + + if (silc_thread_get_tls()) + return silc_thread_get_tls(); + + /* Allocate Tls for the thread */ + tls = (SilcTls)silc_calloc(1, sizeof(*tls)); + if (!tls) + return NULL; + + Dll::SetTls(tls); + + /* Take shared data */ + tls->shared_data = 1; + tls->lock = other->lock; + tls->variables = other->variables; + + return tls; +} + +SilcTls silc_thread_get_tls(void) +{ + return STATIC_CAST(SilcTls, Dll::Tls()); +} + +void silc_thread_tls_uninit(void) +{ + SilcTls tls = silc_thread_get_tls(); + + if (!tls || tls->shared_data) + return; + + if (tls->tls_variables) + silc_hash_table_free(tls->tls_variables); + if (tls->variables) + silc_hash_table_free(tls->variables); + if (tls->lock) + silc_mutex_free(tls->lock); + + tls->variables = NULL; + tls->lock = NULL; +} + +} /* extern "C" */