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