this repo has no description
1#include <stdlib.h>
2#include <darling/emulation/linux_premigration/ext/for-xtrace.h>
3#include "tls.h"
4#include "memory.h"
5#include "lock.h"
6#include <darling/emulation/common/simple.h>
7#include <pthread/tsd_private.h>
8#include "xtracelib.h"
9
10#ifndef XTRACE_TLS_DEBUG
11 #define XTRACE_TLS_DEBUG 0
12#endif
13
14#if XTRACE_TLS_DEBUG
15 #define xtrace_tls_debug(x, ...) xtrace_log(x "\n", ## __VA_ARGS__)
16#else
17 #define xtrace_tls_debug(x, ...)
18#endif
19
20// 32 TLS vars should be enough, right?
21#define TLS_TABLE_MAX_SIZE 32
22
23typedef struct tls_table* tls_table_t;
24struct tls_table {
25 size_t size;
26 void* table[TLS_TABLE_MAX_SIZE][3];
27};
28
29// since we still need to handle some calls after pthread_terminate is called and libpthread unwinds its TLS right before calling pthread_terminate,
30// we have to use a slightly hackier technique: using one of the system's reserved but unused TLS keys; we use one from the range we currently reserve
31// for Darling.
32
33#include <darling/emulation/common/tsd.h>
34
35// TODO: also perform TLS cleanup for other threads when doing a fork
36
37extern "C"
38void xtrace_tls_thread_cleanup(void) {
39 tls_table_t table = (tls_table_t)_pthread_getspecific_direct(__PTK_DARLING_XTRACE_TLS);
40 if (!table) {
41 xtrace_tls_debug("no table to cleanup for this thread");
42 return;
43 }
44 xtrace_tls_debug("destroying table %p", table);
45 for (size_t i = 0; i < table->size; ++i) {
46 if (table->table[i][2]) {
47 xtrace_tls_debug("destroying value %p for key %p", table->table[i][1], table->table[i][0]);
48 ((xtrace_tls_destructor_f)table->table[i][2])(table->table[1]);
49 }
50 xtrace_tls_debug("freeing value %p for key %p", table->table[i][1], table->table[i][0]);
51 xtrace_free(table->table[i][1]);
52 }
53 xtrace_tls_debug("freeing table %p", table);
54 xtrace_free(table);
55};
56
57extern "C"
58void* xtrace_tls(void* key, size_t size, bool* created, xtrace_tls_destructor_f destructor) {
59 xtrace_tls_debug("looking up tls variable for key %p", key);
60
61 tls_table_t table = (tls_table_t)_pthread_getspecific_direct(__PTK_DARLING_XTRACE_TLS);
62
63 xtrace_tls_debug("got %p as table pointer from pthread", table);
64
65 // if the table doesn't exist yet, create it
66 if (table == NULL) {
67 xtrace_tls_debug("table is NULL, creating now...");
68 table = (tls_table_t)xtrace_malloc(sizeof(struct tls_table));
69 if (table == NULL) {
70 xtrace_abort("xtrace: failed TLS table memory allocation");
71 }
72 table->size = 0;
73 _pthread_setspecific_direct(__PTK_DARLING_XTRACE_TLS, table);
74 }
75
76 // check if the key is already present
77 for (size_t i = 0; i < table->size; ++i) {
78 if (table->table[i][0] == key) {
79 xtrace_tls_debug("found entry in table for key %p with value %p", key, table->table[i][1]);
80 if (created) {
81 *created = false;
82 }
83 return table->table[i][1];
84 }
85 }
86
87 // otherwise, create it
88 xtrace_tls_debug("creating new entry in table for key %p", key);
89 size_t index = table->size++;
90 if (index >= TLS_TABLE_MAX_SIZE) {
91 xtrace_abort("xtrace: too many TLS variables");
92 }
93 table->table[index][0] = key;
94 table->table[index][1] = xtrace_malloc(size);
95 table->table[index][2] = (void*)destructor;
96 if (table->table[index][1] == NULL) {
97 xtrace_abort("xtrace: failed TLS variable memory allocation");
98 }
99 xtrace_tls_debug("new table entry created for key %p with value %p", key, table->table[index][1]);
100 if (created) {
101 *created = true;
102 }
103 return table->table[index][1];
104};