1275970Scy/* 2275970Scy * Copyright 2009-2012 Niels Provos and Nick Mathewson 3275970Scy * 4275970Scy * Redistribution and use in source and binary forms, with or without 5275970Scy * modification, are permitted provided that the following conditions 6275970Scy * are met: 7275970Scy * 1. Redistributions of source code must retain the above copyright 8275970Scy * notice, this list of conditions and the following disclaimer. 9275970Scy * 2. Redistributions in binary form must reproduce the above copyright 10275970Scy * notice, this list of conditions and the following disclaimer in the 11275970Scy * documentation and/or other materials provided with the distribution. 12275970Scy * 3. The name of the author may not be used to endorse or promote products 13275970Scy * derived from this software without specific prior written permission. 14275970Scy * 15275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25275970Scy */ 26275970Scy#include "event2/event-config.h" 27275970Scy#include "evconfig-private.h" 28275970Scy 29275970Scy/* With glibc we need to define _GNU_SOURCE to get PTHREAD_MUTEX_RECURSIVE. 30275970Scy * This comes from evconfig-private.h 31275970Scy */ 32275970Scy#include <pthread.h> 33275970Scy 34275970Scystruct event_base; 35275970Scy#include "event2/thread.h" 36275970Scy 37275970Scy#include <stdlib.h> 38275970Scy#include <string.h> 39275970Scy#include "mm-internal.h" 40275970Scy#include "evthread-internal.h" 41275970Scy 42275970Scystatic pthread_mutexattr_t attr_recursive; 43275970Scy 44275970Scystatic void * 45275970Scyevthread_posix_lock_alloc(unsigned locktype) 46275970Scy{ 47275970Scy pthread_mutexattr_t *attr = NULL; 48275970Scy pthread_mutex_t *lock = mm_malloc(sizeof(pthread_mutex_t)); 49275970Scy if (!lock) 50275970Scy return NULL; 51275970Scy if (locktype & EVTHREAD_LOCKTYPE_RECURSIVE) 52275970Scy attr = &attr_recursive; 53275970Scy if (pthread_mutex_init(lock, attr)) { 54275970Scy mm_free(lock); 55275970Scy return NULL; 56275970Scy } 57275970Scy return lock; 58275970Scy} 59275970Scy 60275970Scystatic void 61275970Scyevthread_posix_lock_free(void *lock_, unsigned locktype) 62275970Scy{ 63275970Scy pthread_mutex_t *lock = lock_; 64275970Scy pthread_mutex_destroy(lock); 65275970Scy mm_free(lock); 66275970Scy} 67275970Scy 68275970Scystatic int 69275970Scyevthread_posix_lock(unsigned mode, void *lock_) 70275970Scy{ 71275970Scy pthread_mutex_t *lock = lock_; 72275970Scy if (mode & EVTHREAD_TRY) 73275970Scy return pthread_mutex_trylock(lock); 74275970Scy else 75275970Scy return pthread_mutex_lock(lock); 76275970Scy} 77275970Scy 78275970Scystatic int 79275970Scyevthread_posix_unlock(unsigned mode, void *lock_) 80275970Scy{ 81275970Scy pthread_mutex_t *lock = lock_; 82275970Scy return pthread_mutex_unlock(lock); 83275970Scy} 84275970Scy 85275970Scystatic unsigned long 86275970Scyevthread_posix_get_id(void) 87275970Scy{ 88275970Scy union { 89275970Scy pthread_t thr; 90275970Scy#if EVENT__SIZEOF_PTHREAD_T > EVENT__SIZEOF_LONG 91275970Scy ev_uint64_t id; 92275970Scy#else 93275970Scy unsigned long id; 94275970Scy#endif 95275970Scy } r; 96275970Scy#if EVENT__SIZEOF_PTHREAD_T < EVENT__SIZEOF_LONG 97275970Scy memset(&r, 0, sizeof(r)); 98275970Scy#endif 99275970Scy r.thr = pthread_self(); 100275970Scy return (unsigned long)r.id; 101275970Scy} 102275970Scy 103275970Scystatic void * 104275970Scyevthread_posix_cond_alloc(unsigned condflags) 105275970Scy{ 106275970Scy pthread_cond_t *cond = mm_malloc(sizeof(pthread_cond_t)); 107275970Scy if (!cond) 108275970Scy return NULL; 109275970Scy if (pthread_cond_init(cond, NULL)) { 110275970Scy mm_free(cond); 111275970Scy return NULL; 112275970Scy } 113275970Scy return cond; 114275970Scy} 115275970Scy 116275970Scystatic void 117275970Scyevthread_posix_cond_free(void *cond_) 118275970Scy{ 119275970Scy pthread_cond_t *cond = cond_; 120275970Scy pthread_cond_destroy(cond); 121275970Scy mm_free(cond); 122275970Scy} 123275970Scy 124275970Scystatic int 125275970Scyevthread_posix_cond_signal(void *cond_, int broadcast) 126275970Scy{ 127275970Scy pthread_cond_t *cond = cond_; 128275970Scy int r; 129275970Scy if (broadcast) 130275970Scy r = pthread_cond_broadcast(cond); 131275970Scy else 132275970Scy r = pthread_cond_signal(cond); 133275970Scy return r ? -1 : 0; 134275970Scy} 135275970Scy 136275970Scystatic int 137275970Scyevthread_posix_cond_wait(void *cond_, void *lock_, const struct timeval *tv) 138275970Scy{ 139275970Scy int r; 140275970Scy pthread_cond_t *cond = cond_; 141275970Scy pthread_mutex_t *lock = lock_; 142275970Scy 143275970Scy if (tv) { 144275970Scy struct timeval now, abstime; 145275970Scy struct timespec ts; 146275970Scy evutil_gettimeofday(&now, NULL); 147275970Scy evutil_timeradd(&now, tv, &abstime); 148275970Scy ts.tv_sec = abstime.tv_sec; 149275970Scy ts.tv_nsec = abstime.tv_usec*1000; 150275970Scy r = pthread_cond_timedwait(cond, lock, &ts); 151275970Scy if (r == ETIMEDOUT) 152275970Scy return 1; 153275970Scy else if (r) 154275970Scy return -1; 155275970Scy else 156275970Scy return 0; 157275970Scy } else { 158275970Scy r = pthread_cond_wait(cond, lock); 159275970Scy return r ? -1 : 0; 160275970Scy } 161275970Scy} 162275970Scy 163275970Scyint 164275970Scyevthread_use_pthreads(void) 165275970Scy{ 166275970Scy struct evthread_lock_callbacks cbs = { 167275970Scy EVTHREAD_LOCK_API_VERSION, 168275970Scy EVTHREAD_LOCKTYPE_RECURSIVE, 169275970Scy evthread_posix_lock_alloc, 170275970Scy evthread_posix_lock_free, 171275970Scy evthread_posix_lock, 172275970Scy evthread_posix_unlock 173275970Scy }; 174275970Scy struct evthread_condition_callbacks cond_cbs = { 175275970Scy EVTHREAD_CONDITION_API_VERSION, 176275970Scy evthread_posix_cond_alloc, 177275970Scy evthread_posix_cond_free, 178275970Scy evthread_posix_cond_signal, 179275970Scy evthread_posix_cond_wait 180275970Scy }; 181275970Scy /* Set ourselves up to get recursive locks. */ 182275970Scy if (pthread_mutexattr_init(&attr_recursive)) 183275970Scy return -1; 184275970Scy if (pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE)) 185275970Scy return -1; 186275970Scy 187275970Scy evthread_set_lock_callbacks(&cbs); 188275970Scy evthread_set_condition_callbacks(&cond_cbs); 189275970Scy evthread_set_id_callback(evthread_posix_get_id); 190275970Scy return 0; 191275970Scy} 192