1290001Sglebius/* 2290001Sglebius * Copyright 2009-2012 Niels Provos and Nick Mathewson 3290001Sglebius * 4290001Sglebius * Redistribution and use in source and binary forms, with or without 5290001Sglebius * modification, are permitted provided that the following conditions 6290001Sglebius * are met: 7290001Sglebius * 1. Redistributions of source code must retain the above copyright 8290001Sglebius * notice, this list of conditions and the following disclaimer. 9290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright 10290001Sglebius * notice, this list of conditions and the following disclaimer in the 11290001Sglebius * documentation and/or other materials provided with the distribution. 12290001Sglebius * 3. The name of the author may not be used to endorse or promote products 13290001Sglebius * derived from this software without specific prior written permission. 14290001Sglebius * 15290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16290001Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17290001Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18290001Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19290001Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20290001Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21290001Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24290001Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25290001Sglebius */ 26290001Sglebius#include "event2/event-config.h" 27290001Sglebius#include "evconfig-private.h" 28290001Sglebius 29290001Sglebius/* With glibc we need to define _GNU_SOURCE to get PTHREAD_MUTEX_RECURSIVE. 30290001Sglebius * This comes from evconfig-private.h 31290001Sglebius */ 32290001Sglebius#include <pthread.h> 33290001Sglebius 34290001Sglebiusstruct event_base; 35290001Sglebius#include "event2/thread.h" 36290001Sglebius 37290001Sglebius#include <stdlib.h> 38290001Sglebius#include <string.h> 39290001Sglebius#include "mm-internal.h" 40290001Sglebius#include "evthread-internal.h" 41290001Sglebius 42290001Sglebiusstatic pthread_mutexattr_t attr_recursive; 43290001Sglebius 44290001Sglebiusstatic void * 45290001Sglebiusevthread_posix_lock_alloc(unsigned locktype) 46290001Sglebius{ 47290001Sglebius pthread_mutexattr_t *attr = NULL; 48290001Sglebius pthread_mutex_t *lock = mm_malloc(sizeof(pthread_mutex_t)); 49290001Sglebius if (!lock) 50290001Sglebius return NULL; 51290001Sglebius if (locktype & EVTHREAD_LOCKTYPE_RECURSIVE) 52290001Sglebius attr = &attr_recursive; 53290001Sglebius if (pthread_mutex_init(lock, attr)) { 54290001Sglebius mm_free(lock); 55290001Sglebius return NULL; 56290001Sglebius } 57290001Sglebius return lock; 58290001Sglebius} 59290001Sglebius 60290001Sglebiusstatic void 61290001Sglebiusevthread_posix_lock_free(void *lock_, unsigned locktype) 62290001Sglebius{ 63290001Sglebius pthread_mutex_t *lock = lock_; 64290001Sglebius pthread_mutex_destroy(lock); 65290001Sglebius mm_free(lock); 66290001Sglebius} 67290001Sglebius 68290001Sglebiusstatic int 69290001Sglebiusevthread_posix_lock(unsigned mode, void *lock_) 70290001Sglebius{ 71290001Sglebius pthread_mutex_t *lock = lock_; 72290001Sglebius if (mode & EVTHREAD_TRY) 73290001Sglebius return pthread_mutex_trylock(lock); 74290001Sglebius else 75290001Sglebius return pthread_mutex_lock(lock); 76290001Sglebius} 77290001Sglebius 78290001Sglebiusstatic int 79290001Sglebiusevthread_posix_unlock(unsigned mode, void *lock_) 80290001Sglebius{ 81290001Sglebius pthread_mutex_t *lock = lock_; 82290001Sglebius return pthread_mutex_unlock(lock); 83290001Sglebius} 84290001Sglebius 85290001Sglebiusstatic unsigned long 86290001Sglebiusevthread_posix_get_id(void) 87290001Sglebius{ 88290001Sglebius union { 89290001Sglebius pthread_t thr; 90290001Sglebius#if EVENT__SIZEOF_PTHREAD_T > EVENT__SIZEOF_LONG 91290001Sglebius ev_uint64_t id; 92290001Sglebius#else 93290001Sglebius unsigned long id; 94290001Sglebius#endif 95290001Sglebius } r; 96290001Sglebius#if EVENT__SIZEOF_PTHREAD_T < EVENT__SIZEOF_LONG 97290001Sglebius memset(&r, 0, sizeof(r)); 98290001Sglebius#endif 99290001Sglebius r.thr = pthread_self(); 100290001Sglebius return (unsigned long)r.id; 101290001Sglebius} 102290001Sglebius 103290001Sglebiusstatic void * 104290001Sglebiusevthread_posix_cond_alloc(unsigned condflags) 105290001Sglebius{ 106290001Sglebius pthread_cond_t *cond = mm_malloc(sizeof(pthread_cond_t)); 107290001Sglebius if (!cond) 108290001Sglebius return NULL; 109290001Sglebius if (pthread_cond_init(cond, NULL)) { 110290001Sglebius mm_free(cond); 111290001Sglebius return NULL; 112290001Sglebius } 113290001Sglebius return cond; 114290001Sglebius} 115290001Sglebius 116290001Sglebiusstatic void 117290001Sglebiusevthread_posix_cond_free(void *cond_) 118290001Sglebius{ 119290001Sglebius pthread_cond_t *cond = cond_; 120290001Sglebius pthread_cond_destroy(cond); 121290001Sglebius mm_free(cond); 122290001Sglebius} 123290001Sglebius 124290001Sglebiusstatic int 125290001Sglebiusevthread_posix_cond_signal(void *cond_, int broadcast) 126290001Sglebius{ 127290001Sglebius pthread_cond_t *cond = cond_; 128290001Sglebius int r; 129290001Sglebius if (broadcast) 130290001Sglebius r = pthread_cond_broadcast(cond); 131290001Sglebius else 132290001Sglebius r = pthread_cond_signal(cond); 133290001Sglebius return r ? -1 : 0; 134290001Sglebius} 135290001Sglebius 136290001Sglebiusstatic int 137290001Sglebiusevthread_posix_cond_wait(void *cond_, void *lock_, const struct timeval *tv) 138290001Sglebius{ 139290001Sglebius int r; 140290001Sglebius pthread_cond_t *cond = cond_; 141290001Sglebius pthread_mutex_t *lock = lock_; 142290001Sglebius 143290001Sglebius if (tv) { 144290001Sglebius struct timeval now, abstime; 145290001Sglebius struct timespec ts; 146290001Sglebius evutil_gettimeofday(&now, NULL); 147290001Sglebius evutil_timeradd(&now, tv, &abstime); 148290001Sglebius ts.tv_sec = abstime.tv_sec; 149290001Sglebius ts.tv_nsec = abstime.tv_usec*1000; 150290001Sglebius r = pthread_cond_timedwait(cond, lock, &ts); 151290001Sglebius if (r == ETIMEDOUT) 152290001Sglebius return 1; 153290001Sglebius else if (r) 154290001Sglebius return -1; 155290001Sglebius else 156290001Sglebius return 0; 157290001Sglebius } else { 158290001Sglebius r = pthread_cond_wait(cond, lock); 159290001Sglebius return r ? -1 : 0; 160290001Sglebius } 161290001Sglebius} 162290001Sglebius 163290001Sglebiusint 164290001Sglebiusevthread_use_pthreads(void) 165290001Sglebius{ 166290001Sglebius struct evthread_lock_callbacks cbs = { 167290001Sglebius EVTHREAD_LOCK_API_VERSION, 168290001Sglebius EVTHREAD_LOCKTYPE_RECURSIVE, 169290001Sglebius evthread_posix_lock_alloc, 170290001Sglebius evthread_posix_lock_free, 171290001Sglebius evthread_posix_lock, 172290001Sglebius evthread_posix_unlock 173290001Sglebius }; 174290001Sglebius struct evthread_condition_callbacks cond_cbs = { 175290001Sglebius EVTHREAD_CONDITION_API_VERSION, 176290001Sglebius evthread_posix_cond_alloc, 177290001Sglebius evthread_posix_cond_free, 178290001Sglebius evthread_posix_cond_signal, 179290001Sglebius evthread_posix_cond_wait 180290001Sglebius }; 181290001Sglebius /* Set ourselves up to get recursive locks. */ 182290001Sglebius if (pthread_mutexattr_init(&attr_recursive)) 183290001Sglebius return -1; 184290001Sglebius if (pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE)) 185290001Sglebius return -1; 186290001Sglebius 187290001Sglebius evthread_set_lock_callbacks(&cbs); 188290001Sglebius evthread_set_condition_callbacks(&cond_cbs); 189290001Sglebius evthread_set_id_callback(evthread_posix_get_id); 190290001Sglebius return 0; 191290001Sglebius} 192