File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / TSRM / TSRM.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:34:34 2012 UTC (12 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_29p0, v5_4_29, v5_4_20p0, v5_4_20, v5_4_17p0, v5_4_17, HEAD
php 5.4.3+patches

    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) */
  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) */
  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 */
  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: 
  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 */
  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 */
  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: 
  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 */
  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 */
  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 */
  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 */
  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 */
  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 */
  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 */
  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: */
  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: */
  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
  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: 
  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: 
  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
  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: 
  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 */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>