/* 
 * An XaoS thread API implementation
 * Many functions are implemented as macros that maps simple
 * XaoS thread API into architecture depended API.
 * I tried avoid functions because of speed issues
 * So this header will be quite messy soon :)
 *
 * Supported API for now:
 * pthread (POSIX) enabled using USE_PTHREAD
 * nothread (my own) enabled by default
 */
#ifndef THREAD_H
#define THREAD_H 1
#include <fconfig.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MAXTHREADS 32
    /*You might increase this constant if needed
       (xaos on connection machine? :) */

#define NSEMAPHORS 2
#define MAXSEMAPHORS 2
#define NSLEEPS 2
#define MAXCONDS 2

#ifdef USE_PTHREAD
#include <pthread.h>
#endif
#ifdef __BEOS__
#include <OS.h>
#endif

    struct taskinfo {
	int n;
#ifdef USE_PTHREAD
	pthread_t id;
#endif
#ifdef _plan9_
	int id;
#endif
#ifdef __BEOS__
	thread_id id;
#endif
    };

    extern struct taskinfo definfo;
    extern int ethreads;	/*Is threading enabled? */
    extern int nthreads;	/*Number of threads */
    typedef void (*xfunction) (void *, struct taskinfo *, int, int);

/*No-thread API implementation version */
#define nothread { }
#define nothread_init(nthreads) nothread
#define nothread_uninit() nothread
#define nothread_function(f,data,range) f(data,&definfo,0,range)
#define nothread_bgjob(f,d) f(d,&definfo,0,0)
#define nothread_lock(n) nothread
#define nothread_unlock(n) nothread
#define nothread_sync() nothread
#define nothread_sleep(n,l) nothread
#define nothread_wakeup(n) nothread
#define nothread_wakefirst(n) nothread

#define xth_wrap(f1,f2) if(nthreads!=1) f1(); else f2();

#ifdef USE_PTHREAD
/* A posix thread API maps */
    void pth_init(int nthreads);
    void pth_uninit(void);
    void pth_function(xfunction f, void *d, int r);
    void pth_synchronize(void);
    void pth_bgjob(xfunction f, void *d);
    extern pthread_mutex_t semaphors[MAXSEMAPHORS];
    extern pthread_cond_t conds[MAXCONDS];

/*Map pthread API to XaoS thread API */

#define xth_init(nthreads) pth_init(nthreads)
#define xth_uninit() pth_uninit()
#define xth_lock(n) if(ethreads) pthread_mutex_lock(semaphors+(n))
#define xth_unlock(n) if(ethreads) pthread_mutex_unlock(semaphors+(n))
#define xth_function(f,d,r) if(ethreads) pth_function(f,d,r); else nothread_function(f,d,r)
#define xth_nthread(ts) (ethreads?ts->n:0)
#define xth_sync() if(ethreads) pth_synchronize();
#define xth_bgjob(f,d) if(ethreads) pth_bgjob(f,d); else f(d,&definfo,0,0);
#define xth_sleep(n,l) if(ethreads) pthread_cond_wait(conds+(n),semaphors+(l))
#define xth_wakeup(n) if(ethreads) pthread_cond_broadcast(conds+(n))
#define xth_wakefirst(n) if(ethreads) pthread_cond_signal(conds+(n))
#define API_MAPPED
#endif				/*USE_PTHREAD */

#ifdef _plan9_

    struct Stack {
	int nwaiting;
	int tags[MAXTHREADS];
    };
#ifdef _plan9v2_
#include <lock.h>		/* in plan9v3 part of libc */
#endif
/* A plan9 thread API maps */
    void p9wait(struct Stack *s, Lock * l);
    void p9wakeup(struct Stack *s);
    void p9wakeall(struct Stack *s);
    void p9init(int nthreads);
    void p9uninit(void);
    void p9function(xfunction f, void *d, int r);
    void p9synchronize(void);
    void p9bgjob(xfunction f, void *d);
    extern Lock semaphors[MAXSEMAPHORS];
    extern struct Stack conds[MAXCONDS];

/*Map pthread API to XaoS thread API */

