// 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
