TSRM.c 21 KB

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