/*
 * sThreads.c -- stubbed out PCR
 * 
 * July 6, 1993 - mfp
 *  XR←PauseAbortable fixed to set the return value as specified in Threads.h
 */

#include <xr/Threads.h>
#include <xr/ThreadsDynamicEnvironment.h>
#include <xr/sMisc.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#include <stdlib.h>
#include <errno.h>
extern char **envp;
static long bootTime;
struct XR←ThreadRep theOnlyThread;
XR←Thread XR←currThread = &theOnlyThread;

void
SPCR←Init() {
    extern int SPCR←debugMessages;
    
    (void) time(&bootTime);
    
    if (getenv("SPCR←DEBUG")) SPCR←debugMessages = 1;
    
    GC←register←displacement(8);
}

struct cu←info {
	void (**cu←proc)();
	XR←Pointer cu←data;
};

struct cu←info * cleanupInfo;

static void generic←cu←proc()
{
    
    (**(cleanupInfo -> cu←proc))(cleanupInfo -> cu←data);
}

int
XR←RegisterTerminationCleanupProc(proc, clientData)
void (**proc)();
XR←Pointer clientData;
{
    cleanupInfo = (struct cu←info *)
    				GC←malloc(sizeof (struct cu←info));
    
    if (cleanupInfo == 0) {
        errno = ENOMEM;
        return(-1);
    }
    cleanupInfo -> cu←proc = proc;
    cleanupInfo -> cu←data = clientData;
    return(atexit(generic←cu←proc));
}

XR←Ticks
XR←TicksSinceBoot() {
    return (time(0) - bootTime) * XR←TICKS←PER←SECOND;
}

#undef XR←TicksToMsec
unsigned
XR←TicksToMsec(ticks)
XR←Ticks ticks;
{
    return ticks * XR←MSECS←PER←TICK;
}

#undef XR←MsecToTicks
XR←Ticks
XR←MsecToTicks(msec)
unsigned msec;
{
    return msec / XR←MSECS←PER←TICK;
}

void
XR←InitializeCondition(cv, timeout)
XR←CV cv;
XR←Ticks timeout;
{
    cv->cv←timeout = timeout;
    SPCR←NotImplemented("InitializeCondition");
}

void
XR←InitializeMonitor(ml)
XR←ML ml;
{
    ml->ml←holder = 0;
}

void
XR←MonitorEntry(ml)
XR←ML ml;
{
    if (ml->ml←holder) {
        SPCR←error("Deadlock!\n");
    }
    ml->ml←holder = XR←currThread;
}

void
XR←MonitorExit(ml)
XR←ML ml;
{
    ml->ml←holder = 0;
}

void
XR←SetTimeout(cv, timeout)
XR←CV cv;
XR←Ticks timeout;
{
    cv->cv←timeout = timeout;
}

void
XR←DisableTimeout(cv)
XR←CV cv;
{
    cv->cv←timeout = XR←WAIT←FOREVER;
}

void
XR←DisableAborts(cv)
XR←CV cv;
{
}

void
XR←EnableAborts(cv)
XR←CV cv;
{
    cv->cv←abortable = TRUE;
}

bool
XR←AbortPending ()
{
    return( FALSE );
}

int
XR←WaitCV(cv, ml)
XR←CV cv;
XR←ML ml;
{
    if (cv->cv←timeout != XR←WAIT←FOREVER)
        sleep(XR←TicksToMsec(cv->cv←timeout)/1000);
    else {
        SPCR←error("Waiting forever w/o timeout in a single-process world");
    }
	return 0;
}

int
XR←ValidateCT(ct)
XR←CT ct;
{
    return (ct->ct←thread == XR←currThread) ? 0 : -1;
}

void
XR←Notify(cv)
XR←CV cv;
{
}

void
XR←Broadcast(ct)
XR←CT ct;
{
}

void
XR←UplevelSetjmp(jb)
XR←JmpBuf jb;
{
    SPCR←NotImplemented("XR←UplevelSetJmp");
}

XR←DBMsg
XR←CallDebugger(arg)
XR←Pointer arg;
{
    SPCR←error("Debugger Called\n");
}

XR←Pointer
XR←ExtensionFree(x)
XR←Pointer x;
{
    return NIL;
}

static current←pri = 3;  /* NORMAL */

#undef XR←GetPriority
XR←Pri
XR←GetPriority() {
    return(current←pri);
}

void
XR←SetPriority(pri)
XR←Pri pri;
{
    current←pri = pri;
}

void
XR←Yield() {
}


void
XR←GetCurrent(result)
struct XR←CTRep *result;
{
    result->ct←thread = XR←currThread;
    result -> ct←gen = 1;
}

void
XR←Fork(result, mp)
struct XR←CTRep *result;
XR←MesaProc mp;
{
    SPCR←NotImplemented("XR←Fork");
}

XR←Pointer
XR←JoinCT(ct)
XR←CT ct;
{
    SPCR←NotImplemented("XR←JoinCT");
    return -1;
}

int
XR←PauseAbortable(ticks)
XR←Ticks ticks;
{
    struct timeval timeout;
    unsigned long msec = XR←TicksToMsec(ticks);
    
    timeout.tv←sec = msec/1000;
    timeout.tv←usec = (msec % 1000) * 1000;
    return (select(0,0,0,0, &timeout));
}

int
XR←CancelAbort(ct)
XR←CT ct;
{
    return 0;
}

int
XR←DetachCT(ct)
XR←CT ct;
{
    SPCR←NotImplemented("XR←DetachCT");
    return 0;
}

int
XR←AbortCT(ct)
XR←CT ct;
{
    SPCR←NotImplemented("XR←AbortCT");
    return 0;
}

void
XR←ExitWorld(status)
int status;
{
    ←exit(status);
}

void
XR←RestartHandlee(t, where, result)         /* !!!! no declaration in .h */
XR←Thread t;
jmp←buf where;
unsigned result;
{
    if( t == NIL ) t = XR←currThread;
    else if( t != XR←currThread ) {
         SPCR←error("Current Thread isn't only thread!");
	}
    if( where == NIL ) {
        SPCR←error("Handlee jumpbuf is NIL!");
	}
    XR←longjmp( where, result );
}

XR←Thread
XR←GetNextHandlee(t)        /* !!!! no declaration in .h */
XR←Thread t;
{
    if( t == NIL ) return ( XR←currThread );
    SPCR←error("XR←GetNextHandlee called with thread != NIL!");
}

#undef XR←RegisterThreadStartProc
void
XR←RegisterThreadStartProc(startProc)
XR←MesaProc startProc;
{
}


/* 
 * Per thread data access and set routines
 *  Using a global variable rather than adding a field to the thread 
 *  data structure because perThread data in a single threaded world
 *  might as well be perWorld data
 */
 
XR←Pointer t←perThreadData = 0;

XR←Pointer
XR←GetThreadProperty()
{
	return t←perThreadData;
}

void
XR←SetThreadProperty(p)
XR←Pointer p;
{
	t←perThreadData = p;
}