SuperTinyKernel™ RTOS 1.08.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
STK C pthread-compatible API

Minimal POSIX-threads-style interface for SuperTinyKernel RTOS. More...

Classes

struct  pthread_attr_t
 Thread creation attributes. More...
struct  pthread_mutexattr_t
 Mutex attributes. More...
struct  pthread_mutex_t
 A pthread mutex. More...
struct  pthread_condattr_t
 Condition variable attributes (currently no settable properties). More...
struct  pthread_cond_t
 A pthread condition variable. More...
struct  pthread_rwlockattr_t
 Read-write lock attributes (currently no settable properties). More...
struct  pthread_rwlock_t
 A pthread read-write lock. More...
struct  pthread_spinlock_t
 A pthread spinlock. More...
struct  pthread_barrierattr_t
 Barrier attributes (currently no settable properties). More...
struct  pthread_barrier_t
 A pthread barrier. More...
struct  pthread_once_t
 A pthread_once() control object. More...

Macros

#define STK_C_PTHREAD_MAX_THREADS   (8U)
 Maximum number of concurrently-alive pthread_t's (default: 8).
#define STK_C_PTHREAD_DEFAULT_STACK_WORDS   (1024U)
 Default per-thread stack size in stk_word_t units, used when pthread_attr_t does not specify a stack size or an external stack (default: 1024 words).
#define STK_C_PTHREAD_REAPER_STACK_WORDS   (256U)
 Stack size (in stk_word_t units) for the internal reaper task that reclaims detached-thread resources (default: 256 words).
#define STK_C_PTHREAD_KEYS_MAX   (8U)
 Maximum number of concurrently-alive pthread_key_t's (default: 8).
#define PTHREAD_CREATE_JOINABLE   (0)
#define PTHREAD_CREATE_DETACHED   (1)
#define PTHREAD_MUTEX_NORMAL   (0)
#define PTHREAD_MUTEX_DEFAULT   (PTHREAD_MUTEX_NORMAL)
#define PTHREAD_MUTEX_ERRORCHECK   (1)
#define PTHREAD_MUTEX_RECURSIVE   (2)
#define PTHREAD_MUTEX_INITIALIZER   {0}
#define PTHREAD_COND_INITIALIZER   {0}
#define PTHREAD_RWLOCK_INITIALIZER   {0}
#define PTHREAD_PROCESS_PRIVATE   (0)
#define PTHREAD_PROCESS_SHARED   (1)
#define PTHREAD_BARRIER_SERIAL_THREAD   (-1)
 Returned by pthread_barrier_wait() to exactly one arbitrary caller per round; all others receive 0. See "pthread_barrier_wait() note" in the file-level docs.
#define PTHREAD_ONCE_INIT   {0}
#define PTHREAD_KEYS_MAX   (STK_C_PTHREAD_KEYS_MAX)
 POSIX-standard name for STK_C_PTHREAD_KEYS_MAX (this file).
#define PTHREAD_DESTRUCTOR_ITERATIONS   (4)
 Maximum number of passes over a finishing thread's keys made while destructors keep setting new non-NULL values for their own key. See "pthread_key_t / thread-specific data limitation" in the file-level docs.

Typedefs

typedef struct pthread_stk_ctrl_tpthread_t
 Opaque thread handle.
typedef struct pthread_attr_t pthread_attr_t
 Thread creation attributes.
typedef struct pthread_mutexattr_t pthread_mutexattr_t
 Mutex attributes.
typedef struct pthread_mutex_t pthread_mutex_t
 A pthread mutex.
typedef struct pthread_condattr_t pthread_condattr_t
 Condition variable attributes (currently no settable properties).
typedef struct pthread_cond_t pthread_cond_t
 A pthread condition variable.
typedef struct pthread_rwlockattr_t pthread_rwlockattr_t
 Read-write lock attributes (currently no settable properties).
typedef struct pthread_rwlock_t pthread_rwlock_t
 A pthread read-write lock.
typedef struct pthread_spinlock_t pthread_spinlock_t
 A pthread spinlock.
typedef struct pthread_barrierattr_t pthread_barrierattr_t
 Barrier attributes (currently no settable properties).
typedef struct pthread_barrier_t pthread_barrier_t
 A pthread barrier.
typedef struct pthread_once_t pthread_once_t
 A pthread_once() control object.
typedef unsigned int pthread_key_t
 A thread-specific data key.

Functions

void stk_pthread_bind_kernel (stk_kernel_t *kernel)
 Bind the STK kernel instance that pthread_create() will add new threads to.
int pthread_attr_init (pthread_attr_t *attr)
 Initialize a thread attributes object with default values (default stack size, no external stack, joinable).
int pthread_attr_destroy (pthread_attr_t *attr)
 Destroy a thread attributes object (no-op; no owned resources).
int pthread_attr_setstacksize (pthread_attr_t *attr, size_t stacksize)
 Set the requested stack size in bytes.
int pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *stacksize)
 Get the currently requested stack size in bytes (0 = default).
int pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, size_t stacksize)
 Supply an external, caller-owned stack buffer for the thread.
int pthread_attr_getstack (const pthread_attr_t *attr, void **stackaddr, size_t *stacksize)
 Get the previously-set external stack (NULL/0 if none set).
int pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate)
 Set PTHREAD_CREATE_JOINABLE or PTHREAD_CREATE_DETACHED.
int pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstate)
 Get the current detach-state setting.
int pthread_create (pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
 Create and start a new thread.
int pthread_join (pthread_t thread, void **retval)
 Block until the given joinable thread finishes, then reclaim its resources.
int pthread_detach (pthread_t thread)
 Mark a thread as detached.
void pthread_exit (void *retval)
 Terminate the calling thread.
pthread_t pthread_self (void)
 Return the calling thread's own handle.
int pthread_equal (pthread_t t1, pthread_t t2)
 Compare two thread handles for equality.
int pthread_yield (void)
 Voluntarily give up the CPU to another ready task (cooperative yield), then resume once rescheduled.
int pthread_mutexattr_init (pthread_mutexattr_t *attr)
int pthread_mutexattr_destroy (pthread_mutexattr_t *attr)
int pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type)
 Set the mutex type.
int pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type)
int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
 Initialize a mutex.
int pthread_mutex_destroy (pthread_mutex_t *mutex)
int pthread_mutex_lock (pthread_mutex_t *mutex)
int pthread_mutex_trylock (pthread_mutex_t *mutex)
int pthread_mutex_unlock (pthread_mutex_t *mutex)
int pthread_mutex_timedlock (pthread_mutex_t *mutex, const struct timespec *abstime)
 Lock with an absolute deadline.
int pthread_condattr_init (pthread_condattr_t *attr)
int pthread_condattr_destroy (pthread_condattr_t *attr)
int pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr)
int pthread_cond_destroy (pthread_cond_t *cond)
int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
 Atomically unlock mutex and wait for a signal; re-locks mutex before returning.
int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
 As pthread_cond_wait(), with an absolute deadline.
int pthread_cond_signal (pthread_cond_t *cond)
int pthread_cond_broadcast (pthread_cond_t *cond)
int pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
int pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr)
int pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
 Initialize a read-write lock.
int pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
 Acquire the lock for shared reading. Blocks until available.
int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
 Try to acquire the read lock without blocking.
int pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, const struct timespec *abstime)
 Acquire the read lock with an absolute deadline.
int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
 Acquire the lock for exclusive writing. Blocks until available.
int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
 Try to acquire the write lock without blocking.
int pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, const struct timespec *abstime)
 Acquire the write lock with an absolute deadline.
int pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
 Release a read or write hold, whichever the calling thread holds.
int pthread_spin_init (pthread_spinlock_t *lock, int pshared)
 Initialize a spinlock.
int pthread_spin_destroy (pthread_spinlock_t *lock)
int pthread_spin_lock (pthread_spinlock_t *lock)
 Acquire the spinlock, spinning until available.
int pthread_spin_trylock (pthread_spinlock_t *lock)
 Try to acquire the spinlock without blocking.
