evthread_pthread.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright 2009-2012 Niels Provos and Nick Mathewson
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * 3. The name of the author may not be used to endorse or promote products
  13. * derived from this software without specific prior written permission.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "event2/event-config.h"
  27. #include "evconfig-private.h"
  28. /* With glibc we need to define _GNU_SOURCE to get PTHREAD_MUTEX_RECURSIVE.
  29. * This comes from evconfig-private.h
  30. */
  31. #include <pthread.h>
  32. struct event_base;
  33. #include "event2/thread.h"
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include "mm-internal.h"
  37. #include "evthread-internal.h"
  38. static pthread_mutexattr_t attr_recursive;
  39. static void *
  40. evthread_posix_lock_alloc(unsigned locktype)
  41. {
  42. pthread_mutexattr_t *attr = NULL;
  43. pthread_mutex_t *lock = mm_malloc(sizeof(pthread_mutex_t));
  44. if (!lock)
  45. return NULL;
  46. if (locktype & EVTHREAD_LOCKTYPE_RECURSIVE)
  47. attr = &attr_recursive;
  48. if (pthread_mutex_init(lock, attr)) {
  49. mm_free(lock);
  50. return NULL;
  51. }
  52. return lock;
  53. }
  54. static void
  55. evthread_posix_lock_free(void *lock_, unsigned locktype)
  56. {
  57. pthread_mutex_t *lock = lock_;
  58. pthread_mutex_destroy(lock);
  59. mm_free(lock);
  60. }
  61. static int
  62. evthread_posix_lock(unsigned mode, void *lock_)
  63. {
  64. pthread_mutex_t *lock = lock_;
  65. if (mode & EVTHREAD_TRY)
  66. return pthread_mutex_trylock(lock);
  67. else
  68. return pthread_mutex_lock(lock);
  69. }
  70. static int
  71. evthread_posix_unlock(unsigned mode, void *lock_)
  72. {
  73. pthread_mutex_t *lock = lock_;
  74. return pthread_mutex_unlock(lock);
  75. }
  76. static unsigned long
  77. evthread_posix_get_id(void)
  78. {
  79. union {
  80. pthread_t thr;
  81. #if EVENT__SIZEOF_PTHREAD_T > EVENT__SIZEOF_LONG
  82. ev_uint64_t id;
  83. #else
  84. unsigned long id;
  85. #endif
  86. } r;
  87. #if EVENT__SIZEOF_PTHREAD_T < EVENT__SIZEOF_LONG
  88. memset(&r, 0, sizeof(r));
  89. #endif
  90. r.thr = pthread_self();
  91. return (unsigned long)r.id;
  92. }
  93. static void *
  94. evthread_posix_cond_alloc(unsigned condflags)
  95. {
  96. pthread_cond_t *cond = mm_malloc(sizeof(pthread_cond_t));
  97. if (!cond)
  98. return NULL;
  99. if (pthread_cond_init(cond, NULL)) {
  100. mm_free(cond);
  101. return NULL;
  102. }
  103. return cond;
  104. }
  105. static void
  106. evthread_posix_cond_free(void *cond_)
  107. {
  108. pthread_cond_t *cond = cond_;
  109. pthread_cond_destroy(cond);
  110. mm_free(cond);
  111. }
  112. static int
  113. evthread_posix_cond_signal(void *cond_, int broadcast)
  114. {
  115. pthread_cond_t *cond = cond_;
  116. int r;
  117. if (broadcast)
  118. r = pthread_cond_broadcast(cond);
  119. else
  120. r = pthread_cond_signal(cond);
  121. return r ? -1 : 0;
  122. }
  123. static int
  124. evthread_posix_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
  125. {
  126. int r;
  127. pthread_cond_t *cond = cond_;
  128. pthread_mutex_t *lock = lock_;
  129. if (tv) {
  130. struct timeval now, abstime;
  131. struct timespec ts;
  132. evutil_gettimeofday(&now, NULL);
  133. evutil_timeradd(&now, tv, &abstime);
  134. ts.tv_sec = abstime.tv_sec;
  135. ts.tv_nsec = abstime.tv_usec*1000;
  136. r = pthread_cond_timedwait(cond, lock, &ts);
  137. if (r == ETIMEDOUT)
  138. return 1;
  139. else if (r)
  140. return -1;
  141. else
  142. return 0;
  143. } else {
  144. r = pthread_cond_wait(cond, lock);
  145. return r ? -1 : 0;
  146. }
  147. }
  148. int
  149. evthread_use_pthreads(void)
  150. {
  151. struct evthread_lock_callbacks cbs = {
  152. EVTHREAD_LOCK_API_VERSION,
  153. EVTHREAD_LOCKTYPE_RECURSIVE,
  154. evthread_posix_lock_alloc,
  155. evthread_posix_lock_free,
  156. evthread_posix_lock,
  157. evthread_posix_unlock
  158. };
  159. struct evthread_condition_callbacks cond_cbs = {
  160. EVTHREAD_CONDITION_API_VERSION,
  161. evthread_posix_cond_alloc,
  162. evthread_posix_cond_free,
  163. evthread_posix_cond_signal,
  164. evthread_posix_cond_wait
  165. };
  166. /* Set ourselves up to get recursive locks. */
  167. if (pthread_mutexattr_init(&attr_recursive))
  168. return -1;
  169. if (pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE))
  170. return -1;
  171. evthread_set_lock_callbacks(&cbs);
  172. evthread_set_condition_callbacks(&cond_cbs);
  173. evthread_set_id_callback(evthread_posix_get_id);
  174. return 0;
  175. }