5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2006 - 2008 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 #include "silcruntime.h"
24 /************************ Static utility functions **************************/
26 static SilcTls silc_thread_tls_init_shared(SilcTls other);
28 /**************************** SILC Thread API *******************************/
32 /* Thread structure for Symbian */
33 struct SilcSymbianThread {
35 SilcThreadStart start_func;
42 /* The actual thread function */
44 static TInt silc_thread_start(TAny *context)
47 SilcSymbianThread *tc = (SilcSymbianThread *)context;
48 SilcThreadStart start_func = tc->start_func;
49 void *user_context = tc->context;
50 SilcBool waitable = tc->waitable;
51 SilcTls tls, other = tc->tls;
56 tls = silc_thread_tls_init_shared(other);
58 CTrapCleanup *cs = CTrapCleanup::New();
60 CActiveScheduler *s = new CActiveScheduler;
62 CActiveScheduler::Install(s);
64 /* Call the thread function */
65 TRAPD(ret_val, ret = start_func(user_context));
72 if (tls->tls_variables)
73 silc_hash_table_free(tls->tls_variables);
75 silc_thread_exit(ret);
81 /* Executed new thread */
83 SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
87 SilcSymbianThread *tc;
93 SILC_LOG_DEBUG(("Creating new thread"));
95 tc = (SilcSymbianThread *)silc_calloc(1, sizeof(*tc));
98 tc->start_func = start_func;
99 tc->context = context;
100 tc->waitable = waitable;
102 /* Allocate thread */
103 thread = new RThread;
109 /* Create the thread */
110 silc_snprintf(tmp, sizeof(tmp), "thread-%p", tc);
111 silc_utf8_c2w((const unsigned char *)tmp, strlen(tmp), wname,
112 sizeof(wname) / sizeof(wname[0]));
113 TBuf<24> name((unsigned short *)wname);
115 ret = thread->Create(name, silc_thread_start, 8192, NULL, tc);
116 if (ret != KErrNone) {
117 SILC_LOG_ERROR(("Could not create new thread, error %d", ret));
123 /* Start the thread */
126 /* Close our instance to the thread */
129 return (SilcThread)thread;
131 /* Call thread callback immediately */
132 (*start_func)(context);
137 /* Exits current thread */
139 void silc_thread_exit(void *exit_value)
142 RThread().Kill((TInt)exit_value);
146 /* Returns current thread context */
148 SilcThread silc_thread_self(void)
151 RThread thread = RThread();
152 return (SilcThread)&thread;
158 /* Blocks calling thread to wait for `thread' to finish. */
160 SilcBool silc_thread_wait(SilcThread thread, void **exit_value)
164 RThread *t = (RThread *)thread;
166 User::WaitForAnyRequest();
173 /* Yield processor */
175 void silc_thread_yield(void)
179 #endif /* SILC_THREADS */
182 /***************************** SILC Mutex API *******************************/
184 /* SILC Mutex structure */
185 struct SilcMutexStruct {
188 #endif /* SILC_THREADS */
189 unsigned int locked : 1;
192 SilcBool silc_mutex_alloc(SilcMutex *mutex)
195 *mutex = (SilcMutex)silc_calloc(1, sizeof(**mutex));
198 (*mutex)->mutex = new RMutex();
199 if (!(*mutex)->mutex) {
203 if ((*mutex)->mutex->CreateLocal() != KErrNone) {
204 delete (*mutex)->mutex;
208 (*mutex)->locked = FALSE;
212 #endif /* SILC_THREADS */
215 void silc_mutex_free(SilcMutex mutex)
219 mutex->mutex->Close();
223 #endif /* SILC_THREADS */
226 void silc_mutex_lock(SilcMutex mutex)
230 mutex->mutex->Wait();
231 mutex->locked = TRUE;
233 #endif /* SILC_THREADS */
236 void silc_mutex_unlock(SilcMutex mutex)
240 mutex->locked = FALSE;
241 mutex->mutex->Signal();
243 #endif /* SILC_THREADS */
246 void silc_mutex_assert_locked(SilcMutex mutex)
250 SILC_ASSERT(mutex->locked);
251 #endif /* SILC_THREADS */
254 /***************************** SILC Rwlock API *****************************/
256 /* SILC read/write lock structure */
257 struct SilcRwLockStruct {
261 #endif /* SILC_THREADS */
262 unsigned int readers : 31;
263 unsigned int locked : 1;
266 SilcBool silc_rwlock_alloc(SilcRwLock *rwlock)
269 *rwlock = (SilcRwLock)silc_calloc(1, sizeof(**rwlock));
272 if (!silc_mutex_alloc(&(*rwlock)->mutex)) {
276 if (!silc_cond_alloc(&(*rwlock)->cond)) {
277 silc_mutex_free((*rwlock)->mutex);
284 #endif /* SILC_THREADS */
287 void silc_rwlock_free(SilcRwLock rwlock)
291 silc_mutex_free(rwlock->mutex);
292 silc_cond_free(rwlock->cond);
295 #endif /* SILC_THREADS */
298 void silc_rwlock_rdlock(SilcRwLock rwlock)
302 silc_mutex_lock(rwlock->mutex);
304 silc_mutex_unlock(rwlock->mutex);
306 #endif /* SILC_THREADS */
309 void silc_rwlock_wrlock(SilcRwLock rwlock)
313 silc_mutex_lock(rwlock->mutex);
314 while (rwlock->readers > 0)
315 silc_cond_wait(rwlock->cond, rwlock->mutex);
316 rwlock->locked = TRUE;
318 #endif /* SILC_THREADS */
321 void silc_rwlock_unlock(SilcRwLock rwlock)
325 if (rwlock->locked) {
327 rwlock->locked = FALSE;
328 silc_mutex_unlock(rwlock->mutex);
333 silc_mutex_lock(rwlock->mutex);
335 silc_cond_broadcast(rwlock->cond);
336 silc_mutex_unlock(rwlock->mutex);
338 #endif /* SILC_THREADS */
341 /****************************** SILC Cond API *******************************/
343 /* SILC Conditional Variable context */
344 struct SilcCondStruct {
349 #endif /* SILC_THREADS*/
352 SilcBool silc_cond_alloc(SilcCond *cond)
355 *cond = (SilcCond)silc_calloc(1, sizeof(**cond));
358 (*cond)->cond = new RCondVar();
359 if (!(*cond)->cond) {
363 if ((*cond)->cond->CreateLocal() != KErrNone) {
364 delete (*cond)->cond;
371 #endif /* SILC_THREADS*/
374 void silc_cond_free(SilcCond cond)
380 #endif /* SILC_THREADS*/
383 void silc_cond_signal(SilcCond cond)
386 cond->cond->Signal();
387 #endif /* SILC_THREADS*/
390 void silc_cond_broadcast(SilcCond cond)
393 cond->cond->Broadcast();
394 #endif /* SILC_THREADS*/
397 void silc_cond_wait(SilcCond cond, SilcMutex mutex)
400 cond->cond->Wait(*mutex->mutex);
401 #endif /* SILC_THREADS*/
404 SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex,
410 ret = cond->cond->TimedWait(*mutex->mutex, (TInt)timeout * 1000);
412 SILC_LOG_DEBUG(("TimedWait returned %d", ret));
413 return ret != KErrTimedOut;
415 return (cond->cond->Wait(*mutex->mutex) == KErrNone);
418 #endif /* SILC_THREADS*/
421 /************************** Thread-local Storage ****************************/
423 SilcTls silc_thread_tls_init(void)
427 if (silc_thread_get_tls())
428 return silc_thread_get_tls();
430 /* Allocate Tls for the thread */
431 tls = (SilcTls)silc_calloc(1, sizeof(*tls));
437 /* Allocate global lock */
438 silc_mutex_alloc(&tls->lock);
443 static SilcTls silc_thread_tls_init_shared(SilcTls other)
447 if (silc_thread_get_tls())
448 return silc_thread_get_tls();
450 /* Allocate Tls for the thread */
451 tls = (SilcTls)silc_calloc(1, sizeof(*tls));
457 /* Take shared data */
458 tls->shared_data = 1;
459 tls->lock = other->lock;
460 tls->variables = other->variables;
465 SilcTls silc_thread_get_tls(void)
467 return STATIC_CAST(SilcTls, Dll::Tls());
470 void silc_thread_tls_uninit(void)
472 SilcTls tls = silc_thread_get_tls();
474 if (!tls || tls->shared_data)
477 if (tls->tls_variables)
478 silc_hash_table_free(tls->tls_variables);
480 silc_hash_table_free(tls->variables);
482 silc_mutex_free(tls->lock);
484 tls->variables = NULL;