Skip to content

Commit 7506274

Browse files
cfriedtfabiobaltieri
authored andcommitted
posix: use sys_sem instead of k_spinlock for pool synch
Based on Andy's talk at eoss 2024, use the sys/sem.h api instead of the spinlock.h api to synchronize pooled elements since it has minimal overhead like semaphores but also works from userspace. Signed-off-by: Chris Friedt <[email protected]>
1 parent 5a0b1b1 commit 7506274

File tree

4 files changed

+214
-199
lines changed

4 files changed

+214
-199
lines changed

lib/posix/options/key.c

Lines changed: 64 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <zephyr/posix/pthread.h>
1212
#include <zephyr/sys/bitarray.h>
1313
#include <zephyr/sys/__assert.h>
14+
#include <zephyr/sys/sem.h>
1415

1516
struct pthread_key_data {
1617
sys_snode_t node;
@@ -19,7 +20,7 @@ struct pthread_key_data {
1920

2021
LOG_MODULE_REGISTER(pthread_key, CONFIG_PTHREAD_KEY_LOG_LEVEL);
2122

22-
static struct k_spinlock pthread_key_lock;
23+
static SYS_SEM_DEFINE(pthread_key_lock, 1, 1);
2324

2425
/* This is non-standard (i.e. an implementation detail) */
2526
#define PTHREAD_KEY_INITIALIZER (-1)
@@ -128,42 +129,40 @@ int pthread_key_create(pthread_key_t *key,
128129
int pthread_key_delete(pthread_key_t key)
129130
{
130131
size_t bit;
131-
__unused int ret;
132-
pthread_key_obj *key_obj;
132+
int ret = EINVAL;
133+
pthread_key_obj *key_obj = NULL;
133134
struct pthread_key_data *key_data;
134135
sys_snode_t *node_l, *next_node_l;
135-
k_spinlock_key_t key_key;
136136

137-
key_key = k_spin_lock(&pthread_key_lock);
137+
SYS_SEM_LOCK(&pthread_key_lock) {
138+
key_obj = get_posix_key(key);
139+
if (key_obj == NULL) {
140+
ret = EINVAL;
141+
SYS_SEM_LOCK_BREAK;
142+
}
138143

139-
key_obj = get_posix_key(key);
140-
if (key_obj == NULL) {
141-
k_spin_unlock(&pthread_key_lock, key_key);
142-
return EINVAL;
143-
}
144+
/* Delete thread-specific elements associated with the key */
145+
SYS_SLIST_FOR_EACH_NODE_SAFE(&(key_obj->key_data_l), node_l, next_node_l) {
144146

145-
/* Delete thread-specific elements associated with the key */
146-
SYS_SLIST_FOR_EACH_NODE_SAFE(&(key_obj->key_data_l),
147-
node_l, next_node_l) {
147+
/* Remove the object from the list key_data_l */
148+
key_data = (struct pthread_key_data *)sys_slist_get(&(key_obj->key_data_l));
148149

149-
/* Remove the object from the list key_data_l */
150-
key_data = (struct pthread_key_data *)
151-
sys_slist_get(&(key_obj->key_data_l));
150+
/* Deallocate the object's memory */
151+
k_free((void *)key_data);
152+
LOG_DBG("Freed key data %p for key %x in thread %x", key_data, key,
153+
pthread_self());
154+
}
152155

153-
/* Deallocate the object's memory */
154-
k_free((void *)key_data);
155-
LOG_DBG("Freed key data %p for key %x in thread %x", key_data, key, pthread_self());
156+
bit = posix_key_to_offset(key_obj);
157+
ret = sys_bitarray_free(&posix_key_bitarray, 1, bit);
158+
__ASSERT_NO_MSG(ret == 0);
156159
}
157160

158-
bit = posix_key_to_offset(key_obj);
159-
ret = sys_bitarray_free(&posix_key_bitarray, 1, bit);
160-
__ASSERT_NO_MSG(ret == 0);
161-
162-
k_spin_unlock(&pthread_key_lock, key_key);
163-
164-
LOG_DBG("Deleted key %p (%x)", key_obj, key);
161+
if (ret == 0) {
162+
LOG_DBG("Deleted key %p (%x)", key_obj, key);
163+
}
165164

166-
return 0;
165+
return ret;
167166
}
168167

169168
/**
@@ -173,12 +172,10 @@ int pthread_key_delete(pthread_key_t key)
173172
*/
174173
int pthread_setspecific(pthread_key_t key, const void *value)
175174
{
176-
pthread_key_obj *key_obj;
175+
pthread_key_obj *key_obj = NULL;
177176
struct posix_thread *thread;
178177
struct pthread_key_data *key_data;
179-
pthread_thread_data *thread_spec_data;
180-
k_spinlock_key_t key_key;
181-
sys_snode_t *node_l;
178+
sys_snode_t *node_l = NULL;
182179
int retval = 0;
183180

184181
thread = to_posix_thread(pthread_self());
@@ -190,37 +187,38 @@ int pthread_setspecific(pthread_key_t key, const void *value)
190187
* If the key is already in the list, re-assign its value.
191188
* Else add the key to the thread's list.
192189
*/
193-
key_key = k_spin_lock(&pthread_key_lock);
194-
195-
key_obj = get_posix_key(key);
196-
if (key_obj == NULL) {
197-
k_spin_unlock(&pthread_key_lock, key_key);
198-
return EINVAL;
199-
}
200-
201-
SYS_SLIST_FOR_EACH_NODE(&(thread->key_list), node_l) {
190+
SYS_SEM_LOCK(&pthread_key_lock) {
191+
key_obj = get_posix_key(key);
192+
if (key_obj == NULL) {
193+
retval = EINVAL;
194+
SYS_SEM_LOCK_BREAK;
195+
}
202196

203-
thread_spec_data = (pthread_thread_data *)node_l;
197+
SYS_SLIST_FOR_EACH_NODE(&(thread->key_list), node_l) {
198+
pthread_thread_data *thread_spec_data = (pthread_thread_data *)node_l;
204199

205-
if (thread_spec_data->key == key_obj) {
200+
if (thread_spec_data->key == key_obj) {
201+
/* Key is already present so associate thread specific data */
202+
thread_spec_data->spec_data = (void *)value;
203+
LOG_DBG("Paired key %x to value %p for thread %x", key, value,
204+
pthread_self());
205+
break;
206+
}
207+
}
206208

207-
/* Key is already present so
208-
* associate thread specific data
209-
*/
210-
thread_spec_data->spec_data = (void *)value;
211-
LOG_DBG("Paired key %x to value %p for thread %x", key, value,
212-
pthread_self());
213-
goto out;
209+
retval = 0;
210+
if (node_l != NULL) {
211+
/* Key is already present, so we are done */
212+
SYS_SEM_LOCK_BREAK;
214213
}
215-
}
216214

217-
if (node_l == NULL) {
215+
/* Key and data need to be added */
218216
key_data = k_malloc(sizeof(struct pthread_key_data));
219217

220218
if (key_data == NULL) {
221219
LOG_DBG("Failed to allocate key data for key %x", key);
222220
retval = ENOMEM;
223-
goto out;
221+
SYS_SEM_LOCK_BREAK;
224222
}
225223

226224
LOG_DBG("Allocated key data %p for key %x in thread %x", key_data, key,
@@ -239,9 +237,6 @@ int pthread_setspecific(pthread_key_t key, const void *value)
239237
LOG_DBG("Paired key %x to value %p for thread %x", key, value, pthread_self());
240238
}
241239

242-
out:
243-
k_spin_unlock(&pthread_key_lock, key_key);
244-
245240
return retval;
246241
}
247242

@@ -257,33 +252,30 @@ void *pthread_getspecific(pthread_key_t key)
257252
pthread_thread_data *thread_spec_data;
258253
void *value = NULL;
259254
sys_snode_t *node_l;
260-
k_spinlock_key_t key_key;
261255

262256
thread = to_posix_thread(pthread_self());
263257
if (thread == NULL) {
264258
return NULL;
265259
}
266260

267-
key_key = k_spin_lock(&pthread_key_lock);
268-
269-
key_obj = get_posix_key(key);
270-
if (key_obj == NULL) {
271-
k_spin_unlock(&pthread_key_lock, key_key);
272-
return NULL;
273-
}
261+
SYS_SEM_LOCK(&pthread_key_lock) {
262+
key_obj = get_posix_key(key);
263+
if (key_obj == NULL) {
264+
value = NULL;
265+
SYS_SEM_LOCK_BREAK;
266+
}
274267

275-
/* Traverse the list of keys set by the thread, looking for key */
268+
/* Traverse the list of keys set by the thread, looking for key */
276269

277-
SYS_SLIST_FOR_EACH_NODE(&(thread->key_list), node_l) {
278-
thread_spec_data = (pthread_thread_data *)node_l;
279-
if (thread_spec_data->key == key_obj) {
280-
/* Key is present, so get the set thread data */
281-
value = thread_spec_data->spec_data;
282-
break;
270+
SYS_SLIST_FOR_EACH_NODE(&(thread->key_list), node_l) {
271+
thread_spec_data = (pthread_thread_data *)node_l;
272+
if (thread_spec_data->key == key_obj) {
273+
/* Key is present, so get the set thread data */
274+
value = thread_spec_data->spec_data;
275+
break;
276+
}
283277
}
284278
}
285279

286-
k_spin_unlock(&pthread_key_lock, key_key);
287-
288280
return value;
289281
}

lib/posix/options/mutex.c

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212
#include <zephyr/logging/log.h>
1313
#include <zephyr/posix/pthread.h>
1414
#include <zephyr/sys/bitarray.h>
15+
#include <zephyr/sys/sem.h>
1516

1617
LOG_MODULE_REGISTER(pthread_mutex, CONFIG_PTHREAD_MUTEX_LOG_LEVEL);
1718

18-
static struct k_spinlock pthread_mutex_spinlock;
19+
static SYS_SEM_DEFINE(lock, 1, 1);
1920

2021
int64_t timespec_to_timeoutms(const struct timespec *abstime);
2122

@@ -106,43 +107,50 @@ struct k_mutex *to_posix_mutex(pthread_mutex_t *mu)
106107

107108
static int acquire_mutex(pthread_mutex_t *mu, k_timeout_t timeout)
108109
{
109-
int type;
110-
size_t bit;
111-
int ret = 0;
112-
struct k_mutex *m;
113-
k_spinlock_key_t key;
110+
int type = -1;
111+
size_t bit = -1;
112+
int ret = EINVAL;
113+
size_t lock_count = -1;
114+
struct k_mutex *m = NULL;
115+
struct k_thread *owner = NULL;
116+
117+
SYS_SEM_LOCK(&lock) {
118+
m = to_posix_mutex(mu);
119+
if (m == NULL) {
120+
ret = EINVAL;
121+
SYS_SEM_LOCK_BREAK;
122+
}
114123

115-
key = k_spin_lock(&pthread_mutex_spinlock);
124+
LOG_DBG("Locking mutex %p with timeout %llx", m, timeout.ticks);
116125

117-
m = to_posix_mutex(mu);
118-
if (m == NULL) {
119-
k_spin_unlock(&pthread_mutex_spinlock, key);
120-
return EINVAL;
126+
ret = 0;
127+
bit = posix_mutex_to_offset(m);
128+
type = posix_mutex_type[bit];
129+
owner = m->owner;
130+
lock_count = m->lock_count;
121131
}
122132

123-
LOG_DBG("Locking mutex %p with timeout %llx", m, timeout.ticks);
124-
125-
bit = posix_mutex_to_offset(m);
126-
type = posix_mutex_type[bit];
133+
if (ret != 0) {
134+
goto handle_error;
135+
}
127136

128-
if (m->owner == k_current_get()) {
137+
if (owner == k_current_get()) {
129138
switch (type) {
130139
case PTHREAD_MUTEX_NORMAL:
131140
if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
132-
k_spin_unlock(&pthread_mutex_spinlock, key);
133141
LOG_DBG("Timeout locking mutex %p", m);
134-
return EBUSY;
142+
ret = EBUSY;
143+
break;
135144
}
136145
/* On most POSIX systems, this usually results in an infinite loop */
137-
k_spin_unlock(&pthread_mutex_spinlock, key);
138146
LOG_DBG("Attempt to relock non-recursive mutex %p", m);
139147
do {
140148
(void)k_sleep(K_FOREVER);
141149
} while (true);
142150
CODE_UNREACHABLE;
143151
break;
144152
case PTHREAD_MUTEX_RECURSIVE:
145-
if (m->lock_count >= MUTEX_MAX_REC_LOCK) {
153+
if (lock_count >= MUTEX_MAX_REC_LOCK) {
146154
LOG_DBG("Mutex %p locked recursively too many times", m);
147155
ret = EAGAIN;
148156
}
@@ -157,7 +165,6 @@ static int acquire_mutex(pthread_mutex_t *mu, k_timeout_t timeout)
157165
break;
158166
}
159167
}
160-
k_spin_unlock(&pthread_mutex_spinlock, key);
161168

162169
if (ret == 0) {
163170
ret = k_mutex_lock(m, timeout);
@@ -171,6 +178,7 @@ static int acquire_mutex(pthread_mutex_t *mu, k_timeout_t timeout)
171178
}
172179
}
173180

181+
handle_error:
174182
if (ret < 0) {
175183
LOG_DBG("k_mutex_unlock() failed: %d", ret);
176184
ret = -ret;

0 commit comments

Comments
 (0)