xref: /PHP-5.5/TSRM/TSRM.c (revision 34d93f0c)
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