91 lines
3.6 KiB
C
91 lines
3.6 KiB
C
// threads.h — C11 threading API. Single-core IIgs / bare-metal: every
|
|
// thread function fails with `thrd_error`. Mutexes / cond-vars compile
|
|
// but produce no synchronization — callers running on a single core
|
|
// don't need any. This header is here so portable C11 code that
|
|
// `#include <threads.h>` and uses `thrd_t` etc. compiles.
|
|
|
|
#ifndef _THREADS_H
|
|
#define _THREADS_H
|
|
|
|
#include <time.h>
|
|
|
|
enum {
|
|
thrd_success = 0,
|
|
thrd_busy = 1,
|
|
thrd_error = 2,
|
|
thrd_nomem = 3,
|
|
thrd_timedout = 4
|
|
};
|
|
|
|
enum {
|
|
mtx_plain = 0,
|
|
mtx_recursive = 1,
|
|
mtx_timed = 2
|
|
};
|
|
|
|
#define ONCE_FLAG_INIT 0
|
|
#define TSS_DTOR_ITERATIONS 1
|
|
|
|
typedef int thrd_t;
|
|
typedef int (*thrd_start_t)(void *);
|
|
typedef struct { int _x; } mtx_t;
|
|
typedef struct { int _x; } cnd_t;
|
|
typedef int once_flag;
|
|
typedef unsigned short tss_t;
|
|
typedef void (*tss_dtor_t)(void *);
|
|
|
|
// All thread create/join calls fail — no scheduler.
|
|
static inline int thrd_create(thrd_t *t, thrd_start_t f, void *a) {
|
|
(void)t; (void)f; (void)a;
|
|
return thrd_error;
|
|
}
|
|
static inline thrd_t thrd_current(void) { return 0; }
|
|
static inline int thrd_equal(thrd_t a, thrd_t b) { return a == b; }
|
|
static inline void thrd_exit(int v) { (void)v; for (;;) {} }
|
|
static inline int thrd_join(thrd_t t, int *res) { (void)t; (void)res; return thrd_error; }
|
|
static inline int thrd_detach(thrd_t t) { (void)t; return thrd_error; }
|
|
static inline int thrd_sleep(const struct timespec *d,
|
|
struct timespec *r) { (void)d; (void)r; return -1; }
|
|
static inline void thrd_yield(void) { }
|
|
|
|
// Mutex / cond — no-ops on a uniprocessor.
|
|
static inline int mtx_init(mtx_t *m, int t) { (void)m; (void)t; return thrd_success; }
|
|
static inline int mtx_lock(mtx_t *m) { (void)m; return thrd_success; }
|
|
static inline int mtx_trylock(mtx_t *m) { (void)m; return thrd_success; }
|
|
static inline int mtx_timedlock(mtx_t *m,
|
|
const struct timespec *t) {
|
|
(void)m; (void)t; return thrd_success;
|
|
}
|
|
static inline int mtx_unlock(mtx_t *m) { (void)m; return thrd_success; }
|
|
static inline void mtx_destroy(mtx_t *m) { (void)m; }
|
|
|
|
static inline int cnd_init(cnd_t *c) { (void)c; return thrd_success; }
|
|
static inline int cnd_signal(cnd_t *c) { (void)c; return thrd_success; }
|
|
static inline int cnd_broadcast(cnd_t *c) { (void)c; return thrd_success; }
|
|
static inline int cnd_wait(cnd_t *c, mtx_t *m) { (void)c; (void)m; return thrd_error; }
|
|
static inline int cnd_timedwait(cnd_t *c, mtx_t *m,
|
|
const struct timespec *t) {
|
|
(void)c; (void)m; (void)t; return thrd_timedout;
|
|
}
|
|
static inline void cnd_destroy(cnd_t *c) { (void)c; }
|
|
|
|
// call_once — straightforward on a single-core target.
|
|
static inline void call_once(once_flag *f, void (*fn)(void)) {
|
|
if (!*f) { *f = 1; fn(); }
|
|
}
|
|
|
|
// Thread-specific storage: no other threads, so it's just a pointer.
|
|
// At most 8 keys.
|
|
extern void *__tss_slots[8];
|
|
extern int __tss_next;
|
|
static inline int tss_create(tss_t *k, tss_dtor_t d) {
|
|
(void)d;
|
|
if (__tss_next >= 8) return thrd_error;
|
|
*k = (tss_t)__tss_next++;
|
|
return thrd_success;
|
|
}
|
|
static inline void *tss_get(tss_t k) { return __tss_slots[k]; }
|
|
static inline int tss_set(tss_t k, void *v) { __tss_slots[k] = v; return thrd_success; }
|
|
static inline void tss_delete(tss_t k) { (void)k; }
|
|
|
|
#endif
|