source: trunk/src/sh_pthread.c @ 440

Last change on this file since 440 was 408, checked in by katerina, 9 years ago

Fix for ticket #311 (Thread safety of --enable-ptrace).

File size: 7.4 KB
Line 
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"
10extern volatile  int      sh_thread_pause_flag;
11
12SH_MUTEX_INIT(mutex_skey,         PTHREAD_MUTEX_INITIALIZER);
13SH_MUTEX_INIT(mutex_resolv,       PTHREAD_MUTEX_INITIALIZER);
14SH_MUTEX_INIT(mutex_pwent,        PTHREAD_MUTEX_INITIALIZER);
15SH_MUTEX_INIT(mutex_readdir,      PTHREAD_MUTEX_INITIALIZER);
16SH_MUTEX_INIT(mutex_thread_nolog, PTHREAD_MUTEX_INITIALIZER);
17
18int 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
23void sh_pthread_mutex_unlock (void *arg)
24{
25  (void) pthread_mutex_unlock ((pthread_mutex_t *)arg);
26  return;
27}
28
29int 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
72static pthread_t threads[SH_NUM_THREADS];
73static int       ithread[SH_NUM_THREADS];
74static pthread_mutex_t  create_mutex = PTHREAD_MUTEX_INITIALIZER;
75
76int 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
126int 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
159void 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
167void * 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                  0 != this_module->mod_timer(time(NULL)))
188                {
189                  /* If module has been de-activated on reconfigure,
190                   * mod_check() must return non-zero.
191                   * The mod_cleanup() routine must then enable the
192                   * module to be re-activated eventually.
193                   */
194                  if (0 != this_module->mod_check())
195                    break;
196                  pthread_testcancel();
197                }
198              if (0 == (SH_MODFL_NOTIMER & this_module->flags))
199                retry_msleep(1,0);
200            }
201
202          pthread_cleanup_pop(1); /* notreached,but required */
203        }
204    }
205
206  pthread_cleanup_pop(1);
207
208  return NULL;
209}
210
211
212/*
213 *  ----  Implementation of recursive mutexes from libxml2  ----
214 */
215#if !defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
216/**
217 * libxml2 threads.c: set of generic threading related routines
218 *
219 * Gary Pennington <Gary.Pennington@uk.sun.com>
220 * daniel@veillard.com
221 
222 * Except where otherwise noted in the source code (e.g. the files hash.c,
223 * list.c and the trio files, which are covered by a similar licence but
224 * with different Copyright notices) all the files are:
225 *
226 *    Copyright (C) 1998-2003 Daniel Veillard.  All Rights Reserved.
227 *
228 * Permission is hereby granted, free of charge, to any person obtaining a copy
229 * of this software and associated documentation files (the "Software"), to deal
230 * in the Software without restriction, including without limitation the rights
231 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
232 * copies of the Software, and to permit persons to whom the Software is fur-
233 * nished to do so, subject to the following conditions:
234 *
235 * The above copyright notice and this permission notice shall be included in
236 * all copies or substantial portions of the Software.
237 *
238 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
239 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
240 * NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
241 * DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
242 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
243 * NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
244 *
245 * Except as contained in this notice, the name of Daniel Veillard shall not
246 * be used in advertising or otherwise to promote the sale, use or other deal-
247 * ings in this Software without prior written authorization from him.
248 */
249
250/* Modified NewRMutex -> InitRMutex. We use a static structure, rather than
251 * allocating one. Also dropped code for non-POSIX OSes.
252 */
253void sh_InitRMutex(struct sh_RMutex * tok)
254{
255  pthread_mutex_init(&tok->lock, NULL);
256  tok->held = 0;
257  tok->waiters = 0;
258  pthread_cond_init(&tok->cv, NULL);
259
260  return;
261}
262
263void sh_RMutexLock(struct sh_RMutex * tok)
264{
265  if (tok == NULL)
266    return;
267
268  pthread_mutex_lock(&tok->lock);
269  if (tok->held) {
270    if (pthread_equal(tok->tid, pthread_self())) {
271      tok->held++;
272      pthread_mutex_unlock(&tok->lock);
273      return;
274    } else {
275      tok->waiters++;
276      while (tok->held)
277        pthread_cond_wait(&tok->cv, &tok->lock);
278      tok->waiters--;
279    }
280  }
281  tok->tid = pthread_self();
282  tok->held = 1;
283  pthread_mutex_unlock(&tok->lock);
284}
285
286void sh_RMutexUnlock(void * arg)
287{
288  struct sh_RMutex * tok = (struct sh_RMutex *) arg;
289
290  if (tok == NULL)
291    return;
292   
293  pthread_mutex_lock(&tok->lock);
294  tok->held--;
295  if (tok->held == 0) {
296    if (tok->waiters)
297      pthread_cond_signal(&tok->cv);
298    tok->tid = 0;
299  }
300  pthread_mutex_unlock(&tok->lock);
301}
302#endif
303
304#else
305
306#include <signal.h>
307
308int sh_pthread_setsigmask(int how, const void *set, void *oldset)
309{
310  return sigprocmask(how, (const sigset_t *)set, (sigset_t *)oldset);
311}
312
313
314#endif
Note: See TracBrowser for help on using the repository browser.