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_VERSION   (0x20261004)
 Interface version.
#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_CREATE_USER_NP   (0)
#define PTHREAD_CREATE_PRIVILEGED_NP   (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" in the file-level docs.

Typedefs

typedef struct pthread_stk_ctrl_t * pthread_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 stack size in bytes that threads created with attr will use.
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 (stackaddr is NULL 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_attr_setprivileged_np (pthread_attr_t *attr, int mode)
 Non-portable: select the STK access mode of threads created with attr.
int pthread_attr_getprivileged_np (const pthread_attr_t *attr, int *mode)
 Non-portable: get the access mode set in attr.
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)
 Initialize a mutex attributes object with default values (PTHREAD_MUTEX_DEFAULT).
int pthread_mutexattr_destroy (pthread_mutexattr_t *attr)
 Destroy a mutex attributes object (no-op; no owned resources).
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)
 Get the mutex type stored in attr.
int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
 Initialize a mutex.
int pthread_mutex_destroy (pthread_mutex_t *mutex)
 Destroy a mutex, releasing the underlying STK mutex object.
int pthread_mutex_lock (pthread_mutex_t *mutex)
 Lock a mutex, blocking until it becomes available.
int pthread_mutex_trylock (pthread_mutex_t *mutex)
 Try to lock a mutex without blocking.
int pthread_mutex_unlock (pthread_mutex_t *mutex)
 Unlock a mutex held by the calling thread.
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)
 Initialize a condition variable attributes object (no settable properties).
int pthread_condattr_destroy (pthread_condattr_t *attr)
 Destroy a condition variable attributes object (no-op).
int pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr)
 Initialize a condition variable.
int pthread_cond_destroy (pthread_cond_t *cond)
 Destroy a condition variable, releasing the underlying STK object.
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)
 Wake one thread waiting on cond (no effect if none is waiting).
int pthread_cond_broadcast (pthread_cond_t *cond)
 Wake all threads waiting on cond (no effect if none is waiting).
int pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
 Initialize a read-write lock attributes object (no settable properties).
int pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr)
 Destroy a read-write lock attributes object (no-op).
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)
 Destroy a read-write lock, releasing the underlying STK object.
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)
 Destroy a spinlock.
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)
 Release a spinlock held by the calling thread.
int pthread_barrierattr_init (pthread_barrierattr_t *attr)
 Initialize a barrier attributes object (no settable properties).
int pthread_barrierattr_destroy (pthread_barrierattr_t *attr)
 Destroy a barrier attributes object (no-op).
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)
 Destroy a barrier, releasing the underlying STK barrier object.
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 418 of file stk_c_pthread.h.

Referenced by pthread_barrier_wait(), and stk_pthread_compile_check().

◆ PTHREAD_COND_INITIALIZER

#define PTHREAD_COND_INITIALIZER   {0}

Definition at line 350 of file stk_c_pthread.h.

◆ PTHREAD_CREATE_DETACHED

#define PTHREAD_CREATE_DETACHED   (1)

Definition at line 287 of file stk_c_pthread.h.

Referenced by pthread_attr_setdetachstate(), and pthread_create().

◆ PTHREAD_CREATE_JOINABLE

#define PTHREAD_CREATE_JOINABLE   (0)

◆ PTHREAD_CREATE_PRIVILEGED_NP

#define PTHREAD_CREATE_PRIVILEGED_NP   (1)

Definition at line 294 of file stk_c_pthread.h.

Referenced by pthread_attr_setprivileged_np(), and pthread_create().

◆ PTHREAD_CREATE_USER_NP

#define PTHREAD_CREATE_USER_NP   (0)

◆ 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" in the file-level docs.

Definition at line 452 of file stk_c_pthread.h.

Referenced by stk::pthread::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 444 of file stk_c_pthread.h.

Referenced by stk_pthread_compile_check().

◆ PTHREAD_MUTEX_DEFAULT

#define PTHREAD_MUTEX_DEFAULT   (PTHREAD_MUTEX_NORMAL)

Definition at line 314 of file stk_c_pthread.h.

Referenced by pthread_mutex_init(), and pthread_mutexattr_init().

◆ PTHREAD_MUTEX_ERRORCHECK

#define PTHREAD_MUTEX_ERRORCHECK   (1)

◆ PTHREAD_MUTEX_INITIALIZER

#define PTHREAD_MUTEX_INITIALIZER   {0}

Definition at line 330 of file stk_c_pthread.h.

◆ PTHREAD_MUTEX_NORMAL

#define PTHREAD_MUTEX_NORMAL   (0)

Definition at line 313 of file stk_c_pthread.h.

Referenced by stk::pthread::IsValidMutexType().

◆ PTHREAD_MUTEX_RECURSIVE

#define PTHREAD_MUTEX_RECURSIVE   (2)

Definition at line 316 of file stk_c_pthread.h.

Referenced by stk::pthread::IsValidMutexType(), and stk_pthread_compile_check().

◆ PTHREAD_ONCE_INIT

#define PTHREAD_ONCE_INIT   {0}

Definition at line 433 of file stk_c_pthread.h.

◆ PTHREAD_PROCESS_PRIVATE

#define PTHREAD_PROCESS_PRIVATE   (0)

Definition at line 378 of file stk_c_pthread.h.

Referenced by pthread_spin_init(), and stk_pthread_compile_check().

◆ PTHREAD_PROCESS_SHARED

#define PTHREAD_PROCESS_SHARED   (1)

Definition at line 379 of file stk_c_pthread.h.

◆ PTHREAD_RWLOCK_INITIALIZER

#define PTHREAD_RWLOCK_INITIALIZER   {0}

Definition at line 376 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 228 of file stk_c_pthread.h.

Referenced by stk_pthread_compile_check().

◆ 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 244 of file stk_c_pthread.h.

Referenced by stk::pthread::IsKeyUsed(), pthread_key_create(), pthread_key_delete(), pthread_stk_ctrl_t::Reset(), and stk::pthread::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). Tasks adopted via pthread_self() / pthread_setspecific() count against this limit permanently.

Definition at line 216 of file stk_c_pthread.h.

Referenced by stk::pthread::AcquireThreadSlot(), stk::pthread::DequeueReap(), stk::pthread::EnqueueReap(), stk::pthread::EnsureStackPool(), and stk::pthread::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 236 of file stk_c_pthread.h.

Referenced by stk::pthread::EnsureReaper().

◆ STK_C_PTHREAD_VERSION

#define STK_C_PTHREAD_VERSION   (0x20261004)

Interface version.

Definition at line 202 of file stk_c_pthread.h.

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 439 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
PTHREAD_MUTEX_NORMAL / DEFAULT, PTHREAD_MUTEX_RECURSIVE and PTHREAD_MUTEX_ERRORCHECK are supported. The underlying stk::sync::Mutex is always recursive, so PTHREAD_MUTEX_NORMAL behaves like PTHREAD_MUTEX_RECURSIVE (POSIX leaves relocking a NORMAL mutex undefined, so this is conforming). Behavior per type:
  • NORMAL/DEFAULT, RECURSIVE: relocking by the owner succeeds and must be balanced by the same number of unlocks (maximum depth stk::sync::Mutex::RECURSION_MAX, then EAGAIN).
  • ERRORCHECK: relocking by the owner returns EDEADLK (trylock: EBUSY).
  • all types: unlocking a mutex not owned by the caller returns EPERM.

◆ 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 RWMutex::TimedReadLock()).

◆ 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_* note" in the file-level docs.

◆ pthread_t

typedef struct pthread_stk_ctrl_t* pthread_t

Opaque thread handle.

Definition at line 273 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).

Parameters
[in]attrAttributes object to destroy.

Definition at line 777 of file stk_c_pthread.cpp.

778{
779 return (attr != nullptr) ? 0 : EINVAL;
780}

Referenced by stk_pthread_compile_check().

Here is the caller graph for this function:

◆ pthread_attr_getdetachstate()

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

Get the current detach-state setting.

Parameters
[in]attrAttributes object to query.
[out]detachstateReceives PTHREAD_CREATE_JOINABLE or PTHREAD_CREATE_DETACHED.

Definition at line 853 of file stk_c_pthread.cpp.

854{
855 int result = EINVAL;
856
857 if ((attr != nullptr) && (detachstate != nullptr))
858 {
859 *detachstate = attr->__detachstate;
860 result = 0;
861 }
862
863 return result;
864}
int __detachstate
PTHREAD_CREATE_JOINABLE / _DETACHED.

