Add Tizen 2.0 packaging
[profile/ivi/eina.git] / src / include / eina_inline_lock_win32.x
1 /* EINA - EFL data type library
2  * Copyright (C) 2011 Vincent Torri
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library;
16  * if not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifndef EINA_INLINE_LOCK_WIN32_X_
20 #define EINA_INLINE_LOCK_WIN32_X_
21
22 #ifdef EINA_UNUSED
23 # undef EINA_UNUSED
24 #endif
25 #ifdef __GNUC__
26 # define EINA_UNUSED __attribute__((unused))
27 #else
28 # define EINA_UNUSED
29 #endif
30
31 #include <windows.h>
32
33 typedef CRITICAL_SECTION       Eina_Lock;
34 typedef struct _Eina_Condition Eina_Condition;
35 typedef struct _Eina_RWLock    Eina_RWLock;
36 typedef DWORD                  Eina_TLS;
37 typedef HANDLE                 Eina_Semaphore;
38
39 #if _WIN32_WINNT >= 0x0600
40 struct _Eina_Condition
41 {
42    CRITICAL_SECTION  *mutex;
43    CONDITION_VARIABLE condition;
44 };
45
46 struct _Eina_RWLock
47 {
48    SRWLOCK  mutex;
49
50   Eina_Bool is_read_mode : 1;
51 };
52 #else
53 struct _Eina_Condition
54 {
55    int               waiters_count;
56    CRITICAL_SECTION  waiters_count_lock;
57    CRITICAL_SECTION *mutex;
58    HANDLE            semaphore;
59    HANDLE            waiters_done;
60    Eina_Bool         was_broadcast;
61 };
62
63 struct _Eina_RWLock
64 {
65    LONG           readers_count;
66    LONG           writers_count;
67    int            readers;
68    int            writers;
69
70    Eina_Lock      mutex;
71    Eina_Condition cond_read;
72    Eina_Condition cond_write;
73 };
74 #endif
75
76
77 EAPI extern Eina_Bool _eina_threads_activated;
78
79
80 static inline Eina_Bool
81 eina_lock_new(Eina_Lock *mutex)
82 {
83    InitializeCriticalSection(mutex);
84
85    return EINA_TRUE;
86 }
87
88 static inline void
89 eina_lock_free(Eina_Lock *mutex)
90 {
91    DeleteCriticalSection(mutex);
92 }
93
94 static inline Eina_Lock_Result
95 eina_lock_take(Eina_Lock *mutex)
96 {
97 #ifdef EINA_HAVE_ON_OFF_THREADS
98   if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
99 #endif
100
101    EnterCriticalSection(mutex);
102
103    return EINA_LOCK_SUCCEED;
104 }
105
106 static inline Eina_Lock_Result
107 eina_lock_take_try(Eina_Lock *mutex)
108 {
109 #ifdef EINA_HAVE_ON_OFF_THREADS
110    if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
111 #endif
112
113    return TryEnterCriticalSection(mutex) == 0 ? EINA_LOCK_FAIL : EINA_LOCK_SUCCEED;
114 }
115
116 static inline Eina_Lock_Result
117 eina_lock_release(Eina_Lock *mutex)
118 {
119 #ifdef EINA_HAVE_ON_OFF_THREADS
120    if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
121 #endif
122
123    LeaveCriticalSection(mutex);
124
125    return EINA_LOCK_SUCCEED;
126 }
127
128 static inline void
129 eina_lock_debug(const Eina_Lock *mutex)
130 {
131    (void)mutex;
132 }
133
134 static inline Eina_Bool
135 eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
136 {
137    cond->mutex = mutex;
138 #if _WIN32_WINNT >= 0x0600
139    InitializeConditionVariable(&cond->condition);
140 #else
141    cond->waiters_count = 0;
142    cond->was_broadcast = EINA_FALSE;
143    cond->semaphore = CreateSemaphore(NULL,       // no security
144                                      0,          // initially 0
145                                      0x7fffffff, // max count
146                                      NULL);      // unnamed
147    if (!cond->semaphore)
148      return EINA_FALSE;
149
150    InitializeCriticalSection(&cond->waiters_count_lock);
151
152    cond->waiters_done = CreateEvent(NULL,  // no security
153                                     FALSE, // auto-reset
154                                     FALSE, // non-signaled initially
155                                     NULL); // unnamed
156    if (!cond->waiters_done)
157      {
158         CloseHandle(cond->semaphore);
159         return EINA_FALSE;
160      }
161 #endif
162
163    return EINA_TRUE;
164 }
165
166 static inline void
167 eina_condition_free(Eina_Condition *cond)
168 {
169 #if _WIN32_WINNT >= 0x0600
170    /* Nothing to do */
171    (void)cond;
172 #else
173    CloseHandle(cond->waiters_done);
174    DeleteCriticalSection(&cond->waiters_count_lock);
175    CloseHandle(cond->semaphore);
176 #endif
177 }
178
179 static inline Eina_Bool
180 _eina_condition_internal_timedwait(Eina_Condition *cond, DWORD t)
181 {
182 #if _WIN32_WINNT >= 0x0600
183    SleepConditionVariableCS(&cond->condition, cond->mutex, t);
184 #else
185    DWORD ret;
186    Eina_Bool last_waiter;
187
188    /* Avoid race conditions. */
189    EnterCriticalSection(&cond->waiters_count_lock);
190    cond->waiters_count++;
191    LeaveCriticalSection(&cond->waiters_count_lock);
192
193    /*
194     * This call atomically releases the mutex and waits on the
195     * semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
196     * are called by another thread.
197     */
198    ret = SignalObjectAndWait(cond->mutex, cond->semaphore, t, FALSE);
199    if (ret == WAIT_FAILED)
200      return EINA_FALSE;
201
202    /* Reacquire lock to avoid race conditions. */
203    EnterCriticalSection(&cond->waiters_count_lock);
204
205    /* We're no longer waiting... */
206    cond->waiters_count--;
207
208    /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
209    last_waiter = (cond->was_broadcast) && (cond->waiters_count == 0);
210
211    LeaveCriticalSection(&cond->waiters_count_lock);
212
213    /*
214     * If we're the last waiter thread during this particular broadcast
215     * then let all the other threads proceed.
216     */
217   if (last_waiter)
218     {
219        /*
220         * This call atomically signals the <waiters_done_> event and waits until
221         * it can acquire the <external_mutex>.  This is required to ensure fairness.
222         */
223        ret = SignalObjectAndWait(cond->waiters_done, cond->mutex, t, FALSE);
224        if (ret == WAIT_FAILED)
225          return EINA_FALSE;
226     }
227   else
228     {
229        /*
230         * Always regain the external mutex since that's the guarantee we
231         * give to our callers.
232         */
233        ret = WaitForSingleObject(cond->mutex, t);
234        if (ret == WAIT_FAILED)
235          return EINA_FALSE;
236     }
237 #endif
238
239    return EINA_TRUE;
240 }
241
242 static inline Eina_Bool
243 eina_condition_timedwait(Eina_Condition *cond, double val)
244 {
245    return _eina_condition_internal_timedwait(cond, (DWORD)(val * 1000));
246 }
247
248 static inline Eina_Bool
249 eina_condition_wait(Eina_Condition *cond)
250 {
251    return _eina_condition_internal_timedwait(cond, INFINITE);
252 }
253
254 static inline Eina_Bool
255 eina_condition_broadcast(Eina_Condition *cond)
256 {
257 #if _WIN32_WINNT >= 0x0600
258    WakeAllConditionVariable(&cond->condition);
259    return EINA_TRUE;
260 #else
261    Eina_Bool have_waiters;
262
263    /*
264     * This is needed to ensure that <waiters_count_> and <was_broadcast_> are
265     * consistent relative to each other.
266     */
267    EnterCriticalSection(&cond->waiters_count_lock);
268    have_waiters = EINA_FALSE;
269
270    if (cond->waiters_count > 0)
271      {
272         /*
273          * We are broadcasting, even if there is just one waiter...
274          * Record that we are broadcasting, which helps optimize
275          * <pthread_cond_wait> for the non-broadcast case.
276          */
277         cond->was_broadcast = EINA_TRUE;
278         have_waiters = EINA_TRUE;
279      }
280
281    if (have_waiters)
282      {
283         DWORD ret;
284
285         /* Wake up all the waiters atomically. */
286         ret = ReleaseSemaphore(cond->semaphore, cond->waiters_count, 0);
287         LeaveCriticalSection(&cond->waiters_count_lock);
288         if (!ret) return EINA_FALSE;
289
290         /*
291          * Wait for all the awakened threads to acquire the counting
292          * semaphore.
293          */
294         ret = WaitForSingleObject(cond->waiters_done, INFINITE);
295         if (ret == WAIT_FAILED)
296           return EINA_FALSE;
297         /*
298          * This assignment is okay, even without the <waiters_count_lock_> held
299          * because no other waiter threads can wake up to access it.
300          */
301         cond->was_broadcast = EINA_FALSE;
302      }
303    else
304      LeaveCriticalSection(&cond->waiters_count_lock);
305
306    return EINA_TRUE;
307 #endif
308 }
309
310 static inline Eina_Bool
311 eina_condition_signal(Eina_Condition *cond)
312 {
313 #if _WIN32_WINNT >= 0x0600
314    WakeConditionVariable(&cond->condition);
315 #else
316    Eina_Bool have_waiters;
317
318    EnterCriticalSection(&cond->waiters_count_lock);
319    have_waiters = (cond->waiters_count > 0);
320    LeaveCriticalSection(&cond->waiters_count_lock);
321
322    /* If there aren't any waiters, then this is a no-op. */
323   if (have_waiters)
324     {
325        if (!ReleaseSemaphore(cond->semaphore, 1, 0))
326          return EINA_FALSE;
327     }
328 #endif
329
330    return EINA_TRUE;
331 }
332
333 static inline Eina_Bool
334 eina_rwlock_new(Eina_RWLock *mutex)
335 {
336 #if _WIN32_WINNT >= 0x0600
337    InitializeSRWLock(&mutex->mutex);
338    return EINA_TRUE;
339 #else
340    if (!eina_lock_new(&(mutex->mutex))) return EINA_FALSE;
341    if (!eina_condition_new(&(mutex->cond_read), &(mutex->mutex)))
342      goto on_error1;
343    if (!eina_condition_new(&(mutex->cond_write), &(mutex->mutex)))
344      goto on_error2;
345
346    mutex->readers_count = 0;
347    mutex->writers_count = 0;
348    mutex->readers = 0;
349    mutex->writers = 0;
350
351    return EINA_TRUE;
352
353  on_error2:
354    eina_condition_free(&(mutex->cond_read));
355  on_error1:
356    eina_lock_free(&(mutex->mutex));
357    return EINA_FALSE;
358 #endif
359 }
360
361 static inline void
362 eina_rwlock_free(Eina_RWLock *mutex)
363 {
364 #if _WIN32_WINNT >= 0x0600
365    (void)mutex;
366 #else
367    eina_condition_free(&(mutex->cond_read));
368    eina_condition_free(&(mutex->cond_write));
369    eina_lock_free(&(mutex->mutex));
370 #endif
371 }
372
373 static inline Eina_Lock_Result
374 eina_rwlock_take_read(Eina_RWLock *mutex)
375 {
376 #if _WIN32_WINNT >= 0x0600
377    AcquireSRWLockShared(&mutex->mutex);
378    mutex->is_read_mode = EINA_TRUE;
379 #else
380    DWORD res = 0;
381
382    if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
383      return EINA_LOCK_FAIL;
384
385    if (mutex->writers)
386      {
387         mutex->readers_count++;
388         while (mutex->writers)
389           {
390              EnterCriticalSection(&mutex->cond_write.waiters_count_lock);
391              mutex->cond_read.waiters_count++;
392              LeaveCriticalSection(&mutex->cond_write.waiters_count_lock);
393              res = WaitForSingleObject(mutex->cond_write.semaphore, INFINITE);
394              if (res != WAIT_OBJECT_0) break;
395           }
396         mutex->readers_count--;
397      }
398    if (res == 0)
399      mutex->readers++;
400    eina_lock_release(&(mutex->mutex));
401 #endif
402
403    return EINA_LOCK_SUCCEED;
404 }
405
406 static inline Eina_Lock_Result
407 eina_rwlock_take_write(Eina_RWLock *mutex)
408 {
409 #if _WIN32_WINNT >= 0x0600
410    AcquireSRWLockExclusive(&mutex->mutex);
411    mutex->is_read_mode = EINA_FALSE;
412 #else
413    DWORD res = 0;
414
415    if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
416      return EINA_LOCK_FAIL;
417
418    if (mutex->writers || mutex->readers > 0)
419      {
420         mutex->writers_count++;
421         while (mutex->writers || mutex->readers > 0)
422           {
423              EnterCriticalSection(&mutex->cond_write.waiters_count_lock);
424              mutex->cond_read.waiters_count++;
425              LeaveCriticalSection(&mutex->cond_write.waiters_count_lock);
426              res = WaitForSingleObject(mutex->cond_write.semaphore, INFINITE);
427              if (res != WAIT_OBJECT_0) break;
428           }
429         mutex->writers_count--;
430      }
431    if (res == 0) mutex->writers = 1;
432    eina_lock_release(&(mutex->mutex));
433 #endif
434
435    return EINA_LOCK_SUCCEED;
436 }
437
438 static inline Eina_Lock_Result
439 eina_rwlock_release(Eina_RWLock *mutex)
440 {
441 #if _WIN32_WINNT >= 0x0600
442    if (mutex->is_read_mode)
443      ReleaseSRWLockShared(&mutex->mutex);
444    else
445      ReleaseSRWLockExclusive(&mutex->mutex);
446 #else
447    if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
448      return EINA_LOCK_FAIL;
449
450    if (mutex->writers)
451      {
452         mutex->writers = 0;
453         if (mutex->readers_count == 1)
454           {
455              EnterCriticalSection(&mutex->cond_read.waiters_count_lock);
456              if (mutex->cond_read.waiters_count > 0)
457                ReleaseSemaphore(mutex->cond_read.semaphore, 1, 0);
458              LeaveCriticalSection(&mutex->cond_read.waiters_count_lock);
459           }
460         else if (mutex->readers_count > 0)
461           eina_condition_broadcast(&(mutex->cond_read));
462         else if (mutex->writers_count > 0)
463           {
464              EnterCriticalSection (&mutex->cond_write.waiters_count_lock);
465              if (mutex->cond_write.waiters_count > 0)
466                ReleaseSemaphore(mutex->cond_write.semaphore, 1, 0);
467              LeaveCriticalSection (&mutex->cond_write.waiters_count_lock);
468           }
469      }
470    else if (mutex->readers > 0)
471      {
472         mutex->readers--;
473         if (mutex->readers == 0 && mutex->writers_count > 0)
474           {
475              EnterCriticalSection (&mutex->cond_write.waiters_count_lock);
476              if (mutex->cond_write.waiters_count > 0)
477                ReleaseSemaphore(mutex->cond_write.semaphore, 1, 0);
478              LeaveCriticalSection (&mutex->cond_write.waiters_count_lock);
479           }
480      }
481    eina_lock_release(&(mutex->mutex));
482 #endif
483
484    return EINA_LOCK_SUCCEED;
485 }
486
487 static inline Eina_Bool
488 eina_tls_new(Eina_TLS *key)
489 {
490    if ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
491       return EINA_FALSE;
492    return EINA_TRUE;
493 }
494
495 static inline void
496 eina_tls_free(Eina_TLS key)
497 {
498    TlsFree(key);
499 }
500
501 static inline void *
502 eina_tls_get(Eina_TLS key)
503 {
504    return (void*)TlsGetValue(key);
505 }
506
507 static inline Eina_Bool
508 eina_tls_set(Eina_TLS key, const void *data)
509 {
510    if (TlsSetValue(key, (LPVOID)data) == 0)
511       return EINA_FALSE;
512    return EINA_TRUE;
513 }
514
515 static inline Eina_Bool
516 eina_semaphore_new(Eina_Semaphore *sem, int count_init)
517 {
518    if (!sem || (count_init <= 0))
519      return EINA_FALSE;
520
521    *sem = CreateSemaphore(NULL, count_init, 32767, NULL);
522    if (!*sem)
523      return EINA_FALSE;
524 }
525
526 static inline Eina_Bool
527 eina_semaphore_free(Eina_Semaphore *sem)
528 {
529   if (!sem)
530      return EINA_FALSE;
531
532   CloseHandle(*sem);
533 }
534
535 static inline Eina_Bool
536 eina_semaphore_lock(Eina_Semaphore *sem)
537 {
538    DWORD res;
539
540    if (!sem)
541      return EINA_FALSE;
542
543    res = WaitForSingleObject(*sem, 0L);
544    if (res == WAIT_OBJECT_0)
545      return EINA_TRUE;
546
547    return EINA_FALSE;
548 }
549
550 static inline Eina_Bool
551 eina_semaphore_release(Eina_Semaphore *sem, int count_release)
552 {
553    if (!sem)
554      return EINA_FALSE;
555
556    return ReleaseSemaphore(*sem, count_release, NULL) ? EINA_TRUE : EINA_FALSE;
557 }
558
559 #endif