]>
Commit | Line | Data |
---|---|---|
36bf1958 | 1 | #include "git-compat-util.h" |
0a4d5b97 | 2 | #include "strbuf.h" |
ee4512ed | 3 | #include "thread-utils.h" |
36bf1958 | 4 | #include "trace.h" |
ee4512ed JH |
5 | #include "trace2/tr2_tls.h" |
6 | ||
7 | /* | |
8 | * Initialize size of the thread stack for nested regions. | |
9 | * This is used to store nested region start times. Note that | |
10 | * this stack is per-thread and not per-trace-key. | |
11 | */ | |
12 | #define TR2_REGION_NESTING_INITIAL_SIZE (100) | |
13 | ||
14 | static struct tr2tls_thread_ctx *tr2tls_thread_main; | |
a0897249 | 15 | static uint64_t tr2tls_us_start_process; |
ee4512ed JH |
16 | |
17 | static pthread_mutex_t tr2tls_mutex; | |
18 | static pthread_key_t tr2tls_key; | |
19 | ||
20 | static int tr2_next_thread_id; /* modify under lock */ | |
21 | ||
a0897249 JH |
22 | void tr2tls_start_process_clock(void) |
23 | { | |
24 | if (tr2tls_us_start_process) | |
25 | return; | |
26 | ||
27 | /* | |
28 | * Keep the absolute start time of the process (i.e. the main | |
29 | * process) in a fixed variable since other threads need to | |
30 | * access it. This allows them to do that without a lock on | |
31 | * main thread's array data (because of reallocs). | |
32 | */ | |
33 | tr2tls_us_start_process = getnanotime() / 1000; | |
34 | } | |
35 | ||
a70839cf | 36 | struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_base_name, |
a0897249 | 37 | uint64_t us_thread_start) |
ee4512ed | 38 | { |
ee4512ed | 39 | struct tr2tls_thread_ctx *ctx = xcalloc(1, sizeof(*ctx)); |
24a4c45d | 40 | struct strbuf buf = STRBUF_INIT; |
ee4512ed JH |
41 | |
42 | /* | |
43 | * Implicitly "tr2tls_push_self()" to capture the thread's start | |
44 | * time in array_us_start[0]. For the main thread this gives us the | |
45 | * application run time. | |
46 | */ | |
47 | ctx->alloc = TR2_REGION_NESTING_INITIAL_SIZE; | |
48 | ctx->array_us_start = (uint64_t *)xcalloc(ctx->alloc, sizeof(uint64_t)); | |
a0897249 | 49 | ctx->array_us_start[ctx->nr_open_regions++] = us_thread_start; |
ee4512ed JH |
50 | |
51 | ctx->thread_id = tr2tls_locked_increment(&tr2_next_thread_id); | |
52 | ||
24a4c45d | 53 | strbuf_init(&buf, 0); |
ee4512ed | 54 | if (ctx->thread_id) |
24a4c45d JH |
55 | strbuf_addf(&buf, "th%02d:", ctx->thread_id); |
56 | strbuf_addstr(&buf, thread_base_name); | |
57 | if (buf.len > TR2_MAX_THREAD_NAME) | |
58 | strbuf_setlen(&buf, TR2_MAX_THREAD_NAME); | |
59 | ctx->thread_name = strbuf_detach(&buf, NULL); | |
ee4512ed JH |
60 | |
61 | pthread_setspecific(tr2tls_key, ctx); | |
62 | ||
63 | return ctx; | |
64 | } | |
65 | ||
66 | struct tr2tls_thread_ctx *tr2tls_get_self(void) | |
67 | { | |
5fdae9d3 JH |
68 | struct tr2tls_thread_ctx *ctx; |
69 | ||
70 | if (!HAVE_THREADS) | |
71 | return tr2tls_thread_main; | |
72 | ||
73 | ctx = pthread_getspecific(tr2tls_key); | |
ee4512ed JH |
74 | |
75 | /* | |
5bbb9251 JH |
76 | * If the current thread's thread-proc did not call |
77 | * trace2_thread_start(), then the thread will not have any | |
78 | * thread-local storage. Create it now and silently continue. | |
ee4512ed JH |
79 | */ |
80 | if (!ctx) | |
a0897249 | 81 | ctx = tr2tls_create_self("unknown", getnanotime() / 1000); |
ee4512ed JH |
82 | |
83 | return ctx; | |
84 | } | |
85 | ||
86 | int tr2tls_is_main_thread(void) | |
87 | { | |
5fdae9d3 JH |
88 | if (!HAVE_THREADS) |
89 | return 1; | |
ee4512ed | 90 | |
5fdae9d3 | 91 | return pthread_getspecific(tr2tls_key) == tr2tls_thread_main; |
ee4512ed JH |
92 | } |
93 | ||
94 | void tr2tls_unset_self(void) | |
95 | { | |
96 | struct tr2tls_thread_ctx *ctx; | |
97 | ||
98 | ctx = tr2tls_get_self(); | |
99 | ||
100 | pthread_setspecific(tr2tls_key, NULL); | |
101 | ||
24a4c45d | 102 | free((char *)ctx->thread_name); |
ee4512ed JH |
103 | free(ctx->array_us_start); |
104 | free(ctx); | |
105 | } | |
106 | ||
107 | void tr2tls_push_self(uint64_t us_now) | |
108 | { | |
109 | struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); | |
110 | ||
111 | ALLOC_GROW(ctx->array_us_start, ctx->nr_open_regions + 1, ctx->alloc); | |
112 | ctx->array_us_start[ctx->nr_open_regions++] = us_now; | |
113 | } | |
114 | ||
115 | void tr2tls_pop_self(void) | |
116 | { | |
117 | struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); | |
118 | ||
119 | if (!ctx->nr_open_regions) | |
24a4c45d | 120 | BUG("no open regions in thread '%s'", ctx->thread_name); |
ee4512ed JH |
121 | |
122 | ctx->nr_open_regions--; | |
123 | } | |
124 | ||
125 | void tr2tls_pop_unwind_self(void) | |
126 | { | |
127 | struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); | |
128 | ||
129 | while (ctx->nr_open_regions > 1) | |
130 | tr2tls_pop_self(); | |
131 | } | |
132 | ||
133 | uint64_t tr2tls_region_elasped_self(uint64_t us) | |
134 | { | |
135 | struct tr2tls_thread_ctx *ctx; | |
136 | uint64_t us_start; | |
137 | ||
138 | ctx = tr2tls_get_self(); | |
139 | if (!ctx->nr_open_regions) | |
140 | return 0; | |
141 | ||
142 | us_start = ctx->array_us_start[ctx->nr_open_regions - 1]; | |
143 | ||
144 | return us - us_start; | |
145 | } | |
146 | ||
147 | uint64_t tr2tls_absolute_elapsed(uint64_t us) | |
148 | { | |
149 | if (!tr2tls_thread_main) | |
150 | return 0; | |
151 | ||
a0897249 | 152 | return us - tr2tls_us_start_process; |
ee4512ed JH |
153 | } |
154 | ||
155 | void tr2tls_init(void) | |
156 | { | |
a0897249 JH |
157 | tr2tls_start_process_clock(); |
158 | ||
ee4512ed JH |
159 | pthread_key_create(&tr2tls_key, NULL); |
160 | init_recursive_mutex(&tr2tls_mutex); | |
161 | ||
a0897249 JH |
162 | tr2tls_thread_main = |
163 | tr2tls_create_self("main", tr2tls_us_start_process); | |
ee4512ed JH |
164 | } |
165 | ||
166 | void tr2tls_release(void) | |
167 | { | |
168 | tr2tls_unset_self(); | |
169 | tr2tls_thread_main = NULL; | |
170 | ||
171 | pthread_mutex_destroy(&tr2tls_mutex); | |
172 | pthread_key_delete(tr2tls_key); | |
173 | } | |
174 | ||
175 | int tr2tls_locked_increment(int *p) | |
176 | { | |
177 | int current_value; | |
178 | ||
179 | pthread_mutex_lock(&tr2tls_mutex); | |
180 | current_value = *p; | |
181 | *p = current_value + 1; | |
182 | pthread_mutex_unlock(&tr2tls_mutex); | |
183 | ||
184 | return current_value; | |
185 | } | |
8ad57564 JH |
186 | |
187 | void tr2tls_lock(void) | |
188 | { | |
189 | pthread_mutex_lock(&tr2tls_mutex); | |
190 | } | |
191 | ||
192 | void tr2tls_unlock(void) | |
193 | { | |
194 | pthread_mutex_unlock(&tr2tls_mutex); | |
195 | } |