Skip to content

Commit 3a56d27

Browse files
cfriedtstephanosio
authored andcommitted
posix: cond: abstract pthread_cond_t as uint32_t
Consistent with the change of `pthread_t` from `struct posix_thread` to `uint32_t`, we can now also abstract `pthread_cond_t` as `uint32_t` and separate `struct posix_cond` as an implementation detail, hidden from POSIX API consumers. This change deprecates `PTHREAD_COND_DEFINE()` in favour of the (standardized) `PTHREAD_COND_INITIALIZER`. This change introduces `CONFIG_MAX_PTHREAD_COND_COUNT`. Signed-off-by: Chris Friedt <[email protected]>
1 parent afae448 commit 3a56d27

File tree

5 files changed

+190
-33
lines changed

5 files changed

+190
-33
lines changed

include/zephyr/posix/posix_types.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,7 @@ typedef struct pthread_mutexattr {
5757
} pthread_mutexattr_t;
5858

5959
/* Condition variables */
60-
typedef struct pthread_cond {
61-
_wait_q_t wait_q;
62-
} pthread_cond_t;
60+
typedef uint32_t pthread_cond_t;
6361

6462
typedef struct pthread_condattr {
6563
} pthread_condattr_t;

include/zephyr/posix/pthread.h

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ extern "C" {
3636
/* The minimum allowable stack size */
3737
#define PTHREAD_STACK_MIN Z_KERNEL_STACK_SIZE_ADJUST(0)
3838

39+
/**
40+
* @brief Declare a condition variable as initialized
41+
*
42+
* Initialize a condition variable with the default condition variable attributes.
43+
*/
44+
#define PTHREAD_COND_INITIALIZER (-1)
45+
3946
/**
4047
* @brief Declare a pthread condition variable
4148
*
@@ -44,35 +51,23 @@ extern "C" {
4451
* strategies for kernel objects.
4552
*
4653
* @param name Symbol name of the condition variable
54+
* @deprecated Use @c PTHREAD_COND_INITIALIZER instead.
4755
*/
48-
#define PTHREAD_COND_DEFINE(name) \
49-
struct pthread_cond name = { \
50-
.wait_q = Z_WAIT_Q_INIT(&name.wait_q), \
51-
}
56+
#define PTHREAD_COND_DEFINE(name) pthread_cond_t name = PTHREAD_COND_INITIALIZER
5257

5358
/**
5459
* @brief POSIX threading compatibility API
5560
*
5661
* See IEEE 1003.1
5762
*/
58-
static inline int pthread_cond_init(pthread_cond_t *cv,
59-
const pthread_condattr_t *att)
60-
{
61-
ARG_UNUSED(att);
62-
z_waitq_init(&cv->wait_q);
63-
return 0;
64-
}
63+
int pthread_cond_init(pthread_cond_t *cv, const pthread_condattr_t *att);
6564

6665
/**
6766
* @brief POSIX threading compatibility API
6867
*
6968
* See IEEE 1003.1
7069
*/
71-
static inline int pthread_cond_destroy(pthread_cond_t *cv)
72-
{
73-
ARG_UNUSED(cv);
74-
return 0;
75-
}
70+
int pthread_cond_destroy(pthread_cond_t *cv);
7671

7772
/**
7873
* @brief POSIX threading compatibility API

lib/posix/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ config MAX_PTHREAD_MUTEX_COUNT
4242
help
4343
Maximum number of simultaneously active mutexes in a POSIX application.
4444

45+
config MAX_PTHREAD_COND_COUNT
46+
int "Maximum simultaneously active condition variables in a POSIX application"
47+
default 5
48+
range 0 255
49+
help
50+
Maximum number of simultaneously active condition variables in a POSIX application.
51+
4552
config SEM_VALUE_MAX
4653
int "Maximum semaphore limit"
4754
default 32767

lib/posix/posix_internal.h

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ struct posix_mutex {
2020
_wait_q_t wait_q;
2121
};
2222

23+
struct posix_cond {
24+
_wait_q_t wait_q;
25+
};
26+
2327
enum pthread_state {
2428
/* The thread structure is unallocated and available for reuse. */
2529
PTHREAD_TERMINATED = 0,
@@ -51,14 +55,6 @@ struct posix_thread {
5155
pthread_cond_t state_cond;
5256
};
5357

54-
struct posix_thread *to_posix_thread(pthread_t pthread);
55-
56-
/* get and possibly initialize a posix_mutex */
57-
struct posix_mutex *to_posix_mutex(pthread_mutex_t *mu);
58-
59-
/* get a previously initialized posix_mutex */
60-
struct posix_mutex *get_posix_mutex(pthread_mutex_t mut);
61-
6258
static inline bool is_pthread_obj_initialized(uint32_t obj)
6359
{
6460
return (obj & PTHREAD_OBJ_MASK_INIT) != 0;
@@ -74,4 +70,18 @@ static inline uint32_t mark_pthread_obj_uninitialized(uint32_t obj)
7470
return obj & ~PTHREAD_OBJ_MASK_INIT;
7571
}
7672

73+
struct posix_thread *to_posix_thread(pthread_t pthread);
74+
75+
/* get and possibly initialize a posix_mutex */
76+
struct posix_mutex *to_posix_mutex(pthread_mutex_t *mu);
77+
78+
/* get a previously initialized posix_mutex */
79+
struct posix_mutex *get_posix_mutex(pthread_mutex_t mut);
80+
81+
/* get and possibly initialize a posix_cond */
82+
struct posix_cond *to_posix_cond(pthread_cond_t *cvar);
83+
84+
/* get a previously initialized posix_cond */
85+
struct posix_cond *get_posix_cond(pthread_cond_t cond);
86+
7787
#endif

lib/posix/pthread_cond.c

Lines changed: 153 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,88 @@
88
#include <ksched.h>
99
#include <zephyr/wait_q.h>
1010
#include <zephyr/posix/pthread.h>
11+
#include <zephyr/sys/bitarray.h>
1112

1213
#include "posix_internal.h"
1314

1415
extern struct k_spinlock z_pthread_spinlock;
1516

1617
int64_t timespec_to_timeoutms(const struct timespec *abstime);
1718

18-
static int cond_wait(pthread_cond_t *cv, pthread_mutex_t *mu,
19-
k_timeout_t timeout)
19+
static struct posix_cond posix_cond_pool[CONFIG_MAX_PTHREAD_COND_COUNT];
20+
SYS_BITARRAY_DEFINE_STATIC(posix_cond_bitarray, CONFIG_MAX_PTHREAD_COND_COUNT);
21+
22+
/*
23+
* We reserve the MSB to mark a pthread_cond_t as initialized (from the
24+
* perspective of the application). With a linear space, this means that
25+
* the theoretical pthread_cond_t range is [0,2147483647].
26+
*/
27+
BUILD_ASSERT(CONFIG_MAX_PTHREAD_COND_COUNT < PTHREAD_OBJ_MASK_INIT,
28+
"CONFIG_MAX_PTHREAD_COND_COUNT is too high");
29+
30+
static inline size_t posix_cond_to_offset(struct posix_cond *cv)
31+
{
32+
return cv - posix_cond_pool;
33+
}
34+
35+
static inline size_t to_posix_cond_idx(pthread_cond_t cond)
36+
{
37+
return mark_pthread_obj_uninitialized(cond);
38+
}
39+
40+
struct posix_cond *get_posix_cond(pthread_cond_t cond)
41+
{
42+
int actually_initialized;
43+
size_t bit = to_posix_cond_idx(cond);
44+
45+
/* if the provided cond does not claim to be initialized, its invalid */
46+
if (!is_pthread_obj_initialized(cond)) {
47+
return NULL;
48+
}
49+
50+
/* Mask off the MSB to get the actual bit index */
51+
if (sys_bitarray_test_bit(&posix_cond_bitarray, bit, &actually_initialized) < 0) {
52+
return NULL;
53+
}
54+
55+
if (actually_initialized == 0) {
56+
/* The cond claims to be initialized but is actually not */
57+
return NULL;
58+
}
59+
60+
return &posix_cond_pool[bit];
61+
}
62+
63+
struct posix_cond *to_posix_cond(pthread_cond_t *cvar)
64+
{
65+
size_t bit;
66+
struct posix_cond *cv;
67+
68+
if (*cvar != PTHREAD_COND_INITIALIZER) {
69+
return get_posix_cond(*cvar);
70+
}
71+
72+
/* Try and automatically associate a posix_cond */
73+
if (sys_bitarray_alloc(&posix_cond_bitarray, 1, &bit) < 0) {
74+
/* No conds left to allocate */
75+
return NULL;
76+
}
77+
78+
/* Record the associated posix_cond in mu and mark as initialized */
79+
*cvar = mark_pthread_obj_initialized(bit);
80+
cv = &posix_cond_pool[bit];
81+
82+
/* Initialize the condition variable here */
83+
z_waitq_init(&cv->wait_q);
84+
85+
return cv;
86+
}
87+
88+
static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, k_timeout_t timeout)
2089
{
2190
int ret;
2291
k_spinlock_key_t key;
92+
struct posix_cond *cv;
2393
struct posix_mutex *m;
2494

2595
key = k_spin_lock(&z_pthread_spinlock);
@@ -29,6 +99,12 @@ static int cond_wait(pthread_cond_t *cv, pthread_mutex_t *mu,
2999
return EINVAL;
30100
}
31101

102+
cv = to_posix_cond(cond);
103+
if (cv == NULL) {
104+
k_spin_unlock(&z_pthread_spinlock, key);
105+
return EINVAL;
106+
}
107+
32108
__ASSERT_NO_MSG(m->lock_count == 1U);
33109
m->lock_count = 0U;
34110
m->owner = NULL;
@@ -48,14 +124,41 @@ static int cond_wait(pthread_cond_t *cv, pthread_mutex_t *mu,
48124
return ret == -EAGAIN ? ETIMEDOUT : ret;
49125
}
50126

51-
int pthread_cond_signal(pthread_cond_t *cv)
127+
int pthread_cond_signal(pthread_cond_t *cvar)
52128
{
129+
k_spinlock_key_t key;
130+
struct posix_cond *cv;
131+
132+
key = k_spin_lock(&z_pthread_spinlock);
133+
134+
cv = to_posix_cond(cvar);
135+
if (cv == NULL) {
136+
k_spin_unlock(&z_pthread_spinlock, key);
137+
return EINVAL;
138+
}
139+
140+
k_spin_unlock(&z_pthread_spinlock, key);
141+
53142
z_sched_wake(&cv->wait_q, 0, NULL);
143+
54144
return 0;
55145
}
56146

57-
int pthread_cond_broadcast(pthread_cond_t *cv)
147+
int pthread_cond_broadcast(pthread_cond_t *cvar)
58148
{
149+
k_spinlock_key_t key;
150+
struct posix_cond *cv;
151+
152+
key = k_spin_lock(&z_pthread_spinlock);
153+
154+
cv = to_posix_cond(cvar);
155+
if (cv == NULL) {
156+
k_spin_unlock(&z_pthread_spinlock, key);
157+
return EINVAL;
158+
}
159+
160+
k_spin_unlock(&z_pthread_spinlock, key);
161+
59162
z_sched_wake_all(&cv->wait_q, 0, NULL);
60163
return 0;
61164
}
@@ -65,9 +168,53 @@ int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mut)
65168
return cond_wait(cv, mut, K_FOREVER);
66169
}
67170

