2 * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
7 #include "pthread_private.h"
13 static pthread_key sKeyTable
[PTHREAD_KEYS_MAX
];
14 static int32 sNextSequence
= 1;
17 /*! Retrieves the destructor of a key locklessly.
18 Returns the destructor's sequence in \a sequence.
20 static pthread_key_destructor
21 get_key_destructor(uint32 key
, int32
& sequence
)
23 pthread_key_destructor destructor
= NULL
;
26 sequence
= sKeyTable
[key
].sequence
;
27 if (sequence
== PTHREAD_UNUSED_SEQUENCE
)
30 destructor
= sKeyTable
[key
].destructor
;
31 } while (sKeyTable
[key
].sequence
!= sequence
);
37 /*! Function to get the thread specific value of a key in a lockless
39 \a sequence must be the sequence of the key table that this value
43 get_key_value(pthread_thread
* thread
, uint32 key
, int32 sequence
)
45 pthread_key_data
& keyData
= thread
->specific
[key
];
46 int32 specificSequence
;
50 specificSequence
= keyData
.sequence
;
51 if (specificSequence
!= sequence
)
54 value
= keyData
.value
;
55 } while (specificSequence
!= sequence
);
62 __pthread_key_call_destructors(pthread_thread
* thread
)
64 for (uint32 key
= 0; key
< PTHREAD_KEYS_MAX
; key
++) {
66 pthread_key_destructor destructor
= get_key_destructor(key
, sequence
);
67 void* value
= get_key_value(thread
, key
, sequence
);
69 if (value
!= NULL
&& destructor
!= NULL
)
75 // #pragma mark - public API
79 pthread_key_create(pthread_key_t
* _key
, void (*destructor
)(void*))
81 int32 nextSequence
= atomic_add(&sNextSequence
, 1);
83 for (uint32 key
= 0; key
< PTHREAD_KEYS_MAX
; key
++) {
84 int32 sequence
= sKeyTable
[key
].sequence
;
85 if (sequence
!= PTHREAD_UNUSED_SEQUENCE
)
88 // try to acquire this slot
90 if (atomic_test_and_set(&sKeyTable
[key
].sequence
, nextSequence
,
91 sequence
) != sequence
)
94 sKeyTable
[key
].destructor
= destructor
;
104 pthread_key_delete(pthread_key_t key
)
106 if (key
< 0 || key
>= PTHREAD_KEYS_MAX
)
109 int32 sequence
= atomic_get_and_set(&sKeyTable
[key
].sequence
,
110 PTHREAD_UNUSED_SEQUENCE
);
111 if (sequence
== PTHREAD_UNUSED_SEQUENCE
)
119 pthread_getspecific(pthread_key_t key
)
121 pthread_thread
* thread
= pthread_self();
123 if (key
< 0 || key
>= PTHREAD_KEYS_MAX
)
126 // check if this key is used, and our value belongs to its current meaning
127 int32 sequence
= atomic_get(&sKeyTable
[key
].sequence
);
128 if (sequence
== PTHREAD_UNUSED_SEQUENCE
129 || thread
->specific
[key
].sequence
!= sequence
)
132 return thread
->specific
[key
].value
;
137 pthread_setspecific(pthread_key_t key
, const void* value
)
139 if (key
< 0 || key
>= PTHREAD_KEYS_MAX
)
142 int32 sequence
= atomic_get(&sKeyTable
[key
].sequence
);
143 if (sequence
== PTHREAD_UNUSED_SEQUENCE
)
146 pthread_key_data
& keyData
= pthread_self()->specific
[key
];
147 keyData
.sequence
= sequence
;
148 keyData
.value
= const_cast<void*>(value
);