|
2 | 2 | #include "ia2.h" |
3 | 3 | #include "thread_name.h" |
4 | 4 |
|
| 5 | +#include <stdatomic.h> |
| 6 | + |
5 | 7 | // Only enable this code that stores these addresses when debug logging is enabled. |
6 | 8 | // This reduces the trusted codebase and avoids runtime overhead. |
7 | 9 | #if IA2_DEBUG_MEMORY |
|
10 | 12 | // so that it can be used in `ia2_internal.h` within `_IA2_INIT_RUNTIME` |
11 | 13 | // to only initialize the `ia2_threads_metadata` global once. |
12 | 14 |
|
13 | | -#define array_len(a) (sizeof(a) / sizeof(*(a))) |
| 15 | +#define min(a, b) ((a) < (b) ? (a) : (b)) |
14 | 16 |
|
15 | | -struct ia2_thread_metadata *ia2_all_threads_metadata_get_for_current_thread(struct ia2_all_threads_metadata *const this) { |
16 | | - const pid_t tid = gettid(); |
17 | | - |
18 | | - if (pthread_mutex_lock(&this->lock) != 0) { |
19 | | - perror("pthread_mutex_lock in ia2_all_threads_data_lookup failed"); |
| 17 | +struct ia2_thread_metadata *ia2_all_threads_metadata_new_for_current_thread(struct ia2_all_threads_metadata *const this) { |
| 18 | + const size_t thread = atomic_fetch_add(&this->num_threads, 1); |
| 19 | + if (thread >= IA2_MAX_THREADS) { |
| 20 | + fprintf(stderr, "created %zu threads, but can't store them all (max is IA2_MAX_THREADS: %zu)\n", |
| 21 | + thread + 1, (size_t)IA2_MAX_THREADS); |
20 | 22 | abort(); |
21 | 23 | } |
22 | 24 |
|
23 | | - if (this->num_threads >= array_len(this->thread_metadata)) { |
24 | | - fprintf(stderr, "created %zu threads, but can't store them all (max is IA2_MAX_THREADS)\n", this->num_threads); |
25 | | - abort(); |
26 | | - } |
27 | | - |
28 | | - struct ia2_thread_metadata *metadata = NULL; |
29 | | - for (size_t i = 0; i < this->num_threads; i++) { |
30 | | - if (this->tids[i] == tid) { |
31 | | - metadata = &this->thread_metadata[i]; |
32 | | - goto unlock; |
33 | | - } |
34 | | - } |
35 | | - |
36 | | - metadata = &this->thread_metadata[this->num_threads]; |
37 | | - this->tids[this->num_threads] = tid; |
38 | | - this->num_threads++; |
| 25 | + const pid_t tid = gettid(); |
| 26 | + this->tids[thread] = tid; |
39 | 27 |
|
| 28 | + struct ia2_thread_metadata *metadata = &this->thread_metadata[thread]; |
40 | 29 | metadata->tid = tid; |
41 | 30 | metadata->thread = pthread_self(); |
| 31 | + return metadata; |
| 32 | +} |
42 | 33 |
|
43 | | -unlock: |
44 | | - if (pthread_mutex_unlock(&this->lock) != 0) { |
45 | | - perror("pthread_mutex_unlock in ia2_all_threads_data_lookup failed"); |
46 | | - abort(); |
| 34 | +struct ia2_thread_metadata *ia2_all_threads_metadata_get_for_current_thread(struct ia2_all_threads_metadata *const this) { |
| 35 | + const pid_t tid = gettid(); |
| 36 | + |
| 37 | + // We won't see threads created/registered after this, |
| 38 | + // but `ia2_all_threads_metadata_new_for_current_thread` |
| 39 | + // was supposed to be called first for this function to find it. |
| 40 | + const size_t num_threads = min(IA2_MAX_THREADS, atomic_load(&this->num_threads)); |
| 41 | + |
| 42 | + for (size_t thread = 0; thread < num_threads; thread++) { |
| 43 | + if (this->tids[thread] == tid) { |
| 44 | + return &this->thread_metadata[thread]; |
| 45 | + } |
47 | 46 | } |
48 | 47 |
|
49 | | - return metadata; |
| 48 | + fprintf(stderr, |
| 49 | + "ia2_thread_metadata not found for thread %ld\n" |
| 50 | + "ia2_thread_metadata_new_for_current_thread must not have been previously called on this thread\n", |
| 51 | + (long)tid); |
| 52 | + abort(); |
50 | 53 | } |
51 | 54 |
|
52 | 55 | struct ia2_addr_location ia2_all_threads_metadata_find_addr(struct ia2_all_threads_metadata *const this, const uintptr_t addr) { |
53 | | - struct ia2_addr_location location = { |
54 | | - .name = NULL, |
55 | | - .thread_metadata = NULL, |
56 | | - .compartment = -1, |
57 | | - }; |
58 | | - if (pthread_mutex_lock(&this->lock) != 0) { |
59 | | - perror("pthread_mutex_lock in ia2_all_threads_data_find_addr failed"); |
60 | | - goto ret; |
61 | | - } |
| 56 | + // We won't see threads created/registered after this, |
| 57 | + // but this is supposed to be best effort, so that's okay. |
| 58 | + const size_t num_threads = min(IA2_MAX_THREADS, atomic_load(&this->num_threads)); |
| 59 | + |
62 | 60 | for (size_t thread = 0; thread < this->num_threads; thread++) { |
63 | 61 | const pid_t tid = this->tids[thread]; |
64 | 62 | const struct ia2_thread_metadata *const thread_metadata = &this->thread_metadata[thread]; |
65 | 63 |
|
66 | 64 | if (addr == thread_metadata->tls_addr_compartment1_first || addr == thread_metadata->tls_addr_compartment1_second) { |
67 | | - location.name = "tls"; |
68 | | - location.thread_metadata = thread_metadata; |
69 | | - location.compartment = 1; |
70 | | - goto unlock; |
| 65 | + return (struct ia2_addr_location){ |
| 66 | + .name = "tls", |
| 67 | + .thread_metadata = thread_metadata, |
| 68 | + .compartment = 1, |
| 69 | + }; |
71 | 70 | } |
72 | 71 |
|
73 | 72 | for (int compartment = 0; compartment < IA2_MAX_COMPARTMENTS; compartment++) { |
74 | 73 | if (addr == thread_metadata->stack_addrs[compartment]) { |
75 | | - location.name = "stack"; |
76 | | - location.thread_metadata = thread_metadata; |
77 | | - location.compartment = compartment; |
78 | | - goto unlock; |
| 74 | + return (struct ia2_addr_location){ |
| 75 | + .name = "stack", |
| 76 | + .thread_metadata = thread_metadata, |
| 77 | + .compartment = compartment, |
| 78 | + }; |
79 | 79 | } |
80 | 80 | if (addr == thread_metadata->tls_addrs[compartment]) { |
81 | | - location.name = "tls"; |
82 | | - location.thread_metadata = thread_metadata; |
83 | | - location.compartment = compartment; |
84 | | - goto unlock; |
| 81 | + return (struct ia2_addr_location){ |
| 82 | + .name = "tls", |
| 83 | + .thread_metadata = thread_metadata, |
| 84 | + .compartment = compartment, |
| 85 | + }; |
85 | 86 | } |
86 | 87 | } |
87 | 88 | } |
88 | 89 |
|
89 | | - goto unlock; |
90 | | - |
91 | | -unlock: |
92 | | - if (pthread_mutex_unlock(&this->lock) != 0) { |
93 | | - perror("pthread_mutex_unlock in ia2_all_threads_data_find_addr failed"); |
94 | | - } |
95 | | -ret: |
96 | | - return location; |
| 90 | + return (struct ia2_addr_location){ |
| 91 | + .name = NULL, |
| 92 | + .thread_metadata = NULL, |
| 93 | + .compartment = -1, |
| 94 | + }; |
97 | 95 | } |
98 | 96 |
|
99 | 97 | // Moved `ia2_threads_metadata` from here to `ia2_internal.h` |
100 | 98 | // so that it can be used in `_IA2_INIT_RUNTIME` |
101 | 99 | // to only initialize the `ia2_threads_metadata` global once. |
102 | 100 | extern struct ia2_all_threads_metadata ia2_threads_metadata; |
103 | 101 |
|
| 102 | +struct ia2_thread_metadata *ia2_thread_metadata_new_for_current_thread(void) { |
| 103 | + return ia2_all_threads_metadata_new_for_current_thread(&ia2_threads_metadata); |
| 104 | +} |
| 105 | + |
104 | 106 | struct ia2_thread_metadata *ia2_thread_metadata_get_for_current_thread(void) { |
105 | 107 | return ia2_all_threads_metadata_get_for_current_thread(&ia2_threads_metadata); |
106 | 108 | } |
|
0 commit comments