xref: /PHP-7.3/TSRM/TSRM.c (revision 9afce019)
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