#define xth_init(nthreads) p9init(nthreads)
#define xth_uninit() p9uninit()
#define xth_lock(n) if(ethreads) lock(semaphors+(n))
#define xth_unlock(n) if(ethreads) unlock(semaphors+(n))
#define xth_function(f,d,r) if(ethreads) p9function(f,d,r); else nothread_function(f,d,r)
#define xth_nthread(ts) (ethreads?ts->n:0)
#define xth_sync() if(ethreads) p9synchronize();
#define xth_bgjob(f,d) if(ethreads) p9bgjob(f,d); else f(d,&definfo,0,0);
#define xth_sleep(n,l) if(ethreads) p9wait(conds+(n), semaphors+(l))
#define xth_wakeup(n) if(ethreads) p9wakeall(conds+(n))
#define xth_wakefirst(n) if(ethreads) p9wakeup(conds+(n))
#define API_MAPPED
#endif				/*USE_PTHREAD */

#ifdef __BEOS__
    typedef struct {
	int32 cnt;
	sem_id sem;
    } benaphore;

    void acquire_benaphore(benaphore * p);
    void release_benaphore(benaphore * p);
#ifdef __GNUC__
    extern
#endif
    inline void acquire_benaphore(benaphore * p) {
	if (atomic_add(&(p->cnt), 1) >= 1) {
	    /* Someone was faster. */
	    while (acquire_sem(p->sem) == B_INTERRUPTED);
	}
    }
#ifdef __GNUC__
    extern
#endif
    inline void release_benaphore(benaphore * p) {
	if (atomic_add(&(p->cnt), -1) > 1) {
	    /* Someone was slower. */
	    release_sem(p->sem);
	}
    }

    extern benaphore mutexes[MAXSEMAPHORS];
    extern benaphore condvars[MAXCONDS];

    void be_thread_init(int num_threads);
    void be_thread_uninit(void);
    void be_thread_function(xfunction f, void *d, int r);
    void be_thread_synchronize(void);
    void be_thread_bgjob(xfunction f, void *d);
    void be_thread_sleep(benaphore * pCondition, benaphore * pMutex);
    void be_thread_wakeup(benaphore * pCondition);
    void be_thread_wakefirst(benaphore * pCondition);

/* Map BeOS API to XaoS thread API. */

#define xth_init(nthreads) be_thread_init(nthreads)
#define xth_uninit() be_thread_uninit()
#define xth_function(f,d,r) if(ethreads) be_thread_function(f,d,r); else nothread_function(f,d,r)
#define xth_nthread(ts) (ethreads?ts->n:0)
#define xth_sync() if(ethreads) be_thread_synchronize();
#define xth_bgjob(f,d) if(ethreads) be_thread_bgjob(f,d); else f(d,&definfo,0,0);
#define xth_lock(n) if(ethreads) acquire_benaphore(mutexes+(n))
#define xth_unlock(n) if(ethreads) release_benaphore(mutexes+(n))
#define xth_sleep(n,l) if(ethreads) be_thread_sleep(condvars+(n),mutexes+(l))
#define xth_wakeup(n) if(ethreads) be_thread_wakeup(condvars+(n))
#define xth_wakefirst(n) if(ethreads) be_thread_wakefirst(condvars+(n))
#define API_MAPPED
#endif				/* __BEOS__ */

#ifndef API_MAPPED
/*
 * No thread support is compiled - do just wrappers 
 * to nothread implementation
 */
#define nthreads 1
#define ethreads 0
#define xth_init(n) nothread_init(n)
#define xth_uninit() nothread_uninit()
#define xth_function(f,d,r) nothread_function(f,d,r)
#define xth_lock(n) nothread_lock(n)
#define xth_unlock(n) nothread_unlock(n)
#define xth_sync() nothread_sync()
#define xth_bgjob(f,d) nothread_bgjob(f,d)
#define xth_nthread(ts) 0
#define xth_wakeup(n) nothreads_wakeup(n)
#define xth_wakefirst(n) nothreads_wakefirst(n)
#define xth_sleep(n,l) nothreads_sleep(n,l)
#endif

#ifdef __cplusplus
}
#endif
#endif
