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