posix: pthread: implement pthread spinlocks
pthread_spinlock_t support is part of the base threading requirement. Signed-off-by: Christopher Friedt <cfriedt@meta.com>
This commit is contained in:
parent
28a8b151cf
commit
452205ff61
@ -55,6 +55,7 @@ typedef struct pthread_attr pthread_attr_t;
|
||||
BUILD_ASSERT(sizeof(pthread_attr_t) >= sizeof(struct pthread_attr));
|
||||
|
||||
typedef uint32_t pthread_t;
|
||||
typedef uint32_t pthread_spinlock_t;
|
||||
|
||||
/* Semaphore */
|
||||
typedef struct k_sem sem_t;
|
||||
|
||||
@ -25,6 +25,10 @@ extern "C" {
|
||||
#define PTHREAD_CREATE_DETACHED 0
|
||||
#define PTHREAD_CREATE_JOINABLE 1
|
||||
|
||||
/* Pthread resource visibility */
|
||||
#define PTHREAD_PROCESS_PRIVATE 0
|
||||
#define PTHREAD_PROCESS_SHARED 1
|
||||
|
||||
/* Pthread cancellation */
|
||||
#define _PTHREAD_CANCEL_POS 0
|
||||
#define PTHREAD_CANCEL_ENABLE (0U << _PTHREAD_CANCEL_POS)
|
||||
@ -495,6 +499,45 @@ int pthread_setname_np(pthread_t thread, const char *name);
|
||||
*/
|
||||
int pthread_getname_np(pthread_t thread, char *name, size_t len);
|
||||
|
||||
#ifdef CONFIG_PTHREAD_IPC
|
||||
|
||||
/**
|
||||
* @brief Destroy a pthread_spinlock_t.
|
||||
*
|
||||
* See IEEE 1003.1
|
||||
*/
|
||||
int pthread_spin_destroy(pthread_spinlock_t *lock);
|
||||
|
||||
/**
|
||||
* @brief Initialize a thread_spinlock_t.
|
||||
*
|
||||
* See IEEE 1003.1
|
||||
*/
|
||||
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
|
||||
|
||||
/**
|
||||
* @brief Lock a previously initialized thread_spinlock_t.
|
||||
*
|
||||
* See IEEE 1003.1
|
||||
*/
|
||||
int pthread_spin_lock(pthread_spinlock_t *lock);
|
||||
|
||||
/**
|
||||
* @brief Attempt to lock a previously initialized thread_spinlock_t.
|
||||
*
|
||||
* See IEEE 1003.1
|
||||
*/
|
||||
int pthread_spin_trylock(pthread_spinlock_t *lock);
|
||||
|
||||
/**
|
||||
* @brief Unlock a previously locked thread_spinlock_t.
|
||||
*
|
||||
* See IEEE 1003.1
|
||||
*/
|
||||
int pthread_spin_unlock(pthread_spinlock_t *lock);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -26,6 +26,7 @@ zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC pthread_mutex.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC pthread_barrier.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC pthread.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC pthread_sched.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC pthread_spinlock.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK clock.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK nanosleep.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK sleep.c)
|
||||
|
||||
@ -74,6 +74,13 @@ config MAX_PTHREAD_BARRIER_COUNT
|
||||
help
|
||||
Maximum number of simultaneously active keys in a POSIX application.
|
||||
|
||||
config MAX_PTHREAD_SPINLOCK_COUNT
|
||||
int "Maximum simultaneously active spinlocks in a POSIX application"
|
||||
default 5
|
||||
range 0 255
|
||||
help
|
||||
Maximum number of simultaneously active spinlocks in a POSIX application.
|
||||
|
||||
config SEM_VALUE_MAX
|
||||
int "Maximum semaphore limit"
|
||||
default 32767
|
||||
|
||||
161
lib/posix/pthread_spinlock.c
Normal file
161
lib/posix/pthread_spinlock.c
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Meta
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "posix_internal.h"
|
||||
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/posix/pthread.h>
|
||||
#include <zephyr/sys/bitarray.h>
|
||||
|
||||
union _spinlock_storage {
|
||||
struct k_spinlock lock;
|
||||
uint8_t byte;
|
||||
};
|
||||
#if !defined(CONFIG_SMP) && !defined(CONFIG_SPIN_VALIDATE)
|
||||
BUILD_ASSERT(sizeof(struct k_spinlock) == 0,
|
||||
"please remove the _spinlock_storage workaround if, at some point, k_spinlock is no "
|
||||
"longer zero bytes when CONFIG_SMP=n && CONFIG_SPIN_VALIDATE=n");
|
||||
#endif
|
||||
|
||||
static union _spinlock_storage posix_spinlock_pool[CONFIG_MAX_PTHREAD_SPINLOCK_COUNT];
|
||||
static k_spinlock_key_t posix_spinlock_key[CONFIG_MAX_PTHREAD_SPINLOCK_COUNT];
|
||||
SYS_BITARRAY_DEFINE_STATIC(posix_spinlock_bitarray, CONFIG_MAX_PTHREAD_SPINLOCK_COUNT);
|
||||
|
||||
/*
|
||||
* We reserve the MSB to mark a pthread_spinlock_t as initialized (from the
|
||||
* perspective of the application). With a linear space, this means that
|
||||
* the theoretical pthread_spinlock_t range is [0,2147483647].
|
||||
*/
|
||||
BUILD_ASSERT(CONFIG_MAX_PTHREAD_SPINLOCK_COUNT < PTHREAD_OBJ_MASK_INIT,
|
||||
"CONFIG_MAX_PTHREAD_SPINLOCK_COUNT is too high");
|
||||
|
||||
static inline size_t posix_spinlock_to_offset(struct k_spinlock *l)
|
||||
{
|
||||
return (union _spinlock_storage *)l - posix_spinlock_pool;
|
||||
}
|
||||
|
||||
static inline size_t to_posix_spinlock_idx(pthread_spinlock_t lock)
|
||||
{
|
||||
return mark_pthread_obj_uninitialized(lock);
|
||||
}
|
||||
|
||||
static struct k_spinlock *get_posix_spinlock(pthread_spinlock_t *lock)
|
||||
{
|
||||
size_t bit;
|
||||
int actually_initialized;
|
||||
|
||||
if (lock == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* if the provided spinlock does not claim to be initialized, its invalid */
|
||||
bit = to_posix_spinlock_idx(*lock);
|
||||
if (!is_pthread_obj_initialized(*lock)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Mask off the MSB to get the actual bit index */
|
||||
if (sys_bitarray_test_bit(&posix_spinlock_bitarray, bit, &actually_initialized) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (actually_initialized == 0) {
|
||||
/* The spinlock claims to be initialized but is actually not */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (struct k_spinlock *)&posix_spinlock_pool[bit];
|
||||
}
|
||||
|
||||
int pthread_spin_init(pthread_spinlock_t *lock, int pshared)
|
||||
{
|
||||
int ret;
|
||||
size_t bit;
|
||||
|
||||
if (lock == NULL ||
|
||||
!(pshared == PTHREAD_PROCESS_PRIVATE || pshared == PTHREAD_PROCESS_SHARED)) {
|
||||
/* not specified as part of POSIX but this is the Linux behavior */
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
ret = sys_bitarray_alloc(&posix_spinlock_bitarray, 1, &bit);
|
||||
if (ret < 0) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
*lock = mark_pthread_obj_initialized(bit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_spin_destroy(pthread_spinlock_t *lock)
|
||||
{
|
||||
int err;
|
||||
size_t bit;
|
||||
struct k_spinlock *l;
|
||||
|
||||
l = get_posix_spinlock(lock);
|
||||
if (l == NULL) {
|
||||
/* not specified as part of POSIX but this is the Linux behavior */
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
bit = posix_spinlock_to_offset(l);
|
||||
err = sys_bitarray_free(&posix_spinlock_bitarray, 1, bit);
|
||||
__ASSERT_NO_MSG(err == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_spin_lock(pthread_spinlock_t *lock)
|
||||
{
|
||||
size_t bit;
|
||||
struct k_spinlock *l;
|
||||
|
||||
l = get_posix_spinlock(lock);
|
||||
if (l == NULL) {
|
||||
/* not specified as part of POSIX but this is the Linux behavior */
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
bit = posix_spinlock_to_offset(l);
|
||||
posix_spinlock_key[bit] = k_spin_lock(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_spin_trylock(pthread_spinlock_t *lock)
|
||||
{
|
||||
size_t bit;
|
||||
struct k_spinlock *l;
|
||||
|
||||
l = get_posix_spinlock(lock);
|
||||
if (l == NULL) {
|
||||
/* not specified as part of POSIX but this is the Linux behavior */
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
bit = posix_spinlock_to_offset(l);
|
||||
return k_spin_trylock(l, &posix_spinlock_key[bit]);
|
||||
}
|
||||
|
||||
int pthread_spin_unlock(pthread_spinlock_t *lock)
|
||||
{
|
||||
size_t bit;
|
||||
struct k_spinlock *l;
|
||||
|
||||
l = get_posix_spinlock(lock);
|
||||
if (l == NULL) {
|
||||
/* not specified as part of POSIX but this is the Linux behavior */
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
bit = posix_spinlock_to_offset(l);
|
||||
k_spin_unlock(l, posix_spinlock_key[bit]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user