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