5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2007 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.
23 /**************************** SILC Thread API *******************************/
27 /* Thread structure for WIN32 */
30 SilcThreadStart start_func;
35 /* Actual routine that is called by WIN32 when the thread is created.
36 We will call the start_func from here. When this returns the thread
39 unsigned __stdcall silc_thread_win32_start(void *context)
41 SilcWin32Thread thread = (SilcWin32Thread)context;
44 tls = silc_thread_tls_init();
46 tls->platform_context = thread;
48 silc_thread_exit(thread->start_func(thread->context));
56 SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
60 SilcWin32Thread thread;
63 SILC_LOG_DEBUG(("Creating new thread"));
65 thread = silc_calloc(1, sizeof(*thread));
68 thread->start_func = start_func;
69 thread->context = context;
70 thread->waitable = waitable;
72 _beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE)silc_thread_win32_start,
73 (void *)thread, 0, &id);
75 if (!thread->thread) {
76 SILC_LOG_ERROR(("Could not create new thread"));
81 return (SilcThread)thread;
83 /* Call thread callback immediately */
84 (*start_func)(context);
89 void silc_thread_exit(void *exit_value)
92 SilcTls tls = silc_thread_get_tls();
93 SilcWin32Thread thread = tls->platform_context;
96 /* If the thread is waitable the memory is freed only in silc_thread_wait
97 by another thread. If not waitable, free it now. */
98 if (!thread->waitable)
106 SilcThread silc_thread_self(void)
109 SilcTls tls = silc_thread_get_tls();
110 SilcWin32Thread self = tls->platform_context;
113 /* This should only happen for the main thread. */
114 HANDLE handle = GetCurrentThread ();
115 HANDLE process = GetCurrentProcess ();
116 self = silc_calloc(1, sizeof(*self));
118 DuplicateHandle(process, handle, process,
119 &self->thread, 0, FALSE,
120 DUPLICATE_SAME_ACCESS);
121 tls->platform_context = self;
125 return (SilcThread)self;
131 SilcBool silc_thread_wait(SilcThread thread, void **exit_value)
134 SilcWin32Thread self = (SilcWin32Thread)thread;
136 SILC_LOG_DEBUG(("Waiting for thread %p", self));
141 /* The thread is waitable thus we will free all memory after the
142 WaitForSingleObject returns, the thread is destroyed after that. */
143 WaitForSingleObject(self->thread, INFINITE);
144 CloseHandle(self->thread);
155 void silc_thread_yield(void)
159 #endif /* SILC_THREADS */
163 /***************************** SILC Mutex API *******************************/
165 /* SILC Mutex structure */
166 struct SilcMutexStruct {
168 CRITICAL_SECTION mutex;
169 #endif /* SILC_THREADS */
170 unsigned int locked : 1;
173 SilcBool silc_mutex_alloc(SilcMutex *mutex)
176 *mutex = silc_calloc(1, sizeof(**mutex));
179 InitializeCriticalSection(&((*mutex)->mutex));
183 #endif /* SILC_THREADS */
186 void silc_mutex_free(SilcMutex mutex)
190 DeleteCriticalSection(&mutex->mutex);
193 #endif /* SILC_THREADS */
196 void silc_mutex_lock(SilcMutex mutex)
200 EnterCriticalSection(&mutex->mutex);
201 SILC_ASSERT(mutex->locked == FALSE);
202 mutex->locked = TRUE;
204 #endif /* SILC_THREADS */
207 void silc_mutex_unlock(SilcMutex mutex)
211 SILC_ASSERT(mutex->locked == TRUE);
212 mutex->locked = FALSE;
213 LeaveCriticalSection(&mutex->mutex);
215 #endif /* SILC_THREADS */
218 void silc_mutex_assert_locked(SilcMutex mutex)
222 SILC_ASSERT(mutex->locked);
223 #endif /* SILC_THREADS */
227 /***************************** SILC Rwlock API ******************************/
229 /* SILC read/write lock structure */
230 struct SilcRwLockStruct {
234 #endif /* SILC_THREADS */
235 unsigned int readers : 31;
236 unsigned int locked : 1;
239 SilcBool silc_rwlock_alloc(SilcRwLock *rwlock)
242 *rwlock = silc_calloc(1, sizeof(**rwlock));
245 if (!silc_mutex_alloc(&(*rwlock)->mutex)) {
249 if (!silc_cond_alloc(&(*rwlock)->cond)) {
250 silc_mutex_free((*rwlock)->mutex);
257 #endif /* SILC_THREADS */
260 void silc_rwlock_free(SilcRwLock rwlock)
264 silc_mutex_free(rwlock->mutex);
265 silc_cond_free(rwlock->cond);
268 #endif /* SILC_THREADS */
271 void silc_rwlock_rdlock(SilcRwLock rwlock)
275 silc_mutex_lock(rwlock->mutex);
277 silc_mutex_unlock(rwlock->mutex);
279 #endif /* SILC_THREADS */
282 void silc_rwlock_wrlock(SilcRwLock rwlock)
286 silc_mutex_lock(rwlock->mutex);
287 while (rwlock->readers > 0)
288 silc_cond_wait(rwlock->cond, rwlock->mutex);
289 rwlock->locked = TRUE;
291 #endif /* SILC_THREADS */
294 void silc_rwlock_unlock(SilcRwLock rwlock)
298 if (rwlock->locked) {
300 rwlock->locked = FALSE;
301 silc_mutex_unlock(rwlock->mutex);
306 silc_mutex_lock(rwlock->mutex);
308 silc_cond_broadcast(rwlock->cond);
309 silc_mutex_unlock(rwlock->mutex);
311 #endif /* SILC_THREADS */
315 /**************************** SILC Cond API ******************************/
317 /* SILC Conditional Variable context */
318 struct SilcCondStruct {
321 #endif /* SILC_THREADS*/
322 unsigned int waiters : 23;
323 unsigned int signal : 1;
326 SilcBool silc_cond_alloc(SilcCond *cond)
329 *cond = silc_calloc(1, sizeof(**cond));
332 (*cond)->event = CreateEvent(NULL, TRUE, FALSE, NULL);
336 #endif /* SILC_THREADS*/
339 void silc_cond_free(SilcCond cond)
342 CloseHandle(cond->event);
344 #endif /* SILC_THREADS*/
347 void silc_cond_signal(SilcCond cond)
351 SetEvent(cond->event);
352 #endif /* SILC_THREADS*/
355 void silc_cond_broadcast(SilcCond cond)
359 SetEvent(cond->event);
360 #endif /* SILC_THREADS*/
363 void silc_cond_wait(SilcCond cond, SilcMutex mutex)
366 silc_cond_timedwait(cond, mutex, 0);
367 #endif /* SILC_THREADS*/
370 SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex,
374 DWORD ret, t = INFINITE;
381 silc_mutex_unlock(mutex);
383 ret = WaitForSingleObject(cond->event, t);
385 silc_mutex_lock(mutex);
388 if (ret != WAIT_OBJECT_0)
392 cond->signal = FALSE;
393 ResetEvent(cond->event);
397 #endif /* SILC_THREADS*/
401 /************************** Thread-local Storage ****************************/
405 static DWORD silc_tls;
406 SilcBool silc_tls_set = FALSE;
408 SilcTls silc_thread_tls_init(void)
413 silc_tls = TlsAlloc();
414 if (silc_tls == TLS_OUT_OF_INDEXES) {
415 SILC_LOG_ERROR(("Error creating Thread-local storage"));
422 if (silc_thread_get_tls())
423 return silc_thread_get_tls();
425 /* Allocate Tls for the thread */
426 tls = silc_calloc(1, sizeof(*tls));
428 SILC_LOG_ERROR(("Error allocating Thread-local storage"));
432 TlsSetValue(silc_tls, tls);
436 SilcTls silc_thread_get_tls(void)
438 return (SilcTls)TlsGetValue(silc_tls);
444 SilcTls tls_ptr = NULL;
446 SilcTls silc_thread_tls_init(void)
448 if (silc_thread_get_tls())
449 return silc_thread_get_tls();
452 memset(tls_ptr, 0, sizeof(*tls_ptr));
456 SilcTls silc_thread_get_tls(void)
461 #endif /* SILC_THREADS */