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