1570af302Sopenharmony_ci#include "pthread_impl.h"
2570af302Sopenharmony_ci#include "fork_impl.h"
3570af302Sopenharmony_ci#include "pthread_ffrt.h"
4570af302Sopenharmony_ci#include <stdbool.h>
5570af302Sopenharmony_ci
6570af302Sopenharmony_civolatile size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX;
7570af302Sopenharmony_civoid *__pthread_tsd_main[PTHREAD_KEYS_MAX] = { 0 };
8570af302Sopenharmony_ci
9570af302Sopenharmony_cistatic void (*keys[PTHREAD_KEYS_MAX])(void *);
10570af302Sopenharmony_ci
11570af302Sopenharmony_cistatic pthread_rwlock_t key_lock = PTHREAD_RWLOCK_INITIALIZER;
12570af302Sopenharmony_ci
13570af302Sopenharmony_cistatic pthread_key_t next_key;
14570af302Sopenharmony_ci
15570af302Sopenharmony_cistatic void nodtor(void *dummy)
16570af302Sopenharmony_ci{
17570af302Sopenharmony_ci}
18570af302Sopenharmony_ci
19570af302Sopenharmony_cistatic void dummy_0(void)
20570af302Sopenharmony_ci{
21570af302Sopenharmony_ci}
22570af302Sopenharmony_ci
23570af302Sopenharmony_ciweak_alias(dummy_0, __tl_lock);
24570af302Sopenharmony_ciweak_alias(dummy_0, __tl_unlock);
25570af302Sopenharmony_ci
26570af302Sopenharmony_civoid __pthread_key_atfork(int who)
27570af302Sopenharmony_ci{
28570af302Sopenharmony_ci	if (who<0) __pthread_rwlock_rdlock(&key_lock);
29570af302Sopenharmony_ci	else if (!who) __pthread_rwlock_unlock(&key_lock);
30570af302Sopenharmony_ci	else key_lock = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER;
31570af302Sopenharmony_ci}
32570af302Sopenharmony_ci
33570af302Sopenharmony_ciint __pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
34570af302Sopenharmony_ci{
35570af302Sopenharmony_ci	pthread_t self = __pthread_self();
36570af302Sopenharmony_ci
37570af302Sopenharmony_ci	/* This can only happen in the main thread before
38570af302Sopenharmony_ci	 * pthread_create has been called. */
39570af302Sopenharmony_ci	if (!self->tsd) self->tsd = __pthread_tsd_main;
40570af302Sopenharmony_ci
41570af302Sopenharmony_ci	/* Purely a sentinel value since null means slot is free. */
42570af302Sopenharmony_ci	if (!dtor) dtor = nodtor;
43570af302Sopenharmony_ci
44570af302Sopenharmony_ci	__pthread_rwlock_wrlock(&key_lock);
45570af302Sopenharmony_ci	pthread_key_t j = next_key;
46570af302Sopenharmony_ci	do {
47570af302Sopenharmony_ci		if (!keys[j]) {
48570af302Sopenharmony_ci			keys[next_key = *k = j] = dtor;
49570af302Sopenharmony_ci			__pthread_rwlock_unlock(&key_lock);
50570af302Sopenharmony_ci			return 0;
51570af302Sopenharmony_ci		}
52570af302Sopenharmony_ci	} while ((j=(j+1)%PTHREAD_KEYS_MAX) != next_key);
53570af302Sopenharmony_ci
54570af302Sopenharmony_ci	__pthread_rwlock_unlock(&key_lock);
55570af302Sopenharmony_ci	return EAGAIN;
56570af302Sopenharmony_ci}
57570af302Sopenharmony_ci
58570af302Sopenharmony_ciint __pthread_key_delete(pthread_key_t k)
59570af302Sopenharmony_ci{
60570af302Sopenharmony_ci	sigset_t set;
61570af302Sopenharmony_ci	pthread_t self = __pthread_self(), td=self;
62570af302Sopenharmony_ci
63570af302Sopenharmony_ci	__block_app_sigs(&set);
64570af302Sopenharmony_ci	__pthread_rwlock_wrlock(&key_lock);
65570af302Sopenharmony_ci
66570af302Sopenharmony_ci	__tl_lock();
67570af302Sopenharmony_ci	do td->tsd[k] = 0;
68570af302Sopenharmony_ci	while ((td=td->next)!=self);
69570af302Sopenharmony_ci	__tl_unlock();
70570af302Sopenharmony_ci
71570af302Sopenharmony_ci	keys[k] = 0;
72570af302Sopenharmony_ci
73570af302Sopenharmony_ci	__pthread_rwlock_unlock(&key_lock);
74570af302Sopenharmony_ci	__restore_sigs(&set);
75570af302Sopenharmony_ci
76570af302Sopenharmony_ci	return 0;
77570af302Sopenharmony_ci}
78570af302Sopenharmony_ci
79570af302Sopenharmony_civoid __pthread_tsd_run_dtors()
80570af302Sopenharmony_ci{
81570af302Sopenharmony_ci	pthread_t self = __pthread_self();
82570af302Sopenharmony_ci	int i, j;
83570af302Sopenharmony_ci	for (j=0; self->tsd_used && j<PTHREAD_DESTRUCTOR_ITERATIONS; j++) {
84570af302Sopenharmony_ci		__pthread_rwlock_rdlock(&key_lock);
85570af302Sopenharmony_ci		self->tsd_used = 0;
86570af302Sopenharmony_ci		for (i=0; i<PTHREAD_KEYS_MAX; i++) {
87570af302Sopenharmony_ci			void *val = self->tsd[i];
88570af302Sopenharmony_ci			void (*dtor)(void *) = keys[i];
89570af302Sopenharmony_ci			self->tsd[i] = 0;
90570af302Sopenharmony_ci			if (val && dtor && dtor != nodtor) {
91570af302Sopenharmony_ci				__pthread_rwlock_unlock(&key_lock);
92570af302Sopenharmony_ci				dtor(val);
93570af302Sopenharmony_ci				__pthread_rwlock_rdlock(&key_lock);
94570af302Sopenharmony_ci			}
95570af302Sopenharmony_ci		}
96570af302Sopenharmony_ci		__pthread_rwlock_unlock(&key_lock);
97570af302Sopenharmony_ci	}
98570af302Sopenharmony_ci}
99570af302Sopenharmony_ci
100570af302Sopenharmony_civoid __pthread_tsd_run_dtors_ex1()
101570af302Sopenharmony_ci{
102570af302Sopenharmony_ci	pthread_t self = __pthread_self();
103570af302Sopenharmony_ci	int i, j;
104570af302Sopenharmony_ci	bool tsd_used = true;
105570af302Sopenharmony_ci	for (j=0; tsd_used && j<PTHREAD_DESTRUCTOR_ITERATIONS; j++) {
106570af302Sopenharmony_ci		__pthread_rwlock_rdlock(&key_lock);
107570af302Sopenharmony_ci		tsd_used = false;
108570af302Sopenharmony_ci		for (i=0; i<PTHREAD_KEYS_MAX; i++) {
109570af302Sopenharmony_ci			void *val = self->tsd[i];
110570af302Sopenharmony_ci			void (*dtor)(void *) = keys[i];
111570af302Sopenharmony_ci			self->tsd[i] = 0;
112570af302Sopenharmony_ci			if (val && dtor && dtor != nodtor) {
113570af302Sopenharmony_ci				__pthread_rwlock_unlock(&key_lock);
114570af302Sopenharmony_ci				dtor(val);
115570af302Sopenharmony_ci				tsd_used = true;
116570af302Sopenharmony_ci				__pthread_rwlock_rdlock(&key_lock);
117570af302Sopenharmony_ci			}
118570af302Sopenharmony_ci		}
119570af302Sopenharmony_ci		__pthread_rwlock_unlock(&key_lock);
120570af302Sopenharmony_ci	}
121570af302Sopenharmony_ci}
122570af302Sopenharmony_ci
123570af302Sopenharmony_ciweak_alias(__pthread_key_create, pthread_key_create);
124570af302Sopenharmony_ciweak_alias(__pthread_key_delete, pthread_key_delete);
125570af302Sopenharmony_ciweak_alias(__pthread_tsd_run_dtors_ex1, pthread_tsd_run_dtors);