X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsymbian%2Fsilcsymbianthread.cpp;h=05a2e893b294a22ed8b72e20ad838e0dc35dda49;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=5d637b423ed6af34307232fdf9d3a18aab63546d;hpb=9905799a86c606304fd7df2cd401de1740a272a1;p=silc.git diff --git a/lib/silcutil/symbian/silcsymbianthread.cpp b/lib/silcutil/symbian/silcsymbianthread.cpp index 5d637b42..05a2e893 100644 --- a/lib/silcutil/symbian/silcsymbianthread.cpp +++ b/lib/silcutil/symbian/silcsymbianthread.cpp @@ -1,270 +1,440 @@ -/* - - silcsymbianthread.cpp - - Author: Pekka Riikonen - - Copyright (C) 2006 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. - -*/ - -#include "silc.h" -#include - -/**************************** SILC Thread API *******************************/ - -/* Thread structure for Symbian */ -typedef struct { -#ifdef SILC_THREADS - RThread *thread; - SilcThreadStart start_func; - void *context; - bool waitable; -#else - void *tmp; -#endif -} *SilcSymbianThread; - -/* The actual thread function */ - -TInt silc_thread_epoc_start(TAny *context) -{ -#ifdef SILC_THREADS - SilcSymbianThread thread = (SilcSymbianThread)context; - void *ret; - - ret = thread->start_func(thread->context); - silc_thread_exit(ret); - -#endif - return 0; -} - -SilcThread silc_thread_create(SilcThreadStart start_func, void *context, - bool waitable) -{ -#ifdef SILC_THREADS - SilcSymbianThread thread; - TInt ret; - TBuf<32> name; - - SILC_LOG_DEBUG(("Creating new thread")); - - thread = (SilcSymbianThread)silc_calloc(1, sizeof(*thread)); - if (!thread) - return NULL; - thread->start_func = start_func; - thread->context = context; - thread->waitable = waitable; - - /* Create the thread */ - /* XXX Unique name should be given for the thread */ - thread->thread = new RThread(); - if (!thread->thread) { - silc_free(thread); - return NULL; - } - - name = (TText *)"silc" + time(NULL); - ret = thread->thread->Create(name, silc_thread_epoc_start, - 8192, 4096, 1024 * 1024, (TAny *)thread); - if (ret != KErrNone) { - SILC_LOG_ERROR(("Could not create new thread")); - delete thread->thread; - silc_free(thread); - return NULL; - } - thread->thread->Resume(); - - return (SilcThread)thread; -#else - /* Call thread callback immediately */ - (*start_func)(context); - return NULL; -#endif -} - -void silc_thread_exit(void *exit_value) -{ -#ifdef SILC_THREADS - /* XXX */ -#endif -} - -SilcThread silc_thread_self(void) -{ -#ifdef SILC_THREADS - /* XXX */ - return NULL; -#else - return NULL; -#endif -} - -SilcBool silc_thread_wait(SilcThread thread, void **exit_value) -{ -#ifdef SILC_THREADS - /* XXX */ - return TRUE; -#else - return FALSE; -#endif -} - -/***************************** SILC Mutex API *******************************/ - -/* SILC Mutex structure */ -struct SilcMutexStruct { -#ifdef SILC_THREADS - RMutex *mutex; -#endif /* SILC_THREADS */ - unsigned int locked : 1; -}; - -SilcBool silc_mutex_alloc(SilcMutex *mutex) -{ -#ifdef SILC_THREADS - *mutex = (SilcMutex)silc_calloc(1, sizeof(**mutex)); - if (*mutex == NULL) - return FALSE; - (*mutex)->mutex = new RMutex(); - if (!(*mutex)->mutex) { - silc_free(*mutex); - return FALSE; - } - if ((*mutex)->mutex->CreateLocal() != KErrNone) { - delete (*mutex)->mutex; - silc_free(*mutex); - return FALSE; - } - (*mutex)->locked = FALSE; - return TRUE; -#else - return FALSE; -#endif /* SILC_THREADS */ -} - -void silc_mutex_free(SilcMutex mutex) -{ -#ifdef SILC_THREADS - if (mutex) { - mutex->mutex->Close(); - delete mutex->mutex; - silc_free(mutex); - } -#endif /* SILC_THREADS */ -} - -void silc_mutex_lock(SilcMutex mutex) -{ -#ifdef SILC_THREADS - if (mutex) { - mutex->mutex->Wait(); - mutex->locked = TRUE; - } -#endif /* SILC_THREADS */ -} - -void silc_mutex_unlock(SilcMutex mutex) -{ -#ifdef SILC_THREADS - if (mutex) { - mutex->mutex->Signal(); - mutex->locked = FALSE; - } -#endif /* SILC_THREADS */ -} - -void silc_mutex_assert_locked(SilcMutex mutex) -{ -#ifdef SILC_THREADS - if (mutex) - SILC_ASSERT(mutex->locked); -#endif /* SILC_THREADS */ -} - - -/****************************** SILC Cond API *******************************/ - -/* SILC Conditional Variable context */ -struct SilcCondStruct { -#ifdef SILC_THREADS - RCondVar *cond; -#else - void *tmp; -#endif /* SILC_THREADS*/ -}; - -SilcBool silc_cond_alloc(SilcCond *cond) -{ -#ifdef SILC_THREADS - *cond = (SilcCond)silc_calloc(1, sizeof(**cond)); - if (*cond == NULL) - return FALSE; - (*cond)->cond = new RCondVar(); - if (!(*cond)->cond) { - silc_free(*cond); - return FALSE; - } - if ((*cond)->cond->CreateLocal() != KErrNone) { - delete (*cond)->cond; - silc_free(*cond); - return FALSE; - } - return TRUE; -#else - return FALSE; -#endif /* SILC_THREADS*/ -} - -void silc_cond_free(SilcCond cond) -{ -#ifdef SILC_THREADS - cond->cond->Close(); - delete cond->cond; - silc_free(cond); -#endif /* SILC_THREADS*/ -} - -void silc_cond_signal(SilcCond cond) -{ -#ifdef SILC_THREADS - cond->cond->Signal(); -#endif /* SILC_THREADS*/ -} - -void silc_cond_broadcast(SilcCond cond) -{ -#ifdef SILC_THREADS - cond->cond->Broadcast(); -#endif /* SILC_THREADS*/ -} - -void silc_cond_wait(SilcCond cond, SilcMutex mutex) -{ -#ifdef SILC_THREADS - cond->cond->Wait(*mutex->mutex); -#endif /* SILC_THREADS*/ -} - -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); - return (cond->cond->Wait(*mutex->mutex) == KErrNone); -#else - return FALSE; -#endif /* SILC_THREADS*/ -} +/* + + silcsymbianthread.cpp + + Author: Pekka Riikonen + + Copyright (C) 2006 - 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. + +*/ + +#include "silc.h" +#include +#include + +/**************************** SILC Thread API *******************************/ + +extern "C" { + +/* Thread structure for Symbian */ +struct SilcSymbianThread { +#ifdef SILC_THREADS + SilcThreadStart start_func; + void *context; + SilcBool waitable; +#else + void *tmp; +#endif +}; + +/* The actual thread function */ + +static TInt silc_thread_start(TAny *context) +{ +#ifdef SILC_THREADS + SilcSymbianThread *tc = (SilcSymbianThread *)context; + SilcThreadStart start_func = tc->start_func; + void *user_context = tc->context; + SilcBool waitable = tc->waitable; + void *ret = NULL; + SilcTls tls; + + silc_free(tc); + + tls = silc_thread_tls_init(); + + 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; + } + + silc_free(tls); + silc_thread_exit(ret); + +#endif + return KErrNone; +} + +/* Executed new thread */ + +SilcThread silc_thread_create(SilcThreadStart start_func, void *context, + SilcBool waitable) +{ +#ifdef SILC_THREADS + SilcSymbianThread *tc; + RThread *thread; + TInt ret; + char tmp[24]; + SilcUInt16 wname[24]; + + SILC_LOG_DEBUG(("Creating new thread")); + + tc = (SilcSymbianThread *)silc_calloc(1, sizeof(*tc)); + if (!tc) + return NULL; + tc->start_func = start_func; + tc->context = context; + tc->waitable = waitable; + + /* Allocate thread */ + thread = new RThread; + if (!thread) { + silc_free(tc); + return NULL; + } + + /* Create the thread */ + 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, error %d", ret)); + delete thread; + silc_free(tc); + return NULL; + } + + /* Start the thread */ + thread->Resume(); + + /* Close our instance to the thread */ + thread->Close(); + + return (SilcThread)thread; +#else + /* Call thread callback immediately */ + (*start_func)(context); + return NULL; +#endif +} + +/* Exits current thread */ + +void silc_thread_exit(void *exit_value) +{ +#ifdef SILC_THREADS + RThread().Kill((TInt)exit_value); +#endif +} + +/* Returns current thread context */ + +SilcThread silc_thread_self(void) +{ +#ifdef SILC_THREADS + RThread thread = RThread(); + return (SilcThread)&thread; +#else + return NULL; +#endif +} + +/* Blocks calling thread to wait for `thread' to finish. */ + +SilcBool silc_thread_wait(SilcThread thread, void **exit_value) +{ +#ifdef SILC_THREADS + TRequestStatus req; + RThread *t = (RThread *)thread; + t->Logon(req); + User::WaitForAnyRequest(); + return TRUE; +#else + return FALSE; +#endif +} + +/* Yield processor */ + +void silc_thread_yield(void) +{ +#ifdef SILC_THREADS + User::After(1); +#endif /* SILC_THREADS */ +} + +/***************************** SILC Mutex API *******************************/ + +/* SILC Mutex structure */ +struct SilcMutexStruct { +#ifdef SILC_THREADS + RMutex *mutex; +#endif /* SILC_THREADS */ + unsigned int locked : 1; +}; + +SilcBool silc_mutex_alloc(SilcMutex *mutex) +{ +#ifdef SILC_THREADS + *mutex = (SilcMutex)silc_calloc(1, sizeof(**mutex)); + if (*mutex == NULL) + return FALSE; + (*mutex)->mutex = new RMutex(); + if (!(*mutex)->mutex) { + silc_free(*mutex); + return FALSE; + } + if ((*mutex)->mutex->CreateLocal() != KErrNone) { + delete (*mutex)->mutex; + silc_free(*mutex); + return FALSE; + } + (*mutex)->locked = FALSE; + return TRUE; +#else + return FALSE; +#endif /* SILC_THREADS */ +} + +void silc_mutex_free(SilcMutex mutex) +{ +#ifdef SILC_THREADS + if (mutex) { + mutex->mutex->Close(); + delete mutex->mutex; + silc_free(mutex); + } +#endif /* SILC_THREADS */ +} + +void silc_mutex_lock(SilcMutex mutex) +{ +#ifdef SILC_THREADS + if (mutex) { + mutex->mutex->Wait(); + mutex->locked = TRUE; + } +#endif /* SILC_THREADS */ +} + +void silc_mutex_unlock(SilcMutex mutex) +{ +#ifdef SILC_THREADS + if (mutex) { + mutex->locked = FALSE; + mutex->mutex->Signal(); + } +#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 = (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 *******************************/ + +/* SILC Conditional Variable context */ +struct SilcCondStruct { +#ifdef SILC_THREADS + RCondVar *cond; +#else + void *tmp; +#endif /* SILC_THREADS*/ +}; + +SilcBool silc_cond_alloc(SilcCond *cond) +{ +#ifdef SILC_THREADS + *cond = (SilcCond)silc_calloc(1, sizeof(**cond)); + if (*cond == NULL) + return FALSE; + (*cond)->cond = new RCondVar(); + if (!(*cond)->cond) { + silc_free(*cond); + return FALSE; + } + if ((*cond)->cond->CreateLocal() != KErrNone) { + delete (*cond)->cond; + silc_free(*cond); + return FALSE; + } + return TRUE; +#else + return FALSE; +#endif /* SILC_THREADS*/ +} + +void silc_cond_free(SilcCond cond) +{ +#ifdef SILC_THREADS + cond->cond->Close(); + delete cond->cond; + silc_free(cond); +#endif /* SILC_THREADS*/ +} + +void silc_cond_signal(SilcCond cond) +{ +#ifdef SILC_THREADS + cond->cond->Signal(); +#endif /* SILC_THREADS*/ +} + +void silc_cond_broadcast(SilcCond cond) +{ +#ifdef SILC_THREADS + cond->cond->Broadcast(); +#endif /* SILC_THREADS*/ +} + +void silc_cond_wait(SilcCond cond, SilcMutex mutex) +{ +#ifdef SILC_THREADS + cond->cond->Wait(*mutex->mutex); +#endif /* SILC_THREADS*/ +} + +SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex, + int timeout) +{ +#ifdef SILC_THREADS + 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); + + return tls; +} + +SilcTls silc_thread_get_tls(void) +{ + return STATIC_CAST(SilcTls, Dll::Tls()); +} + +} /* extern "C" */