blob: 70f3e82cb6ff997a3a13becc8e60e8062389f343 [file] [log] [blame]
John Park398c74a2018-10-20 21:17:39 -07001#include "aos/complex_thread_local.h"
Brian Silverman2fa99cb2014-09-06 00:53:00 -04002
3#include <pthread.h>
4
John Park33858a32018-09-28 23:05:48 -07005#include "aos/die.h"
John Park65170ac2020-01-08 20:15:24 -08006#include "absl/base/call_once.h"
Brian Silverman2fa99cb2014-09-06 00:53:00 -04007
8#define SIMPLE_CHECK(call) \
9 do { \
10 const int value = call; \
11 if (value != 0) { \
12 PRDie(value, "%s failed", #call); \
13 } \
14 } while (false)
15
16namespace aos {
17namespace {
18
19void ExecuteDestructorList(void *v) {
20 for (const ComplexThreadLocalDestructor *c =
21 static_cast<ComplexThreadLocalDestructor *>(v);
22 c != nullptr; c = c->next) {
23 c->function(c->param);
24 }
25}
26
John Park65170ac2020-01-08 20:15:24 -080027void CreateKey(pthread_key_t **r) {
28 static pthread_key_t hr;
29 SIMPLE_CHECK(pthread_key_create(&hr, ExecuteDestructorList));
30 *r = &hr;
Brian Silverman2fa99cb2014-09-06 00:53:00 -040031}
32
John Park65170ac2020-01-08 20:15:24 -080033absl::once_flag key_once;
Brian Silverman2fa99cb2014-09-06 00:53:00 -040034
John Park65170ac2020-01-08 20:15:24 -080035pthread_key_t *GetKey() {
36 static pthread_key_t *key = nullptr;
37 absl::call_once(key_once, CreateKey, &key);
38 return key;
39}
Brian Silverman2fa99cb2014-09-06 00:53:00 -040040} // namespace
41
42void ComplexThreadLocalDestructor::Add() {
43 static_assert(
44 ::std::is_pod<ComplexThreadLocalDestructor>::value,
45 "ComplexThreadLocalDestructor might not be safe to pass through void*");
John Park65170ac2020-01-08 20:15:24 -080046 pthread_key_t *key = GetKey();
Brian Silverman2fa99cb2014-09-06 00:53:00 -040047
48 next = static_cast<ComplexThreadLocalDestructor *>(pthread_getspecific(*key));
49 SIMPLE_CHECK(pthread_setspecific(*key, this));
50}
51
52void ComplexThreadLocalDestructor::Remove() {
John Park65170ac2020-01-08 20:15:24 -080053 pthread_key_t *key = GetKey();
Brian Silverman2fa99cb2014-09-06 00:53:00 -040054
55 ComplexThreadLocalDestructor *previous = nullptr;
56 for (ComplexThreadLocalDestructor *c =
57 static_cast<ComplexThreadLocalDestructor *>(
58 pthread_getspecific(*key));
59 c != nullptr; c = c->next) {
60 if (c == this) {
61 // If it's the first one.
62 if (previous == nullptr) {
63 SIMPLE_CHECK(pthread_setspecific(*key, next));
64 } else {
65 previous->next = next;
66 }
67 return;
68 }
69 previous = c;
70 }
71 ::aos::Die("%p is not in the destructor list\n", this);
72}
73
74} // namespace aos