Advertisement
iliyabylich04

TSHR

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