1 #include "config_xor.h"
2
3 #include "sh_pthread.h"
4
5 #ifdef HAVE_PTHREAD
6
7 #include <signal.h>
8 #include "sh_calls.h"
9 #include "sh_modules.h"
10 extern volatile int sh_thread_pause_flag;
11
12 SH_MUTEX_INIT(mutex_skey, PTHREAD_MUTEX_INITIALIZER);
13 SH_MUTEX_INIT(mutex_resolv, PTHREAD_MUTEX_INITIALIZER);
14 SH_MUTEX_INIT(mutex_pwent, PTHREAD_MUTEX_INITIALIZER);
15 SH_MUTEX_INIT(mutex_readdir, PTHREAD_MUTEX_INITIALIZER);
16 SH_MUTEX_INIT(mutex_thread_nolog, PTHREAD_MUTEX_INITIALIZER);
17
sh_pthread_setsigmask(int how,const void * set,void * oldset)18 int sh_pthread_setsigmask(int how, const void *set, void *oldset)
19 {
20 return pthread_sigmask(how, (const sigset_t *)set, (sigset_t *)oldset);
21 }
22
sh_pthread_mutex_unlock(void * arg)23 void sh_pthread_mutex_unlock (void *arg)
24 {
25 (void) pthread_mutex_unlock ((pthread_mutex_t *)arg);
26 return;
27 }
28
sh_pthread_init_threadspecific(void)29 int sh_pthread_init_threadspecific(void)
30 {
31 int rc = 0;
32 #ifdef SH_STEALTH
33 do {
34 extern int sh_g_thread(void);
35
36 rc = sh_g_thread();
37 } while (0);
38 #endif
39
40 return rc;
41 }
42
43
44 /*
45 * ---- Utilities for modules ----
46 */
47
48 /* MODULES: init()
49 *
50 * #ifdef HAVE_PTHREAD
51 * if (arg != NULL)
52 * {
53 * if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
54 * return SH_MOD_THREAD;
55 * else
56 * return SH_MOD_FAILED;
57 * }
58 * #else
59 * return sh_utmp_init_internal();
60 * #endif
61 *
62 *
63 * sh_threaded_module_run(module_struct)
64 * -- calls internal init,
65 * -- polls timer,
66 * -- runs module check,
67 * -- runs sh_pthread_testcancel()
68 * -- returns (return == exit)
69 */
70
71 #define SH_NUM_THREADS 16
72 static pthread_t threads[SH_NUM_THREADS];
73 static int ithread[SH_NUM_THREADS];
74 static pthread_mutex_t create_mutex = PTHREAD_MUTEX_INITIALIZER;
75
sh_pthread_create(void * (* start_routine)(void *),void * arg)76 int sh_pthread_create(void *(*start_routine)(void*), void *arg)
77 {
78 int rc, nthread = 1;
79 sigset_t signal_set;
80 int retval = 0;
81
82 pthread_mutex_lock(&create_mutex);
83
84 /* block all signals
85 */
86 sigfillset( &signal_set );
87 #if defined(SCREW_IT_UP)
88 /*
89 * raise(SIGTRAP) sends to same thread, like
90 * pthread_kill(pthread_self(), sig); so we need to unblock the
91 * signal.
92 */
93 sigdelset( &signal_set, SIGTRAP );
94 #endif
95 pthread_sigmask( SIG_BLOCK, &signal_set, NULL );
96
97 /* find a free slot in threads[]
98 */
99 while (nthread < SH_NUM_THREADS)
100 {
101 if (ithread[nthread] == 0)
102 break;
103 ++nthread;
104 if (nthread == SH_NUM_THREADS)
105 {
106 retval = -1;
107 goto err_out;
108 }
109 }
110
111 rc = pthread_create(&threads[nthread], NULL, start_routine, arg);
112 if (rc != 0)
113 {
114 retval = -1;
115 goto err_out;
116 }
117
118 ithread[nthread] = 1;
119
120 err_out:
121 pthread_sigmask( SIG_UNBLOCK, &signal_set, NULL );
122 pthread_mutex_unlock(&create_mutex);
123 return retval;
124 }
125
sh_pthread_cancel_all()126 int sh_pthread_cancel_all()
127 {
128 int i;
129 int ret = 0;
130
131 SH_MUTEX_LOCK(create_mutex);
132
133 for (i = 1; i < SH_NUM_THREADS; ++i)
134 {
135 if (ithread[i] != 0)
136 if (0 != pthread_cancel(threads[i]))
137 ithread[i] = 0;
138 }
139
140 for (i = 1; i < SH_NUM_THREADS; ++i)
141 {
142 if (ithread[i] != 0)
143 pthread_join(threads[i], NULL);
144 ithread[i] = 0;
145 }
146
147 SH_MUTEX_UNLOCK(create_mutex);
148 return ret;
149 }
150
151 /* ---- Utility functions for modules ----
152 */
153
154 #undef S_TRUE
155 #define S_TRUE 1
156 #undef S_FALSE
157 #define S_FALSE 0
158
sh_threaded_module_cleanup(void * arg)159 void sh_threaded_module_cleanup(void *arg)
160 {
161 sh_mtype * this_module = (sh_mtype *) arg;
162 this_module->mod_cleanup();
163 this_module->initval = -1;
164 return;
165 }
166
sh_threaded_module_run(void * arg)167 void * sh_threaded_module_run(void *arg)
168 {
169 sh_mtype * this_module = (sh_mtype *) arg;
170
171 /* First we lock the module. This ensures that it cannot be
172 * run twice.
173 */
174 pthread_cleanup_push(sh_pthread_mutex_unlock, (void*) &(this_module->mod_mutex));
175 pthread_mutex_lock(&(this_module->mod_mutex));
176
177 if (0 == sh_pthread_init_threadspecific())
178 {
179
180 if (0 == this_module->mod_init(NULL))
181 {
182 pthread_cleanup_push(sh_threaded_module_cleanup, arg);
183
184 while (1)
185 {
186 if (sh_thread_pause_flag != S_TRUE)
187 {
188 this_module->flags &= ~SH_MODFL_ISPAUSED;
189
190 if (0 != this_module->mod_timer(time(NULL)))
191 {
192 /* If module has been de-activated on reconfigure,
193 * mod_check() must return non-zero.
194 * The mod_cleanup() routine must then enable the
195 * module to be re-activated eventually.
196 */
197 if (0 != this_module->mod_check())
198 break;
199 pthread_testcancel();
200 }
201 }
202 else
203 {
204 this_module->flags |= SH_MODFL_ISPAUSED;
205 }
206 if (0 == (SH_MODFL_NOTIMER & this_module->flags) ||
207 sh_thread_pause_flag == S_TRUE)
208 retry_msleep(1,0);
209 }
210
211 pthread_cleanup_pop(1); /* notreached,but required */
212 }
213 }
214
215 pthread_cleanup_pop(1);
216
217 return NULL;
218 }
219
220
221 /*
222 * ---- Implementation of recursive mutexes from libxml2 ----
223 */
224 #if !defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
225 /**
226 * libxml2 threads.c: set of generic threading related routines
227 *
228 * Gary Pennington <Gary.Pennington@uk.sun.com>
229 * daniel@veillard.com
230
231 * Except where otherwise noted in the source code (e.g. the files hash.c,
232 * list.c and the trio files, which are covered by a similar licence but
233 * with different Copyright notices) all the files are:
234 *
235 * Copyright (C) 1998-2003 Daniel Veillard. All Rights Reserved.
236 *
237 * Permission is hereby granted, free of charge, to any person obtaining a copy
238 * of this software and associated documentation files (the "Software"), to deal
239 * in the Software without restriction, including without limitation the rights
240 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
241 * copies of the Software, and to permit persons to whom the Software is fur-
242 * nished to do so, subject to the following conditions:
243 *
244 * The above copyright notice and this permission notice shall be included in
245 * all copies or substantial portions of the Software.
246 *
247 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
248 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
249 * NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
250 * DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
251 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
252 * NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
253 *
254 * Except as contained in this notice, the name of Daniel Veillard shall not
255 * be used in advertising or otherwise to promote the sale, use or other deal-
256 * ings in this Software without prior written authorization from him.
257 */
258
259 /* Modified NewRMutex -> InitRMutex. We use a static structure, rather than
260 * allocating one. Also dropped code for non-POSIX OSes.
261 */
sh_InitRMutex(struct sh_RMutex * tok)262 void sh_InitRMutex(struct sh_RMutex * tok)
263 {
264 pthread_mutex_init(&tok->lock, NULL);
265 tok->held = 0;
266 tok->waiters = 0;
267 pthread_cond_init(&tok->cv, NULL);
268
269 return;
270 }
271
sh_RMutexLock(struct sh_RMutex * tok)272 void sh_RMutexLock(struct sh_RMutex * tok)
273 {
274 if (tok == NULL)
275 return;
276
277 pthread_mutex_lock(&tok->lock);
278 if (tok->held) {
279 if (pthread_equal(tok->tid, pthread_self())) {
280 tok->held++;
281 pthread_mutex_unlock(&tok->lock);
282 return;
283 } else {
284 tok->waiters++;
285 while (tok->held)
286 pthread_cond_wait(&tok->cv, &tok->lock);
287 tok->waiters--;
288 }
289 }
290 tok->tid = pthread_self();
291 tok->held = 1;
292 pthread_mutex_unlock(&tok->lock);
293 }
294
sh_RMutexUnlock(void * arg)295 void sh_RMutexUnlock(void * arg)
296 {
297 struct sh_RMutex * tok = (struct sh_RMutex *) arg;
298
299 if (tok == NULL)
300 return;
301
302 pthread_mutex_lock(&tok->lock);
303 tok->held--;
304 if (tok->held == 0) {
305 if (tok->waiters)
306 pthread_cond_signal(&tok->cv);
307 tok->tid = 0;
308 }
309 pthread_mutex_unlock(&tok->lock);
310 }
311 #endif
312
313 #else
314
315 #include <signal.h>
316
sh_pthread_setsigmask(int how,const void * set,void * oldset)317 int sh_pthread_setsigmask(int how, const void *set, void *oldset)
318 {
319 return sigprocmask(how, (const sigset_t *)set, (sigset_t *)oldset);
320 }
321
322
323 #endif
324