Clear locked flag before unlocking mutex, not after.
[crypto.git] / lib / silcutil / symbian / silcsymbianthread.cpp
1 /*
2
3   silcsymbianthread.cpp
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2006 - 2007 Pekka Riikonen
8
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.
12
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.
17
18 */
19
20 #include "silc.h"
21 #include <e32base.h>
22 #include <e32std.h>
23
24 /**************************** SILC Thread API *******************************/
25
26 extern "C" {
27
28 /* Thread structure for Symbian */
29 struct SilcSymbianThread {
30 #ifdef SILC_THREADS
31   SilcThreadStart start_func;
32   void *context;
33   SilcBool waitable;
34 #else
35   void *tmp;
36 #endif
37 };
38
39 /* The actual thread function */
40
41 static TInt silc_thread_start(TAny *context)
42 {
43 #ifdef SILC_THREADS
44   SilcSymbianThread *tc = (SilcSymbianThread *)context;
45   SilcThreadStart start_func = tc->start_func;
46   void *user_context = tc->context;
47   SilcBool waitable = tc->waitable;
48   void *ret = NULL;
49
50   silc_free(tc);
51
52   CTrapCleanup *cs = CTrapCleanup::New();
53   if (cs) {
54     CActiveScheduler *s = new CActiveScheduler;
55     if(s) {
56       CActiveScheduler::Install(s);
57
58       /* Call the thread function */
59       TRAPD(ret_val, ret = start_func(user_context));
60
61       delete s;
62     }
63     delete cs;
64   }
65
66   silc_thread_exit(ret);
67
68 #endif
69   return KErrNone;
70 }
71
72 /* Executed new thread */
73
74 SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
75                               SilcBool waitable)
76 {
77 #ifdef SILC_THREADS
78   SilcSymbianThread *tc;
79   RThread *thread;
80   TInt ret;
81   char tmp[24];
82   SilcUInt16 wname[24];
83
84   SILC_LOG_DEBUG(("Creating new thread"));
85
86   tc = (SilcSymbianThread *)silc_calloc(1, sizeof(*tc));
87   if (!tc)
88     return NULL;
89   tc->start_func = start_func;
90   tc->context = context;
91   tc->waitable = waitable;
92
93   /* Allocate thread */
94   thread = new RThread;
95   if (!thread) {
96     silc_free(tc);
97     return NULL;
98   }
99
100   /* Create the thread */
101   silc_snprintf(tmp, sizeof(tmp), "thread-%p", tc);
102   silc_utf8_c2w((const unsigned char *)tmp, strlen(tmp), wname,
103                 sizeof(wname) / sizeof(wname[0]));
104   TBuf<24> name((unsigned short *)wname);
105   name.PtrZ();
106   ret = thread->Create(name, silc_thread_start, 8192, NULL, tc);
107   if (ret != KErrNone) {
108     SILC_LOG_ERROR(("Could not create new thread, error %d", ret));
109     delete thread;
110     silc_free(tc);
111     return NULL;
112   }
113
114   /* Start the thread */
115   thread->Resume();
116
117   /* Close our instance to the thread */
118   thread->Close();
119
120   return (SilcThread)thread;
121 #else
122   /* Call thread callback immediately */
123   (*start_func)(context);
124   return NULL;
125 #endif
126 }
127
128 /* Exits current thread */
129
130 void silc_thread_exit(void *exit_value)
131 {
132 #ifdef SILC_THREADS
133   RThread().Kill((TInt)exit_value);
134 #endif
135 }
136
137 /* Returns current thread context */
138
139 SilcThread silc_thread_self(void)
140 {
141 #ifdef SILC_THREADS
142   RThread thread = RThread();
143   return (SilcThread)&thread;
144 #else
145   return NULL;
146 #endif
147 }
148
149 /* Blocks calling thread to wait for `thread' to finish. */
150
151 SilcBool silc_thread_wait(SilcThread thread, void **exit_value)
152 {
153 #ifdef SILC_THREADS
154   TRequestStatus req;
155   RThread *t = (RThread *)thread;
156   t->Logon(req);
157   User::WaitForAnyRequest();
158   return TRUE;
159 #else
160   return FALSE;
161 #endif
162 }
163
164 /* Yield processor */
165
166 void silc_thread_yield(void)
167 {
168 #ifdef SILC_THREADS
169   User::After(1);
170 #endif /* SILC_THREADS */
171 }
172
173 /***************************** SILC Mutex API *******************************/
174
175 /* SILC Mutex structure */
176 struct SilcMutexStruct {
177 #ifdef SILC_THREADS
178   RMutex *mutex;
179 #endif /* SILC_THREADS */
180   unsigned int locked : 1;
181 };
182
183 SilcBool silc_mutex_alloc(SilcMutex *mutex)
184 {
185 #ifdef SILC_THREADS
186   *mutex = (SilcMutex)silc_calloc(1, sizeof(**mutex));
187   if (*mutex == NULL)
188     return FALSE;
189   (*mutex)->mutex = new RMutex();
190   if (!(*mutex)->mutex) {
191     silc_free(*mutex);
192     return FALSE;
193   }
194   if ((*mutex)->mutex->CreateLocal() != KErrNone) {
195     delete (*mutex)->mutex;
196     silc_free(*mutex);
197     return FALSE;
198   }
199   (*mutex)->locked = FALSE;
200   return TRUE;
201 #else
202   return FALSE;
203 #endif /* SILC_THREADS */
204 }
205
206 void silc_mutex_free(SilcMutex mutex)
207 {
208 #ifdef SILC_THREADS
209   if (mutex) {
210     mutex->mutex->Close();
211     delete mutex->mutex;
212     silc_free(mutex);
213   }
214 #endif /* SILC_THREADS */
215 }
216
217 void silc_mutex_lock(SilcMutex mutex)
218 {
219 #ifdef SILC_THREADS
220   if (mutex) {
221     mutex->mutex->Wait();
222     mutex->locked = TRUE;
223   }
224 #endif /* SILC_THREADS */
225 }
226
227 void silc_mutex_unlock(SilcMutex mutex)
228 {
229 #ifdef SILC_THREADS
230   if (mutex) {
231     mutex->locked = FALSE;
232     mutex->mutex->Signal();
233   }
234 #endif /* SILC_THREADS */
235 }
236
237 void silc_mutex_assert_locked(SilcMutex mutex)
238 {
239 #ifdef SILC_THREADS
240   if (mutex)
241     SILC_ASSERT(mutex->locked);
242 #endif /* SILC_THREADS */
243 }
244
245 /***************************** SILC Rwlock API *****************************/
246
247 /* SILC read/write lock structure */
248 struct SilcRwLockStruct {
249 #ifdef SILC_THREADS
250   SilcMutex mutex;
251   SilcCond cond;
252 #endif /* SILC_THREADS */
253   unsigned int readers : 31;
254   unsigned int locked  : 1;
255 };
256
257 SilcBool silc_rwlock_alloc(SilcRwLock *rwlock)
258 {
259 #ifdef SILC_THREADS
260   *rwlock = (SilcRwLock)silc_calloc(1, sizeof(**rwlock));
261   if (!(*rwlock))
262     return FALSE;
263   if (!silc_mutex_alloc(&(*rwlock)->mutex)) {
264     silc_free(*rwlock);
265     return FALSE;
266   }
267   if (!silc_cond_alloc(&(*rwlock)->cond)) {
268     silc_mutex_free((*rwlock)->mutex);
269     silc_free(*rwlock);
270     return FALSE;
271   }
272   return TRUE;
273 #else
274   return FALSE;
275 #endif /* SILC_THREADS */
276 }
277
278 void silc_rwlock_free(SilcRwLock rwlock)
279 {
280 #ifdef SILC_THREADS
281   if (rwlock) {
282     silc_mutex_free(rwlock->mutex);
283     silc_cond_free(rwlock->cond);
284     silc_free(rwlock);
285   }
286 #endif /* SILC_THREADS */
287 }
288
289 void silc_rwlock_rdlock(SilcRwLock rwlock)
290 {
291 #ifdef SILC_THREADS
292   if (rwlock) {
293     silc_mutex_lock(rwlock->mutex);
294     rwlock->readers++;
295     silc_mutex_unlock(rwlock->mutex);
296   }
297 #endif /* SILC_THREADS */
298 }
299
300 void silc_rwlock_wrlock(SilcRwLock rwlock)
301 {
302 #ifdef SILC_THREADS
303   if (rwlock) {
304     silc_mutex_lock(rwlock->mutex);
305     while (rwlock->readers > 0)
306       silc_cond_wait(rwlock->cond, rwlock->mutex);
307     rwlock->locked = TRUE;
308   }
309 #endif /* SILC_THREADS */
310 }
311
312 void silc_rwlock_unlock(SilcRwLock rwlock)
313 {
314 #ifdef SILC_THREADS
315   if (rwlock) {
316     if (rwlock->locked) {
317       /* Unlock writer */
318       rwlock->locked = FALSE;
319       silc_mutex_unlock(rwlock->mutex);
320       return;
321     }
322
323     /* Unlock reader */
324     silc_mutex_lock(rwlock->mutex);
325     rwlock->readers--;
326     silc_cond_broadcast(rwlock->cond);
327     silc_mutex_unlock(rwlock->mutex);
328   }
329 #endif /* SILC_THREADS */
330 }
331
332 /****************************** SILC Cond API *******************************/
333
334 /* SILC Conditional Variable context */
335 struct SilcCondStruct {
336 #ifdef SILC_THREADS
337   RCondVar *cond;
338 #else
339   void *tmp;
340 #endif /* SILC_THREADS*/
341 };
342
343 SilcBool silc_cond_alloc(SilcCond *cond)
344 {
345 #ifdef SILC_THREADS
346   *cond = (SilcCond)silc_calloc(1, sizeof(**cond));
347   if (*cond == NULL)
348     return FALSE;
349   (*cond)->cond = new RCondVar();
350   if (!(*cond)->cond) {
351     silc_free(*cond);
352     return FALSE;
353   }
354   if ((*cond)->cond->CreateLocal() != KErrNone) {
355     delete (*cond)->cond;
356     silc_free(*cond);
357     return FALSE;
358   }
359   return TRUE;
360 #else
361   return FALSE;
362 #endif /* SILC_THREADS*/
363 }
364
365 void silc_cond_free(SilcCond cond)
366 {
367 #ifdef SILC_THREADS
368   cond->cond->Close();
369   delete cond->cond;
370   silc_free(cond);
371 #endif /* SILC_THREADS*/
372 }
373
374 void silc_cond_signal(SilcCond cond)
375 {
376 #ifdef SILC_THREADS
377   cond->cond->Signal();
378 #endif /* SILC_THREADS*/
379 }
380
381 void silc_cond_broadcast(SilcCond cond)
382 {
383 #ifdef SILC_THREADS
384   cond->cond->Broadcast();
385 #endif /* SILC_THREADS*/
386 }
387
388 void silc_cond_wait(SilcCond cond, SilcMutex mutex)
389 {
390 #ifdef SILC_THREADS
391   cond->cond->Wait(*mutex->mutex);
392 #endif /* SILC_THREADS*/
393 }
394
395 SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex,
396                              int timeout)
397 {
398 #ifdef SILC_THREADS
399   TInt ret;
400   if (timeout) {
401     ret = cond->cond->TimedWait(*mutex->mutex, (TInt)timeout * 1000);
402     if (ret != KErrNone)
403       SILC_LOG_DEBUG(("TimedWait returned %d", ret));
404     return ret != KErrTimedOut;
405   }
406   return (cond->cond->Wait(*mutex->mutex) == KErrNone);
407 #else
408   return FALSE;
409 #endif /* SILC_THREADS*/
410 }
411
412 } /* extern "C" */