TSRM.c 21 KB

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