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