this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

xtrace: Add destructors for TLS variables

+50 -31
+4 -4
src/xtrace/bsd_trace.cpp
··· 1465 1465 xtrace_log(", ext[0] = 0x%llx, ext[1] = 0x%llx, ext[2] = 0x%llx, ext[3] = 0x%llx, qos = %d, xflags = 0x%x }", event->ext[0], event->ext[1], event->ext[2], event->ext[3], event->qos, event->xflags); 1466 1466 }; 1467 1467 1468 - DEFINE_XTRACE_TLS_VAR(void*, kevent_stored_list, NULL); 1469 - DEFINE_XTRACE_TLS_VAR(void*, kevent64_stored_list, NULL); 1470 - DEFINE_XTRACE_TLS_VAR(void*, kevent_qos_stored_list, NULL); 1468 + DEFINE_XTRACE_TLS_VAR(void*, kevent_stored_list, NULL, NULL); 1469 + DEFINE_XTRACE_TLS_VAR(void*, kevent64_stored_list, NULL, NULL); 1470 + DEFINE_XTRACE_TLS_VAR(void*, kevent_qos_stored_list, NULL, NULL); 1471 1471 1472 1472 enum class kevent_type { 1473 1473 kevent, ··· 1699 1699 int max_fd; 1700 1700 }; 1701 1701 1702 - DEFINE_XTRACE_TLS_VAR(select_fdsets, stored_select_fdsets, ((struct select_fdsets){NULL, NULL, NULL, -1})); 1702 + DEFINE_XTRACE_TLS_VAR(select_fdsets, stored_select_fdsets, ((struct select_fdsets){NULL, NULL, NULL, -1}), NULL); 1703 1703 1704 1704 static void print_fdset(const fd_set* set, int max_fd) { 1705 1705 bool isFirst = true;
+3 -3
src/xtrace/mach_trace.cpp
··· 13 13 #include "mig_trace.h" 14 14 #include "tls.h" 15 15 16 - DEFINE_XTRACE_TLS_VAR(int, mach_call_nr, -1); 17 - DEFINE_XTRACE_TLS_VAR(void*, argument_ptr, NULL); 18 - DEFINE_XTRACE_TLS_VAR(mach_port_name_t, request_port, MACH_PORT_NULL); 16 + DEFINE_XTRACE_TLS_VAR(int, mach_call_nr, -1, NULL); 17 + DEFINE_XTRACE_TLS_VAR(void*, argument_ptr, NULL, NULL); 18 + DEFINE_XTRACE_TLS_VAR(mach_port_name_t, request_port, MACH_PORT_NULL, NULL); 19 19 20 20 static void print_kern_return(int nr, uintptr_t rv); 21 21 static void print_port_return(int nr, uintptr_t rv);
+1 -1
src/xtrace/mig_trace.c
··· 76 76 closedir(xtrace_mig_dir); 77 77 } 78 78 79 - DEFINE_XTRACE_TLS_VAR(bool, is_first_arg, false); 79 + DEFINE_XTRACE_TLS_VAR(bool, is_first_arg, false, NULL); 80 80 81 81 #define BEFORE if (!get_is_first_arg()) xtrace_log(", ") 82 82 #define AFTER set_is_first_arg(false)
+19 -13
src/xtrace/tls.c
··· 17 17 #define xtrace_tls_debug(x, ...) 18 18 #endif 19 19 20 - // 10 TLS vars should be enough, right? 21 - #define TLS_TABLE_MAX_SIZE 10 20 + // 32 TLS vars should be enough, right? 21 + #define TLS_TABLE_MAX_SIZE 32 22 22 23 23 typedef struct tls_table* tls_table_t; 24 24 struct tls_table { 25 25 size_t size; 26 - void* table[TLS_TABLE_MAX_SIZE][2]; 26 + void* table[TLS_TABLE_MAX_SIZE][3]; 27 27 }; 28 28 29 29 // since we still need to handle some calls after pthread_terminate is called and libpthread unwinds its TLS right before calling pthread_terminate, ··· 32 32 33 33 #define __PTK_XTRACE_TLS 200 34 34 35 - // unfortunately, this approach also means that we can't automatically free the TLS memory when the thread dies, since the TLS table needs to stay alive after pthread_terminate. 36 - // in order to clean up the memory without a pthread key destructor, we'd need to modify our libsystem_kernel to inform us (via a hook) in every case where the thread could die. 37 - // 38 - // leaking a bit of memory per-thread being xtrace'd shouldn't be a big problem, unless the tracee is creating and terminating threads very quickly. 39 - // but it'd be nice if this could eventually be fixed (probably by adding a death hook to libsystem_kernel, as described above). 35 + // TODO: also perform TLS cleanup for other threads when doing a fork 40 36 41 - #if 0 42 - static void tls_table_destructor(void* _table) { 43 - tls_table_t table = _table; 37 + void xtrace_tls_thread_cleanup(void) { 38 + tls_table_t table = _pthread_getspecific_direct(__PTK_XTRACE_TLS); 39 + if (!table) { 40 + xtrace_tls_debug("no table to cleanup for this thread"); 41 + return; 42 + } 44 43 xtrace_tls_debug("destroying table %p", table); 45 44 for (size_t i = 0; i < table->size; ++i) { 45 + if (table->table[i][2]) { 46 + xtrace_tls_debug("destroying value %p for key %p", table->table[i][1], table->table[i][0]); 47 + ((xtrace_tls_destructor_f)table->table[i][2])(table->table[1]); 48 + } 46 49 xtrace_tls_debug("freeing value %p for key %p", table->table[i][1], table->table[i][0]); 47 50 xtrace_free(table->table[i][1]); 48 51 } 49 52 xtrace_tls_debug("freeing table %p", table); 50 53 xtrace_free(table); 51 54 }; 52 - #endif 53 55 54 - void* xtrace_tls(void* key, size_t size, bool* created) { 56 + void* xtrace_tls(void* key, size_t size, bool* created, xtrace_tls_destructor_f destructor) { 55 57 xtrace_tls_debug("looking up tls variable for key %p", key); 56 58 57 59 tls_table_t table = _pthread_getspecific_direct(__PTK_XTRACE_TLS); ··· 83 85 // otherwise, create it 84 86 xtrace_tls_debug("creating new entry in table for key %p", key); 85 87 size_t index = table->size++; 88 + if (index >= TLS_TABLE_MAX_SIZE) { 89 + xtrace_abort("xtrace: too many TLS variables"); 90 + } 86 91 table->table[index][0] = key; 87 92 table->table[index][1] = xtrace_malloc(size); 93 + table->table[index][2] = destructor; 88 94 if (table->table[index][1] == NULL) { 89 95 xtrace_abort("xtrace: failed TLS variable memory allocation"); 90 96 }
+15 -8
src/xtrace/tls.h
··· 8 8 9 9 XTRACE_DECLARATIONS_BEGIN; 10 10 11 - #define DEFINE_XTRACE_TLS_VAR(type, name, default_value) \ 11 + typedef void (*xtrace_tls_destructor_f)(void* value); 12 + 13 + #define DEFINE_XTRACE_TLS_VAR(type, name, default_value, destructor) \ 12 14 static char name ## _key = '\0'; \ 13 15 XTRACE_INLINE \ 16 + void destroy_ ## name(void* value) { \ 17 + void (*dtor)(type*) = (destructor); \ 18 + if (dtor) { \ 19 + dtor((type*)value); \ 20 + } \ 21 + }; \ 22 + XTRACE_INLINE \ 14 23 type get_ ## name(void) { \ 15 24 bool created = false; \ 16 - type* var = (type*)xtrace_tls(&(name ## _key), sizeof(type), &created); \ 25 + type* var = (type*)xtrace_tls(&(name ## _key), sizeof(type), &created, destroy_ ## name); \ 17 26 if (created) { \ 18 27 *var = default_value; \ 19 28 } \ ··· 22 31 XTRACE_INLINE \ 23 32 void set_ ## name(type value) { \ 24 33 bool created = false; \ 25 - type* var = (type*)xtrace_tls(&(name ## _key), sizeof(type), NULL); \ 26 - if (created) { \ 27 - *var = default_value; \ 28 - } \ 34 + type* var = (type*)xtrace_tls(&(name ## _key), sizeof(type), NULL, destroy_ ## name); \ 29 35 *var = value; \ 30 36 }; \ 31 37 XTRACE_INLINE \ 32 38 type* get_ptr_ ## name(void) { \ 33 39 bool created = false; \ 34 - type* var = (type*)xtrace_tls(&(name ## _key), sizeof(type), &created); \ 40 + type* var = (type*)xtrace_tls(&(name ## _key), sizeof(type), &created, destroy_ ## name); \ 35 41 if (created) { \ 36 42 *var = default_value; \ 37 43 } \ 38 44 return var; \ 39 45 }; 40 46 41 - void* xtrace_tls(void* key, size_t size, bool* created); 47 + void* xtrace_tls(void* key, size_t size, bool* created, xtrace_tls_destructor_f destructor); 48 + void xtrace_tls_thread_cleanup(void); 42 49 43 50 XTRACE_DECLARATIONS_END; 44 51
+8 -2
src/xtrace/xtracelib.c
··· 101 101 static xtrace_once_t xtrace_common_logfile_once = XTRACE_ONCE_INITIALIZER; 102 102 int xtrace_common_logfile = -1; 103 103 104 - DEFINE_XTRACE_TLS_VAR(int, xtrace_per_thread_logfile, -1); 104 + static void xtrace_per_thread_logfile_destroy(int* ptr) { 105 + if (xtrace_use_per_thread_logfile && ptr && *ptr >= 0) { 106 + _close_for_xtrace(*ptr); 107 + } 108 + }; 109 + 110 + DEFINE_XTRACE_TLS_VAR(int, xtrace_per_thread_logfile, -1, xtrace_per_thread_logfile_destroy); 105 111 106 112 static void xtrace_setup_options(void) 107 113 { ··· 229 235 int nrs[64]; 230 236 }; 231 237 232 - DEFINE_XTRACE_TLS_VAR(struct nested_call_struct, nested_call, (struct nested_call_struct) {0}); 238 + DEFINE_XTRACE_TLS_VAR(struct nested_call_struct, nested_call, (struct nested_call_struct) {0}, NULL); 233 239 234 240 void handle_generic_entry(const struct calldef* defs, const char* type, int nr, void* args[]) 235 241 {