1 /* $Id: threads.h,v 1.10 2010/06/05 19:36:35 fredette Exp $ */ 2 3 /* tme/threads.h - header file for threads: */ 4 5 /* 6 * Copyright (c) 2003 Matt Fredette 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Matt Fredette. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #ifndef _TME_THREADS_H 37 #define _TME_THREADS_H 38 39 #include <tme/common.h> 40 _TME_RCSID("$Id: threads.h,v 1.10 2010/06/05 19:36:35 fredette Exp $"); 41 42 /* includes: */ 43 #include <errno.h> 44 #include <sys/time.h> 45 46 /* note that our locking model never allows recursive locking. */ 47 48 /* setjmp/longjmp threading: */ 49 #ifdef TME_THREADS_SJLJ 50 51 /* setjmp/longjmp threads are cooperative: */ 52 #define TME_THREADS_COOPERATIVE (TRUE) 53 54 /* our errno convention: */ 55 #define TME_EDEADLK EBUSY 56 #define TME_EBUSY EBUSY 57 #define TME_THREADS_ERRNO(rc) (rc) 58 59 /* initializing and starting: */ 60 void tme_sjlj_threads_init _TME_P((void)); 61 #define tme_threads_init tme_sjlj_threads_init 62 #ifdef _TME_HAVE_GTK 63 void tme_sjlj_threads_gtk_init _TME_P((void)); 64 #define tme_threads_gtk_init tme_sjlj_threads_gtk_init 65 void tme_sjlj_threads_gtk_yield _TME_P((void)); 66 #define tme_threads_gtk_yield tme_sjlj_threads_gtk_yield 67 #endif /* _TME_HAVE_GTK */ 68 void tme_sjlj_threads_run _TME_P((void)); 69 #define tme_threads_run tme_sjlj_threads_run 70 71 /* thread suspension: */ 72 #define tme_thread_suspend_others() do { } while (/* CONSTCOND */ 0) 73 #define tme_thread_resume_others() do { } while (/* CONSTCOND */ 0) 74 75 /* if we want speed over lock debugging, we can compile very simple 76 rwlock operations: */ 77 #ifdef TME_NO_DEBUG_LOCKS 78 typedef int tme_rwlock_t; 79 #define tme_rwlock_init(l) (*(l) = FALSE, TME_OK) 80 #define tme_rwlock_rdlock(l) (*(l) = TRUE, TME_OK) 81 #define tme_rwlock_tryrdlock(l) (*(l) ? TME_EBUSY : tme_rwlock_rdlock(l)) 82 #define tme_rwlock_unlock(l) (*(l) = FALSE, TME_OK) 83 #else /* !TME_NO_DEBUG_LOCKS */ 84 85 /* debugging rwlocks: */ 86 typedef struct tme_sjlj_rwlock { 87 88 /* nonzero iff the lock is locked: */ 89 int _tme_sjlj_rwlock_locked; 90 91 /* the file and line number of the last locker or unlocker: */ 92 _tme_const char *_tme_sjlj_rwlock_file; 93 unsigned long _tme_sjlj_rwlock_line; 94 } tme_rwlock_t; 95 96 /* lock operations: */ 97 int tme_sjlj_rwlock_init _TME_P((struct tme_sjlj_rwlock *)); 98 int tme_sjlj_rwlock_lock _TME_P((struct tme_sjlj_rwlock *, _tme_const char *, unsigned long, int)); 99 int tme_sjlj_rwlock_unlock _TME_P((struct tme_sjlj_rwlock *, _tme_const char *, unsigned long)); 100 #define tme_rwlock_init tme_sjlj_rwlock_init 101 #if defined(__FILE__) && defined(__LINE__) 102 #define tme_rwlock_rdlock(l) tme_sjlj_rwlock_lock(l, __FILE__, __LINE__, FALSE) 103 #define tme_rwlock_tryrdlock(l) tme_sjlj_rwlock_lock(l, __FILE__, __LINE__, TRUE) 104 #define tme_rwlock_unlock(l) tme_sjlj_rwlock_unlock(l, __FILE__, __LINE__) 105 #else /* !defined(__FILE__) || !defined(__LINE__) */ 106 #define tme_rwlock_rdlock(l) tme_sjlj_rwlock_lock(l, NULL, 0, FALSE) 107 #define tme_rwlock_tryrdlock(l) tme_sjlj_rwlock_lock(l, NULL, 0, TRUE) 108 #define tme_rwlock_unlock(l) tme_sjlj_rwlock_unlock(l, NULL, 0) 109 #endif /* !defined(__FILE__) || !defined(__LINE__) */ 110 111 #endif /* TME_NO_DEBUG_LOCKS */ 112 113 /* since our thread model doesn't allow recursive locking, write locking 114 is always the same as read locking: */ 115 #define tme_rwlock_wrlock tme_rwlock_rdlock 116 #define tme_rwlock_trywrlock tme_rwlock_tryrdlock 117 118 /* with cooperative threads, it doesn't make any sense to wait for locks: */ 119 #define tme_rwlock_timedrdlock(l, usec) tme_rwlock_tryrdlock(l) 120 #define tme_rwlock_timedwrlock(l, usec) tme_rwlock_trywrlock(l) 121 122 /* mutexes. we use a read/write lock to represent a mutex, and always 123 lock it for writing. we do *not* allow recursive locking: */ 124 #define tme_mutex_t tme_rwlock_t 125 #define tme_mutex_lock tme_rwlock_wrlock 126 #define tme_mutex_trylock tme_rwlock_trywrlock 127 #define tme_mutex_timedlock(t, usec) tme_mutex_trylock(t) 128 #define tme_mutex_unlock tme_rwlock_unlock 129 #define tme_mutex_init tme_rwlock_init 130 131 /* conditions: */ 132 typedef int tme_cond_t; 133 #define tme_cond_init(x) do { } while (/* CONSTCOND */ 0) 134 void tme_sjlj_cond_wait_yield _TME_P((tme_cond_t *, tme_mutex_t *)); 135 void tme_sjlj_cond_sleep_yield _TME_P((tme_cond_t *, tme_mutex_t *, const struct timeval *)); 136 void tme_sjlj_cond_notify _TME_P((tme_cond_t *, int)); 137 #define tme_cond_wait_yield tme_sjlj_cond_wait_yield 138 #define tme_cond_sleep_yield tme_sjlj_cond_sleep_yield 139 #define tme_cond_notify tme_sjlj_cond_notify 140 141 /* deadlock sleeping: */ 142 #define TME_THREAD_TIMEDLOCK (0) 143 #define TME_THREAD_DEADLOCK_SLEEP abort 144 145 /* threads: */ 146 typedef void (*tme_thread_t) _TME_P((void *)); 147 void tme_sjlj_thread_create _TME_P((tme_thread_t, void *)); 148 #define tme_thread_create tme_sjlj_thread_create 149 void tme_sjlj_yield _TME_P((void)); 150 #define tme_thread_yield tme_sjlj_yield 151 void tme_sjlj_exit _TME_P((void)); 152 #define tme_thread_exit tme_sjlj_exit 153 154 /* sleeping: */ 155 void tme_sjlj_sleep _TME_P((unsigned long, unsigned long)); 156 #define tme_thread_sleep tme_sjlj_sleep 157 void tme_sjlj_sleep_yield _TME_P((unsigned long, unsigned long)); 158 #define tme_thread_sleep_yield tme_sjlj_sleep_yield 159 160 /* I/O: */ 161 #define tme_thread_read read 162 #define tme_thread_write write 163 #define tme_thread_select select 164 int tme_sjlj_select_yield _TME_P((int, fd_set *, fd_set *, fd_set *, struct timeval *)); 165 ssize_t tme_sjlj_read_yield _TME_P((int, void *, size_t)); 166 ssize_t tme_sjlj_write_yield _TME_P((int, void *, size_t)); 167 #define tme_thread_select_yield tme_sjlj_select_yield 168 #define tme_thread_read_yield tme_sjlj_read_yield 169 #define tme_thread_write_yield tme_sjlj_write_yield 170 171 /* time: */ 172 void tme_sjlj_gettimeofday _TME_P((struct timeval *)); 173 #define tme_gettimeofday tme_sjlj_gettimeofday 174 extern int tme_sjlj_thread_short; 175 #define tme_thread_long() do { tme_sjlj_thread_short = FALSE; } while (/* CONSTCOND */ 0) 176 177 #endif /* TME_THREADS_SJLJ */ 178 179 #endif /* !_TME_THREADS_H */ 180