5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 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"
22 /************************ Static utility functions **************************/
24 static SilcTls silc_thread_tls_init_shared(SilcTls other);
26 /**************************** SILC Thread API *******************************/
30 /* Thread structure for WIN32 */
33 SilcThreadStart start_func;
39 /* Actual routine that is called by WIN32 when the thread is created.
40 We will call the start_func from here. When this returns the thread
43 unsigned __stdcall silc_thread_win32_start(void *context)
45 SilcWin32Thread thread = (SilcWin32Thread)context;
46 SilcTls other = thread->tls, tls;
48 tls = silc_thread_tls_init_shared(other);
50 tls->platform_context = thread;
52 silc_thread_exit(thread->start_func(thread->context));
54 if (tls->tls_variables)
55 silc_hash_table_free(tls->tls_variables);
62 SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
66 SilcWin32Thread thread;
69 SILC_LOG_DEBUG(("Creating new thread"));
71 thread = silc_calloc(1, sizeof(*thread));
74 thread->start_func = start_func;
75 thread->context = context;
76 thread->waitable = waitable;
77 thread->tls = silc_thread_get_tls();
79 _beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE)silc_thread_win32_start,
80 (void *)thread, 0, &id);
82 if (!thread->thread) {
83 SILC_LOG_ERROR(("Could not create new thread"));
84 silc_set_errno_reason(SILC_ERR, "Could not create new thread");
89 return (SilcThread)thread;
91 /* Call thread callback immediately */
92 (*start_func)(context);
97 void silc_thread_exit(void *exit_value)
100 SilcTls tls = silc_thread_get_tls();
101 SilcWin32Thread thread = tls->platform_context;
104 /* If the thread is waitable the memory is freed only in silc_thread_wait
105 by another thread. If not waitable, free it now. */
106 if (!thread->waitable)
114 SilcThread silc_thread_self(void)
117 SilcTls tls = silc_thread_get_tls();
118 SilcWin32Thread self = tls->platform_context;
121 /* This should only happen for the main thread. */
122 HANDLE handle = GetCurrentThread ();
123 HANDLE process = GetCurrentProcess ();
124 self = silc_calloc(1, sizeof(*self));
126 DuplicateHandle(process, handle, process,
127 &self->thread, 0, FALSE,
128 DUPLICATE_SAME_ACCESS);
129 tls->platform_context = self;
133 return (SilcThread)self;
139 SilcBool silc_thread_wait(SilcThread thread, void **exit_value)
142 SilcWin32Thread self = (SilcWin32Thread)thread;
144 SILC_LOG_DEBUG(("Waiting for thread %p", self));
149 /* The thread is waitable thus we will free all memory after the
150 WaitForSingleObject returns, the thread is destroyed after that. */
151 WaitForSingleObject(self->thread, INFINITE);
152 CloseHandle(self->thread);
163 void silc_thread_yield(void)
167 #endif /* SILC_THREADS */
171 /***************************** SILC Mutex API *******************************/
173 /* SILC Mutex structure */
174 struct SilcMutexStruct {
176 CRITICAL_SECTION mutex;
177 #endif /* SILC_THREADS */
178 unsigned int locked : 1;
181 SilcBool silc_mutex_alloc(SilcMutex *mutex)
184 *mutex = silc_calloc(1, sizeof(**mutex));
187 InitializeCriticalSection(&((*mutex)->mutex));
191 #endif /* SILC_THREADS */
194 void silc_mutex_free(SilcMutex mutex)
198 DeleteCriticalSection(&mutex->mutex);
201 #endif /* SILC_THREADS */
204 void silc_mutex_lock(SilcMutex mutex)
208 EnterCriticalSection(&mutex->mutex);
209 SILC_ASSERT(mutex->locked == FALSE);
210 mutex->locked = TRUE;
212 #endif /* SILC_THREADS */
215 void silc_mutex_unlock(SilcMutex mutex)
219 SILC_ASSERT(mutex->locked == TRUE);
220 mutex->locked = FALSE;
221 LeaveCriticalSection(&mutex->mutex);
223 #endif /* SILC_THREADS */
226 void silc_mutex_assert_locked(SilcMutex mutex)
230 SILC_ASSERT(mutex->locked);
231 #endif /* SILC_THREADS */
235 /***************************** SILC Rwlock API ******************************/
237 /* SILC read/write lock structure */
238 struct SilcRwLockStruct {
242 #endif /* SILC_THREADS */
243 unsigned int readers : 31;
244 unsigned int locked : 1;
247 SilcBool silc_rwlock_alloc(SilcRwLock *rwlock)
250 *rwlock = silc_calloc(1, sizeof(**rwlock));
253 if (!silc_mutex_alloc(&(*rwlock)->mutex)) {
257 if (!silc_cond_alloc(&(*rwlock)->cond)) {
258 silc_mutex_free((*rwlock)->mutex);
265 #endif /* SILC_THREADS */
268 void silc_rwlock_free(SilcRwLock rwlock)
272 silc_mutex_free(rwlock->mutex);
273 silc_cond_free(rwlock->cond);
276 #endif /* SILC_THREADS */
279 void silc_rwlock_rdlock(SilcRwLock rwlock)
283 silc_mutex_lock(rwlock->mutex);
285 silc_mutex_unlock(rwlock->mutex);
287 #endif /* SILC_THREADS */
290 void silc_rwlock_wrlock(SilcRwLock rwlock)
294 silc_mutex_lock(rwlock->mutex);
295 while (rwlock->readers > 0)
296 silc_cond_wait(rwlock->cond, rwlock->mutex);
297 rwlock->locked = TRUE;
299 #endif /* SILC_THREADS */
302 void silc_rwlock_unlock(SilcRwLock rwlock)
306 if (rwlock->locked) {
308 rwlock->locked = FALSE;
309 silc_mutex_unlock(rwlock->mutex);
314 silc_mutex_lock(rwlock->mutex);
316 silc_cond_broadcast(rwlock->cond);
317 silc_mutex_unlock(rwlock->mutex);
319 #endif /* SILC_THREADS */
323 /**************************** SILC Cond API ******************************/
325 /* SILC Conditional Variable context */
326 struct SilcCondStruct {
329 #endif /* SILC_THREADS*/
330 unsigned int waiters : 23;
331 unsigned int signal : 1;
334 SilcBool silc_cond_alloc(SilcCond *cond)
337 *cond = silc_calloc(1, sizeof(**cond));
340 (*cond)->event = CreateEvent(NULL, TRUE, FALSE, NULL);
344 #endif /* SILC_THREADS*/
347 void silc_cond_free(SilcCond cond)
350 CloseHandle(cond->event);
352 #endif /* SILC_THREADS*/
355 void silc_cond_signal(SilcCond cond)
359 SetEvent(cond->event);
360 #endif /* SILC_THREADS*/
363 void silc_cond_broadcast(SilcCond cond)
367 SetEvent(cond->event);
368 #endif /* SILC_THREADS*/
371 void silc_cond_wait(SilcCond cond, SilcMutex mutex)
374 silc_cond_timedwait(cond, mutex, 0);
375 #endif /* SILC_THREADS*/
378 SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex,
382 DWORD ret, t = INFINITE;
389 silc_mutex_unlock(mutex);
391 ret = WaitForSingleObject(cond->event, t);
393 silc_mutex_lock(mutex);
396 if (ret != WAIT_OBJECT_0)
400 cond->signal = FALSE;
401 ResetEvent(cond->event);
405 #endif /* SILC_THREADS*/
409 /************************** Thread-local Storage ****************************/
413 static DWORD silc_tls;
414 SilcBool silc_tls_set = FALSE;
416 SilcTls silc_thread_tls_init(void)
421 silc_tls = TlsAlloc();
422 if (silc_tls == TLS_OUT_OF_INDEXES) {
423 SILC_LOG_ERROR(("Error creating Thread-local storage"));
430 if (silc_thread_get_tls())
431 return silc_thread_get_tls();
433 /* Allocate Tls for the thread */
434 tls = silc_calloc(1, sizeof(*tls));
436 SILC_LOG_ERROR(("Error allocating Thread-local storage"));
439 TlsSetValue(silc_tls, tls);
441 /* Allocate global lock */
442 silc_mutex_alloc(&tls->lock);
447 static SilcTls silc_thread_tls_init_shared(SilcTls other)
452 silc_tls = TlsAlloc();
453 if (silc_tls == TLS_OUT_OF_INDEXES) {
454 SILC_LOG_ERROR(("Error creating Thread-local storage"));
461 if (silc_thread_get_tls())
462 return silc_thread_get_tls();
464 /* Allocate Tls for the thread */
465 tls = silc_calloc(1, sizeof(*tls));
467 SILC_LOG_ERROR(("Error allocating Thread-local storage"));
470 TlsSetValue(silc_tls, tls);
472 /* Take shared data */
473 tls->shared_data = 1;
474 tls->lock = other->lock;
475 tls->variables = other->variables;
480 SilcTls silc_thread_get_tls(void)
482 return (SilcTls)TlsGetValue(silc_tls);
485 void silc_thread_tls_uninit(void)
487 SilcTls tls = silc_thread_get_tls();
489 if (!tls || tls->shared_data)
492 if (tls->tls_variables)
493 silc_hash_table_free(tls->tls_variables);
495 silc_hash_table_free(tls->variables);
497 silc_mutex_free(tls->lock);
499 tls->variables = NULL;
506 SilcTls tls_ptr = NULL;
508 SilcTls silc_thread_tls_init(void)
510 if (silc_thread_get_tls())
511 return silc_thread_get_tls();
514 memset(tls_ptr, 0, sizeof(*tls_ptr));
518 static SilcTls silc_thread_tls_init_shared(SilcTls other)
520 return silc_thread_tls_init();
523 SilcTls silc_thread_get_tls(void)
528 void silc_thread_tls_uninit(void)
530 if (tls.tls_variables)
531 silc_hash_table_free(tls.tls_variables);
533 silc_hash_table_free(tls.variables);
535 silc_mutex_free(tls.lock);
538 #endif /* SILC_THREADS */