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