int pthread_spin_unlock (pthread_spinlock_t *lock)
int pthread_barrierattr_init (pthread_barrierattr_t *attr)
int pthread_barrierattr_destroy (pthread_barrierattr_t *attr)
int pthread_barrier_init (pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
 Initialize a barrier for count participating threads.
int pthread_barrier_destroy (pthread_barrier_t *barrier)
int pthread_barrier_wait (pthread_barrier_t *barrier)
 Block until count threads have called this function, then release them all together; the barrier resets for reuse.
int pthread_once (pthread_once_t *once_control, void(*init_routine)(void))
 Call init_routine exactly once for a given once_control, no matter how many threads call pthread_once() on it concurrently.
int pthread_key_create (pthread_key_t *key, void(*destructor)(void *))
 Allocate a new thread-specific data key.
int pthread_key_delete (pthread_key_t key)
 Free a thread-specific data key.
int pthread_setspecific (pthread_key_t key, const void *value)
 Set the calling thread's value for key.
void * pthread_getspecific (pthread_key_t key)
 Get the calling thread's value for key.

Detailed Description

Minimal POSIX-threads-style interface for SuperTinyKernel RTOS.

Macro Definition Documentation

◆ PTHREAD_BARRIER_SERIAL_THREAD

#define PTHREAD_BARRIER_SERIAL_THREAD   (-1)

Returned by pthread_barrier_wait() to exactly one arbitrary caller per round; all others receive 0. See "pthread_barrier_wait() note" in the file-level docs.

Definition at line 339 of file stk_c_pthread.h.

Referenced by pthread_barrier_wait().

◆ PTHREAD_COND_INITIALIZER

#define PTHREAD_COND_INITIALIZER   {0}

Definition at line 273 of file stk_c_pthread.h.

◆ PTHREAD_CREATE_DETACHED

#define PTHREAD_CREATE_DETACHED   (1)

Definition at line 227 of file stk_c_pthread.h.

Referenced by pthread_attr_setdetachstate(), and pthread_create().

◆ PTHREAD_CREATE_JOINABLE

#define PTHREAD_CREATE_JOINABLE   (0)

Definition at line 226 of file stk_c_pthread.h.

Referenced by pthread_attr_init(), and pthread_attr_setdetachstate().

◆ PTHREAD_DESTRUCTOR_ITERATIONS

#define PTHREAD_DESTRUCTOR_ITERATIONS   (4)

Maximum number of passes over a finishing thread's keys made while destructors keep setting new non-NULL values for their own key. See "pthread_key_t / thread-specific data limitation" in the file-level docs.

Definition at line 373 of file stk_c_pthread.h.

Referenced by anonymous_namespace{stk_c_pthread.cpp}::RunKeyDestructors().

◆ PTHREAD_KEYS_MAX

#define PTHREAD_KEYS_MAX   (STK_C_PTHREAD_KEYS_MAX)

POSIX-standard name for STK_C_PTHREAD_KEYS_MAX (this file).

Definition at line 365 of file stk_c_pthread.h.

◆ PTHREAD_MUTEX_DEFAULT

#define PTHREAD_MUTEX_DEFAULT   (PTHREAD_MUTEX_NORMAL)

Definition at line 238 of file stk_c_pthread.h.

Referenced by pthread_mutexattr_init().

◆ PTHREAD_MUTEX_ERRORCHECK

#define PTHREAD_MUTEX_ERRORCHECK   (1)

Definition at line 239 of file stk_c_pthread.h.

◆ PTHREAD_MUTEX_INITIALIZER

#define PTHREAD_MUTEX_INITIALIZER   {0}

Definition at line 253 of file stk_c_pthread.h.

◆ PTHREAD_MUTEX_NORMAL

#define PTHREAD_MUTEX_NORMAL   (0)

Definition at line 237 of file stk_c_pthread.h.

Referenced by pthread_mutex_init(), and pthread_mutexattr_settype().

◆ PTHREAD_MUTEX_RECURSIVE

#define PTHREAD_MUTEX_RECURSIVE   (2)

Definition at line 240 of file stk_c_pthread.h.

◆ PTHREAD_ONCE_INIT

#define PTHREAD_ONCE_INIT   {0}

Definition at line 354 of file stk_c_pthread.h.

◆ PTHREAD_PROCESS_PRIVATE

#define PTHREAD_PROCESS_PRIVATE   (0)

Definition at line 301 of file stk_c_pthread.h.

Referenced by pthread_spin_init().

◆ PTHREAD_PROCESS_SHARED

#define PTHREAD_PROCESS_SHARED   (1)

Definition at line 302 of file stk_c_pthread.h.

◆ PTHREAD_RWLOCK_INITIALIZER

#define PTHREAD_RWLOCK_INITIALIZER   {0}

Definition at line 299 of file stk_c_pthread.h.

◆ STK_C_PTHREAD_DEFAULT_STACK_WORDS

#define STK_C_PTHREAD_DEFAULT_STACK_WORDS   (1024U)

Default per-thread stack size in stk_word_t units, used when pthread_attr_t does not specify a stack size or an external stack (default: 1024 words).

Note
Threads created with this exact size are served from a static BlockMemoryPool (STK_C_PTHREAD_MAX_THREADS blocks, zero heap use). Any other requested size falls back to malloc().

Definition at line 173 of file stk_c_pthread.h.

◆ STK_C_PTHREAD_KEYS_MAX

#define STK_C_PTHREAD_KEYS_MAX   (8U)

Maximum number of concurrently-alive pthread_key_t's (default: 8).

Note
Also exposed under the POSIX-standard name PTHREAD_KEYS_MAX.

Definition at line 189 of file stk_c_pthread.h.

Referenced by pthread_getspecific(), pthread_key_create(), pthread_key_delete(), pthread_setspecific(), and anonymous_namespace{stk_c_pthread.cpp}::RunKeyDestructors().

◆ STK_C_PTHREAD_MAX_THREADS

#define STK_C_PTHREAD_MAX_THREADS   (8U)

Maximum number of concurrently-alive pthread_t's (default: 8).

Note
A thread stays "alive" from pthread_create() until its resources are reclaimed (by pthread_join(), or by the internal reaper for detached threads once they finish).

Definition at line 161 of file stk_c_pthread.h.

Referenced by anonymous_namespace{stk_c_pthread.cpp}::AcquireThreadSlot(), anonymous_namespace{stk_c_pthread.cpp}::DequeueReap(), anonymous_namespace{stk_c_pthread.cpp}::EnqueueReap(), anonymous_namespace{stk_c_pthread.cpp}::EnsureStackPool(), and anonymous_namespace{stk_c_pthread.cpp}::STK_BLOCKPOOL_STORAGE_DECL().

◆ STK_C_PTHREAD_REAPER_STACK_WORDS

#define STK_C_PTHREAD_REAPER_STACK_WORDS   (256U)

Stack size (in stk_word_t units) for the internal reaper task that reclaims detached-thread resources (default: 256 words).

Definition at line 181 of file stk_c_pthread.h.

Referenced by anonymous_namespace{stk_c_pthread.cpp}::EnsureReaper().

Typedef Documentation

◆ pthread_attr_t

typedef struct pthread_attr_t pthread_attr_t

Thread creation attributes.

Note
Fields are considered private; use the pthread_attr_* accessors.

◆ pthread_barrier_t

typedef struct pthread_barrier_t pthread_barrier_t

A pthread barrier.

Note
Fields are considered private. No static-initializer macro (matching real POSIX) - pthread_barrier_init() must be called before use, since it is where the trip count is supplied.

◆ pthread_barrierattr_t

typedef struct pthread_barrierattr_t pthread_barrierattr_t

Barrier attributes (currently no settable properties).

◆ pthread_cond_t

typedef struct pthread_cond_t pthread_cond_t

A pthread condition variable.

Note
Fields are considered private. May be statically initialized with PTHREAD_COND_INITIALIZER, in which case the underlying STK condition variable is created lazily on first use.

◆ pthread_condattr_t

typedef struct pthread_condattr_t pthread_condattr_t

Condition variable attributes (currently no settable properties).

◆ pthread_key_t

typedef unsigned int pthread_key_t

A thread-specific data key.

Note
An index into an internal key table; there is no analogue to a NULL handle, so use pthread_key_create()'s return value to check success.

Definition at line 360 of file stk_c_pthread.h.

◆ pthread_mutex_t

typedef struct pthread_mutex_t pthread_mutex_t

A pthread mutex.

Note
Fields are considered private. May be statically initialized with PTHREAD_MUTEX_INITIALIZER, in which case the underlying STK mutex is created lazily on first use.

◆ pthread_mutexattr_t

typedef struct pthread_mutexattr_t pthread_mutexattr_t

Mutex attributes.

Note
Only PTHREAD_MUTEX_NORMAL / PTHREAD_MUTEX_DEFAULT are supported.

◆ pthread_once_t

typedef struct pthread_once_t pthread_once_t

A pthread_once() control object.

Note
Fields are considered private. Statically initialized with PTHREAD_ONCE_INIT; the guard mutex used to block concurrent callers is created lazily on first use. See "pthread_once() note" in the file-level docs.

◆ pthread_rwlock_t

typedef struct pthread_rwlock_t pthread_rwlock_t

A pthread read-write lock.

Note
Fields are considered private. May be statically initialized with PTHREAD_RWLOCK_INITIALIZER, in which case the underlying STK rwmutex is created lazily on first use.
See also
"pthread_rwlock_unlock() disambiguation" in the file-level docs regarding the __wrlocked field.

◆ pthread_rwlockattr_t

typedef struct pthread_rwlockattr_t pthread_rwlockattr_t

Read-write lock attributes (currently no settable properties).

Note
In particular there is no reader/writer preference setting; the underlying stk_rwmutex_t always applies a writer-preference policy (see stk_rwmutex_read_lock() in stk_c.h).

◆ pthread_spinlock_t

typedef struct pthread_spinlock_t pthread_spinlock_t

A pthread spinlock.

Note
Fields are considered private. Unlike the other pthread objects in this shim, spinlocks have no static-initializer macro (matching real POSIX) - pthread_spin_init() must be called before use.
See also
"pthread_spin_* recursion note" in the file-level docs.

◆ pthread_t

typedef struct pthread_stk_ctrl_t* pthread_t

Opaque thread handle.

Definition at line 214 of file stk_c_pthread.h.

Function Documentation

◆ pthread_attr_destroy()

int pthread_attr_destroy ( pthread_attr_t * attr)

Destroy a thread attributes object (no-op; no owned resources).

Definition at line 473 of file stk_c_pthread.cpp.

474{
475 if (attr == nullptr) { return EINVAL; }
476 return 0;
477}

◆ pthread_attr_getdetachstate()

int pthread_attr_getdetachstate ( const pthread_attr_t * attr,
int * detachstate )

Get the current detach-state setting.

Definition at line 526 of file stk_c_pthread.cpp.

527{
528 if ((attr == nullptr) || (detachstate == nullptr)) { return EINVAL; }
529
530 *detachstate = attr->__detachstate;
531 return 0;
532}

References pthread_attr_t::__detachstate.

◆ pthread_attr_getstack()

int pthread_attr_getstack ( const pthread_attr_t * attr,
void ** stackaddr,
size_t * stacksize )

Get the previously-set external stack (NULL/0 if none set).

Definition at line 505 of file stk_c_pthread.cpp.

506{
507 if ((attr == nullptr) || (stackaddr == nullptr) || (stacksize == nullptr)) { return EINVAL; }
508
509 *stackaddr = attr->__ext_stack;
510 *stacksize = attr->__stack_bytes;
511 return 0;
512}
stk_word_t * __ext_stack

References pthread_attr_t::__ext_stack, and pthread_attr_t::__stack_bytes.

◆ pthread_attr_getstacksize()

int pthread_attr_getstacksize ( const pthread_attr_t * attr,
size_t * stacksize )

Get the currently requested stack size in bytes (0 = default).

Definition at line 487 of file stk_c_pthread.cpp.

488{
489 if ((attr == nullptr) || (stacksize == nullptr)) { return EINVAL; }
490
491 *stacksize = (attr->__stack_bytes != 0U) ? attr->__stack_bytes : kDefaultStackBytes;
492 return 0;
493}

References pthread_attr_t::__stack_bytes, and anonymous_namespace{stk_c_pthread.cpp}::kDefaultStackBytes.

◆ pthread_attr_init()

int pthread_attr_init ( pthread_attr_t * attr)

Initialize a thread attributes object with default values (default stack size, no external stack, joinable).

Definition at line 463 of file stk_c_pthread.cpp.

464{
465 if (attr == nullptr) { return EINVAL; }
466
467 attr->__stack_bytes = 0U;
468 attr->__ext_stack = nullptr;
470 return 0;
471}
#define PTHREAD_CREATE_JOINABLE

References pthread_attr_t::__detachstate, pthread_attr_t::__ext_stack, pthread_attr_t::__stack_bytes, and PTHREAD_CREATE_JOINABLE.

◆ pthread_attr_setdetachstate()

int pthread_attr_setdetachstate ( pthread_attr_t * attr,
int detachstate )

Set PTHREAD_CREATE_JOINABLE or PTHREAD_CREATE_DETACHED.

Definition at line 514 of file stk_c_pthread.cpp.

515{
516 if ((attr == nullptr) ||
517 ((detachstate != PTHREAD_CREATE_JOINABLE) && (detachstate != PTHREAD_CREATE_DETACHED)))
518 {
519 return EINVAL;
520 }
521
522 attr->__detachstate = detachstate;
523 return 0;
524}
#define PTHREAD_CREATE_DETACHED

References pthread_attr_t::__detachstate, PTHREAD_CREATE_DETACHED, and PTHREAD_CREATE_JOINABLE.

◆ pthread_attr_setstack()

int pthread_attr_setstack ( pthread_attr_t * attr,
void * stackaddr,
size_t stacksize )

Supply an external, caller-owned stack buffer for the thread.

The buffer is never freed by this shim; the caller must keep it valid for the entire lifetime of the thread.

Parameters
[in]stackaddrPointer to a stk_word_t-aligned buffer.
[in]stacksizeSize of the buffer in bytes.

Definition at line 495 of file stk_c_pthread.cpp.

496{
497 if ((attr == nullptr) || (stackaddr == nullptr) || (stacksize < sizeof(stk_word_t))) { return EINVAL; }
498 if ((reinterpret_cast<uintptr_t>(stackaddr) & STK_ALIGN_MASK) != 0U) { return EINVAL; }
499
500 attr->__ext_stack = static_cast<stk_word_t *>(stackaddr);
501 attr->__stack_bytes = stacksize;
502 return 0;
503}
#define STK_ALIGN_MASK
Alignment mask.
Definition stk_c.h:159
uintptr_t stk_word_t
CPU register type.
Definition stk_c.h:94

References pthread_attr_t::__ext_stack, pthread_attr_t::__stack_bytes, and STK_ALIGN_MASK.

◆ pthread_attr_setstacksize()

int pthread_attr_setstacksize ( pthread_attr_t * attr,
size_t stacksize )

Set the requested stack size in bytes.

Note
Only exactly STK_C_PTHREAD_DEFAULT_STACK_WORDS * sizeof(stk_word_t) bytes is served from the static pool; any other value falls back to malloc() at pthread_create() time.

Definition at line 479 of file stk_c_pthread.cpp.

480{
481 if ((attr == nullptr) || (stacksize == 0U)) { return EINVAL; }
482
483 attr->__stack_bytes = stacksize;
484 return 0;
485}

References pthread_attr_t::__stack_bytes.

◆ pthread_barrier_destroy()

int pthread_barrier_destroy ( pthread_barrier_t * barrier)

Definition at line 1068 of file stk_c_pthread.cpp.

1069{
1070 if (barrier == nullptr) { return EINVAL; }
1071
1072 if (barrier->__handle != nullptr)
1073 {
1074 stk_barrier_destroy(barrier->__handle);
1075 barrier->__handle = nullptr;
1076 }
1077 return 0;
1078}
void stk_barrier_destroy(stk_barrier_t *barrier)
Destroy a Barrier.
stk_barrier_t * __handle

References pthread_barrier_t::__handle, and stk_barrier_destroy().

Here is the call graph for this function:

◆ pthread_barrier_init()

int pthread_barrier_init ( pthread_barrier_t * barrier,
const pthread_barrierattr_t * attr,
unsigned int count )

Initialize a barrier for count participating threads.

Parameters
[in]attrOptional, or NULL for defaults (no settable properties).
[in]countNumber of threads that must call pthread_barrier_wait() before any of them is released. Must not be 0.
Returns
0 on success, EINVAL if count is 0, EAGAIN if the underlying STK barrier could not be created.

Definition at line 1057 of file stk_c_pthread.cpp.

1059{
1060 if (barrier == nullptr) { return EINVAL; }
1061 if (count == 0U) { return EINVAL; }
1062
1063 barrier->__handle = stk_barrier_create(&barrier->__mem, sizeof(barrier->__mem),
1064 static_cast<uint32_t>(count));
1065 return (barrier->__handle != nullptr) ? 0 : EAGAIN;
1066}
stk_barrier_t * stk_barrier_create(stk_barrier_mem_t *const membuf, uint32_t membuf_size, uint32_t count)
Create a Barrier (using provided memory).
stk_barrier_mem_t __mem

References pthread_barrier_t::__handle, pthread_barrier_t::__mem, and stk_barrier_create().

Here is the call graph for this function:

◆ pthread_barrier_wait()

int pthread_barrier_wait ( pthread_barrier_t * barrier)

Block until count threads have called this function, then release them all together; the barrier resets for reuse.

Returns
PTHREAD_BARRIER_SERIAL_THREAD to exactly one arbitrary caller, 0 to the rest.
See also
"pthread_barrier_wait() note" in the file-level docs (ISR-unsafe).

Definition at line 1080 of file stk_c_pthread.cpp.

1081{
1082 if ((barrier == nullptr) || (barrier->__handle == nullptr)) { return EINVAL; }
1083
1085}
bool stk_barrier_wait(stk_barrier_t *barrier)
Block the calling task until count tasks have called stk_barrier_wait().
#define PTHREAD_BARRIER_SERIAL_THREAD
Returned by pthread_barrier_wait() to exactly one arbitrary caller per round; all others receive 0....

References pthread_barrier_t::__handle, PTHREAD_BARRIER_SERIAL_THREAD, and stk_barrier_wait().

Here is the call graph for this function:

◆ pthread_barrierattr_destroy()

int pthread_barrierattr_destroy ( pthread_barrierattr_t * attr)

Definition at line 1051 of file stk_c_pthread.cpp.

1052{
1053 if (attr == nullptr) { return EINVAL; }
1054 return 0;
1055}

◆ pthread_barrierattr_init()

int pthread_barrierattr_init ( pthread_barrierattr_t * attr)

Definition at line 1043 of file stk_c_pthread.cpp.

1044{
1045 if (attr == nullptr) { return EINVAL; }
1046
1047 attr->__reserved = 0;
1048 return 0;
1049}

References pthread_barrierattr_t::__reserved.

◆ pthread_cond_broadcast()

int pthread_cond_broadcast ( pthread_cond_t * cond)

Definition at line 874 of file stk_c_pthread.cpp.

875{
876 if (cond == nullptr) { return EINVAL; }
877
879 return 0;
880}
void stk_cv_notify_all(stk_cv_t *cv)
Wake all tasks waiting on the condition variable.
stk_cv_t * EnsureCond(pthread_cond_t *c)

References anonymous_namespace{stk_c_pthread.cpp}::EnsureCond(), and stk_cv_notify_all().

Here is the call graph for this function:

◆ pthread_cond_destroy()

int pthread_cond_destroy ( pthread_cond_t * cond)

Definition at line 835 of file stk_c_pthread.cpp.

836{
837 if (cond == nullptr) { return EINVAL; }
838
839 if (cond->__handle != nullptr)
840 {
842 cond->__handle = nullptr;
843 }
844 return 0;
845}
void stk_cv_destroy(stk_cv_t *cv)
Destroy a Condition Variable.
stk_cv_t * __handle

References pthread_cond_t::__handle, and stk_cv_destroy().

Here is the call graph for this function:

◆ pthread_cond_init()

int pthread_cond_init ( pthread_cond_t * cond,
const pthread_condattr_t * attr )

Definition at line 827 of file stk_c_pthread.cpp.

828{
829 if (cond == nullptr) { return EINVAL; }
830
831 cond->__handle = stk_cv_create(&cond->__mem, sizeof(cond->__mem));
832 return (cond->__handle != nullptr) ? 0 : EAGAIN;
833}
stk_cv_t * stk_cv_create(stk_cv_mem_t *const membuf, uint32_t membuf_size)
Create a Condition Variable (using provided memory).
stk_cv_mem_t __mem

References pthread_cond_t::__handle, pthread_cond_t::__mem, and stk_cv_create().

Here is the call graph for this function:

◆ pthread_cond_signal()

int pthread_cond_signal ( pthread_cond_t * cond)

Definition at line 866 of file stk_c_pthread.cpp.

867{
868 if (cond == nullptr) { return EINVAL; }
869
871 return 0;
872}
void stk_cv_notify_one(stk_cv_t *cv)
Wake one task waiting on the condition variable.

References anonymous_namespace{stk_c_pthread.cpp}::EnsureCond(), and stk_cv_notify_one().

Here is the call graph for this function:

◆ pthread_cond_timedwait()

int pthread_cond_timedwait ( pthread_cond_t * cond,
pthread_mutex_t * mutex,
const struct timespec * abstime )

As pthread_cond_wait(), with an absolute deadline.

Returns
0 on success, ETIMEDOUT if the deadline passed first.
See also
"pthread_cond_timedwait() / pthread_mutex_timedlock() limitation" in the file-level docs regarding the meaning of abstime.

Definition at line 855 of file stk_c_pthread.cpp.

856{
857 if ((cond == nullptr) || (mutex == nullptr) || (mutex->__handle == nullptr) || (abstime == nullptr))
858 {
859 return EINVAL;
860 }
861
862 const bool signaled = stk_cv_wait(EnsureCond(cond), mutex->__handle, TimespecToRelativeTimeout(abstime));
863 return signaled ? 0 : ETIMEDOUT;
864}
bool stk_cv_wait(stk_cv_t *cv, stk_mutex_t *mtx, stk_timeout_t timeout)
Wait for a signal on the condition variable.
stk_timeout_t TimespecToRelativeTimeout(const struct timespec *abstime)
stk_mutex_t * __handle

References pthread_mutex_t::__handle, anonymous_namespace{stk_c_pthread.cpp}::EnsureCond(), stk_cv_wait(), and anonymous_namespace{stk_c_pthread.cpp}::TimespecToRelativeTimeout().

Here is the call graph for this function:

◆ pthread_cond_wait()

int pthread_cond_wait ( pthread_cond_t * cond,
pthread_mutex_t * mutex )

Atomically unlock mutex and wait for a signal; re-locks mutex before returning.

Definition at line 847 of file stk_c_pthread.cpp.

848{
849 if ((cond == nullptr) || (mutex == nullptr) || (mutex->__handle == nullptr)) { return EINVAL; }
850
851 (void)stk_cv_wait(EnsureCond(cond), mutex->__handle, STK_WAIT_INFINITE);
852 return 0;
853}
#define STK_WAIT_INFINITE
Infinite timeout constant.
Definition stk_c.h:147

References pthread_mutex_t::__handle, anonymous_namespace{stk_c_pthread.cpp}::EnsureCond(), stk_cv_wait(), and STK_WAIT_INFINITE.

Here is the call graph for this function:

◆ pthread_condattr_destroy()

int pthread_condattr_destroy ( pthread_condattr_t * attr)

Definition at line 821 of file stk_c_pthread.cpp.

822{
823 if (attr == nullptr) { return EINVAL; }
824 return 0;
825}

◆ pthread_condattr_init()

int pthread_condattr_init ( pthread_condattr_t * attr)

Definition at line 813 of file stk_c_pthread.cpp.

814{
815 if (attr == nullptr) { return EINVAL; }
816
817 attr->__reserved = 0;
818 return 0;
819}

References pthread_condattr_t::__reserved.

◆ pthread_create()

int pthread_create ( pthread_t * thread,
const pthread_attr_t * attr,
void *(* start_routine )(void *),
void * arg )

Create and start a new thread.

Parameters
[out]threadReceives the new thread's handle on success.
[in]attrOptional attributes, or NULL for defaults.
[in]start_routineThread entry function.
[in]argArgument passed to start_routine.
Returns
0 on success, or an errno-style error code: EINVAL - no kernel bound (see stk_pthread_bind_kernel()). EAGAIN - STK_C_PTHREAD_MAX_THREADS slots exhausted, stack allocation failed, or the underlying STK task could not be created.
Note
Requires the bound kernel to be KERNEL_DYNAMIC.

Definition at line 537 of file stk_c_pthread.cpp.

539{
540 STK_C_ASSERT(s_BoundKernel != nullptr);
541 STK_C_ASSERT(thread != nullptr);
542 STK_C_ASSERT(start_routine != nullptr);
543
544 if ((s_BoundKernel == nullptr) || (thread == nullptr) || (start_routine == nullptr))
545 {
546 return EINVAL;
547 }
548
550 if (ctrl == nullptr)
551 {
552 return EAGAIN;
553 }
554
555 const size_t stack_bytes = ((attr != nullptr) && (attr->__stack_bytes != 0U)) ?
557 const uint32_t stack_words =
558 static_cast<uint32_t>((stack_bytes + sizeof(stk_word_t) - 1U) / sizeof(stk_word_t));
559
560 if ((attr != nullptr) && (attr->__ext_stack != nullptr))
561 {
562 ctrl->stack = attr->__ext_stack;
563 ctrl->stack_owned = false;
564 ctrl->stack_from_pool = false;
565 }
566 else if (stack_bytes == kDefaultStackBytes)
567 {
568 stk_blockpool_t *const pool = EnsureStackPool();
569 void *const blk = (pool != nullptr) ? stk_blockpool_try_alloc(pool) : nullptr;
570 if (blk != nullptr)
571 {
572 ctrl->stack = static_cast<stk_word_t *>(blk);
573 ctrl->stack_owned = true;
574 ctrl->stack_from_pool = true;
575 }
576 else
577 {
578 ctrl->stack = static_cast<stk_word_t *>(malloc(stack_bytes));
579 ctrl->stack_owned = true;
580 ctrl->stack_from_pool = false;
581 }
582 }
583 else
584 {
585 ctrl->stack = static_cast<stk_word_t *>(malloc(stack_bytes));
586 ctrl->stack_owned = true;
587 ctrl->stack_from_pool = false;
588 }
589
590 if (ctrl->stack == nullptr)
591 {
593 ctrl->busy = false;
595 return EAGAIN;
596 }
597
598 ctrl->start_routine = start_routine;
599 ctrl->arg = arg;
600 ctrl->retval = nullptr;
601 ctrl->detached = ((attr != nullptr) && (attr->__detachstate == PTHREAD_CREATE_DETACHED));
602
603 ctrl->done_event = stk_event_create(&ctrl->done_event_mem, sizeof(ctrl->done_event_mem),
604 true /* manual_reset */);
605
606 ctrl->task = stk_task_create_user(PthreadTrampoline, ctrl, ctrl->stack, stack_words);
607 if (ctrl->task == nullptr)
608 {
609 if (ctrl->done_event != nullptr) { stk_event_destroy(ctrl->done_event); }
610 if (ctrl->stack_owned)
611 {
612 if (ctrl->stack_from_pool) { (void)stk_blockpool_free(s_StackPool, ctrl->stack); }
613 else { free(ctrl->stack); }
614 }
616 ctrl->busy = false;
618 return EAGAIN;
619 }
620
621 EnsureReaper();
622
624
625 *thread = ctrl;
626 return 0;
627}
void * malloc(std::size_t size)
void free(void *ptr)
stk_task_t * stk_task_create_user(stk_task_entry_t entry, void *arg, stk_word_t *stack, uint32_t stack_size)
Create user-mode task.
Definition stk_c.cpp:568
void stk_event_destroy(stk_event_t *ev)
Destroy an Event.
stk_event_t * stk_event_create(stk_event_mem_t *const membuf, uint32_t membuf_size, bool manual_reset)
Create an Event (using provided memory).
void stk_kernel_add_task(stk_kernel_t *k, stk_task_t *tsk)
Add task to non-HRT kernel (static or dynamic).
Definition stk_c.cpp:429
void stk_critical_section_enter()
Enter global critical section - disable context switches on current core.
Definition stk_c.cpp:682
#define STK_C_ASSERT(e)
Assertion macro used inside STK C bindings.
Definition stk_c.h:75
void stk_critical_section_exit()
Leave global critical section - re-enable context switches.
Definition stk_c.cpp:687
bool stk_blockpool_free(stk_blockpool_t *pool, void *ptr)
Return a previously allocated block to the pool.
void * stk_blockpool_try_alloc(stk_blockpool_t *pool)
Non-blocking allocation attempt.
stk_event_mem_t done_event_mem
stk_event_t * done_event
void *(* start_routine)(void *)

References pthread_attr_t::__detachstate, pthread_attr_t::__ext_stack, pthread_attr_t::__stack_bytes, anonymous_namespace{stk_c_pthread.cpp}::AcquireThreadSlot(), pthread_stk_ctrl_t::arg, pthread_stk_ctrl_t::busy, pthread_stk_ctrl_t::detached, pthread_stk_ctrl_t::done_event, pthread_stk_ctrl_t::done_event_mem, anonymous_namespace{stk_c_pthread.cpp}::EnsureReaper(), anonymous_namespace{stk_c_pthread.cpp}::EnsureStackPool(), free(), anonymous_namespace{stk_c_pthread.cpp}::kDefaultStackBytes, malloc(), PTHREAD_CREATE_DETACHED, anonymous_namespace{stk_c_pthread.cpp}::PthreadTrampoline(), pthread_stk_ctrl_t::retval, anonymous_namespace{stk_c_pthread.cpp}::s_BoundKernel, anonymous_namespace{stk_c_pthread.cpp}::s_StackPool, pthread_stk_ctrl_t::stack, pthread_stk_ctrl_t::stack_from_pool, pthread_stk_ctrl_t::stack_owned, pthread_stk_ctrl_t::start_routine, stk_blockpool_free(), stk_blockpool_try_alloc(), STK_C_ASSERT, stk_critical_section_enter(), stk_critical_section_exit(), stk_event_create(), stk_event_destroy(), stk_kernel_add_task(), stk_task_create_user(), and pthread_stk_ctrl_t::task.

Here is the call graph for this function:

◆ pthread_detach()

int pthread_detach ( pthread_t thread)

Mark a thread as detached.

A detached thread's resources are reclaimed automatically (by an internal reaper task) once it finishes; it must not be joined.

Returns
0 on success, EINVAL if thread is NULL, already joined, or already detached.

Definition at line 657 of file stk_c_pthread.cpp.

658{
659 pthread_stk_ctrl_t *const ctrl = thread;
660 if (ctrl == nullptr) { return EINVAL; }
661
662 bool ok = false;
664 if (!ctrl->joined && !ctrl->detached)
665 {
666 ctrl->detached = true;
667 ok = true;
668 }
670
671 if (!ok) { return EINVAL; }
672
673 MaybeReap(ctrl);
674 return 0;
675}

References pthread_stk_ctrl_t::detached, pthread_stk_ctrl_t::joined, anonymous_namespace{stk_c_pthread.cpp}::MaybeReap(), stk_critical_section_enter(), and stk_critical_section_exit().

Here is the call graph for this function:

◆ pthread_equal()

int pthread_equal ( pthread_t t1,
pthread_t t2 )

Compare two thread handles for equality.

Definition at line 712 of file stk_c_pthread.cpp.

713{
714 return (t1 == t2) ? 1 : 0;
715}

◆ pthread_exit()

void pthread_exit ( void * retval)

Terminate the calling thread.

Parameters
[in]retvalValue made available to a joiner via pthread_join(), or discarded if the thread is detached.
Note
Does not return.

Definition at line 677 of file stk_c_pthread.cpp.

678{
679 pthread_stk_ctrl_t *const ctrl = static_cast<pthread_stk_ctrl_t *>(stk_tls_get());
680
681 if (ctrl != nullptr)
682 {
683 RunKeyDestructors(ctrl);
684
686 ctrl->retval = retval;
687 ctrl->finished = true;
689
691 MaybeReap(ctrl);
692
693 STK_C_ASSERT(s_BoundKernel != nullptr);
695 }
696
697 // Safety net: if the task is somehow still running past the removal request
698 // (or ctrl was NULL, i.e. this wasn't called from a pthread_create()'d thread),
699 // park here instead of falling back into caller code that isn't expecting to
700 // regain control.
701 for (;;)
702 {
704 }
705}
bool stk_event_set(stk_event_t *ev)
Set the event to signaled state.
void * stk_tls_get(void)
Get thread-local pointer (platform-specific slot).
void stk_sleep(stk_timeout_t ticks)
Put current task to sleep (non-HRT kernels only).
Definition stk_c.cpp:646
void stk_kernel_schedule_task_removal(stk_kernel_t *k, stk_task_t *task)
Schedule removal of a running task from the kernel on the next tick.
Definition stk_c.cpp:453

References pthread_stk_ctrl_t::done_event, pthread_stk_ctrl_t::finished, anonymous_namespace{stk_c_pthread.cpp}::MaybeReap(), pthread_stk_ctrl_t::retval, anonymous_namespace{stk_c_pthread.cpp}::RunKeyDestructors(), anonymous_namespace{stk_c_pthread.cpp}::s_BoundKernel, STK_C_ASSERT, stk_critical_section_enter(), stk_critical_section_exit(), stk_event_set(), stk_kernel_schedule_task_removal(), stk_sleep(), stk_tls_get(), STK_WAIT_INFINITE, and pthread_stk_ctrl_t::task.

Here is the call graph for this function:

◆ pthread_getspecific()

void * pthread_getspecific ( pthread_key_t key)

Get the calling thread's value for key.

Returns
The stored value, or NULL if key is invalid, no value has been set, or the calling task was not created via pthread_create().

Definition at line 1168 of file stk_c_pthread.cpp.

1169{
1170 if ((key >= STK_C_PTHREAD_KEYS_MAX) || !s_Keys[key].used) { return nullptr; }
1171
1172 ThreadCtrl *const ctrl = static_cast<ThreadCtrl *>(stk_tls_get());
1173 if (ctrl == nullptr) { return nullptr; } // not a pthread_create()'d task; see file docs
1174
1175 return ctrl->tsd[key];
1176}
#define STK_C_PTHREAD_KEYS_MAX
Maximum number of concurrently-alive pthread_key_t's (default: 8).

References anonymous_namespace{stk_c_pthread.cpp}::s_Keys, STK_C_PTHREAD_KEYS_MAX, stk_tls_get(), and pthread_stk_ctrl_t::tsd.

Here is the call graph for this function:

◆ pthread_join()

int pthread_join ( pthread_t thread,
void ** retval )

Block until the given joinable thread finishes, then reclaim its resources.

Parameters
[in]threadThread to join.
[out]retvalOptional; receives the thread's return value / the value passed to pthread_exit().
Returns
0 on success, EINVAL if thread is NULL, already joined, or detached.

Definition at line 629 of file stk_c_pthread.cpp.

630{
631 pthread_stk_ctrl_t *const ctrl = thread;
632 if (ctrl == nullptr) { return EINVAL; }
633
634 bool ok = false;
636 if (!ctrl->detached && !ctrl->joined)
637 {
638 ctrl->joined = true;
639 ok = true;
640 }
642
643 if (!ok) { return EINVAL; }
644
646
647 if (retval != nullptr)
648 {
649 *retval = ctrl->retval;
650 }
651
652 WaitForTaskGone(ctrl->task);
654 return 0;
655}
bool stk_event_wait(stk_event_t *ev, stk_timeout_t timeout)
Wait for the event to become signaled.
void ReleaseThreadResources(ThreadCtrl *ctrl)

References pthread_stk_ctrl_t::detached, pthread_stk_ctrl_t::done_event, pthread_stk_ctrl_t::joined, anonymous_namespace{stk_c_pthread.cpp}::ReleaseThreadResources(), pthread_stk_ctrl_t::retval, stk_critical_section_enter(), stk_critical_section_exit(), stk_event_wait(), STK_WAIT_INFINITE, pthread_stk_ctrl_t::task, and anonymous_namespace{stk_c_pthread.cpp}::WaitForTaskGone().

Here is the call graph for this function:

◆ pthread_key_create()

int pthread_key_create ( pthread_key_t * key,
void(* destructor )(void *) )

Allocate a new thread-specific data key.

Parameters
[out]keyReceives the new key on success.
[in]destructorOptional; called with a thread's non-NULL value for this key when that thread finishes. May be NULL.
Returns
0 on success, EINVAL if key is NULL, EAGAIN if STK_C_PTHREAD_KEYS_MAX slots are exhausted.

Definition at line 1116 of file stk_c_pthread.cpp.

1117{
1118 if (key == nullptr) { return EINVAL; }
1119
1120 int result = EAGAIN;
1121
1123 for (std::size_t i = 0U; i < STK_C_PTHREAD_KEYS_MAX; ++i)
1124 {
1125 if (!s_Keys[i].used)
1126 {
1127 s_Keys[i].used = true;
1128 s_Keys[i].destructor = destructor;
1129 *key = static_cast<pthread_key_t>(i);
1130 result = 0;
1131 break;
1132 }
1133 }
1135
1136 return result;
1137}
unsigned int pthread_key_t
A thread-specific data key.

References anonymous_namespace{stk_c_pthread.cpp}::KeyEntry::destructor, anonymous_namespace{stk_c_pthread.cpp}::s_Keys, STK_C_PTHREAD_KEYS_MAX, stk_critical_section_enter(), stk_critical_section_exit(), and anonymous_namespace{stk_c_pthread.cpp}::KeyEntry::used.

Here is the call graph for this function:

◆ pthread_key_delete()

int pthread_key_delete ( pthread_key_t key)

Free a thread-specific data key.

Does not run destructors and does not clear any thread's stored value for this key (matching POSIX); reusing a stale value after deletion is undefined behavior, as in real pthreads.

Returns
0 on success, EINVAL if key was never created (or already deleted).

Definition at line 1139 of file stk_c_pthread.cpp.

1140{
1141 if (key >= STK_C_PTHREAD_KEYS_MAX) { return EINVAL; }
1142
1143 int result = EINVAL;
1144
1146 if (s_Keys[key].used)
1147 {
1148 s_Keys[key].used = false;
1149 s_Keys[key].destructor = nullptr;
1150 result = 0;
1151 }
1153
1154 return result;
1155}

References anonymous_namespace{stk_c_pthread.cpp}::KeyEntry::destructor, anonymous_namespace{stk_c_pthread.cpp}::s_Keys, STK_C_PTHREAD_KEYS_MAX, stk_critical_section_enter(), stk_critical_section_exit(), and anonymous_namespace{stk_c_pthread.cpp}::KeyEntry::used.

Here is the call graph for this function:

◆ pthread_mutex_destroy()

int pthread_mutex_destroy ( pthread_mutex_t * mutex)

Definition at line 766 of file stk_c_pthread.cpp.

767{
768 if (mutex == nullptr) { return EINVAL; }
769
770 if (mutex->__handle != nullptr)
771 {
773 mutex->__handle = nullptr;
774 }
775 return 0;
776}
void stk_mutex_destroy(stk_mutex_t *mtx)
Destroy a Mutex.

References pthread_mutex_t::__handle, and stk_mutex_destroy().

Here is the call graph for this function:

◆ pthread_mutex_init()

int pthread_mutex_init ( pthread_mutex_t * mutex,
const pthread_mutexattr_t * attr )

Initialize a mutex.

Parameters
[in]attrOptional, or NULL for defaults. Only NORMAL/DEFAULT type is supported; any other type returns ENOTSUP and leaves the mutex uninitialized.

Definition at line 757 of file stk_c_pthread.cpp.

758{
759 if (mutex == nullptr) { return EINVAL; }
760 if ((attr != nullptr) && (attr->__type != PTHREAD_MUTEX_NORMAL)) { return ENOTSUP; }
761
762 mutex->__handle = stk_mutex_create(&mutex->__mem, sizeof(mutex->__mem));
763 return (mutex->__handle != nullptr) ? 0 : EAGAIN;
764}
stk_mutex_t * stk_mutex_create(stk_mutex_mem_t *const membuf, uint32_t membuf_size)
Create a Mutex (using provided memory).
#define PTHREAD_MUTEX_NORMAL
stk_mutex_mem_t __mem

References pthread_mutex_t::__handle, pthread_mutex_t::__mem, pthread_mutexattr_t::__type, PTHREAD_MUTEX_NORMAL, and stk_mutex_create().

Here is the call graph for this function:

◆ pthread_mutex_lock()

int pthread_mutex_lock ( pthread_mutex_t * mutex)

Definition at line 778 of file stk_c_pthread.cpp.

779{
780 if (mutex == nullptr) { return EINVAL; }
781
783 return 0;
784}
void stk_mutex_lock(stk_mutex_t *mtx)
Lock the mutex. Blocks until available.
stk_mutex_t * EnsureMutex(pthread_mutex_t *m)

References anonymous_namespace{stk_c_pthread.cpp}::EnsureMutex(), and stk_mutex_lock().

Here is the call graph for this function:

◆ pthread_mutex_timedlock()

int pthread_mutex_timedlock ( pthread_mutex_t * mutex,
const struct timespec * abstime )

Lock with an absolute deadline.

Returns
0 on success, ETIMEDOUT if the deadline passed first.
See also
"pthread_cond_timedwait() / pthread_mutex_timedlock() limitation" in the file-level docs regarding the meaning of abstime.

Definition at line 802 of file stk_c_pthread.cpp.

803{
804 if ((mutex == nullptr) || (abstime == nullptr)) { return EINVAL; }
805
806 const bool locked = stk_mutex_timed_lock(EnsureMutex(mutex), TimespecToRelativeTimeout(abstime));
807 return locked ? 0 : ETIMEDOUT;
808}
bool stk_mutex_timed_lock(stk_mutex_t *mtx, stk_timeout_t timeout)
Try to lock the mutex with a timeout.

References anonymous_namespace{stk_c_pthread.cpp}::EnsureMutex(), stk_mutex_timed_lock(), and anonymous_namespace{stk_c_pthread.cpp}::TimespecToRelativeTimeout().

Here is the call graph for this function:

◆ pthread_mutex_trylock()

int pthread_mutex_trylock ( pthread_mutex_t * mutex)

Definition at line 786 of file stk_c_pthread.cpp.

787{
788 if (mutex == nullptr) { return EINVAL; }
789
790 return stk_mutex_trylock(EnsureMutex(mutex)) ? 0 : EBUSY;
791}
bool stk_mutex_trylock(stk_mutex_t *mtx)
Try locking the mutex. Does not block if already locked.

References anonymous_namespace{stk_c_pthread.cpp}::EnsureMutex(), and stk_mutex_trylock().

Here is the call graph for this function:

◆ pthread_mutex_unlock()

int pthread_mutex_unlock ( pthread_mutex_t * mutex)

Definition at line 793 of file stk_c_pthread.cpp.

794{
795 if (mutex == nullptr) { return EINVAL; }
796 if (mutex->__handle == nullptr) { return EINVAL; }
797
799 return 0;
800}
void stk_mutex_unlock(stk_mutex_t *mtx)
Unlock the mutex.

References pthread_mutex_t::__handle, and stk_mutex_unlock().

Here is the call graph for this function:

◆ pthread_mutexattr_destroy()

int pthread_mutexattr_destroy ( pthread_mutexattr_t * attr)

Definition at line 734 of file stk_c_pthread.cpp.

735{
736 if (attr == nullptr) { return EINVAL; }
737 return 0;
738}

◆ pthread_mutexattr_gettype()

int pthread_mutexattr_gettype ( const pthread_mutexattr_t * attr,
int * type )

Definition at line 749 of file stk_c_pthread.cpp.

750{
751 if ((attr == nullptr) || (type == nullptr)) { return EINVAL; }
752
753 *type = attr->__type;
754 return 0;
755}

References pthread_mutexattr_t::__type.

◆ pthread_mutexattr_init()

int pthread_mutexattr_init ( pthread_mutexattr_t * attr)

Definition at line 726 of file stk_c_pthread.cpp.

727{
728 if (attr == nullptr) { return EINVAL; }
729
731 return 0;
732}
#define PTHREAD_MUTEX_DEFAULT

References pthread_mutexattr_t::__type, and PTHREAD_MUTEX_DEFAULT.

◆ pthread_mutexattr_settype()

int pthread_mutexattr_settype ( pthread_mutexattr_t * attr,
int type )

Set the mutex type.

Returns
0 for PTHREAD_MUTEX_NORMAL/PTHREAD_MUTEX_DEFAULT, ENOTSUP for PTHREAD_MUTEX_RECURSIVE / PTHREAD_MUTEX_ERRORCHECK (not implemented).

Definition at line 740 of file stk_c_pthread.cpp.

741{
742 if (attr == nullptr) { return EINVAL; }
743 if (type != PTHREAD_MUTEX_NORMAL) { return ENOTSUP; }
744
745 attr->__type = type;
746 return 0;
747}

References pthread_mutexattr_t::__type, and PTHREAD_MUTEX_NORMAL.

◆ pthread_once()

int pthread_once ( pthread_once_t * once_control,
void(* init_routine )(void) )

Call init_routine exactly once for a given once_control, no matter how many threads call pthread_once() on it concurrently.

See also
"pthread_once() note" in the file-level docs.
Returns
0 on success, EINVAL if once_control or init_routine is NULL.

Definition at line 1090 of file stk_c_pthread.cpp.

1091{
1092 if ((once_control == nullptr) || (init_routine == nullptr)) { return EINVAL; }
1093
1094 if (once_control->__state == 2) { return 0; } // fast path: already done, no lock needed
1095
1096 stk_mutex_t *const guard = EnsureOnceMutex(once_control);
1097 stk_mutex_lock(guard);
1098
1099 // Re-check under the lock: another thread may have finished init_routine()
1100 // (or be running it right now, in which case this lock() call already blocked
1101 // until it was done) between our unlocked fast-path check above and here.
1102 if (once_control->__state != 2)
1103 {
1104 once_control->__state = 1;
1105 init_routine();
1106 once_control->__state = 2;
1107 }
1108
1109 stk_mutex_unlock(guard);
1110 return 0;
1111}
stk_mutex_t * EnsureOnceMutex(pthread_once_t *o)

References pthread_once_t::__state, anonymous_namespace{stk_c_pthread.cpp}::EnsureOnceMutex(), stk_mutex_lock(), and stk_mutex_unlock().

Here is the call graph for this function:

◆ pthread_rwlock_destroy()

int pthread_rwlock_destroy ( pthread_rwlock_t * rwlock)

Definition at line 908 of file stk_c_pthread.cpp.

909{
910 if (rwlock == nullptr) { return EINVAL; }
911
912 if (rwlock->__handle != nullptr)
913 {
915 rwlock->__handle = nullptr;
916 }
917 return 0;
918}
void stk_rwmutex_destroy(stk_rwmutex_t *rw)
Destroy an RWMutex.
stk_rwmutex_t * __handle

References pthread_rwlock_t::__handle, and stk_rwmutex_destroy().

Here is the call graph for this function:

◆ pthread_rwlock_init()

int pthread_rwlock_init ( pthread_rwlock_t * rwlock,
const pthread_rwlockattr_t * attr )

Initialize a read-write lock.

Parameters
[in]attrOptional, or NULL for defaults (no settable properties).

Definition at line 899 of file stk_c_pthread.cpp.

900{
901 if (rwlock == nullptr) { return EINVAL; }
902
903 rwlock->__handle = stk_rwmutex_create(&rwlock->__mem, sizeof(rwlock->__mem));
904 rwlock->__wrlocked = false;
905 return (rwlock->__handle != nullptr) ? 0 : EAGAIN;
906}
stk_rwmutex_t * stk_rwmutex_create(stk_rwmutex_mem_t *const membuf, uint32_t membuf_size)
Create an RWMutex (using provided memory).
stk_rwmutex_mem_t __mem

References pthread_rwlock_t::__handle, pthread_rwlock_t::__mem, pthread_rwlock_t::__wrlocked, and stk_rwmutex_create().

Here is the call graph for this function:

◆ pthread_rwlock_rdlock()

int pthread_rwlock_rdlock ( pthread_rwlock_t * rwlock)

Acquire the lock for shared reading. Blocks until available.

Blocks if a writer is currently active or writers are waiting (writer-preference policy; see stk_rwmutex_read_lock() in stk_c.h).

Definition at line 920 of file stk_c_pthread.cpp.

921{
922 if (rwlock == nullptr) { return EINVAL; }
923
925 return 0;
926}
void stk_rwmutex_read_lock(stk_rwmutex_t *rw)
Acquire the lock for shared reading. Blocks until available.
stk_rwmutex_t * EnsureRWLock(pthread_rwlock_t *rw)

References anonymous_namespace{stk_c_pthread.cpp}::EnsureRWLock(), and stk_rwmutex_read_lock().

Here is the call graph for this function:

◆ pthread_rwlock_timedrdlock()

int pthread_rwlock_timedrdlock ( pthread_rwlock_t * rwlock,
const struct timespec * abstime )

Acquire the read lock with an absolute deadline.

Returns
0 on success, ETIMEDOUT if the deadline passed first.
See also
"pthread_cond_timedwait() / pthread_mutex_timedlock() limitation" in the file-level docs regarding the meaning of abstime.

Definition at line 935 of file stk_c_pthread.cpp.

936{
937 if ((rwlock == nullptr) || (abstime == nullptr)) { return EINVAL; }
938
939 const bool locked = stk_rwmutex_timed_read_lock(EnsureRWLock(rwlock), TimespecToRelativeTimeout(abstime));
940 return locked ? 0 : ETIMEDOUT;
941}
bool stk_rwmutex_timed_read_lock(stk_rwmutex_t *rw, stk_timeout_t timeout)
Try to acquire the read lock with a timeout.

References anonymous_namespace{stk_c_pthread.cpp}::EnsureRWLock(), stk_rwmutex_timed_read_lock(), and anonymous_namespace{stk_c_pthread.cpp}::TimespecToRelativeTimeout().

Here is the call graph for this function:

◆ pthread_rwlock_timedwrlock()

int pthread_rwlock_timedwrlock ( pthread_rwlock_t * rwlock,
const struct timespec * abstime )

Acquire the write lock with an absolute deadline.

Returns
0 on success, ETIMEDOUT if the deadline passed first.
See also
"pthread_cond_timedwait() / pthread_mutex_timedlock() limitation" in the file-level docs regarding the meaning of abstime.

Definition at line 962 of file stk_c_pthread.cpp.

963{
964 if ((rwlock == nullptr) || (abstime == nullptr)) { return EINVAL; }
965
966 if (!stk_rwmutex_timed_lock(EnsureRWLock(rwlock), TimespecToRelativeTimeout(abstime))) { return ETIMEDOUT; }
967
968 rwlock->__wrlocked = true;
969 return 0;
970}
bool stk_rwmutex_timed_lock(stk_rwmutex_t *rw, stk_timeout_t timeout)
Try to acquire the write lock with a timeout.

References pthread_rwlock_t::__wrlocked, anonymous_namespace{stk_c_pthread.cpp}::EnsureRWLock(), stk_rwmutex_timed_lock(), and anonymous_namespace{stk_c_pthread.cpp}::TimespecToRelativeTimeout().

Here is the call graph for this function:

◆ pthread_rwlock_tryrdlock()

int pthread_rwlock_tryrdlock ( pthread_rwlock_t * rwlock)

Try to acquire the read lock without blocking.

Returns
0 on success, EBUSY if a writer is active or waiting.

Definition at line 928 of file stk_c_pthread.cpp.

929{
930 if (rwlock == nullptr) { return EINVAL; }
931
932 return stk_rwmutex_try_read_lock(EnsureRWLock(rwlock)) ? 0 : EBUSY;
933}
bool stk_rwmutex_try_read_lock(stk_rwmutex_t *rw)
Try to acquire the read lock without blocking.

References anonymous_namespace{stk_c_pthread.cpp}::EnsureRWLock(), and stk_rwmutex_try_read_lock().

Here is the call graph for this function:

◆ pthread_rwlock_trywrlock()

int pthread_rwlock_trywrlock ( pthread_rwlock_t * rwlock)

Try to acquire the write lock without blocking.

Returns
0 on success, EBUSY otherwise.

Definition at line 952 of file stk_c_pthread.cpp.

953{
954 if (rwlock == nullptr) { return EINVAL; }
955
956 if (!stk_rwmutex_trylock(EnsureRWLock(rwlock))) { return EBUSY; }
957
958 rwlock->__wrlocked = true;
959 return 0;
960}
bool stk_rwmutex_trylock(stk_rwmutex_t *rw)
Try to acquire the write lock without blocking.

References pthread_rwlock_t::__wrlocked, anonymous_namespace{stk_c_pthread.cpp}::EnsureRWLock(), and stk_rwmutex_trylock().

Here is the call graph for this function:

◆ pthread_rwlock_unlock()

int pthread_rwlock_unlock ( pthread_rwlock_t * rwlock)

Release a read or write hold, whichever the calling thread holds.

See also
"pthread_rwlock_unlock() disambiguation" in the file-level docs.

Definition at line 972 of file stk_c_pthread.cpp.

973{
974 if (rwlock == nullptr) { return EINVAL; }
975 if (rwlock->__handle == nullptr) { return EINVAL; }
976
977 // See "pthread_rwlock_unlock() disambiguation" in stk_c_pthread.h: a write
978 // hold is always exclusive, so __wrlocked unambiguously identifies which
979 // underlying call the current holder must have made. Clear it before
980 // releasing so a racing new writer's own acquisition can't be clobbered.
981 if (rwlock->__wrlocked)
982 {
983 rwlock->__wrlocked = false;
985 }
986 else
987 {
989 }
990 return 0;
991}
void stk_rwmutex_read_unlock(stk_rwmutex_t *rw)
Release the shared reader lock.
void stk_rwmutex_unlock(stk_rwmutex_t *rw)
Release the exclusive writer lock.

References pthread_rwlock_t::__handle, pthread_rwlock_t::__wrlocked, stk_rwmutex_read_unlock(), and stk_rwmutex_unlock().

Here is the call graph for this function:

◆ pthread_rwlock_wrlock()

int pthread_rwlock_wrlock ( pthread_rwlock_t * rwlock)

Acquire the lock for exclusive writing. Blocks until available.

Blocks until all active readers have released their locks and no other writer is active.

Definition at line 943 of file stk_c_pthread.cpp.

944{
945 if (rwlock == nullptr) { return EINVAL; }
946
948 rwlock->__wrlocked = true;
949 return 0;
950}
void stk_rwmutex_lock(stk_rwmutex_t *rw)
Acquire the lock for exclusive writing. Blocks until available.

References pthread_rwlock_t::__wrlocked, anonymous_namespace{stk_c_pthread.cpp}::EnsureRWLock(), and stk_rwmutex_lock().

Here is the call graph for this function:

◆ pthread_rwlockattr_destroy()

int pthread_rwlockattr_destroy ( pthread_rwlockattr_t * attr)

Definition at line 893 of file stk_c_pthread.cpp.

894{
895 if (attr == nullptr) { return EINVAL; }
896 return 0;
897}

◆ pthread_rwlockattr_init()

int pthread_rwlockattr_init ( pthread_rwlockattr_t * attr)

Definition at line 885 of file stk_c_pthread.cpp.

886{
887 if (attr == nullptr) { return EINVAL; }
888
889 attr->__reserved = 0;
890 return 0;
891}

References pthread_rwlockattr_t::__reserved.

◆ pthread_self()

pthread_t pthread_self ( void )

Return the calling thread's own handle.

Returns
A valid pthread_t for threads created via pthread_create(); NULL if called from a task that was not created through this shim (e.g. the application's original bootstrap task - see the file-level note).

Definition at line 707 of file stk_c_pthread.cpp.

708{
709 return static_cast<pthread_t>(stk_tls_get());
710}
struct pthread_stk_ctrl_t * pthread_t
Opaque thread handle.

References stk_tls_get().

Here is the call graph for this function:

◆ pthread_setspecific()

int pthread_setspecific ( pthread_key_t key,
const void * value )

Set the calling thread's value for key.

See also
"pthread_key_t / thread-specific data limitation" in the file-level docs.
Returns
0 on success, EINVAL if key is invalid or the calling task was not created via pthread_create().

Definition at line 1157 of file stk_c_pthread.cpp.

1158{
1159 if ((key >= STK_C_PTHREAD_KEYS_MAX) || !s_Keys[key].used) { return EINVAL; }
1160
1161 ThreadCtrl *const ctrl = static_cast<ThreadCtrl *>(stk_tls_get());
1162 if (ctrl == nullptr) { return EINVAL; } // not a pthread_create()'d task; see file docs
1163
1164 ctrl->tsd[key] = const_cast<void *>(value);
1165 return 0;
1166}

References anonymous_namespace{stk_c_pthread.cpp}::s_Keys, STK_C_PTHREAD_KEYS_MAX, stk_tls_get(), and pthread_stk_ctrl_t::tsd.

Here is the call graph for this function:

◆ pthread_spin_destroy()

int pthread_spin_destroy ( pthread_spinlock_t * lock)

Definition at line 1005 of file stk_c_pthread.cpp.

1006{
1007 if (lock == nullptr) { return EINVAL; }
1008
1009 if (lock->__handle != nullptr)
1010 {
1012 lock->__handle = nullptr;
1013 }
1014 return 0;
1015}
void stk_spinlock_destroy(stk_spinlock_t *slock)
Destroy the SpinLock.
stk_spinlock_t * __handle

References pthread_spinlock_t::__handle, and stk_spinlock_destroy().

Here is the call graph for this function:

◆ pthread_spin_init()

int pthread_spin_init ( pthread_spinlock_t * lock,
int pshared )

Initialize a spinlock.

Parameters
[in]psharedMust be PTHREAD_PROCESS_PRIVATE.
Returns
0 on success, ENOTSUP if pshared is PTHREAD_PROCESS_SHARED, EAGAIN if the underlying STK spinlock could not be created.

Definition at line 996 of file stk_c_pthread.cpp.

997{
998 if (lock == nullptr) { return EINVAL; }
999 if (pshared != PTHREAD_PROCESS_PRIVATE) { return ENOTSUP; }
1000
1001 lock->__handle = stk_spinlock_create(&lock->__mem, sizeof(lock->__mem));
1002 return (lock->__handle != nullptr) ? 0 : EAGAIN;
1003}
stk_spinlock_t * stk_spinlock_create(stk_spinlock_mem_t *const membuf, uint32_t membuf_size)
Create a recursive SpinLock.
#define PTHREAD_PROCESS_PRIVATE
stk_spinlock_mem_t __mem

References pthread_spinlock_t::__handle, pthread_spinlock_t::__mem, PTHREAD_PROCESS_PRIVATE, and stk_spinlock_create().

Here is the call graph for this function:

◆ pthread_spin_lock()

int pthread_spin_lock ( pthread_spinlock_t * lock)

Acquire the spinlock, spinning until available.

See also
"pthread_spin_* recursion note" in the file-level docs.

Definition at line 1017 of file stk_c_pthread.cpp.

1018{
1019 if ((lock == nullptr) || (lock->__handle == nullptr)) { return EINVAL; }
1020
1022 return 0;
1023}
void stk_spinlock_lock(stk_spinlock_t *slock)
Acquire the SpinLock (recursive).

References pthread_spinlock_t::__handle, and stk_spinlock_lock().

Here is the call graph for this function:

◆ pthread_spin_trylock()

int pthread_spin_trylock ( pthread_spinlock_t * lock)

Try to acquire the spinlock without blocking.

Returns
0 on success, EBUSY if currently held.

Definition at line 1025 of file stk_c_pthread.cpp.

1026{
1027 if ((lock == nullptr) || (lock->__handle == nullptr)) { return EINVAL; }
1028
1029 return stk_spinlock_trylock(lock->__handle) ? 0 : EBUSY;
1030}
bool stk_spinlock_trylock(stk_spinlock_t *slock)
Attempt to acquire the SpinLock immediately.

References pthread_spinlock_t::__handle, and stk_spinlock_trylock().

Here is the call graph for this function:

◆ pthread_spin_unlock()

int pthread_spin_unlock ( pthread_spinlock_t * lock)

Definition at line 1032 of file stk_c_pthread.cpp.

1033{
1034 if ((lock == nullptr) || (lock->__handle == nullptr)) { return EINVAL; }
1035
1037 return 0;
1038}
void stk_spinlock_unlock(stk_spinlock_t *slock)
Release the SpinLock.

References pthread_spinlock_t::__handle, and stk_spinlock_unlock().

Here is the call graph for this function:

◆ pthread_yield()

int pthread_yield ( void )

Voluntarily give up the CPU to another ready task (cooperative yield), then resume once rescheduled.

Returns
Always 0 (matches the non-standard GNU pthread_yield() signature; the underlying stk_yield() cannot fail).
Note
Non-standard - not in POSIX (POSIX uses sched_yield()), but widely available as a GNU/BSD extension under this name.

Definition at line 717 of file stk_c_pthread.cpp.

718{
719 stk_yield();
720 return 0;
721}
void stk_yield(void)
Voluntarily give up CPU to another ready task (cooperative yield).
Definition stk_c.cpp:651

References stk_yield().

Here is the call graph for this function:

◆ stk_pthread_bind_kernel()

void stk_pthread_bind_kernel ( stk_kernel_t * kernel)

Bind the STK kernel instance that pthread_create() will add new threads to.

Must be called exactly once, before the first pthread_create() call. The kernel must already be created (stk_kernel_create()) and initialized (stk_kernel_init()); it does not need to be started yet, but in practice pthread_create() will only usefully run new threads once stk_kernel_start() has been called on it.

Parameters
[in]kernelKernel handle obtained from stk_kernel_create(). Must be a KERNEL_DYNAMIC kernel (threads need to be able to finish/return).

Definition at line 453 of file stk_c_pthread.cpp.

454{
455 STK_C_ASSERT(kernel != nullptr);
456
457 s_BoundKernel = kernel;
458}

References anonymous_namespace{stk_c_pthread.cpp}::s_BoundKernel, and STK_C_ASSERT.