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