1 /*
2 +----------------------------------------------------------------------+
3 | Thread Safe Resource Manager |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1999-2011, Andi Gutmans, Sascha Schumann, Zeev Suraski |
6 | This source file is subject to the TSRM license, that is bundled |
7 | with this package in the file LICENSE |
8 +----------------------------------------------------------------------+
9 | Authors: Zeev Suraski <zeev@php.net> |
10 +----------------------------------------------------------------------+
11 */
12
13 #include "TSRM.h"
14
15 #ifdef ZTS
16
17 #include <stdio.h>
18
19 #if HAVE_STDARG_H
20 #include <stdarg.h>
21 #endif
22
23 typedef struct _tsrm_tls_entry tsrm_tls_entry;
24
25 #if defined(TSRM_WIN32)
26 /* TSRMLS_CACHE_DEFINE; is already done in Zend, this is being always compiled statically. */
27 #endif
28
29 struct _tsrm_tls_entry {
30 void **storage;
31 int count;
32 THREAD_T thread_id;
33 tsrm_tls_entry *next;
34 };
35
36
37 typedef struct {
38 size_t size;
39 ts_allocate_ctor ctor;
40 ts_allocate_dtor dtor;
41 int done;
42 } tsrm_resource_type;
43
44
45 /* The memory manager table */
46 static tsrm_tls_entry **tsrm_tls_table=NULL;
47 static int tsrm_tls_table_size;
48 static ts_rsrc_id id_count;
49
50 /* The resource sizes table */
51 static tsrm_resource_type *resource_types_table=NULL;
52 static int resource_types_table_size;
53
54
55 static MUTEX_T tsmm_mutex; /* thread-safe memory manager mutex */
56
57 /* New thread handlers */
58 static tsrm_thread_begin_func_t tsrm_new_thread_begin_handler = NULL;
59 static tsrm_thread_end_func_t tsrm_new_thread_end_handler = NULL;
60 static tsrm_shutdown_func_t tsrm_shutdown_handler = NULL;
61
62 /* Debug support */
63 int tsrm_error(int level, const char *format, ...);
64
65 /* Read a resource from a thread's resource storage */
66 static int tsrm_error_level;
67 static FILE *tsrm_error_file;
68
69 #if TSRM_DEBUG
70 #define TSRM_ERROR(args) tsrm_error args
71 #define TSRM_SAFE_RETURN_RSRC(array, offset, range) \
72 { \
73 int unshuffled_offset = TSRM_UNSHUFFLE_RSRC_ID(offset); \
74 \
75 if (offset==0) { \
76 return &array; \
77 } else if ((unshuffled_offset)>=0 && (unshuffled_offset)<(range)) { \
78 TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Successfully fetched resource id %d for thread id %ld - 0x%0.8X", \
79 unshuffled_offset, (long) thread_resources->thread_id, array[unshuffled_offset])); \
80 return array[unshuffled_offset]; \
81 } else { \
82 TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Resource id %d is out of range (%d..%d)", \
83 unshuffled_offset, TSRM_SHUFFLE_RSRC_ID(0), TSRM_SHUFFLE_RSRC_ID(thread_resources->count-1))); \
84 return NULL; \
85 } \
86 }
87 #else
88 #define TSRM_ERROR(args)
89 #define TSRM_SAFE_RETURN_RSRC(array, offset, range) \
90 if (offset==0) { \
91 return &array; \
92 } else { \
93 return array[TSRM_UNSHUFFLE_RSRC_ID(offset)]; \
94 }
95 #endif
96
97 #if defined(GNUPTH)
98 static pth_key_t tls_key;
99 # define tsrm_tls_set(what) pth_key_setdata(tls_key, (void*)(what))
100 # define tsrm_tls_get() pth_key_getdata(tls_key)
101
102 #elif defined(PTHREADS)
103 /* Thread local storage */
104 static pthread_key_t tls_key;
105 # define tsrm_tls_set(what) pthread_setspecific(tls_key, (void*)(what))
106 # define tsrm_tls_get() pthread_getspecific(tls_key)
107
108 #elif defined(TSRM_ST)
109 static int tls_key;
110 # define tsrm_tls_set(what) st_thread_setspecific(tls_key, (void*)(what))
111 # define tsrm_tls_get() st_thread_getspecific(tls_key)
112
113 #elif defined(TSRM_WIN32)
114 static DWORD tls_key;
115 # define tsrm_tls_set(what) TlsSetValue(tls_key, (void*)(what))
116 # define tsrm_tls_get() TlsGetValue(tls_key)
117
118 #else
119 # define tsrm_tls_set(what)
120 # define tsrm_tls_get() NULL
121 # warning tsrm_set_interpreter_context is probably broken on this platform
122 #endif
123
124 TSRM_TLS uint8_t in_main_thread = 0;
125
126 /* Startup TSRM (call once for the entire process) */
tsrm_startup(int expected_threads,int expected_resources,int debug_level,char * debug_filename)127 TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, char *debug_filename)
128 {/*{{{*/
129 #if defined(GNUPTH)
130 pth_init();
131 pth_key_create(&tls_key, 0);
132 #elif defined(PTHREADS)
133 pthread_key_create( &tls_key, 0 );
134 #elif defined(TSRM_ST)
135 st_init();
136 st_key_create(&tls_key, 0);
137 #elif defined(TSRM_WIN32)
138 tls_key = TlsAlloc();
139 #endif
140
141 /* ensure singleton */
142 in_main_thread = 1;
143
144 tsrm_error_file = stderr;
145 tsrm_error_set(debug_level, debug_filename);
146 tsrm_tls_table_size = expected_threads;
147
148 tsrm_tls_table = (tsrm_tls_entry **) calloc(tsrm_tls_table_size, sizeof(tsrm_tls_entry *));
149 if (!tsrm_tls_table) {
150 TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate TLS table"));
151 return 0;
152 }
153 id_count=0;
154
155 resource_types_table_size = expected_resources;
156 resource_types_table = (tsrm_resource_type *) calloc(resource_types_table_size, sizeof(tsrm_resource_type));
157 if (!resource_types_table) {
158 TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate resource types table"));
159 free(tsrm_tls_table);
160 tsrm_tls_table = NULL;
161 return 0;
162 }
163
164 tsmm_mutex = tsrm_mutex_alloc();
165
166 TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Started up TSRM, %d expected threads, %d expected resources", expected_threads, expected_resources));
167 return 1;
168 }/*}}}*/
169
170
171 /* Shutdown TSRM (call once for the entire process) */
tsrm_shutdown(void)172 TSRM_API void tsrm_shutdown(void)
173 {/*{{{*/
174 int i;
175
176 if (!in_main_thread) {
177 /* ensure singleton */
178 return;
179 }
180
181 if (tsrm_tls_table) {
182 for (i=0; i<tsrm_tls_table_size; i++) {
183 tsrm_tls_entry *p = tsrm_tls_table[i], *next_p;
184
185 while (p) {
186 int j;
187
188 next_p = p->next;
189 for (j=0; j<p->count; j++) {
190 if (p->storage[j]) {
191 if (resource_types_table && !resource_types_table[j].done && resource_types_table[j].dtor) {
192 resource_types_table[j].dtor(p->storage[j]);
193 }
194 free(p->storage[j]);
195 }
196 }
197 free(p->storage);
198 free(p);
199 p = next_p;
200 }
201 }
202 free(tsrm_tls_table);
203 tsrm_tls_table = NULL;
204 }
205 if (resource_types_table) {
206 free(resource_types_table);
207 resource_types_table=NULL;
208 }
209 tsrm_mutex_free(tsmm_mutex);
210 tsmm_mutex = NULL;
211 TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Shutdown TSRM"));
212 if (tsrm_error_file!=stderr) {
213 fclose(tsrm_error_file);
214 }
215 #if defined(GNUPTH)
216 pth_kill();
217 #elif defined(PTHREADS)
218 pthread_setspecific(tls_key, 0);
219 pthread_key_delete(tls_key);
220 #elif defined(TSRM_WIN32)
221 TlsFree(tls_key);
222 #endif
223 if (tsrm_shutdown_handler) {
224 tsrm_shutdown_handler();
225 }
226 tsrm_new_thread_begin_handler = NULL;
227 tsrm_new_thread_end_handler = NULL;
228 tsrm_shutdown_handler = NULL;
229 }/*}}}*/
230
231
232 /* allocates a new thread-safe-resource id */
ts_allocate_id(ts_rsrc_id * rsrc_id,size_t size,ts_allocate_ctor ctor,ts_allocate_dtor dtor)233 TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
234 {/*{{{*/
235 int i;
236
237 TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new resource id, %d bytes", size));
238
239 tsrm_mutex_lock(tsmm_mutex);
240
241 /* obtain a resource id */
242 *rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);
243 TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtained resource id %d", *rsrc_id));
244
245 /* store the new resource type in the resource sizes table */
246 if (resource_types_table_size < id_count) {
247 tsrm_resource_type *_tmp;
248 _tmp = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
249 if (!_tmp) {
250 tsrm_mutex_unlock(tsmm_mutex);
251 TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource"));
252 *rsrc_id = 0;
253 return 0;
254 }
255 resource_types_table = _tmp;
256 resource_types_table_size = id_count;
257 }
258 resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size;
259 resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
260 resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
261 resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;
262
263 /* enlarge the arrays for the already active threads */
264 for (i=0; i<tsrm_tls_table_size; i++) {
265 tsrm_tls_entry *p = tsrm_tls_table[i];
266
267 while (p) {
268 if (p->count < id_count) {
269 int j;
270
271 p->storage = (void *) realloc(p->storage, sizeof(void *)*id_count);
272 for (j=p->count; j<id_count; j++) {
273 p->storage[j] = (void *) malloc(resource_types_table[j].size);
274 if (resource_types_table[j].ctor) {
275 resource_types_table[j].ctor(p->storage[j]);
276 }
277 }
278 p->count = id_count;
279 }
280 p = p->next;
281 }
282 }
283 tsrm_mutex_unlock(tsmm_mutex);
284
285 TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new resource id %d", *rsrc_id));
286 return *rsrc_id;
287 }/*}}}*/
288
289
allocate_new_resource(tsrm_tls_entry ** thread_resources_ptr,THREAD_T thread_id)290 static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_T thread_id)
291 {/*{{{*/
292 int i;
293
294 TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Creating data structures for thread %x", thread_id));
295 (*thread_resources_ptr) = (tsrm_tls_entry *) malloc(sizeof(tsrm_tls_entry));
296 (*thread_resources_ptr)->storage = NULL;
297 if (id_count > 0) {
298 (*thread_resources_ptr)->storage = (void **) malloc(sizeof(void *)*id_count);
299 }
300 (*thread_resources_ptr)->count = id_count;
301 (*thread_resources_ptr)->thread_id = thread_id;
302 (*thread_resources_ptr)->next = NULL;
303
304 /* Set thread local storage to this new thread resources structure */
305 tsrm_tls_set(*thread_resources_ptr);
306
307 if (tsrm_new_thread_begin_handler) {
308 tsrm_new_thread_begin_handler(thread_id);
309 }
310 for (i=0; i<id_count; i++) {
311 if (resource_types_table[i].done) {
312 (*thread_resources_ptr)->storage[i] = NULL;
313 } else
314 {
315 (*thread_resources_ptr)->storage[i] = (void *) malloc(resource_types_table[i].size);
316 if (resource_types_table[i].ctor) {
317 resource_types_table[i].ctor((*thread_resources_ptr)->storage[i]);
318 }
319 }
320 }
321
322 if (tsrm_new_thread_end_handler) {
323 tsrm_new_thread_end_handler(thread_id);
324 }
325
326 tsrm_mutex_unlock(tsmm_mutex);
327 }/*}}}*/
328
329
330 /* fetches the requested resource for the current thread */
ts_resource_ex(ts_rsrc_id id,THREAD_T * th_id)331 TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
332 {/*{{{*/
333 THREAD_T thread_id;
334 int hash_value;
335 tsrm_tls_entry *thread_resources;
336
337 if (!th_id) {
338 /* Fast path for looking up the resources for the current
339 * thread. Its used by just about every call to
340 * ts_resource_ex(). This avoids the need for a mutex lock
341 * and our hashtable lookup.
342 */
343 thread_resources = tsrm_tls_get();
344
345 if (thread_resources) {
346 TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for current thread %d", id, (long) thread_resources->thread_id));
347 /* Read a specific resource from the thread's resources.
348 * This is called outside of a mutex, so have to be aware about external
349 * changes to the structure as we read it.
350 */
351 TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count);
352 }
353 thread_id = tsrm_thread_id();
354 } else {
355 thread_id = *th_id;
356 }
357
358 TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for thread %ld", id, (long) thread_id));
359 tsrm_mutex_lock(tsmm_mutex);
360
361 hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
362 thread_resources = tsrm_tls_table[hash_value];
363
364 if (!thread_resources) {
365 allocate_new_resource(&tsrm_tls_table[hash_value], thread_id);
366 return ts_resource_ex(id, &thread_id);
367 } else {
368 do {
369 if (thread_resources->thread_id == thread_id) {
370 break;
371 }
372 if (thread_resources->next) {
373 thread_resources = thread_resources->next;
374 } else {
375 allocate_new_resource(&thread_resources->next, thread_id);
376 return ts_resource_ex(id, &thread_id);
377 /*
378 * thread_resources = thread_resources->next;
379 * break;
380 */
381 }
382 } while (thread_resources);
383 }
384 tsrm_mutex_unlock(tsmm_mutex);
385 /* Read a specific resource from the thread's resources.
386 * This is called outside of a mutex, so have to be aware about external
387 * changes to the structure as we read it.
388 */
389 TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count);
390 }/*}}}*/
391
392 /* frees an interpreter context. You are responsible for making sure that
393 * it is not linked into the TSRM hash, and not marked as the current interpreter */
tsrm_free_interpreter_context(void * context)394 void tsrm_free_interpreter_context(void *context)
395 {/*{{{*/
396 tsrm_tls_entry *next, *thread_resources = (tsrm_tls_entry*)context;
397 int i;
398
399 while (thread_resources) {
400 next = thread_resources->next;
401
402 for (i=0; i<thread_resources->count; i++) {
403 if (resource_types_table[i].dtor) {
404 resource_types_table[i].dtor(thread_resources->storage[i]);
405 }
406 }
407 for (i=0; i<thread_resources->count; i++) {
408 free(thread_resources->storage[i]);
409 }
410 free(thread_resources->storage);
411 free(thread_resources);
412 thread_resources = next;
413 }
414 }/*}}}*/
415
tsrm_set_interpreter_context(void * new_ctx)416 void *tsrm_set_interpreter_context(void *new_ctx)
417 {/*{{{*/
418 tsrm_tls_entry *current;
419
420 current = tsrm_tls_get();
421
422 /* TODO: unlink current from the global linked list, and replace it
423 * it with the new context, protected by mutex where/if appropriate */
424
425 /* Set thread local storage to this new thread resources structure */
426 tsrm_tls_set(new_ctx);
427
428 /* return old context, so caller can restore it when they're done */
429 return current;
430 }/*}}}*/
431
432
433 /* allocates a new interpreter context */
tsrm_new_interpreter_context(void)434 void *tsrm_new_interpreter_context(void)
435 {/*{{{*/
436 tsrm_tls_entry *new_ctx, *current;
437 THREAD_T thread_id;
438
439 thread_id = tsrm_thread_id();
440 tsrm_mutex_lock(tsmm_mutex);
441
442 current = tsrm_tls_get();
443
444 allocate_new_resource(&new_ctx, thread_id);
445
446 /* switch back to the context that was in use prior to our creation
447 * of the new one */
448 return tsrm_set_interpreter_context(current);
449 }/*}}}*/
450
451
452 /* frees all resources allocated for the current thread */
ts_free_thread(void)453 void ts_free_thread(void)
454 {/*{{{*/
455 tsrm_tls_entry *thread_resources;
456 int i;
457 THREAD_T thread_id = tsrm_thread_id();
458 int hash_value;
459 tsrm_tls_entry *last=NULL;
460
461 tsrm_mutex_lock(tsmm_mutex);
462 hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
463 thread_resources = tsrm_tls_table[hash_value];
464
465 while (thread_resources) {
466 if (thread_resources->thread_id == thread_id) {
467 for (i=0; i<thread_resources->count; i++) {
468 if (resource_types_table[i].dtor) {
469 resource_types_table[i].dtor(thread_resources->storage[i]);
470 }
471 }
472 for (i=0; i<thread_resources->count; i++) {
473 free(thread_resources->storage[i]);
474 }
475 free(thread_resources->storage);
476 if (last) {
477 last->next = thread_resources->next;
478 } else {
479 tsrm_tls_table[hash_value] = thread_resources->next;
480 }
481 tsrm_tls_set(0);
482 free(thread_resources);
483 break;
484 }
485 if (thread_resources->next) {
486 last = thread_resources;
487 }
488 thread_resources = thread_resources->next;
489 }
490 tsrm_mutex_unlock(tsmm_mutex);
491 }/*}}}*/
492
493
494 /* frees all resources allocated for all threads except current */
ts_free_worker_threads(void)495 void ts_free_worker_threads(void)
496 {/*{{{*/
497 tsrm_tls_entry *thread_resources;
498 int i;
499 THREAD_T thread_id = tsrm_thread_id();
500 int hash_value;
501 tsrm_tls_entry *last=NULL;
502
503 tsrm_mutex_lock(tsmm_mutex);
504 hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
505 thread_resources = tsrm_tls_table[hash_value];
506
507 while (thread_resources) {
508 if (thread_resources->thread_id != thread_id) {
509 for (i=0; i<thread_resources->count; i++) {
510 if (resource_types_table[i].dtor) {
511 resource_types_table[i].dtor(thread_resources->storage[i]);
512 }
513 }
514 for (i=0; i<thread_resources->count; i++) {
515 free(thread_resources->storage[i]);
516 }
517 free(thread_resources->storage);
518 if (last) {
519 last->next = thread_resources->next;
520 } else {
521 tsrm_tls_table[hash_value] = thread_resources->next;
522 }
523 free(thread_resources);
524 if (last) {
525 thread_resources = last->next;
526 } else {
527 thread_resources = tsrm_tls_table[hash_value];
528 }
529 } else {
530 if (thread_resources->next) {
531 last = thread_resources;
532 }
533 thread_resources = thread_resources->next;
534 }
535 }
536 tsrm_mutex_unlock(tsmm_mutex);
537 }/*}}}*/
538
539
540 /* deallocates all occurrences of a given id */
ts_free_id(ts_rsrc_id id)541 void ts_free_id(ts_rsrc_id id)
542 {/*{{{*/
543 int i;
544 int j = TSRM_UNSHUFFLE_RSRC_ID(id);
545
546 tsrm_mutex_lock(tsmm_mutex);
547
548 TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Freeing resource id %d", id));
549
550 if (tsrm_tls_table) {
551 for (i=0; i<tsrm_tls_table_size; i++) {
552 tsrm_tls_entry *p = tsrm_tls_table[i];
553
554 while (p) {
555 if (p->count > j && p->storage[j]) {
556 if (resource_types_table && resource_types_table[j].dtor) {
557 resource_types_table[j].dtor(p->storage[j]);
558 }
559 free(p->storage[j]);
560 p->storage[j] = NULL;
561 }
562 p = p->next;
563 }
564 }
565 }
566 resource_types_table[j].done = 1;
567
568 tsrm_mutex_unlock(tsmm_mutex);
569
570 TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully freed resource id %d", id));
571 }/*}}}*/
572
573
574
575
576 /*
577 * Utility Functions
578 */
579
580 /* Obtain the current thread id */
tsrm_thread_id(void)581 TSRM_API THREAD_T tsrm_thread_id(void)
582 {/*{{{*/
583 #ifdef TSRM_WIN32
584 return GetCurrentThreadId();
585 #elif defined(GNUPTH)
586 return pth_self();
587 #elif defined(PTHREADS)
588 return pthread_self();
589 #elif defined(TSRM_ST)
590 return st_thread_self();
591 #endif
592 }/*}}}*/
593
594
595 /* Allocate a mutex */
tsrm_mutex_alloc(void)596 TSRM_API MUTEX_T tsrm_mutex_alloc(void)
597 {/*{{{*/
598 MUTEX_T mutexp;
599 #ifdef TSRM_WIN32
600 mutexp = malloc(sizeof(CRITICAL_SECTION));
601 InitializeCriticalSection(mutexp);
602 #elif defined(GNUPTH)
603 mutexp = (MUTEX_T) malloc(sizeof(*mutexp));
604 pth_mutex_init(mutexp);
605 #elif defined(PTHREADS)
606 mutexp = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
607 pthread_mutex_init(mutexp,NULL);
608 #elif defined(TSRM_ST)
609 mutexp = st_mutex_new();
610 #endif
611 #ifdef THR_DEBUG
612 printf("Mutex created thread: %d\n",mythreadid());
613 #endif
614 return( mutexp );
615 }/*}}}*/
616
617
618 /* Free a mutex */
tsrm_mutex_free(MUTEX_T mutexp)619 TSRM_API void tsrm_mutex_free(MUTEX_T mutexp)
620 {/*{{{*/
621 if (mutexp) {
622 #ifdef TSRM_WIN32
623 DeleteCriticalSection(mutexp);
624 free(mutexp);
625 #elif defined(GNUPTH)
626 free(mutexp);
627 #elif defined(PTHREADS)
628 pthread_mutex_destroy(mutexp);
629 free(mutexp);
630 #elif defined(TSRM_ST)
631 st_mutex_destroy(mutexp);
632 #endif
633 }
634 #ifdef THR_DEBUG
635 printf("Mutex freed thread: %d\n",mythreadid());
636 #endif
637 }/*}}}*/
638
639
640 /*
641 Lock a mutex.
642 A return value of 0 indicates success
643 */
tsrm_mutex_lock(MUTEX_T mutexp)644 TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp)
645 {/*{{{*/
646 TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Mutex locked thread: %ld", tsrm_thread_id()));
647 #ifdef TSRM_WIN32
648 EnterCriticalSection(mutexp);
649 return 0;
650 #elif defined(GNUPTH)
651 if (pth_mutex_acquire(mutexp, 0, NULL)) {
652 return 0;
653 }
654 return -1;
655 #elif defined(PTHREADS)
656 return pthread_mutex_lock(mutexp);
657 #elif defined(TSRM_ST)
658 return st_mutex_lock(mutexp);
659 #endif
660 }/*}}}*/
661
662
663 /*
664 Unlock a mutex.
665 A return value of 0 indicates success
666 */
tsrm_mutex_unlock(MUTEX_T mutexp)667 TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp)
668 {/*{{{*/
669 TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Mutex unlocked thread: %ld", tsrm_thread_id()));
670 #ifdef TSRM_WIN32
671 LeaveCriticalSection(mutexp);
672 return 0;
673 #elif defined(GNUPTH)
674 if (pth_mutex_release(mutexp)) {
675 return 0;
676 }
677 return -1;
678 #elif defined(PTHREADS)
679 return pthread_mutex_unlock(mutexp);
680 #elif defined(TSRM_ST)
681 return st_mutex_unlock(mutexp);
682 #endif
683 }/*}}}*/
684
685 /*
686 Changes the signal mask of the calling thread
687 */
688 #ifdef HAVE_SIGPROCMASK
tsrm_sigmask(int how,const sigset_t * set,sigset_t * oldset)689 TSRM_API int tsrm_sigmask(int how, const sigset_t *set, sigset_t *oldset)
690 {/*{{{*/
691 TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Changed sigmask in thread: %ld", tsrm_thread_id()));
692 /* TODO: add support for other APIs */
693 #ifdef PTHREADS
694 return pthread_sigmask(how, set, oldset);
695 #else
696 return sigprocmask(how, set, oldset);
697 #endif
698 }/*}}}*/
699 #endif
700
701
tsrm_set_new_thread_begin_handler(tsrm_thread_begin_func_t new_thread_begin_handler)702 TSRM_API void *tsrm_set_new_thread_begin_handler(tsrm_thread_begin_func_t new_thread_begin_handler)
703 {/*{{{*/
704 void *retval = (void *) tsrm_new_thread_begin_handler;
705
706 tsrm_new_thread_begin_handler = new_thread_begin_handler;
707 return retval;
708 }/*}}}*/
709
710
tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread_end_handler)711 TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread_end_handler)
712 {/*{{{*/
713 void *retval = (void *) tsrm_new_thread_end_handler;
714
715 tsrm_new_thread_end_handler = new_thread_end_handler;
716 return retval;
717 }/*}}}*/
718
719
tsrm_set_shutdown_handler(tsrm_shutdown_func_t shutdown_handler)720 TSRM_API void *tsrm_set_shutdown_handler(tsrm_shutdown_func_t shutdown_handler)
721 {/*{{{*/
722 void *retval = (void *) tsrm_shutdown_handler;
723
724 tsrm_shutdown_handler = shutdown_handler;
725 return retval;
726 }/*}}}*/
727
728
729 /*
730 * Debug support
731 */
732
733 #if TSRM_DEBUG
tsrm_error(int level,const char * format,...)734 int tsrm_error(int level, const char *format, ...)
735 {/*{{{*/
736 if (level<=tsrm_error_level) {
737 va_list args;
738 int size;
739
740 fprintf(tsrm_error_file, "TSRM: ");
741 va_start(args, format);
742 size = vfprintf(tsrm_error_file, format, args);
743 va_end(args);
744 fprintf(tsrm_error_file, "\n");
745 fflush(tsrm_error_file);
746 return size;
747 } else {
748 return 0;
749 }
750 }/*}}}*/
751 #endif
752
753
tsrm_error_set(int level,char * debug_filename)754 void tsrm_error_set(int level, char *debug_filename)
755 {/*{{{*/
756 tsrm_error_level = level;
757
758 #if TSRM_DEBUG
759 if (tsrm_error_file!=stderr) { /* close files opened earlier */
760 fclose(tsrm_error_file);
761 }
762
763 if (debug_filename) {
764 tsrm_error_file = fopen(debug_filename, "w");
765 if (!tsrm_error_file) {
766 tsrm_error_file = stderr;
767 }
768 } else {
769 tsrm_error_file = stderr;
770 }
771 #endif
772 }/*}}}*/
773
tsrm_get_ls_cache(void)774 TSRM_API void *tsrm_get_ls_cache(void)
775 {/*{{{*/
776 return tsrm_tls_get();
777 }/*}}}*/
778
tsrm_is_main_thread(void)779 TSRM_API uint8_t tsrm_is_main_thread(void)
780 {/*{{{*/
781 return in_main_thread;
782 }/*}}}*/
783
tsrm_api_name(void)784 TSRM_API const char *tsrm_api_name(void)
785 {/*{{{*/
786 #if defined(GNUPTH)
787 return "GNU Pth";
788 #elif defined(PTHREADS)
789 return "POSIX Threads";
790 #elif defined(TSRM_ST)
791 return "State Threads";
792 #elif defined(TSRM_WIN32)
793 return "Windows Threads";
794 #else
795 return "Unknown";
796 #endif
797 }/*}}}*/
798
799 #endif /* ZTS */
800
801 /*
802 * Local variables:
803 * tab-width: 4
804 * c-basic-offset: 4
805 * End:
806 * vim600: sw=4 ts=4 fdm=marker
807 * vim<600: sw=4 ts=4
808 */
809