blob: f5ddc9ca55b9f0f5b6f8a7e85d540261961cbdef [file] [log] [blame]
Brian Silverman2fa99cb2014-09-06 00:53:00 -04001#include "aos/linux_code/complex_thread_local.h"
2
3#include <pthread.h>
4
Brian Silverman2fa99cb2014-09-06 00:53:00 -04005#include "aos/common/die.h"
Sabina Davis2ed5ea22017-09-26 22:27:42 -07006#include "aos/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
27pthread_key_t *CreateKey() {
28 static pthread_key_t r;
29 SIMPLE_CHECK(pthread_key_create(&r, ExecuteDestructorList));
30 return &r;
31}
32
33::aos::Once<pthread_key_t> key_once(CreateKey);
34
35} // namespace
36
37void ComplexThreadLocalDestructor::Add() {
38 static_assert(
39 ::std::is_pod<ComplexThreadLocalDestructor>::value,
40 "ComplexThreadLocalDestructor might not be safe to pass through void*");
41 pthread_key_t *const key = key_once.Get();
42
43 next = static_cast<ComplexThreadLocalDestructor *>(pthread_getspecific(*key));
44 SIMPLE_CHECK(pthread_setspecific(*key, this));
45}
46
47void ComplexThreadLocalDestructor::Remove() {
48 pthread_key_t *const key = key_once.Get();
49
50 ComplexThreadLocalDestructor *previous = nullptr;
51 for (ComplexThreadLocalDestructor *c =
52 static_cast<ComplexThreadLocalDestructor *>(
53 pthread_getspecific(*key));
54 c != nullptr; c = c->next) {
55 if (c == this) {
56 // If it's the first one.
57 if (previous == nullptr) {
58 SIMPLE_CHECK(pthread_setspecific(*key, next));
59 } else {
60 previous->next = next;
61 }
62 return;
63 }
64 previous = c;
65 }
66 ::aos::Die("%p is not in the destructor list\n", this);
67}
68
69} // namespace aos