TSRM.c 21 KB

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