21extern "C" void *
malloc(std::size_t size);
22extern "C" void free(
void *ptr);
42 void *(*start_routine)(
void *);
86 reinterpret_cast<uint8_t *
>(s_PthreadStackStorage),
87 sizeof(s_PthreadStackStorage),
188 bool do_reap =
false;
241 for (std::size_t i = 0U; i < n; ++i)
278 ctrl->
stack =
nullptr;
322 (
static_cast<stk_time_t>(abstime->tv_nsec) / 1000000LL);
329 if (rel_ms >
static_cast<stk_time_t>(INT32_MAX))
419 bool any_ran =
false;
423 void *
const value = ctrl->
tsd[i];
424 if (value ==
nullptr) {
continue; }
426 void (*destructor)(
void *) =
nullptr;
428 if (
s_Keys[i].used) { destructor =
s_Keys[i].destructor; }
431 ctrl->
tsd[i] =
nullptr;
432 if (destructor !=
nullptr)
439 if (!any_ran) {
break; }
465 if (attr ==
nullptr) {
return EINVAL; }
475 if (attr ==
nullptr) {
return EINVAL; }
481 if ((attr ==
nullptr) || (stacksize == 0U)) {
return EINVAL; }
489 if ((attr ==
nullptr) || (stacksize ==
nullptr)) {
return EINVAL; }
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; }
507 if ((attr ==
nullptr) || (stackaddr ==
nullptr) || (stacksize ==
nullptr)) {
return EINVAL; }
516 if ((attr ==
nullptr) ||
528 if ((attr ==
nullptr) || (detachstate ==
nullptr)) {
return EINVAL; }
538 void *(*start_routine)(
void *),
void *arg)
544 if ((
s_BoundKernel ==
nullptr) || (thread ==
nullptr) || (start_routine ==
nullptr))
555 const size_t stack_bytes = ((attr !=
nullptr) && (attr->
__stack_bytes != 0U)) ?
557 const uint32_t stack_words =
560 if ((attr !=
nullptr) && (attr->
__ext_stack !=
nullptr))
590 if (ctrl->
stack ==
nullptr)
607 if (ctrl->
task ==
nullptr)
632 if (ctrl ==
nullptr) {
return EINVAL; }
643 if (!ok) {
return EINVAL; }
647 if (retval !=
nullptr)
660 if (ctrl ==
nullptr) {
return EINVAL; }
671 if (!ok) {
return EINVAL; }
714 return (t1 == t2) ? 1 : 0;
728 if (attr ==
nullptr) {
return EINVAL; }
736 if (attr ==
nullptr) {
return EINVAL; }
742 if (attr ==
nullptr) {
return EINVAL; }
751 if ((attr ==
nullptr) || (type ==
nullptr)) {
return EINVAL; }
759 if (mutex ==
nullptr) {
return EINVAL; }
763 return (mutex->
__handle !=
nullptr) ? 0 : EAGAIN;
768 if (mutex ==
nullptr) {
return EINVAL; }
780 if (mutex ==
nullptr) {
return EINVAL; }
788 if (mutex ==
nullptr) {
return EINVAL; }
795 if (mutex ==
nullptr) {
return EINVAL; }
796 if (mutex->
__handle ==
nullptr) {
return EINVAL; }
804 if ((mutex ==
nullptr) || (abstime ==
nullptr)) {
return EINVAL; }
807 return locked ? 0 : ETIMEDOUT;
815 if (attr ==
nullptr) {
return EINVAL; }
823 if (attr ==
nullptr) {
return EINVAL; }
829 if (cond ==
nullptr) {
return EINVAL; }
832 return (cond->
__handle !=
nullptr) ? 0 : EAGAIN;
837 if (cond ==
nullptr) {
return EINVAL; }
849 if ((cond ==
nullptr) || (mutex ==
nullptr) || (mutex->
__handle ==
nullptr)) {
return EINVAL; }
857 if ((cond ==
nullptr) || (mutex ==
nullptr) || (mutex->
__handle ==
nullptr) || (abstime ==
nullptr))
863 return signaled ? 0 : ETIMEDOUT;
868 if (cond ==
nullptr) {
return EINVAL; }
876 if (cond ==
nullptr) {
return EINVAL; }
887 if (attr ==
nullptr) {
return EINVAL; }
895 if (attr ==
nullptr) {
return EINVAL; }
901 if (rwlock ==
nullptr) {
return EINVAL; }
905 return (rwlock->
__handle !=
nullptr) ? 0 : EAGAIN;
910 if (rwlock ==
nullptr) {
return EINVAL; }
922 if (rwlock ==
nullptr) {
return EINVAL; }
930 if (rwlock ==
nullptr) {
return EINVAL; }
937 if ((rwlock ==
nullptr) || (abstime ==
nullptr)) {
return EINVAL; }
940 return locked ? 0 : ETIMEDOUT;
945 if (rwlock ==
nullptr) {
return EINVAL; }
954 if (rwlock ==
nullptr) {
return EINVAL; }
964 if ((rwlock ==
nullptr) || (abstime ==
nullptr)) {
return EINVAL; }
974 if (rwlock ==
nullptr) {
return EINVAL; }
975 if (rwlock->
__handle ==
nullptr) {
return EINVAL; }
998 if (lock ==
nullptr) {
return EINVAL; }
1002 return (lock->
__handle !=
nullptr) ? 0 : EAGAIN;
1007 if (lock ==
nullptr) {
return EINVAL; }
1019 if ((lock ==
nullptr) || (lock->
__handle ==
nullptr)) {
return EINVAL; }
1027 if ((lock ==
nullptr) || (lock->
__handle ==
nullptr)) {
return EINVAL; }
1034 if ((lock ==
nullptr) || (lock->
__handle ==
nullptr)) {
return EINVAL; }
1045 if (attr ==
nullptr) {
return EINVAL; }
1053 if (attr ==
nullptr) {
return EINVAL; }
1060 if (barrier ==
nullptr) {
return EINVAL; }
1061 if (count == 0U) {
return EINVAL; }
1064 static_cast<uint32_t
>(count));
1065 return (barrier->
__handle !=
nullptr) ? 0 : EAGAIN;
1070 if (barrier ==
nullptr) {
return EINVAL; }
1082 if ((barrier ==
nullptr) || (barrier->
__handle ==
nullptr)) {
return EINVAL; }
1092 if ((once_control ==
nullptr) || (init_routine ==
nullptr)) {
return EINVAL; }
1094 if (once_control->
__state == 2) {
return 0; }
1102 if (once_control->
__state != 2)
1118 if (key ==
nullptr) {
return EINVAL; }
1120 int result = EAGAIN;
1143 int result = EINVAL;
1162 if (ctrl ==
nullptr) {
return EINVAL; }
1164 ctrl->
tsd[key] =
const_cast<void *
>(value);
1173 if (ctrl ==
nullptr) {
return nullptr; }
1175 return ctrl->
tsd[key];
C language binding/interface for SuperTinyKernel RTOS.
C language binding for stk::memory::BlockMemoryPool.
void * malloc(std::size_t size)
A minimal, POSIX-named pthreads-style API implemented on top of the STK C bindings (stk_c....
stk_rwmutex_t * stk_rwmutex_create(stk_rwmutex_mem_t *const membuf, uint32_t membuf_size)
Create an RWMutex (using provided memory).
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.
void stk_task_set_name(stk_task_t *tsk, const char *tname)
Assign human-readable task name (for tracing/debugging).
void stk_barrier_destroy(stk_barrier_t *barrier)
Destroy a Barrier.
void stk_sem_signal(stk_sem_t *sem)
Signal/Release a semaphore resource.
#define STK_WAIT_INFINITE
Infinite timeout constant.
bool stk_event_set(stk_event_t *ev)
Set the event to signaled state.
void stk_mutex_destroy(stk_mutex_t *mtx)
Destroy a Mutex.
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).
bool stk_rwmutex_try_read_lock(stk_rwmutex_t *rw)
Try to acquire the read lock without blocking.
stk_sem_t * stk_sem_create(stk_sem_mem_t *const membuf, uint32_t membuf_size, uint32_t initial_count, uint32_t max_count)
Create a Semaphore (using provided memory).
void * stk_tls_get(void)
Get thread-local pointer (platform-specific slot).
bool stk_event_wait(stk_event_t *ev, stk_timeout_t timeout)
Wait for the event to become signaled.
bool stk_rwmutex_trylock(stk_rwmutex_t *rw)
Try to acquire the write lock without blocking.
bool stk_cv_wait(stk_cv_t *cv, stk_mutex_t *mtx, stk_timeout_t timeout)
Wait for a signal on the condition variable.
void stk_spinlock_destroy(stk_spinlock_t *slock)
Destroy the SpinLock.
void stk_cv_notify_one(stk_cv_t *cv)
Wake one task waiting on the condition variable.
bool stk_spinlock_trylock(stk_spinlock_t *slock)
Attempt to acquire the SpinLock immediately.
struct stk_kernel_t stk_kernel_t
Opaque handle to a kernel instance.
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_yield(void)
Voluntarily give up CPU to another ready task (cooperative yield).
bool stk_mutex_timed_lock(stk_mutex_t *mtx, stk_timeout_t timeout)
Try to lock the mutex with a timeout.
void stk_mutex_lock(stk_mutex_t *mtx)
Lock the mutex. Blocks until available.
void stk_rwmutex_lock(stk_rwmutex_t *rw)
Acquire the lock for exclusive writing. Blocks until available.
void stk_cv_destroy(stk_cv_t *cv)
Destroy a Condition Variable.
#define STK_C_KERNEL_MAX_TASKS
Maximum number of tasks per kernel instance (default: 4).
void stk_sleep(stk_timeout_t ticks)
Put current task to sleep (non-HRT kernels only).
bool stk_mutex_trylock(stk_mutex_t *mtx)
Try locking the mutex. Does not block if already locked.
void stk_rwmutex_read_lock(stk_rwmutex_t *rw)
Acquire the lock for shared reading. Blocks until available.
void stk_mutex_unlock(stk_mutex_t *mtx)
Unlock the mutex.
stk_timeout_t stk_ticks_from_ms_clamped_to_timeout(stk_timeout_t ms)
Get ticks from milliseconds using current kernel tick resolution, clamped to the maximum value repres...
#define STK_ALIGN_MASK
Alignment mask.
bool stk_sem_wait(stk_sem_t *sem, stk_timeout_t timeout)
Wait for a semaphore resource.
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.
void stk_sleep_ms(stk_timeout_t ms)
Put current task to sleep (non-HRT kernels only).
size_t stk_kernel_enumerate_tasks(stk_kernel_t *k, stk_task_t **tasks, size_t max_count)
Enumerate all currently active tasks.
void stk_kernel_add_task(stk_kernel_t *k, stk_task_t *tsk)
Add task to non-HRT kernel (static or dynamic).
void stk_spinlock_lock(stk_spinlock_t *slock)
Acquire the SpinLock (recursive).
void stk_spinlock_unlock(stk_spinlock_t *slock)
Release the SpinLock.
void stk_tls_set(void *ptr)
Set thread-local pointer.
void stk_rwmutex_read_unlock(stk_rwmutex_t *rw)
Release the shared reader lock.
stk_spinlock_t * stk_spinlock_create(stk_spinlock_mem_t *const membuf, uint32_t membuf_size)
Create a recursive SpinLock.
void stk_critical_section_enter()
Enter global critical section - disable context switches on current core.
uintptr_t stk_word_t
CPU register type.
#define STK_C_ASSERT(e)
Assertion macro used inside STK C bindings.
stk_cv_t * stk_cv_create(stk_cv_mem_t *const membuf, uint32_t membuf_size)
Create a Condition Variable (using provided memory).
stk_mutex_t * stk_mutex_create(stk_mutex_mem_t *const membuf, uint32_t membuf_size)
Create a Mutex (using provided memory).
int64_t stk_time_t
Time value.
stk_time_t stk_time_now_ms(void)
Returns current time in milliseconds since kernel start.
bool stk_rwmutex_timed_lock(stk_rwmutex_t *rw, stk_timeout_t timeout)
Try to acquire the write lock with a timeout.
void stk_rwmutex_destroy(stk_rwmutex_t *rw)
Destroy an RWMutex.
bool stk_rwmutex_timed_read_lock(stk_rwmutex_t *rw, stk_timeout_t timeout)
Try to acquire the read lock with a timeout.
int32_t stk_timeout_t
Timeout value.
void stk_critical_section_exit()
Leave global critical section - re-enable context switches.
void stk_cv_notify_all(stk_cv_t *cv)
Wake all tasks waiting on the condition variable.
void stk_rwmutex_unlock(stk_rwmutex_t *rw)
Release the exclusive writer lock.
bool stk_barrier_wait(stk_barrier_t *barrier)
Block the calling task until count tasks have called stk_barrier_wait().
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_blockpool_t * stk_blockpool_create_static(size_t capacity, size_t raw_block_size, uint8_t *storage, size_t storage_size, const char *name)
Create a block pool backed by caller-supplied (external) storage.
#define STK_BLOCKPOOL_STORAGE_DECL(name, capacity, raw_block_size)
Declare a correctly sized and aligned external storage array.
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
Try to acquire the write lock without blocking.
int pthread_condattr_destroy(pthread_condattr_t *attr)
int pthread_attr_init(pthread_attr_t *attr)
Initialize a thread attributes object with default values (default stack size, no external stack,...
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *)
Initialize a read-write lock.
int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *abstime)
Acquire the write lock with an absolute deadline.
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...
#define PTHREAD_DESTRUCTOR_ITERATIONS
Maximum number of passes over a finishing thread's keys made while destructors keep setting new non-N...
int pthread_cond_signal(pthread_cond_t *cond)
int pthread_setspecific(pthread_key_t key, const void *value)
Set the calling thread's value for key.
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
void pthread_exit(void *retval)
Terminate the calling thread.
int pthread_mutex_trylock(pthread_mutex_t *mutex)
int pthread_join(pthread_t thread, void **retval)
Block until the given joinable thread finishes, then reclaim its resources.
#define PTHREAD_MUTEX_DEFAULT
int pthread_condattr_init(pthread_condattr_t *attr)
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
Get the current detach-state setting.
#define PTHREAD_CREATE_DETACHED
int pthread_spin_unlock(pthread_spinlock_t *lock)
int pthread_mutex_destroy(pthread_mutex_t *mutex)
#define STK_C_PTHREAD_DEFAULT_STACK_WORDS
Default per-thread stack size in stk_word_t units, used when pthread_attr_t does not specify a stack ...
#define PTHREAD_PROCESS_PRIVATE
#define STK_C_PTHREAD_KEYS_MAX
Maximum number of concurrently-alive pthread_key_t's (default: 8).
int pthread_attr_destroy(pthread_attr_t *attr)
Destroy a thread attributes object (no-op; no owned resources).
pthread_t pthread_self(void)
Return the calling thread's own handle.
int pthread_spin_lock(pthread_spinlock_t *lock)
Acquire the spinlock, spinning until available.
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
Acquire the lock for exclusive writing. Blocks until available.
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime)
Lock with an absolute deadline.
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
Initialize a mutex.
#define STK_C_PTHREAD_REAPER_STACK_WORDS
Stack size (in stk_word_t units) for the internal reaper task that reclaims detached-thread resources...
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
int pthread_detach(pthread_t thread)
Mark a thread as detached.
unsigned int pthread_key_t
A thread-specific data key.
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
Release a read or write hold, whichever the calling thread holds.
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
struct pthread_stk_ctrl_t * pthread_t
Opaque thread handle.
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
Set the requested stack size in bytes.
#define PTHREAD_BARRIER_SERIAL_THREAD
Returned by pthread_barrier_wait() to exactly one arbitrary caller per round; all others receive 0....
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
Set the mutex type.
int pthread_barrier_wait(pthread_barrier_t *barrier)
Block until count threads have called this function, then release them all together; the barrier rese...
int pthread_spin_destroy(pthread_spinlock_t *lock)
void stk_pthread_bind_kernel(stk_kernel_t *kernel)
Bind the STK kernel instance that pthread_create() will add new threads to.
int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *, unsigned int count)
Initialize a barrier for count participating threads.
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_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize)
Supply an external, caller-owned stack buffer for the thread.
int pthread_mutex_unlock(pthread_mutex_t *mutex)
int pthread_equal(pthread_t t1, pthread_t t2)
Compare two thread handles for equality.
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
int pthread_barrierattr_init(pthread_barrierattr_t *attr)
int pthread_cond_destroy(pthread_cond_t *cond)
int pthread_spin_init(pthread_spinlock_t *lock, int pshared)
Initialize a spinlock.
#define PTHREAD_MUTEX_NORMAL
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
Try to acquire the read lock without blocking.
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_barrierattr_destroy(pthread_barrierattr_t *attr)
#define STK_C_PTHREAD_MAX_THREADS
Maximum number of concurrently-alive pthread_t's (default: 8).
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
Acquire the lock for shared reading. Blocks until available.
int pthread_spin_trylock(pthread_spinlock_t *lock)
Try to acquire the spinlock without blocking.
void * pthread_getspecific(pthread_key_t key)
Get the calling thread's value for key.
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *)
int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, const struct timespec *abstime)
Acquire the read lock with an absolute deadline.
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
Get the currently requested stack size in bytes (0 = default).
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_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
Set PTHREAD_CREATE_JOINABLE or PTHREAD_CREATE_DETACHED.
int pthread_barrier_destroy(pthread_barrier_t *barrier)
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_key_delete(pthread_key_t key)
Free a thread-specific data key.
int pthread_yield(void)
Voluntarily give up the CPU to another ready task (cooperative yield), then resume once rescheduled.
int pthread_key_create(pthread_key_t *key, void(*destructor)(void *))
Allocate a new thread-specific data key.
int pthread_mutexattr_init(pthread_mutexattr_t *attr)
#define PTHREAD_CREATE_JOINABLE
int pthread_cond_broadcast(pthread_cond_t *cond)
stk_timeout_t TimespecToRelativeTimeout(const struct timespec *abstime)
void WaitForTaskGone(stk_task_t *task)
stk_word_t s_ReaperStack[(256U)]
stk_blockpool_t * s_StackPool
stk_sem_mem_t s_ReapSemMem
void EnqueueReap(ThreadCtrl *ctrl)
ThreadCtrl s_Threads[(8U)]
stk_mutex_t * EnsureOnceMutex(pthread_once_t *o)
stk_mutex_t * EnsureMutex(pthread_mutex_t *m)
ThreadCtrl * AcquireThreadSlot()
void MaybeReap(ThreadCtrl *ctrl)
void ReaperEntry(void *arg)
constexpr std::size_t kDefaultStackBytes
stk_kernel_t * s_BoundKernel
stk_task_t * s_ReaperTask
void PthreadTrampoline(void *arg)
pthread_stk_ctrl_t ThreadCtrl
stk_cv_t * EnsureCond(pthread_cond_t *c)
void RunKeyDestructors(ThreadCtrl *ctrl)
void ReleaseThreadResources(ThreadCtrl *ctrl)
stk_rwmutex_t * EnsureRWLock(pthread_rwlock_t *rw)
ThreadCtrl * s_ReapQueue[(8U)]
stk_blockpool_t * EnsureStackPool()
ThreadCtrl * DequeueReap()
Opaque memory container for an Event instance.
Opaque memory container for a Semaphore instance.
stk_event_mem_t done_event_mem
void *(* start_routine)(void *)
void(* destructor)(void *)
Thread creation attributes.
Condition variable attributes (currently no settable properties).
A pthread condition variable.
Read-write lock attributes (currently no settable properties).
A pthread read-write lock.
stk_spinlock_t * __handle
Barrier attributes (currently no settable properties).
A pthread_once() control object.