Files
dusk/.claude/threading.md
T
2026-06-16 10:15:59 -05:00

2.9 KiB

Threading System

Source: src/dusk/thread/

Platform support

Threading currently requires pthreads (DUSK_THREAD_PTHREAD). The implementation lives in the core thread files and is guarded by that compile-time flag -- there are no separate per-platform thread directories.

Thread-local storage uses the THREAD_LOCAL macro, which maps to __thread when pthreads is available. This is used by the error system to give each thread its own ERROR_STATE.

Thread lifecycle

Threads follow a strict state machine:

STOPPED -> STARTING -> RUNNING -> STOP_REQUESTED -> STOPPED
  • threadStart() -- blocking: starts the thread and waits until it reaches RUNNING.
  • threadStop() -- blocking: requests stop and waits until STOPPED.
  • threadStartRequest() -- non-blocking equivalent of threadStart.
  • threadStopRequest() -- non-blocking equivalent of threadStop.

The thread callback polls threadShouldStop() to know when to exit. Never kill a thread forcefully -- always let it stop cooperatively.

Thread API

void threadInit(thread_t *thread, errorret_t (*callback)(thread_t *t));
// Initialise; callback is the thread entry point.

errorret_t threadStart(thread_t *thread);
// Start and block until RUNNING.

errorret_t threadStop(thread_t *thread);
// Request stop, block until STOPPED.

void threadStartRequest(thread_t *thread);
void threadStopRequest(thread_t *thread);
// Non-blocking variants.

bool_t threadShouldStop(const thread_t *thread);
// Call from inside the thread callback to know when to exit.

Mutex API (threadmutex.h)

Each threadmutex_t wraps a pthread mutex and a condition variable.

void threadMutexInit(threadmutex_t *mutex);
void threadMutexDispose(threadmutex_t *mutex);

void threadMutexLock(threadmutex_t *mutex);
void threadMutexUnlock(threadmutex_t *mutex);
bool_t threadMutexTryLock(threadmutex_t *mutex);
// Returns true if the lock was acquired; false if already held.

void threadMutexWaitLock(threadmutex_t *mutex);
// Block until signalled (like pthread_cond_wait).
// Must be called while holding the lock.

void threadMutexSignal(threadmutex_t *mutex);
// Wake one waiter.

Usage example

static errorret_t workerCallback(thread_t *t) {
  while(!threadShouldStop(t)) {
    // do work
  }
  errorOk();
}

thread_t worker;
threadInit(&worker, workerCallback);
errorChain(threadStart(&worker));
// ... later ...
errorChain(threadStop(&worker));

Thread safety rules

  • The error system (ERROR_STATE) is thread-local -- each thread has its own error state. Do not pass errorret_t across thread boundaries without copying the message and lines strings first.
  • Asset loading: the background thread calls loadAsync; the main thread calls loadSync. Never call GPU or SDL functions from the loader background thread.
  • Use assertIsMainThread() / assertNotMainThread() to guard functions that have thread affinity requirements.