68-
int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mut,
69-
const struct timespec *abstime)
171+
int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mut, const struct timespec *abstime)
70172
{
71173
int32_t timeout = (int32_t)timespec_to_timeoutms(abstime);
72174
return cond_wait(cv, mut, K_MSEC(timeout));
73175
}
176+
177+
int pthread_cond_init(pthread_cond_t *cvar, const pthread_condattr_t *att)
178+
{
179+
k_spinlock_key_t key;
180+
struct posix_cond *cv;
181+
182+
ARG_UNUSED(att);
183+
*cvar = PTHREAD_COND_INITIALIZER;
184+
185+
key = k_spin_lock(&z_pthread_spinlock);
186+
187+
cv = to_posix_cond(cvar);
188+
if (cv == NULL) {
189+
k_spin_unlock(&z_pthread_spinlock, key);
190+
return EINVAL;
191+
}
192+
193+
k_spin_unlock(&z_pthread_spinlock, key);
194+
195+
return 0;
196+
}
197+
198+
int pthread_cond_destroy(pthread_cond_t *cvar)
199+
{
200+
__unused int rc;
201+
k_spinlock_key_t key;
202+
struct posix_cond *cv;
203+
pthread_cond_t c = *cvar;
204+
size_t bit = to_posix_cond_idx(c);
205+
206+
key = k_spin_lock(&z_pthread_spinlock);
207+
208+
cv = get_posix_cond(c);
209+
if (cv == NULL) {
210+
k_spin_unlock(&z_pthread_spinlock, key);
211+
return EINVAL;
212+
}
213+
214+
rc = sys_bitarray_free(&posix_cond_bitarray, 1, bit);
215+
__ASSERT(rc == 0, "failed to free bit %zu", bit);
216+
217+
k_spin_unlock(&z_pthread_spinlock, key);
218+
219+
return 0;
220+
}

0 commit comments

Comments
 (0)