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