References pthread_attr_t::__detachstate.

◆ pthread_attr_getprivileged_np()

int pthread_attr_getprivileged_np ( const pthread_attr_t * attr,
int * mode )

Non-portable: get the access mode set in attr.

Parameters
[in]attrAttributes object to query.
[out]modeReceives PTHREAD_CREATE_USER_NP or PTHREAD_CREATE_PRIVILEGED_NP.

Definition at line 880 of file stk_c_pthread.cpp.

881{
882 int result = EINVAL;
883
884 if ((attr != nullptr) && (mode != nullptr))
885 {
886 *mode = attr->__privileged;
887 result = 0;
888 }
889
890 return result;
891}
int __privileged
PTHREAD_CREATE_USER_NP (default) / _PRIVILEGED_NP.

References pthread_attr_t::__privileged.

Referenced by stk_pthread_compile_check().

Here is the caller graph for this function:

◆ pthread_attr_getstack()

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

Get the previously-set external stack (stackaddr is NULL if none set).

Parameters
[in]attrAttributes object to query.
[out]stackaddrReceives the external stack address, or NULL if none was set.
[out]stacksizeReceives the configured stack size in bytes (0 if no size was set).

Definition at line 825 of file stk_c_pthread.cpp.

826{
827 int result = EINVAL;
828
829 if ((attr != nullptr) && (stackaddr != nullptr) && (stacksize != nullptr))
830 {
831 *stackaddr = attr->__ext_stack;
832 *stacksize = attr->__stack_bytes;
833 result = 0;
834 }
835
836 return result;
837}
size_t __stack_bytes
0 = use STK_C_PTHREAD_DEFAULT_STACK_WORDS.
stk_word_t * __ext_stack
Caller-supplied stack, or NULL.

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 stack size in bytes that threads created with attr will use.

If no size was set, reports STK_C_PTHREAD_DEFAULT_STACK_WORDS * sizeof(stk_word_t).

Parameters
[in]attrAttributes object to query.
[out]stacksizeReceives the stack size in bytes (the default size if none was set).

Definition at line 795 of file stk_c_pthread.cpp.

796{
797 int result = EINVAL;
798
799 if ((attr != nullptr) && (stacksize != nullptr))
800 {
801 *stacksize = (attr->__stack_bytes != 0U) ? attr->__stack_bytes : kDefaultStackBytes;
802 result = 0;
803 }
804
805 return result;
806}
constexpr std::size_t kDefaultStackBytes

References pthread_attr_t::__stack_bytes, and stk::pthread::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).

Parameters
[out]attrAttributes object to initialize.

Definition at line 761 of file stk_c_pthread.cpp.

762{
763 int result = EINVAL;
764
765 if (attr != nullptr)
766 {
767 attr->__stack_bytes = 0U;
768 attr->__ext_stack = nullptr;
771 result = 0;
772 }
773
774 return result;
775}
#define PTHREAD_CREATE_USER_NP
#define PTHREAD_CREATE_JOINABLE

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

Referenced by stk_pthread_compile_check().

Here is the caller graph for this function:

◆ pthread_attr_setdetachstate()

int pthread_attr_setdetachstate ( pthread_attr_t * attr,
int detachstate )

Set PTHREAD_CREATE_JOINABLE or PTHREAD_CREATE_DETACHED.

Parameters
[in,out]attrAttributes object to modify.
[in]detachstatePTHREAD_CREATE_JOINABLE or PTHREAD_CREATE_DETACHED.

Definition at line 839 of file stk_c_pthread.cpp.

840{
841 int result = EINVAL;
842
843 if ((attr != nullptr) &&
844 ((detachstate == PTHREAD_CREATE_JOINABLE) || (detachstate == PTHREAD_CREATE_DETACHED)))
845 {
846 attr->__detachstate = detachstate;
847 result = 0;
848 }
849
850 return result;
851}
#define PTHREAD_CREATE_DETACHED

References pthread_attr_t::__detachstate, PTHREAD_CREATE_DETACHED, and PTHREAD_CREATE_JOINABLE.

Referenced by stk_pthread_compile_check().

Here is the caller graph for this function:

◆ pthread_attr_setprivileged_np()

int pthread_attr_setprivileged_np ( pthread_attr_t * attr,
int mode )

Non-portable: select the STK access mode of threads created with attr.

PTHREAD_CREATE_USER_NP (default) creates the thread via stk_task_create_user(); PTHREAD_CREATE_PRIVILEGED_NP via stk_task_create_privileged() (needed e.g. for direct GPIO/peripheral access on some MCUs).

Parameters
[in,out]attrAttributes object to modify.
[in]modePTHREAD_CREATE_USER_NP or PTHREAD_CREATE_PRIVILEGED_NP.
Returns
0 on success, EINVAL on NULL attr or unknown mode.

Definition at line 866 of file stk_c_pthread.cpp.

867{
868 int result = EINVAL;
869
870 if ((attr != nullptr) &&
872 {
873 attr->__privileged = mode;
874 result = 0;
875 }
876
877 return result;
878}
#define PTHREAD_CREATE_PRIVILEGED_NP

References pthread_attr_t::__privileged, PTHREAD_CREATE_PRIVILEGED_NP, and PTHREAD_CREATE_USER_NP.

Referenced by stk_pthread_compile_check().

Here is the caller graph for this function:

◆ 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,out]attrAttributes object to modify.
[in]stackaddrPointer to a stk_word_t-aligned buffer.
[in]stacksizeSize of the buffer in bytes.

Definition at line 808 of file stk_c_pthread.cpp.

809{
810 int result = EINVAL;
811
812 if ((attr != nullptr) && (stackaddr != nullptr) && (stacksize >= sizeof(stk_word_t)))
813 {
814 if ((reinterpret_cast<uintptr_t>(stackaddr) & STK_ALIGN_MASK) == 0U)
815 {
816 attr->__ext_stack = static_cast<stk_word_t *>(stackaddr);
817 attr->__stack_bytes = stacksize;
818 result = 0;
819 }
820 }
821
822 return result;
823}
#define STK_ALIGN_MASK
Alignment mask.
Definition stk_c.h:164
uintptr_t stk_word_t
CPU register type.
Definition stk_c.h:99

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.

Parameters
[in,out]attrAttributes object to modify.
[in]stacksizeRequested stack size in bytes. Must not be 0.
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 782 of file stk_c_pthread.cpp.

783{
784 int result = EINVAL;
785
786 if ((attr != nullptr) && (stacksize != 0U))
787 {
788 attr->__stack_bytes = stacksize;
789 result = 0;
790 }
791
792 return result;
793}

References pthread_attr_t::__stack_bytes.

Referenced by stk_pthread_compile_check().

Here is the caller graph for this function:

◆ pthread_barrier_destroy()

int pthread_barrier_destroy ( pthread_barrier_t * barrier)

Destroy a barrier, releasing the underlying STK barrier object.

No thread may be blocked in pthread_barrier_wait() on it. After destruction it must be re-initialized with pthread_barrier_init() before further use.

Parameters
[in,out]barrierBarrier to destroy.
Returns
0 on success, EINVAL if barrier is NULL.

Definition at line 1648 of file stk_c_pthread.cpp.

1649{
1650 int result = EINVAL;
1651
1652 if (barrier != nullptr)
1653 {
1654 if (barrier->__handle != nullptr)
1655 {
1656 HandleOf(barrier)->~Barrier();
1657 barrier->__handle = nullptr;
1658 }
1659 result = 0;
1660 }
1661
1662 return result;
1663}
static sync::Mutex * HandleOf(pthread_mutex_t *o)
void * __handle
Object constructed in __mem, or NULL if not yet constructed.

