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 *******************************/
26 SilcThreadStart start_func;
28 } *SilcThreadStartContext;
30 static void *silc_thread_start(void *context)
32 SilcThreadStartContext c = context;
33 SilcThreadStart start_func = c->start_func;
34 void *start_context = c->context;
38 silc_thread_tls_init();
40 return start_func(start_context);
43 SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
47 SilcThreadStartContext c;
52 SILC_LOG_DEBUG(("Creating new thread"));
57 c = silc_calloc(1, sizeof(*c));
60 c->start_func = start_func;
63 if (pthread_attr_init(&attr)) {
64 silc_set_errno_posix(errno);
65 SILC_LOG_ERROR(("Thread error: %s", silc_errno_string(silc_errno)));
70 if (pthread_attr_setdetachstate(&attr,
71 waitable ? PTHREAD_CREATE_JOINABLE :
72 PTHREAD_CREATE_DETACHED)) {
73 silc_set_errno_posix(errno);
74 SILC_LOG_ERROR(("Thread error: %s", silc_errno_string(silc_errno)));
75 pthread_attr_destroy(&attr);
80 ret = pthread_create(&thread, &attr, silc_thread_start, c);
82 silc_set_errno_posix(errno);
83 SILC_LOG_ERROR(("Thread error: %s", silc_errno_string(silc_errno)));
84 pthread_attr_destroy(&attr);
89 pthread_attr_destroy(&attr);
91 SILC_LOG_DEBUG(("Created thread %p", (SilcThread)thread));
93 return (SilcThread)thread;
95 /* Call thread callback immediately */
96 (*start_func)(context);
101 void silc_thread_exit(void *exit_value)
104 pthread_exit(exit_value);
108 SilcThread silc_thread_self(void)
111 pthread_t self = pthread_self();
112 return (SilcThread)self;
118 SilcBool silc_thread_wait(SilcThread thread, void **exit_value)
121 SILC_LOG_DEBUG(("Waiting for thread %p", thread));
122 if (!pthread_join(*(pthread_t *)thread, exit_value))
130 void silc_thread_yield(void)
133 #ifdef HAVE_SCHED_YIELD
135 #endif /* HAVE_SCHED_YIELD */
136 #endif /* SILC_THREADS */
139 /***************************** SILC Mutex API *******************************/
141 /* SILC Mutex structure */
142 struct SilcMutexStruct {
144 pthread_mutex_t mutex;
145 #endif /* SILC_THREADS */
146 unsigned int locked : 1;
149 SilcBool silc_mutex_alloc(SilcMutex *mutex)
152 *mutex = silc_calloc(1, sizeof(**mutex));
155 if (pthread_mutex_init(&(*mutex)->mutex, NULL)) {
156 silc_set_errno_posix(errno);
160 (*mutex)->locked = FALSE;
164 #endif /* SILC_THREADS */
167 void silc_mutex_free(SilcMutex mutex)
171 pthread_mutex_destroy(&mutex->mutex);
174 #endif /* SILC_THREADS */
177 void silc_mutex_lock(SilcMutex mutex)
181 SILC_VERIFY(pthread_mutex_lock(&mutex->mutex) == 0);
182 mutex->locked = TRUE;
184 #endif /* SILC_THREADS */
187 void silc_mutex_unlock(SilcMutex mutex)
191 mutex->locked = FALSE;
192 SILC_VERIFY(pthread_mutex_unlock(&mutex->mutex) == 0);
194 #endif /* SILC_THREADS */
197 void silc_mutex_assert_locked(SilcMutex mutex)
201 SILC_VERIFY(mutex->locked);
202 #endif /* SILC_THREADS */
205 /***************************** SILC Rwlock API ******************************/
207 /* SILC read/write lock structure */
208 struct SilcRwLockStruct {
210 pthread_rwlock_t rwlock;
213 #endif /* SILC_THREADS */
216 SilcBool silc_rwlock_alloc(SilcRwLock *rwlock)
219 *rwlock = silc_calloc(1, sizeof(**rwlock));
222 if (pthread_rwlock_init(&(*rwlock)->rwlock, NULL)) {
223 silc_set_errno_posix(errno);
230 #endif /* SILC_THREADS */
233 void silc_rwlock_free(SilcRwLock rwlock)
237 pthread_rwlock_destroy(&rwlock->rwlock);
240 #endif /* SILC_THREADS */
243 void silc_rwlock_rdlock(SilcRwLock rwlock)
247 pthread_rwlock_rdlock(&rwlock->rwlock);
248 #endif /* SILC_THREADS */
251 void silc_rwlock_wrlock(SilcRwLock rwlock)
255 SILC_VERIFY(pthread_rwlock_wrlock(&rwlock->rwlock) == 0);
256 #endif /* SILC_THREADS */
259 void silc_rwlock_unlock(SilcRwLock rwlock)
263 SILC_VERIFY(pthread_rwlock_unlock(&rwlock->rwlock) == 0);
264 #endif /* SILC_THREADS */
267 /****************************** SILC Cond API *******************************/
269 /* SILC Conditional Variable context */
270 struct SilcCondStruct {
275 #endif /* SILC_THREADS*/
278 SilcBool silc_cond_alloc(SilcCond *cond)
281 *cond = silc_calloc(1, sizeof(**cond));
284 if (pthread_cond_init(&(*cond)->cond, NULL)) {
285 silc_set_errno_posix(errno);
292 #endif /* SILC_THREADS*/
295 void silc_cond_free(SilcCond cond)
298 pthread_cond_destroy(&cond->cond);
300 #endif /* SILC_THREADS*/
303 void silc_cond_signal(SilcCond cond)
306 pthread_cond_signal(&cond->cond);
307 #endif /* SILC_THREADS*/
310 void silc_cond_broadcast(SilcCond cond)
313 pthread_cond_broadcast(&cond->cond);
314 #endif /* SILC_THREADS*/
317 void silc_cond_wait(SilcCond cond, SilcMutex mutex)
320 pthread_cond_wait(&cond->cond, &mutex->mutex);
321 #endif /* SILC_THREADS*/
324 SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex,
330 t.tv_sec = timeout / 1000;
331 t.tv_nsec = (timeout % 1000) * 1000;
332 return pthread_cond_timedwait(&cond->cond, &mutex->mutex, &t) == 0;
335 return pthread_cond_wait(&cond->cond, &mutex->mutex) == 0;
338 #endif /* SILC_THREADS*/
341 /************************** Thread-local Storage ****************************/
343 #if (defined(SILC_THREADS) && defined(HAVE_PTHREAD_KEY_CREATE) && \
344 defined(HAVE_PTHREAD_ONCE))
346 static pthread_key_t key;
347 static pthread_once_t key_once = PTHREAD_ONCE_INIT;
349 static void silc_thread_tls_destructor(void *context)
354 static void silc_thread_tls_alloc(void)
356 if (pthread_key_create(&key, silc_thread_tls_destructor))
357 SILC_LOG_ERROR(("Error creating Thread-local storage"));
360 SilcTls silc_thread_tls_init(void)
364 pthread_once(&key_once, silc_thread_tls_alloc);
366 if (silc_thread_get_tls())
367 return silc_thread_get_tls();
369 /* Allocate Tls for the thread */
370 tls = silc_calloc(1, sizeof(*tls));
372 SILC_LOG_ERROR(("Error allocating Thread-local storage"));
376 pthread_setspecific(key, tls);
380 SilcTls silc_thread_get_tls(void)
382 return pthread_getspecific(key);
388 SilcTls tls_ptr = NULL;
390 SilcTls silc_thread_tls_init(void)
392 if (silc_thread_get_tls())
393 return silc_thread_get_tls();
396 memset(tls_ptr, 0, sizeof(*tls_ptr));
400 SilcTls silc_thread_get_tls(void)