1 /*
2 ** Copyright (C) 2006-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8 
9 /*
10 **  skthread.c
11 **
12 **    Common thread routines, useful for debugging.
13 */
14 
15 
16 #include <silk/silk.h>
17 
18 RCSIDENT("$SiLK: skthread.c ef14e54179be 2020-04-14 21:57:45Z mthomas $");
19 
20 #include <silk/utils.h>
21 #include <silk/skthread.h>
22 
23 /* LOCAL DEFINES AND TYPEDEFS */
24 
25 #ifndef SKTHREAD_LOG_IDS
26 #define SKTHREAD_LOG_IDS    0
27 #endif
28 
29 typedef struct skthread_data_st {
30     const char *name;
31     void *(*fn)(void *);
32     void *arg;
33 } skthread_data_t;
34 
35 
36 /* EXPORTED VARIABLE DEFINITIONS */
37 
38 /* Used as a flag so we warn on too many read locks only once.  */
39 int skthread_too_many_readlocks = 0;
40 
41 
42 /* LOCAL VARIABLE DEFINITIONS */
43 
44 static int initialized = 0;
45 static pthread_key_t skthread_name_key;
46 static pthread_key_t skthread_id_key;
47 
48 /* mutex for protecting next_thread_id */
49 static pthread_mutex_t mutex;
50 static uint32_t next_thread_id = 0;
51 
52 
53 /* FUNCTION DEFINITIONS */
54 
55 /*
56  *    Set the thread's name and id.
57  *
58  *    Set the thread's name to the specified argument.  For the ID,
59  *    allocate a uint32_t, set that value to the next unused thread
60  *    ID, and set the thread's ID to that value.
61  */
62 static void
skthread_set_name_id(const char * name)63 skthread_set_name_id(
64     const char         *name)
65 {
66     uint32_t *id = (uint32_t*)malloc(sizeof(uint32_t));
67     if (id != NULL) {
68         pthread_mutex_lock(&mutex);
69         *id = next_thread_id++;
70         pthread_mutex_unlock(&mutex);
71 
72         pthread_setspecific(skthread_id_key, id);
73 #if SKTHREAD_LOG_IDS
74         skAppPrintErr("Thread ID:%" PRIu32 " ('%s') started", *id, name);
75 #endif
76     }
77     pthread_setspecific(skthread_name_key, name);
78 }
79 
80 /*
81  *    Free the id for the current thread.
82  */
83 static void
skthread_free_id(void * id)84 skthread_free_id(
85     void               *id)
86 {
87     if (id) {
88 #if SKTHREAD_LOG_IDS
89         skAppPrintErr("Thread ID:%" PRIu32 " ended", *(uint32_t*)id);
90 #endif  /* SKTHREAD_LOG_IDS */
91         free(id);
92     }
93 }
94 
95 /* initialize skthread code.  called once by main thread */
96 int
skthread_init(const char * name)97 skthread_init(
98     const char         *name)
99 {
100     if (initialized) {
101         return 0;
102     }
103     if (pthread_mutex_init(&mutex, NULL) != 0) {
104         return -1;
105     }
106     if (pthread_key_create(&skthread_name_key, NULL) != 0) {
107         return -1;
108     }
109     if (pthread_key_create(&skthread_id_key, skthread_free_id) != 0) {
110         return -1;
111     }
112     skthread_set_name_id(name);
113 
114     initialized = 1;
115     return 0;
116 }
117 
118 /* teardown skthread code.  called once by main thread */
119 void
skthread_teardown(void)120 skthread_teardown(
121     void)
122 {
123     void *val;
124     if (!initialized) {
125         return;
126     }
127     initialized = 0;
128     val = pthread_getspecific(skthread_id_key);
129     pthread_setspecific(skthread_id_key, NULL);
130     pthread_key_delete(skthread_id_key);
131     pthread_key_delete(skthread_name_key);
132     skthread_free_id(val);
133 }
134 
135 /* return thread's name */
136 const char *
skthread_name(void)137 skthread_name(
138     void)
139 {
140     if (initialized) {
141         const char *rv = (const char *)pthread_getspecific(skthread_name_key);
142         if (rv != NULL) {
143             return rv;
144         }
145     }
146     return "unknown";
147 }
148 
149 /* return thread's ID */
150 uint32_t
skthread_id(void)151 skthread_id(
152     void)
153 {
154     if (initialized) {
155         uint32_t *id = (uint32_t *)pthread_getspecific(skthread_id_key);
156         if (id != NULL) {
157             return *id;
158         }
159     }
160     return SKTHREAD_UNKNOWN_ID;
161 }
162 
163 
164 /*
165  *    Thread entry function.
166  *
167  *    Wrapper function that is invoked by the pthread_create() call in
168  *    skthread_create_helper() function.
169  *
170  *    Sets the thread's name, the thread's ID, sets the thread's
171  *    signal mask to ignore all signals, then invokes the caller's
172  *    function with the caller's argument.
173  *
174  *    The 'vdata' parameter contains the thread's name, the caller's
175  *    function and argument.
176  */
177 static void *
skthread_create_init(void * vdata)178 skthread_create_init(
179     void               *vdata)
180 {
181     skthread_data_t *data = (skthread_data_t *)vdata;
182     void *(*fn)(void *) = data->fn;
183     void *arg = data->arg;
184 
185     /* ignore all signals */
186     skthread_ignore_signals();
187 
188     if (initialized) {
189         skthread_set_name_id(data->name);
190     }
191     free(data);
192 
193     return fn(arg);
194 }
195 
196 
197 /*
198  *    Helper function that implements common parts of
199  *    skthread_create() and skthread_create_detached().
200  */
201 static int
skthread_create_helper(const char * name,pthread_t * thread,void * (* fn)(void *),void * arg,pthread_attr_t * attr)202 skthread_create_helper(
203     const char         *name,
204     pthread_t          *thread,
205     void             *(*fn)(void *),
206     void               *arg,
207     pthread_attr_t     *attr)
208 {
209     skthread_data_t *data;
210     int rv;
211 
212     data = (skthread_data_t *)malloc(sizeof(*data));
213     if (NULL == data) {
214         return errno;
215     }
216     data->name = name;
217     data->fn = fn;
218     data->arg = arg;
219 
220     rv = pthread_create(thread, attr, skthread_create_init, data);
221     if (rv != 0) {
222         free(data);
223     }
224     return rv;
225 }
226 
227 int
skthread_create(const char * name,pthread_t * thread,void * (* fn)(void *),void * arg)228 skthread_create(
229     const char         *name,
230     pthread_t          *thread,
231     void             *(*fn)(void *),
232     void               *arg)
233 {
234     return skthread_create_helper(name, thread, fn, arg, NULL);
235 }
236 
237 
238 int
skthread_create_detached(const char * name,pthread_t * thread,void * (* fn)(void *),void * arg)239 skthread_create_detached(
240     const char         *name,
241     pthread_t          *thread,
242     void             *(*fn)(void *),
243     void               *arg)
244 {
245     pthread_attr_t attr;
246     int rv;
247 
248     rv = pthread_attr_init(&attr);
249     if (rv != 0) {
250         return rv;
251     }
252     rv = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
253     assert(rv == 0);
254 
255     rv = skthread_create_helper(name, thread, fn, arg, &attr);
256     pthread_attr_destroy(&attr);
257 
258     return rv;
259 }
260 
261 
262 void
skthread_ignore_signals(void)263 skthread_ignore_signals(
264     void)
265 {
266     sigset_t sigs;
267 
268     sigfillset(&sigs);
269     sigdelset(&sigs, SIGABRT);
270     sigdelset(&sigs, SIGBUS);
271     sigdelset(&sigs, SIGILL);
272     sigdelset(&sigs, SIGSEGV);
273 
274 #ifdef SIGEMT
275     sigdelset(&sigs, SIGEMT);
276 #endif
277 #ifdef SIGIOT
278     sigdelset(&sigs, SIGIOT);
279 #endif
280 #ifdef SIGSYS
281     sigdelset(&sigs, SIGSYS);
282 #endif
283 
284     pthread_sigmask(SIG_SETMASK, &sigs, NULL);
285 }
286 
287 
288 /*
289 ** Local Variables:
290 ** mode:c
291 ** indent-tabs-mode:nil
292 ** c-basic-offset:4
293 ** End:
294 */
295