References pthread_barrier_t::__handle, and stk::pthread::HandleOf().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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
[out]barrierBarrier to initialize.
[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 1634 of file stk_c_pthread.cpp.

1636{
1637 int result = EINVAL;
1638
1639 if ((barrier != nullptr) && (count != 0U))
1640 {
1641 barrier->__handle = ConstructIn<stk::sync::Barrier>(barrier->__mem, static_cast<uint32_t>(count));
1642 result = 0;
1643 }
1644
1645 return result;
1646}
static T * ConstructIn(Mem &mem, Args &&... args)
Construct object T in-place inside a C memory container.
Definition stk_c.h:2198
stk_barrier_mem_t __mem
In-place storage for the STK barrier object.

References pthread_barrier_t::__handle, pthread_barrier_t::__mem, and stk::ConstructIn().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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.

Parameters
[in,out]barrierBarrier to wait on.
Returns
PTHREAD_BARRIER_SERIAL_THREAD to exactly one arbitrary caller, 0 to the rest, EINVAL if barrier is NULL or was never initialized.
See also
"pthread_barrier_wait() note" in the file-level docs (ISR-unsafe).

Definition at line 1665 of file stk_c_pthread.cpp.

1666{
1667 int result = EINVAL;
1668
1669 if ((barrier != nullptr) && (barrier->__handle != nullptr))
1670 {
1671 result = HandleOf(barrier)->Wait() ? PTHREAD_BARRIER_SERIAL_THREAD : 0;
1672 }
1673
1674 return result;
1675}
#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, stk::pthread::HandleOf(), and PTHREAD_BARRIER_SERIAL_THREAD.

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_barrierattr_destroy()

int pthread_barrierattr_destroy ( pthread_barrierattr_t * attr)

Destroy a barrier attributes object (no-op).

Parameters
[in]attrAttributes object to destroy.
Returns
0 on success, EINVAL if attr is NULL.

Definition at line 1629 of file stk_c_pthread.cpp.

1630{
1631 return (attr != nullptr) ? 0 : EINVAL;
1632}

◆ pthread_barrierattr_init()

int pthread_barrierattr_init ( pthread_barrierattr_t * attr)

Initialize a barrier attributes object (no settable properties).

Parameters
[out]attrAttributes object to initialize.
Returns
0 on success, EINVAL if attr is NULL.

Definition at line 1616 of file stk_c_pthread.cpp.

1617{
1618 int result = EINVAL;
1619
1620 if (attr != nullptr)
1621 {
1622 attr->__reserved = 0;
1623 result = 0;
1624 }
1625
1626 return result;
1627}
int __reserved
Unused (no settable properties); reserved for future use.

References pthread_barrierattr_t::__reserved.

◆ pthread_cond_broadcast()

int pthread_cond_broadcast ( pthread_cond_t * cond)

Wake all threads waiting on cond (no effect if none is waiting).

Parameters
[in,out]condCondition variable to broadcast.
Returns
0 on success, EINVAL if cond is NULL.

Definition at line 1353 of file stk_c_pthread.cpp.

1354{
1355 int result = EINVAL;
1356
1357 if (cond != nullptr)
1358 {
1359 EnsureCond(cond)->NotifyAll();
1360 result = 0;
1361 }
1362
1363 return result;
1364}
static sync::ConditionVariable * EnsureCond(pthread_cond_t *c)
void NotifyAll()
Wake all waiting tasks.

References stk::pthread::EnsureCond(), and stk::sync::ConditionVariable::NotifyAll().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_cond_destroy()

int pthread_cond_destroy ( pthread_cond_t * cond)

Destroy a condition variable, releasing the underlying STK object.

Safe on a never-used PTHREAD_COND_INITIALIZER object. No thread may be waiting on it; destroying a condition variable in use is undefined behavior.

Parameters
[in,out]condCondition variable to destroy.
Returns
0 on success, EINVAL if cond is NULL.

Definition at line 1282 of file stk_c_pthread.cpp.

1283{
1284 int result = EINVAL;
1285
1286 if (cond != nullptr)
1287 {
1288 if (cond->__handle != nullptr)
1289 {
1290 HandleOf(cond)->~ConditionVariable();
1291 cond->__handle = nullptr;
1292 }
1293 result = 0;
1294 }
1295
1296 return result;
1297}
void * __handle
Object constructed in __mem, or NULL if not yet constructed.

References pthread_cond_t::__handle, and stk::pthread::HandleOf().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_cond_init()

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

Initialize a condition variable.

Parameters
[out]condCondition variable to initialize.
[in]attrOptional, or NULL for defaults (no settable properties; the argument is ignored).
Returns
0 on success, EINVAL if cond is NULL.

Definition at line 1269 of file stk_c_pthread.cpp.

1270{
1271 int result = EINVAL;
1272
1273 if (cond != nullptr)
1274 {
1276 result = 0;
1277 }
1278
1279 return result;
1280}
stk_cv_mem_t __mem
In-place storage for the STK condition variable object.

References pthread_cond_t::__handle, pthread_cond_t::__mem, and stk::ConstructIn().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_cond_signal()

int pthread_cond_signal ( pthread_cond_t * cond)

Wake one thread waiting on cond (no effect if none is waiting).

The condition variable is created lazily if needed. Signals are not queued: a signal sent while nobody waits is lost.

Parameters
[in,out]condCondition variable to signal.
Returns
0 on success, EINVAL if cond is NULL.

Definition at line 1340 of file stk_c_pthread.cpp.

1341{
1342 int result = EINVAL;
1343
1344 if (cond != nullptr)
1345 {
1346 EnsureCond(cond)->NotifyOne();
1347 result = 0;
1348 }
1349
1350 return result;
1351}
void NotifyOne()
Wake one waiting task.

References stk::pthread::EnsureCond(), and stk::sync::ConditionVariable::NotifyOne().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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.

mutex is re-locked before returning in all cases, including on timeout.

Parameters
[in,out]condCondition variable to wait on.
[in,out]mutexMutex protecting the predicate; must be locked by the caller. It is released while waiting and re-locked before returning.
[in]abstimeAbsolute deadline on the stk_time_now_ms() timeline (not CLOCK_REALTIME); see the file-level docs.
Returns
0 on success, ETIMEDOUT if the deadline passed first, EINVAL if cond, mutex or abstime is NULL, or mutex has never been initialized/locked.
See also
"pthread_cond_timedwait() / pthread_mutex_timedlock() limitation" in the file-level docs regarding the meaning of abstime.

Definition at line 1319 of file stk_c_pthread.cpp.

1320{
1321 int result = 0;
1322
1323 if ((cond == nullptr) || (mutex == nullptr) || (mutex->__handle == nullptr) || (abstime == nullptr))
1324 {
1325 result = EINVAL;
1326 }
1327 else if ((mutex->__type == PTHREAD_MUTEX_ERRORCHECK) && !IsMutexOwner(HandleOf(mutex)))
1328 {
1329 result = EPERM;
1330 }
1331 else
1332 {
1333 const bool signaled = EnsureCond(cond)->Wait(*HandleOf(mutex), TimespecToRelativeTimeout(abstime));
1334 result = signaled ? 0 : ETIMEDOUT;
1335 }
1336
1337 return result;
1338}
#define PTHREAD_MUTEX_ERRORCHECK
static bool IsMutexOwner(const sync::Mutex *m)
static Timeout TimespecToRelativeTimeout(const struct timespec *abstime)
bool Wait(IMutex &mutex, Timeout timeout_ticks=WAIT_INFINITE)
Wait for a signal.
int __type
PTHREAD_MUTEX_* type; 0 (NORMAL) when statically initialized.
void * __handle
Object constructed in __mem, or NULL if not yet constructed.

References pthread_mutex_t::__handle, pthread_mutex_t::__type, stk::pthread::EnsureCond(), stk::pthread::HandleOf(), stk::pthread::IsMutexOwner(), PTHREAD_MUTEX_ERRORCHECK, stk::pthread::TimespecToRelativeTimeout(), and stk::sync::ConditionVariable::Wait().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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.

Waits without a timeout. As in POSIX, spurious wakeups are possible, so always re-check the predicate in a loop. mutex must be locked by the caller and must have been used or initialized before (its underlying STK mutex must exist). Must not be called from ISR context.

Parameters
[in,out]condCondition variable to wait on.
[in,out]mutexMutex protecting the predicate; must be locked by the caller. It is released while waiting and re-locked before returning.
Note
mutex must be held exactly once. Waiting on a NORMAL/RECURSIVE mutex locked more than once is undefined (as in POSIX): only one level is released, so other threads cannot acquire it.
Returns
0 on success, EPERM (ERRORCHECK, mutex not owned by the caller), EINVAL if cond or mutex is NULL, or mutex has never been initialized/locked.

Definition at line 1299 of file stk_c_pthread.cpp.

1300{
1301 int result = 0;
1302
1303 if ((cond == nullptr) || (mutex == nullptr) || (mutex->__handle == nullptr))
1304 {
1305 result = EINVAL;
1306 }
1307 else if ((mutex->__type == PTHREAD_MUTEX_ERRORCHECK) && !IsMutexOwner(HandleOf(mutex)))
1308 {
1309 result = EPERM;
1310 }
1311 else
1312 {
1313 (void)EnsureCond(cond)->Wait(*HandleOf(mutex)); // WAIT_INFINITE
1314 }
1315
1316 return result;
1317}

References pthread_mutex_t::__handle, pthread_mutex_t::__type, stk::pthread::EnsureCond(), stk::pthread::HandleOf(), stk::pthread::IsMutexOwner(), PTHREAD_MUTEX_ERRORCHECK, and stk::sync::ConditionVariable::Wait().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_condattr_destroy()

int pthread_condattr_destroy ( pthread_condattr_t * attr)

Destroy a condition variable attributes object (no-op).

Parameters
[in]attrAttributes object to destroy.
Returns
0 on success, EINVAL if attr is NULL.

Definition at line 1264 of file stk_c_pthread.cpp.

1265{
1266 return (attr != nullptr) ? 0 : EINVAL;
1267}

◆ pthread_condattr_init()

int pthread_condattr_init ( pthread_condattr_t * attr)

Initialize a condition variable attributes object (no settable properties).

Parameters
[out]attrAttributes object to initialize.
Returns
0 on success, EINVAL if attr is NULL.

Definition at line 1251 of file stk_c_pthread.cpp.

1252{
1253 int result = EINVAL;
1254
1255 if (attr != nullptr)
1256 {
1257 attr->__reserved = 0;
1258 result = 0;
1259 }
1260
1261 return result;
1262}
int __reserved
Unused (no settable properties); reserved for future use.

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 a bound kernel whose type includes KERNEL_DYNAMIC and KERNEL_SYNC (see the file-level docs).

Definition at line 896 of file stk_c_pthread.cpp.

898{
899 STK_C_ASSERT(s_BoundKernel != nullptr);
900 STK_C_ASSERT(thread != nullptr);
901 STK_C_ASSERT(start_routine != nullptr);
902
903 int result = 0;
904
905 if ((s_BoundKernel == nullptr) || (thread == nullptr) || (start_routine == nullptr))
906 {
907 result = EINVAL;
908 }
909 else
910 {
912
913 if (ctrl == nullptr)
914 {
915 result = EAGAIN;
916 }
917 else
918 {
919 const size_t stack_bytes = ((attr != nullptr) && (attr->__stack_bytes != 0U)) ?
921 const uint32_t stack_words =
922 static_cast<uint32_t>((stack_bytes + sizeof(stk_word_t) - 1U) / sizeof(stk_word_t));
923
924 if (!AllocateStack(ctrl, attr, stack_bytes))
925 {
926 {
927 const CsLock cs_;
928
929 ctrl->busy = false;
930 }
931 result = EAGAIN;
932 }
933 else
934 {
935 ctrl->start_routine = start_routine;
936 ctrl->arg = arg;
937 ctrl->retval = nullptr;
938 ctrl->detached = ((attr != nullptr) && (attr->__detachstate == PTHREAD_CREATE_DETACHED));
939 ctrl->done_event = ConstructIn<sync::Event>(ctrl->done_event_buf, true /* manual_reset */);
940
941 const bool privileged = (attr != nullptr) && (attr->__privileged == PTHREAD_CREATE_PRIVILEGED_NP);
942
943 ctrl->task.Initialize(ctrl, ctrl->stack, stack_words,
945
947
948 *thread = ctrl;
949 }
950 }
951 }
952
953 return result;
954}
stk::hw::CriticalSection::ScopedLock CsLock
#define STK_C_ASSERT(e)
Assertion macro used inside STK C bindings.
Definition stk_c.h:80
@ ACCESS_USER
Unprivileged access mode (access to some hardware is restricted, see CPU manual for details)....
Definition stk_common.h:37
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
Definition stk_common.h:38
static ThreadCtrl * AcquireThreadSlot()
static stk_kernel_t * s_BoundKernel
static bool AllocateStack(ThreadCtrl *ctrl, const pthread_attr_t *attr, std::size_t stack_bytes)
static IKernel * ToKernel(stk_kernel_t *k)
virtual void AddTask(ITask *user_task)=0
Add user task.
void Initialize(pthread_stk_ctrl_t *ctrl, stk_word_t *stack, size_t stack_size, EAccessMode mode)
struct pthread_stk_ctrl_t::@024110347346021317207143067073371172206260032255 done_event_buf
void *(* start_routine)(void *)
stk::sync::Event * done_event
stk::pthread::PthreadTask task

References pthread_attr_t::__detachstate, pthread_attr_t::__privileged, pthread_attr_t::__stack_bytes, stk::ACCESS_PRIVILEGED, stk::ACCESS_USER, stk::pthread::AcquireThreadSlot(), stk::IKernel::AddTask(), stk::pthread::AllocateStack(), pthread_stk_ctrl_t::arg, pthread_stk_ctrl_t::busy, stk::ConstructIn(), pthread_stk_ctrl_t::detached, pthread_stk_ctrl_t::done_event, pthread_stk_ctrl_t::done_event_buf, stk::pthread::PthreadTask::Initialize(), stk::pthread::kDefaultStackBytes, PTHREAD_CREATE_DETACHED, PTHREAD_CREATE_PRIVILEGED_NP, pthread_stk_ctrl_t::retval, stk::pthread::s_BoundKernel, pthread_stk_ctrl_t::stack, pthread_stk_ctrl_t::start_routine, STK_C_ASSERT, pthread_stk_ctrl_t::task, and stk::pthread::ToKernel().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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.

Parameters
[in]threadThread to detach, as returned by pthread_create().
Returns
0 on success, EINVAL if thread is NULL, already joined, or already detached.

Definition at line 1003 of file stk_c_pthread.cpp.

1004{
1005 pthread_stk_ctrl_t *const ctrl = thread;
1006 int result = 0;
1007
1008 if (ctrl == nullptr)
1009 {
1010 result = EINVAL;
1011 }
1012 else
1013 {
1014 bool ok = false;
1015 {
1016 const CsLock cs_;
1017
1018 if (!ctrl->joined && !ctrl->detached)
1019 {
1020 ctrl->detached = true;
1021 ok = true;
1022 }
1023 }
1024
1025 if (!ok)
1026 {
1027 result = EINVAL;
1028 }
1029 else
1030 {
1031 MaybeReap(ctrl);
1032 }
1033 }
1034
1035 return result;
1036}
static void MaybeReap(ThreadCtrl *ctrl)

References pthread_stk_ctrl_t::detached, pthread_stk_ctrl_t::joined, and stk::pthread::MaybeReap().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_equal()

int pthread_equal ( pthread_t t1,
pthread_t t2 )

Compare two thread handles for equality.

Parameters
[in]t1First thread handle.
[in]t2Second thread handle.

Definition at line 1078 of file stk_c_pthread.cpp.

1079{
1080 return (t1 == t2) ? 1 : 0;
1081}

Referenced by stk_pthread_compile_check().

Here is the caller graph for this function:

◆ 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. For an adopted task (see "pthread_self() and foreign tasks") only the key destructors run and the task then parks forever.

Definition at line 1038 of file stk_c_pthread.cpp.

1039{
1040 pthread_stk_ctrl_t *const ctrl = CurrentCtrl();
1041
1042 if (ctrl != nullptr)
1043 {
1044 RunKeyDestructors(ctrl);
1045
1046 // An adopted (foreign) task has no ITask we could ask the kernel to remove, so for
1047 // it pthread_exit() only runs the destructors and then parks (see below).
1048 if (!ctrl->adopted)
1049 {
1050 {
1051 const CsLock cs_;
1052
1053 ctrl->retval = retval;
1054 ctrl->finished = true;
1055 }
1056
1057 (void)ctrl->done_event->Set();
1058 MaybeReap(ctrl); // reaper/joiner will wait for ctrl->exited before freeing anything
1059
1060 STK_C_ASSERT(s_BoundKernel != nullptr);
1062 }
1063 }
1064
1065 // Park here instead of falling back into caller code that isn't expecting to
1066 // regain control (the removal above takes effect on the next scheduling round).
1067 for (;;)
1068 {
1070 }
1071}
static void Sleep(Timeout tick_count)
Put calling process into a sleep state.
Definition stk_helper.h:479
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:212
static void RunKeyDestructors(ThreadCtrl *ctrl)
static ThreadCtrl * CurrentCtrl()
virtual void ScheduleTaskRemoval(ITask *user_task)=0
Schedule task removal from scheduling (exit).
bool Set()
Set event to signaled state.

References pthread_stk_ctrl_t::adopted, stk::pthread::CurrentCtrl(), pthread_stk_ctrl_t::done_event, pthread_stk_ctrl_t::finished, stk::pthread::MaybeReap(), pthread_stk_ctrl_t::retval, stk::pthread::RunKeyDestructors(), stk::pthread::s_BoundKernel, stk::IKernel::ScheduleTaskRemoval(), stk::sync::Event::Set(), stk::Sleep(), STK_C_ASSERT, pthread_stk_ctrl_t::task, stk::pthread::ToKernel(), and stk::WAIT_INFINITE.

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_getspecific()

void * pthread_getspecific ( pthread_key_t key)

Get the calling thread's value for key.

Parameters
[in]keyKey to read the calling thread's value for.
Returns
The stored value, or NULL if key is invalid or the calling thread has not set a value for it (never adopts a foreign task).

Definition at line 1794 of file stk_c_pthread.cpp.

1795{
1796 void *result = nullptr;
1797
1798 if (IsKeyUsed(key))
1799 {
1800 ThreadCtrl *const ctrl = CurrentCtrl(); // no adoption: a task that never called setspecific() has no values
1801
1802 if (ctrl != nullptr)
1803 {
1804 result = ctrl->tsd[key];
1805 }
1806 }
1807
1808 return result;
1809}
pthread_stk_ctrl_t ThreadCtrl
static bool IsKeyUsed(pthread_key_t key)
void * tsd[STK_C_PTHREAD_KEYS_MAX]

References stk::pthread::CurrentCtrl(), stk::pthread::IsKeyUsed(), and pthread_stk_ctrl_t::tsd.

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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, detached or adopted, EDEADLK if thread is the calling thread.

Definition at line 956 of file stk_c_pthread.cpp.

957{
958 pthread_stk_ctrl_t *const ctrl = thread;
959 int result = 0;
960
961 if (ctrl == nullptr)
962 {
963 result = EINVAL;
964 }
965 else if (ctrl == CurrentCtrl())
966 {
967 result = EDEADLK; // joining yourself would wait forever
968 }
969 else
970 {
971 bool ok = false;
972 {
973 const CsLock cs_;
974
975 if (!ctrl->detached && !ctrl->joined)
976 {
977 ctrl->joined = true;
978 ok = true;
979 }
980 }
981
982 if (!ok)
983 {
984 result = EINVAL;
985 }
986 else
987 {
988 (void)ctrl->done_event->Wait(); // WAIT_INFINITE
989
990 if (retval != nullptr)
991 {
992 *retval = ctrl->retval;
993 }
994
995 WaitForTaskExit(ctrl);
997 }
998 }
999
1000 return result;
1001}
static void ReleaseThreadResources(ThreadCtrl *ctrl)
static void WaitForTaskExit(ThreadCtrl *ctrl)
bool Wait(Timeout timeout_ticks=WAIT_INFINITE)
Wait until event becomes signaled or the timeout expires.

References stk::pthread::CurrentCtrl(), pthread_stk_ctrl_t::detached, pthread_stk_ctrl_t::done_event, pthread_stk_ctrl_t::joined, stk::pthread::ReleaseThreadResources(), pthread_stk_ctrl_t::retval, stk::sync::Event::Wait(), and stk::pthread::WaitForTaskExit().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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 1728 of file stk_c_pthread.cpp.

1729{
1730 int result = EINVAL;
1731
1732 if (key != nullptr)
1733 {
1734 result = EAGAIN;
1735
1736 const CsLock cs_;
1737
1738 for (std::size_t i = 0U; (result != 0) && (i < STK_C_PTHREAD_KEYS_MAX); ++i)
1739 {
1740 if (!s_Keys[i].used)
1741 {
1742 s_Keys[i].used = true;
1743 s_Keys[i].destructor = destructor;
1744 *key = static_cast<pthread_key_t>(i);
1745 result = 0;
1746 }
1747 }
1748 }
1749
1750 return result;
1751}
#define STK_C_PTHREAD_KEYS_MAX
Maximum number of concurrently-alive pthread_key_t's (default: 8).
unsigned int pthread_key_t
A thread-specific data key.
static KeyEntry s_Keys[STK_C_PTHREAD_KEYS_MAX]

References stk::pthread::s_Keys, and STK_C_PTHREAD_KEYS_MAX.

Referenced by stk_pthread_compile_check().

Here is the caller 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.

Parameters
[in]keyKey to delete, as returned by pthread_key_create().
Returns
0 on success, EINVAL if key was never created (or already deleted).

Definition at line 1753 of file stk_c_pthread.cpp.

1754{
1755 int result = EINVAL;
1756
1757 if (key < STK_C_PTHREAD_KEYS_MAX)
1758 {
1759 const CsLock cs_;
1760
1761 if (s_Keys[key].used)
1762 {
1763 s_Keys[key].used = false;
1764 s_Keys[key].destructor = nullptr;
1765 result = 0;
1766 }
1767 }
1768
1769 return result;
1770}

References stk::pthread::s_Keys, and STK_C_PTHREAD_KEYS_MAX.

Referenced by stk_pthread_compile_check().

Here is the caller graph for this function:

◆ pthread_mutex_destroy()

int pthread_mutex_destroy ( pthread_mutex_t * mutex)

Destroy a mutex, releasing the underlying STK mutex object.

Safe to call on a mutex that was statically initialized with PTHREAD_MUTEX_INITIALIZER but never used (nothing to destroy). The mutex must not be locked and no thread may be blocked on it; destroying a mutex in use is undefined behavior. After destruction the object may be re-initialized with pthread_mutex_init().

Parameters
[in,out]mutexMutex to destroy.
Returns
0 on success, EINVAL if mutex is NULL.

Definition at line 1155 of file stk_c_pthread.cpp.

1156{
1157 int result = EINVAL;
1158
1159 if (mutex != nullptr)
1160 {
1161 if (mutex->__handle != nullptr)
1162 {
1163 HandleOf(mutex)->~Mutex();
1164 mutex->__handle = nullptr;
1165 }
1166 result = 0;
1167 }
1168
1169 return result;
1170}
~Mutex()
Destructor.

References pthread_mutex_t::__handle, stk::pthread::HandleOf(), and stk::sync::Mutex::~Mutex().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_mutex_init()

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

Initialize a mutex.

Parameters
[out]mutexMutex to initialize (storage is embedded in the object, nothing is allocated).
[in]attrOptional, or NULL for defaults (PTHREAD_MUTEX_DEFAULT).
Returns
0 on success, EINVAL if mutex is NULL or attr holds an invalid type (the mutex is left uninitialized).

Definition at line 1136 of file stk_c_pthread.cpp.

1137{
1138 int result = EINVAL;
1139
1140 if (mutex != nullptr)
1141 {
1142 const int type = (attr != nullptr) ? attr->__type : PTHREAD_MUTEX_DEFAULT;
1143
1144 if (IsValidMutexType(type))
1145 {
1146 mutex->__type = type;
1148 result = 0;
1149 }
1150 }
1151
1152 return result;
1153}
#define PTHREAD_MUTEX_DEFAULT
static bool IsValidMutexType(int type)
int __type
PTHREAD_MUTEX_NORMAL / DEFAULT / RECURSIVE / ERRORCHECK.
stk_mutex_mem_t __mem
In-place storage for the STK mutex object.

References pthread_mutex_t::__handle, pthread_mutex_t::__mem, pthread_mutex_t::__type, pthread_mutexattr_t::__type, stk::ConstructIn(), stk::pthread::IsValidMutexType(), and PTHREAD_MUTEX_DEFAULT.

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_mutex_lock()

int pthread_mutex_lock ( pthread_mutex_t * mutex)

Lock a mutex, blocking until it becomes available.

The underlying STK mutex is created lazily on first use for a mutex statically initialized with PTHREAD_MUTEX_INITIALIZER. Blocking puts the calling task to sleep so other tasks can run. For NORMAL and RECURSIVE types relocking from the owning thread succeeds and must be balanced by the same number of unlocks (the underlying STK mutex is recursive). For ERRORCHECK relocking from the owner returns EDEADLK. Must not be called from ISR context.

Parameters
[in,out]mutexMutex to lock.
Returns
0 on success, EDEADLK (ERRORCHECK, already owned by the caller), EAGAIN (maximum recursion depth exceeded), EINVAL if mutex is NULL.

Definition at line 1172 of file stk_c_pthread.cpp.

1173{
1174 int result = EINVAL;
1175
1176 if (mutex != nullptr)
1177 {
1178 sync::Mutex *const m = EnsureMutex(mutex);
1179
1180 result = PreLockCheck(mutex, m, EDEADLK);
1181 if (result == 0)
1182 {
1183 m->Lock();
1184 }
1185 }
1186
1187 return result;
1188}
static sync::Mutex * EnsureMutex(pthread_mutex_t *m)
static int PreLockCheck(const pthread_mutex_t *pm, const sync::Mutex *m, int errorcheck_code)
Recursive mutex primitive that allows the same thread to acquire the lock multiple times.
void Lock() override
Acquire lock.

References stk::pthread::EnsureMutex(), stk::sync::Mutex::Lock(), and stk::pthread::PreLockCheck().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_mutex_timedlock()

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

Lock with an absolute deadline.

If abstime is already in the past the call degenerates into a non-blocking attempt. Timeouts are rounded to STK kernel ticks.

Parameters
[in,out]mutexMutex to lock.
[in]abstimeAbsolute deadline on the stk_time_now_ms() timeline (not CLOCK_REALTIME); see the file-level docs.
Returns
0 on success, ETIMEDOUT if the deadline passed first, EDEADLK (ERRORCHECK, already owned by the caller), EAGAIN (maximum recursion depth exceeded), EINVAL if mutex or abstime is NULL.
See also
"pthread_cond_timedwait() / pthread_mutex_timedlock() limitation" in the file-level docs regarding the meaning of abstime.

Definition at line 1230 of file stk_c_pthread.cpp.

1231{
1232 int result = EINVAL;
1233
1234 if ((mutex != nullptr) && (abstime != nullptr))
1235 {
1236 sync::Mutex *const m = EnsureMutex(mutex);
1237
1238 result = PreLockCheck(mutex, m, EDEADLK);
1239 if (result == 0)
1240 {
1241 result = m->TimedLock(TimespecToRelativeTimeout(abstime)) ? 0 : ETIMEDOUT;
1242 }
1243 }
1244
1245 return result;
1246}
bool TimedLock(Timeout timeout_ticks)
Acquire lock.

References stk::pthread::EnsureMutex(), stk::pthread::PreLockCheck(), stk::sync::Mutex::TimedLock(), and stk::pthread::TimespecToRelativeTimeout().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_mutex_trylock()

int pthread_mutex_trylock ( pthread_mutex_t * mutex)

Try to lock a mutex without blocking.

For NORMAL and RECURSIVE types succeeds if the caller already owns the mutex (nesting depth is incremented). For ERRORCHECK returns EBUSY.

Parameters
[in,out]mutexMutex to try to lock.
Returns
0 on success, EBUSY if the mutex is currently locked (or, for ERRORCHECK, owned by the caller), EAGAIN (maximum recursion depth exceeded), EINVAL if mutex is NULL.

Definition at line 1190 of file stk_c_pthread.cpp.

1191{
1192 int result = EINVAL;
1193
1194 if (mutex != nullptr)
1195 {
1196 sync::Mutex *const m = EnsureMutex(mutex);
1197
1198 result = PreLockCheck(mutex, m, EBUSY);
1199 if (result == 0)
1200 {
1201 result = m->TryLock() ? 0 : EBUSY;
1202 }
1203 }
1204
1205 return result;
1206}
bool TryLock()
Acquire the lock.

References stk::pthread::EnsureMutex(), stk::pthread::PreLockCheck(), and stk::sync::Mutex::TryLock().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_mutex_unlock()

int pthread_mutex_unlock ( pthread_mutex_t * mutex)

Unlock a mutex held by the calling thread.

Unlike pthread_mutex_lock(), never creates the underlying STK mutex: unlocking a statically initialized mutex that has never been locked is an error. As with real pthreads, unlocking a mutex the caller does not own is undefined behavior and is not detected here.

Parameters
[in,out]mutexMutex to unlock; must be locked by the calling thread.
Returns
0 on success, EPERM if the caller does not own the mutex, EINVAL if mutex is NULL or was never initialized/used.

Definition at line 1208 of file stk_c_pthread.cpp.

1209{
1210 int result = EINVAL;
1211
1212 if ((mutex != nullptr) && (mutex->__handle != nullptr))
1213 {
1214 sync::Mutex *const m = HandleOf(mutex);
1215
1216 if (IsMutexOwner(m))
1217 {
1218 m->Unlock();
1219 result = 0;
1220 }
1221 else
1222 {
1223 result = EPERM;
1224 }
1225 }
1226
1227 return result;
1228}
void Unlock() override
Release lock.

References pthread_mutex_t::__handle, stk::pthread::HandleOf(), stk::pthread::IsMutexOwner(), and stk::sync::Mutex::Unlock().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_mutexattr_destroy()

int pthread_mutexattr_destroy ( pthread_mutexattr_t * attr)

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

Parameters
[in]attrAttributes object to destroy.
Returns
0 on success, EINVAL if attr is NULL.

Definition at line 1105 of file stk_c_pthread.cpp.

1106{
1107 return (attr != nullptr) ? 0 : EINVAL;
1108}

Referenced by stk_pthread_compile_check().

Here is the caller graph for this function:

◆ pthread_mutexattr_gettype()

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

Get the mutex type stored in attr.

Parameters
[in]attrAttributes object to query.
[out]typeReceives the mutex type.
Returns
0 on success, EINVAL if attr or type is NULL.

Definition at line 1123 of file stk_c_pthread.cpp.

1124{
1125 int result = EINVAL;
1126
1127 if ((attr != nullptr) && (type != nullptr))
1128 {
1129 *type = attr->__type;
1130 result = 0;
1131 }
1132
1133 return result;
1134}

References pthread_mutexattr_t::__type.

◆ pthread_mutexattr_init()

int pthread_mutexattr_init ( pthread_mutexattr_t * attr)

Initialize a mutex attributes object with default values (PTHREAD_MUTEX_DEFAULT).

Parameters
[out]attrAttributes object to initialize.
Returns
0 on success, EINVAL if attr is NULL.

Definition at line 1092 of file stk_c_pthread.cpp.

1093{
1094 int result = EINVAL;
1095
1096 if (attr != nullptr)
1097 {
1099 result = 0;
1100 }
1101
1102 return result;
1103}

References pthread_mutexattr_t::__type, and PTHREAD_MUTEX_DEFAULT.

Referenced by stk_pthread_compile_check().

Here is the caller graph for this function:

◆ pthread_mutexattr_settype()

int pthread_mutexattr_settype ( pthread_mutexattr_t * attr,
int type )

Set the mutex type.

Parameters
[in,out]attrAttributes object to modify.
[in]typePTHREAD_MUTEX_NORMAL / DEFAULT / RECURSIVE / ERRORCHECK.
Returns
0 on success, EINVAL if attr is NULL or type is not one of the supported values.

Definition at line 1110 of file stk_c_pthread.cpp.

1111{
1112 int result = EINVAL;
1113
1114 if ((attr != nullptr) && IsValidMutexType(type))
1115 {
1116 attr->__type = type;
1117 result = 0;
1118 }
1119
1120 return result;
1121}

References pthread_mutexattr_t::__type, and stk::pthread::IsValidMutexType().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ 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.

Parameters
[in,out]once_controlControl object, statically initialized with PTHREAD_ONCE_INIT.
[in]init_routineFunction to call exactly once. Must not call pthread_once() on the same once_control.
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 1680 of file stk_c_pthread.cpp.

1681{
1682 int result = 0;
1683
1684 if ((once_control == nullptr) || (init_routine == nullptr))
1685 {
1686 result = EINVAL;
1687 }
1688 else if (LoadAcquire(&once_control->__state) != kOnceDone) // fast path: already done, no lock needed
1689 {
1690 stk::sync::Mutex *const guard = EnsureOnceMutex(once_control);
1691
1692 // The guard is held only while init_routine() runs, so "owned by the caller" means
1693 // init_routine() re-entered pthread_once() on the same control object. The guard is a
1694 // recursive Mutex, so Lock() would succeed and init_routine() would recurse until the
1695 // stack overflows; report the misuse instead (POSIX leaves it undefined).
1696 if (IsMutexOwner(guard))
1697 {
1698 result = EDEADLK;
1699 }
1700 else
1701 {
1702 guard->Lock();
1703
1704 // Re-check under the lock: another thread may have finished init_routine()
1705 // (or be running it right now, in which case this lock() call already blocked
1706 // until it was done) between our unlocked fast-path check above and here.
1707 if (once_control->__state != kOnceDone)
1708 {
1709 once_control->__state = kOnceRunning;
1710 init_routine();
1711 StoreRelease(&once_control->__state, kOnceDone); // release: publish init_routine()'s effects
1712 }
1713
1714 guard->Unlock();
1715 }
1716 }
1717 else
1718 {
1719 // already initialized: nothing to do
1720 }
1721
1722 return result;
1723}
static T LoadAcquire(T *p)
constexpr int kOnceRunning
constexpr int kOnceDone
static void StoreRelease(T *p, T v)
static sync::Mutex * EnsureOnceMutex(pthread_once_t *o)
int __state
0 = not started, 1 = running, 2 = done.

References pthread_once_t::__state, stk::pthread::EnsureOnceMutex(), stk::pthread::IsMutexOwner(), stk::pthread::kOnceDone, stk::pthread::kOnceRunning, stk::pthread::LoadAcquire(), stk::sync::Mutex::Lock(), stk::pthread::StoreRelease(), and stk::sync::Mutex::Unlock().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_rwlock_destroy()

int pthread_rwlock_destroy ( pthread_rwlock_t * rwlock)

Destroy a read-write lock, releasing the underlying STK object.

Safe on a never-used PTHREAD_RWLOCK_INITIALIZER object. The lock must not be held and no thread may be blocked on it.

Parameters
[in,out]rwlockRead-write lock to destroy.
Returns
0 on success, EINVAL if rwlock is NULL.

Definition at line 1401 of file stk_c_pthread.cpp.

1402{
1403 int result = EINVAL;
1404
1405 if (rwlock != nullptr)
1406 {
1407 if (rwlock->__handle != nullptr)
1408 {
1409 HandleOf(rwlock)->~RWMutex();
1410 rwlock->__handle = nullptr;
1411 }
1412 result = 0;
1413 }
1414
1415 return result;
1416}
void * __handle
Object constructed in __mem, or NULL if not yet constructed.

References pthread_rwlock_t::__handle, and stk::pthread::HandleOf().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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
[out]rwlockRead-write lock to initialize.
[in]attrOptional, or NULL for defaults (no settable properties).
Returns
0 on success, EINVAL if rwlock is NULL.

Definition at line 1387 of file stk_c_pthread.cpp.

1388{
1389 int result = EINVAL;
1390
1391 if (rwlock != nullptr)
1392 {
1394 rwlock->__wrlocked = false;
1395 result = 0;
1396 }
1397
1398 return result;
1399}
volatile bool __wrlocked
True while held for writing; selects Unlock() vs ReadUnlock() on release.
stk_rwmutex_mem_t __mem
In-place storage for the STK rwmutex object.

References pthread_rwlock_t::__handle, pthread_rwlock_t::__mem, pthread_rwlock_t::__wrlocked, and stk::ConstructIn().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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 RWMutex::TimedReadLock()).

Parameters
[in,out]rwlockRead-write lock to acquire for reading.

Definition at line 1418 of file stk_c_pthread.cpp.

1419{
1420 int result = EINVAL;
1421
1422 if (rwlock != nullptr)
1423 {
1424 EnsureRWLock(rwlock)->ReadLock();
1425 result = 0;
1426 }
1427
1428 return result;
1429}
static sync::RWMutex * EnsureRWLock(pthread_rwlock_t *rw)
void ReadLock()
Acquire the lock for shared reading.

References stk::pthread::EnsureRWLock(), and stk::sync::RWMutex::ReadLock().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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.

Parameters
[in,out]rwlockRead-write lock to acquire for reading.
[in]abstimeAbsolute deadline on the stk_time_now_ms() timeline (not CLOCK_REALTIME); see the file-level docs.
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 1443 of file stk_c_pthread.cpp.

1444{
1445 int result = EINVAL;
1446
1447 if ((rwlock != nullptr) && (abstime != nullptr))
1448 {
1449 const bool locked = EnsureRWLock(rwlock)->TimedReadLock(TimespecToRelativeTimeout(abstime));
1450 result = locked ? 0 : ETIMEDOUT;
1451 }
1452
1453 return result;
1454}
bool TimedReadLock(Timeout timeout_ticks)
Acquire the lock for shared reading with a timeout.

References stk::pthread::EnsureRWLock(), stk::sync::RWMutex::TimedReadLock(), and stk::pthread::TimespecToRelativeTimeout().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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.

Parameters
[in,out]rwlockRead-write lock to acquire for writing.
[in]abstimeAbsolute deadline on the stk_time_now_ms() timeline (not CLOCK_REALTIME); see the file-level docs.
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 1490 of file stk_c_pthread.cpp.

1491{
1492 int result = EINVAL;
1493
1494 if ((rwlock != nullptr) && (abstime != nullptr))
1495 {
1496 if (EnsureRWLock(rwlock)->TimedLock(TimespecToRelativeTimeout(abstime)))
1497 {
1498 rwlock->__wrlocked = true;
1499 result = 0;
1500 }
1501 else
1502 {
1503 result = ETIMEDOUT;
1504 }
1505 }
1506
1507 return result;
1508}

References pthread_rwlock_t::__wrlocked, stk::pthread::EnsureRWLock(), and stk::pthread::TimespecToRelativeTimeout().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_rwlock_tryrdlock()

int pthread_rwlock_tryrdlock ( pthread_rwlock_t * rwlock)

Try to acquire the read lock without blocking.

Parameters
[in,out]rwlockRead-write lock to try to acquire for reading.
Returns
0 on success, EBUSY if a writer is active or waiting.

Definition at line 1431 of file stk_c_pthread.cpp.

1432{
1433 int result = EINVAL;
1434
1435 if (rwlock != nullptr)
1436 {
1437 result = EnsureRWLock(rwlock)->TryReadLock() ? 0 : EBUSY;
1438 }
1439
1440 return result;
1441}
bool TryReadLock()
Attempt to acquire the lock for shared reading without blocking.

References stk::pthread::EnsureRWLock(), and stk::sync::RWMutex::TryReadLock().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_rwlock_trywrlock()

int pthread_rwlock_trywrlock ( pthread_rwlock_t * rwlock)

Try to acquire the write lock without blocking.

Parameters
[in,out]rwlockRead-write lock to try to acquire for writing.
Returns
0 on success, EBUSY otherwise.

Definition at line 1470 of file stk_c_pthread.cpp.

1471{
1472 int result = EINVAL;
1473
1474 if (rwlock != nullptr)
1475 {
1476 if (EnsureRWLock(rwlock)->TryLock())
1477 {
1478 rwlock->__wrlocked = true;
1479 result = 0;
1480 }
1481 else
1482 {
1483 result = EBUSY;
1484 }
1485 }
1486
1487 return result;
1488}

References pthread_rwlock_t::__wrlocked, and stk::pthread::EnsureRWLock().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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.

Parameters
[in,out]rwlockRead-write lock to release; must be held by the calling thread (for reading or writing).
See also
"pthread_rwlock_unlock() disambiguation" in the file-level docs.

Definition at line 1510 of file stk_c_pthread.cpp.

1511{
1512 int result = EINVAL;
1513
1514 if ((rwlock != nullptr) && (rwlock->__handle != nullptr))
1515 {
1516 // See "pthread_rwlock_unlock() disambiguation" in stk_c_pthread.h: a write
1517 // hold is always exclusive, so __wrlocked unambiguously identifies which
1518 // underlying call (Unlock() vs ReadUnlock()) the current holder must have made. Clear it before
1519 // releasing so a racing new writer's own acquisition can't be clobbered.
1520 if (rwlock->__wrlocked)
1521 {
1522 rwlock->__wrlocked = false;
1523 HandleOf(rwlock)->Unlock();
1524 }
1525 else
1526 {
1527 HandleOf(rwlock)->ReadUnlock();
1528 }
1529 result = 0;
1530 }
1531
1532 return result;
1533}

References pthread_rwlock_t::__handle, pthread_rwlock_t::__wrlocked, stk::pthread::HandleOf(), and stk::sync::Mutex::Unlock().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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.

Parameters
[in,out]rwlockRead-write lock to acquire for writing.

Definition at line 1456 of file stk_c_pthread.cpp.

1457{
1458 int result = EINVAL;
1459
1460 if (rwlock != nullptr)
1461 {
1462 EnsureRWLock(rwlock)->Lock();
1463 rwlock->__wrlocked = true;
1464 result = 0;
1465 }
1466
1467 return result;
1468}
void Lock() override
Acquire the lock for exclusive writing (IMutex interface).

References pthread_rwlock_t::__wrlocked, stk::pthread::EnsureRWLock(), and stk::sync::RWMutex::Lock().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_rwlockattr_destroy()

int pthread_rwlockattr_destroy ( pthread_rwlockattr_t * attr)

Destroy a read-write lock attributes object (no-op).

Parameters
[in]attrAttributes object to destroy.
Returns
0 on success, EINVAL if attr is NULL.

Definition at line 1382 of file stk_c_pthread.cpp.

1383{
1384 return (attr != nullptr) ? 0 : EINVAL;
1385}

◆ pthread_rwlockattr_init()

int pthread_rwlockattr_init ( pthread_rwlockattr_t * attr)

Initialize a read-write lock attributes object (no settable properties).

Parameters
[out]attrAttributes object to initialize.
Returns
0 on success, EINVAL if attr is NULL.

Definition at line 1369 of file stk_c_pthread.cpp.

1370{
1371 int result = EINVAL;
1372
1373 if (attr != nullptr)
1374 {
1375 attr->__reserved = 0;
1376 result = 0;
1377 }
1378
1379 return result;
1380}
int __reserved
Unused (no settable properties); reserved for future use.

References pthread_rwlockattr_t::__reserved.

◆ pthread_self()

pthread_t pthread_self ( void )

Return the calling thread's own handle.

Returns
The calling thread's handle. A task not created through this shim (e.g. the bootstrap task) is adopted on first call; NULL only if no pthread slot is left to adopt into (see the file-level note).

Definition at line 1073 of file stk_c_pthread.cpp.

1074{
1075 return static_cast<pthread_t>(CurrentCtrlOrAdopt()); // NULL only if the slot pool is exhausted
1076}
struct pthread_stk_ctrl_t * pthread_t
Opaque thread handle.
static ThreadCtrl * CurrentCtrlOrAdopt()

References stk::pthread::CurrentCtrlOrAdopt().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_setspecific()

int pthread_setspecific ( pthread_key_t key,
const void * value )

Set the calling thread's value for key.

Parameters
[in]keyKey to set the calling thread's value for.
[in]valueValue to associate with the key for the calling thread (may be NULL).
See also
"pthread_key_t / thread-specific data" in the file-level docs.
Returns
0 on success, EINVAL if key is invalid, ENOMEM if the calling task is a foreign task and no pthread slot is left to adopt it into.

Definition at line 1772 of file stk_c_pthread.cpp.

1773{
1774 int result = EINVAL;
1775
1776 if (IsKeyUsed(key))
1777 {
1778 ThreadCtrl *const ctrl = CurrentCtrlOrAdopt(); // foreign tasks are adopted on first use
1779
1780 if (ctrl == nullptr)
1781 {
1782 result = ENOMEM; // pthread slot pool exhausted
1783 }
1784 else
1785 {
1786 ctrl->tsd[key] = const_cast<void *>(value);
1787 result = 0;
1788 }
1789 }
1790
1791 return result;
1792}

References stk::pthread::CurrentCtrlOrAdopt(), stk::pthread::IsKeyUsed(), and pthread_stk_ctrl_t::tsd.

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_spin_destroy()

int pthread_spin_destroy ( pthread_spinlock_t * lock)

Destroy a spinlock.

The spinlock must not be held. After destruction it must be re-initialized with pthread_spin_init() before further use.

Parameters
[in,out]lockSpinlock to destroy.
Returns
0 on success, EINVAL if lock is NULL.

Definition at line 1558 of file stk_c_pthread.cpp.

1559{
1560 int result = EINVAL;
1561
1562 if (lock != nullptr)
1563 {
1564 if (lock->__handle != nullptr)
1565 {
1566 HandleOf(lock)->~SpinLock();
1567 lock->__handle = nullptr;
1568 }
1569 result = 0;
1570 }
1571
1572 return result;
1573}
void * __handle
Object constructed in __mem, or NULL if not yet constructed.

References pthread_spinlock_t::__handle, and stk::pthread::HandleOf().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_spin_init()

int pthread_spin_init ( pthread_spinlock_t * lock,
int pshared )

Initialize a spinlock.

Parameters
[out]lockSpinlock to initialize.
[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 1538 of file stk_c_pthread.cpp.

1539{
1540 int result = EINVAL;
1541
1542 if (lock != nullptr)
1543 {
1544 if (pshared != PTHREAD_PROCESS_PRIVATE)
1545 {
1546 result = ENOTSUP;
1547 }
1548 else
1549 {
1551 result = 0;
1552 }
1553 }
1554
1555 return result;
1556}
#define PTHREAD_PROCESS_PRIVATE
struct pthread_spinlock_t::@072117035232205037233337242056154122155161307376 __mem
In-place storage for the STK spinlock object.

References pthread_spinlock_t::__handle, pthread_spinlock_t::__mem, stk::ConstructIn(), and PTHREAD_PROCESS_PRIVATE.

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_spin_lock()

int pthread_spin_lock ( pthread_spinlock_t * lock)

Acquire the spinlock, spinning until available.

Busy-waits (the task is not put to sleep), so hold it only for very short critical sections. Not recursive: relocking from the owning thread deadlocks.

Parameters
[in,out]lockSpinlock to acquire.
Returns
0 on success, EINVAL if lock is NULL or was never initialized.
See also
"pthread_spin_* note" in the file-level docs.

Definition at line 1575 of file stk_c_pthread.cpp.

1576{
1577 int result = EINVAL;
1578
1579 if ((lock != nullptr) && (lock->__handle != nullptr))
1580 {
1581 HandleOf(lock)->Lock();
1582 result = 0;
1583 }
1584
1585 return result;
1586}

References pthread_spinlock_t::__handle, stk::pthread::HandleOf(), and stk::sync::Mutex::Lock().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_spin_trylock()

int pthread_spin_trylock ( pthread_spinlock_t * lock)

Try to acquire the spinlock without blocking.

Parameters
[in,out]lockSpinlock to try to acquire.
Returns
0 on success, EBUSY if currently held, EINVAL if lock is NULL or was never initialized.

Definition at line 1588 of file stk_c_pthread.cpp.

1589{
1590 int result = EINVAL;
1591
1592 if ((lock != nullptr) && (lock->__handle != nullptr))
1593 {
1594 result = HandleOf(lock)->TryLock() ? 0 : EBUSY;
1595 }
1596
1597 return result;
1598}

References pthread_spinlock_t::__handle, stk::pthread::HandleOf(), and stk::sync::Mutex::TryLock().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pthread_spin_unlock()

int pthread_spin_unlock ( pthread_spinlock_t * lock)

Release a spinlock held by the calling thread.

Parameters
[in,out]lockSpinlock to release; must be held by the calling thread.
Returns
0 on success, EINVAL if lock is NULL or was never initialized.

Definition at line 1600 of file stk_c_pthread.cpp.

1601{
1602 int result = EINVAL;
1603
1604 if ((lock != nullptr) && (lock->__handle != nullptr))
1605 {
1606 HandleOf(lock)->Unlock();
1607 result = 0;
1608 }
1609
1610 return result;
1611}

References pthread_spinlock_t::__handle, stk::pthread::HandleOf(), and stk::sync::Mutex::Unlock().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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 1083 of file stk_c_pthread.cpp.

1084{
1085 stk::Yield();
1086 return 0;
1087}
static void Yield()
Notify scheduler to switch to the next runnable task.
Definition stk_helper.h:536

References stk::Yield().

Referenced by stk_pthread_compile_check().

Here is the call graph for this function:
Here is the caller 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.

Note
Also adds the internal reaper task to the kernel, so STK_C_KERNEL_MAX_TASKS must have room for it. Binding a second, different kernel is not supported (the reaper stays with the first).
Parameters
[in]kernelKernel handle obtained from stk_kernel_create(). Its configured type (STK_C_KERNEL_TYPE_CPU_X) must include KERNEL_DYNAMIC (threads need to be able to finish/return) and KERNEL_SYNC.

Definition at line 749 of file stk_c_pthread.cpp.

750{
751 STK_C_ASSERT(kernel != nullptr);
752
753 s_BoundKernel = kernel;
754
755 EnsureReaper();
756}
static void EnsureReaper()

References stk::pthread::EnsureReaper(), stk::pthread::s_BoundKernel, and STK_C_ASSERT.

Here is the call graph for this function: