···7676 closedir(xtrace_mig_dir);
7777}
78787979-DEFINE_XTRACE_TLS_VAR(bool, is_first_arg, false);
7979+DEFINE_XTRACE_TLS_VAR(bool, is_first_arg, false, NULL);
80808181#define BEFORE if (!get_is_first_arg()) xtrace_log(", ")
8282#define AFTER set_is_first_arg(false)
+19-13
src/xtrace/tls.c
···1717 #define xtrace_tls_debug(x, ...)
1818#endif
19192020-// 10 TLS vars should be enough, right?
2121-#define TLS_TABLE_MAX_SIZE 10
2020+// 32 TLS vars should be enough, right?
2121+#define TLS_TABLE_MAX_SIZE 32
22222323typedef struct tls_table* tls_table_t;
2424struct tls_table {
2525 size_t size;
2626- void* table[TLS_TABLE_MAX_SIZE][2];
2626+ void* table[TLS_TABLE_MAX_SIZE][3];
2727};
28282929// since we still need to handle some calls after pthread_terminate is called and libpthread unwinds its TLS right before calling pthread_terminate,
···32323333#define __PTK_XTRACE_TLS 200
34343535-// 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.
3636-// 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.
3737-//
3838-// 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.
3939-// but it'd be nice if this could eventually be fixed (probably by adding a death hook to libsystem_kernel, as described above).
3535+// TODO: also perform TLS cleanup for other threads when doing a fork
40364141-#if 0
4242-static void tls_table_destructor(void* _table) {
4343- tls_table_t table = _table;
3737+void xtrace_tls_thread_cleanup(void) {
3838+ tls_table_t table = _pthread_getspecific_direct(__PTK_XTRACE_TLS);
3939+ if (!table) {
4040+ xtrace_tls_debug("no table to cleanup for this thread");
4141+ return;
4242+ }
4443 xtrace_tls_debug("destroying table %p", table);
4544 for (size_t i = 0; i < table->size; ++i) {
4545+ if (table->table[i][2]) {
4646+ xtrace_tls_debug("destroying value %p for key %p", table->table[i][1], table->table[i][0]);
4747+ ((xtrace_tls_destructor_f)table->table[i][2])(table->table[1]);
4848+ }
4649 xtrace_tls_debug("freeing value %p for key %p", table->table[i][1], table->table[i][0]);
4750 xtrace_free(table->table[i][1]);
4851 }
4952 xtrace_tls_debug("freeing table %p", table);
5053 xtrace_free(table);
5154};
5252-#endif
53555454-void* xtrace_tls(void* key, size_t size, bool* created) {
5656+void* xtrace_tls(void* key, size_t size, bool* created, xtrace_tls_destructor_f destructor) {
5557 xtrace_tls_debug("looking up tls variable for key %p", key);
56585759 tls_table_t table = _pthread_getspecific_direct(__PTK_XTRACE_TLS);
···8385 // otherwise, create it
8486 xtrace_tls_debug("creating new entry in table for key %p", key);
8587 size_t index = table->size++;
8888+ if (index >= TLS_TABLE_MAX_SIZE) {
8989+ xtrace_abort("xtrace: too many TLS variables");
9090+ }
8691 table->table[index][0] = key;
8792 table->table[index][1] = xtrace_malloc(size);
9393+ table->table[index][2] = destructor;
8894 if (table->table[index][1] == NULL) {
8995 xtrace_abort("xtrace: failed TLS variable memory allocation");
9096 }