/*
Copyright (c) 1993 Xerox Corporation.  All rights reserved.
*/
/*
$Id$

$Date$
 *
 * Private definitions for PCR threads
 *
 */


#ifndef	←←PCR←ThPvt←h
#define ←←PCR←ThPvt←h 1

#include <config/PCR←Arch.h>
#include <config/PCR←StdTypes.h>
#include <th/PCR←ThData.h>
#include <th/PCR←ThTypes.h>
#include <th/PCR←ThCtl.h>

#include <setjmp.h>


#define PCR←ThPvt←NUMPRI	8

/*
 * Forward declarations
 */

typedef volatile struct PCR←ThPvt←TQRep * PCR←ThPvt←TQPtr;
typedef volatile struct PCR←ThPvt←MLRep * PCR←ThPvt←MLPtr;
typedef volatile struct PCR←ThPvt←CVRep * PCR←ThPvt←CVPtr;
typedef volatile struct PCR←ThPvt←ForkDataRep * PCR←ThPvt←ForkDataPtr;
typedef volatile struct PCR←ThPvt←SlotDataRep * PCR←ThPvt←SlotDataPtr;

/*
 * Thread queues
 *
 * Circular queue
 * Queue structure points to tail element
 */


struct PCR←ThPvt←TQRep {
    PCR←ThPvt←SlotDataPtr tq←tl;
};

typedef volatile struct PCR←ThPvt←TQRep PCR←ThPvt←TQ;

#define PCR←ThPvt←TQ←null { NIL }


/*
 * Monitor Locks
 */

struct PCR←ThPvt←MLRep {
    unsigned long ml←lock;
    PCR←ThPvt←TQ ml←tq;
};


typedef volatile struct PCR←ThPvt←MLRep PCR←ThPvt←ML;

#define PCR←ThPvt←ML←null { 0, PCR←ThPvt←TQRep←null }


/*
 * Condition variables
 *
 * CVs are opaque but clients may allocate and initialize them.
 */

struct PCR←ThPvt←CVRep {
    PCR←Bool cv←wakeupWaiting;
    PCR←ThPvt←TQ cv←tq;
};


typedef volatile struct PCR←ThPvt←CVRep PCR←ThPvt←CV;

#define PCR←ThPvt←CV←null { PCR←Bool←false, PCR←ThPvt←TQRep←null }


/*
 * Private per-fork data structure
 *
 * (this is the referent of PCR←Th←T)
 */

struct PCR←ThPvt←ForkDataRep {
    PCR←ThData←T tfd←td;
    PCR←Th←ML tfd←lock;
    PCR←Bool tfd←finished;
    PCR←Th←CV tfd←finishedCV;
    int tfd←exitCode;		/* arg to exit */
    PCR←Any tfd←exitVal;	/* arg to exit */
    PCR←ThPvt←ForkDataPtr tfd←parent; /* forker */
    PCR←ThPvt←ForkDataPtr tfd←nextFinished;
    PCR←sigset←t tfd←sigblocked;
    PCR←sigset←t tfd←sigpending;
    PCR←sigset←t tfd←sigignored;
    PCR←ProcPtr tfd←proc;
    PCR←Any tfd←data;
};

typedef volatile struct PCR←ThPvt←ForkDataRep PCR←ThPvt←ForkData;

#define PCR←ThPvt←ForkDataFromPublic(t) \
	((PCR←ThPvt←ForkData *)(t))

#define PCR←ThPvt←PublicFromForkData(tfd) \
	((PCR←Th←T *)(tfd))

#define PCR←ThPvt←CurrForkData() \
	PCR←ThPvt←ForkDataFromPublic(PCR←Th←CurrThread())

/*
 * Private per-thread-slot data structure
 */

struct PCR←ThPvt←SlotDataRep {

    /* saved machine-dependent context (must be first) */
    PCR←jmp←buf tsd←mdContext;

    /* stack info */
    void * tsd←stk;
    unsigned long tsd←stkBytes;
    void * tsd←stkInitial;
    void * tsd←stkWarmLim;

    /* list of all thread slots */
    PCR←ThPvt←SlotDataPtr tsd←nextSlot;
    PCR←ThPvt←SlotDataPtr tsd←prevSlot;

    /* associated ForkData (active threads only) */
    PCR←ThPvt←ForkDataPtr tsd←tfd;

    /* scheduling state */
    PCR←ThCtl←State tsd←state;
    int tsd←sysCrSecNest;
    PCR←Bool tsd←deferredAction;
    PCR←Bool tsd←mustCheckSigs;

    /* wait/run queue data */
    PCR←ThPvt←SlotDataPtr tsd←next;
    PCR←ThPvt←TQ *tsd←runQ;
    PCR←ThPvt←TQ *tsd←waitQ;
    PCR←Th←ML *tsd←mlNeeded;
    PCR←ERes tsd←waitRes;
    PCR←Bool tsd←ignoreRunExclusive;

    /* timeout data */
    PCR←ThPvt←SlotDataPtr tsd←nextTimeout;
    PCR←ThPvt←SlotDataPtr tsd←prevTimeout;
    PCR←Msec tsd←wakeup;

};

typedef volatile struct PCR←ThPvt←SlotDataRep PCR←ThPvt←SlotData;

#define PCR←ThPvt←SlotDataFromPublic(t) \
	( (PCR←ThPvt←SlotData *)( \
		((PCR←ThPvt←ForkData *)(t))->tfd←td.td←←slotData) )

#define PCR←ThPvt←PublicFromSlotData(tsd) \
	((PCR←Th←T *)(tsd->tsd←tfd))

#define PCR←ThPvt←SlotData←IsOnQ(tsd) \
	((tsd)->tsd←next != NIL)

#define PCR←ThPvt←SlotData←IsOnWaitQ(tsd) \
	((tsd)->tsd←waitQ != NIL)

#define PCR←ThPvt←SlotData←IsOnTimeoutQ(tsd) \
	((tsd)->tsd←nextTimeout != NIL)

/*
 * Currently running thread, thread queues, etc.
 */

#define PCR←ThPvt←CurrSlotData() --> OBSOLETE <--

extern PCR←ThPvt←SlotDataPtr PCR←ThPvt←slots;

extern PCR←ThPvt←TQ PCR←ThPvt←runQ[PCR←ThPvt←NUMPRI];

extern PCR←ThPvt←TQ * PCR←ThPvt←maxNotified;


/*
 * Internal version of YieldTo
 */

extern PCR←ThPvt←SlotData *
PCR←ThPvt←NextMostDeserving(void);
/*
    Approximate the next most deserving thread (other than self)
    for use in public version of YieldTo.
*/

extern PCR←ERes
PCR←ThPvt←Switch(
    PCR←ThPvt←SlotData * switchee /* may be NIL */
);
/*
    Do a thread switch.
    Switch to switchee if possible, otherwise (if switchee
      is NIL or not ready) let scheduler choose.
    Result is return code from blocking primitive (ml or cv).
    Caller must be in sys critical section!
*/

/*
 * Set a thread ready -- used from many thread operations
 */

extern void
PCR←ThPvt←SetRun(PCR←ThPvt←SlotData *tsd, PCR←ERes res);
/*
    Set a thread runnable.
    If it is on wait / timeout queues, remove it.
    Place it on its run queue.
    The thread state is set appropriately.
    If the thread priority warrants it, arrange for a resched.
    The result returned to the original thread call that blocked
      (monitor entry or condition wait) will be res.
    Caller must be in sys critical section.
*/

/*
 * Signal delivery to a thread.
 */

extern PCR←ERes
PCR←ThPvt←DeliverSigs(
    PCR←Th←T *t,
    const PCR←sigset←t *sigs
);
/*
    Thread switcher will call DeliverSigs to deliver signals
      to specified thread (which may be self).
    This proc is exported here so that code other than the switcher
      can use it to deliver signals.
    It wakes up the signalled thread
      (using PCR←ThPvt←SetRun) if it is waiting.
    Caller should be in sys critical section.
*/


extern unsigned
PCR←ThPvt←AcceptPendingSigs(/* result */ PCR←Sig←Action * buf);

extern void
PCR←ThPvt←HandleAcceptedSigs(PCR←Sig←Action * buf, unsigned cnt);
/*
    Called by PCR←ThCrSec←ExitSys() to effect delivery of signals
      that are pending for current thread.
    AcceptPendingSigs stacks pending sigs into *buf, which
      must point to an array of size 1+PCR←NSIG.
    The caller must be in a sys critical section.
    HandleAcceptedSigs calls the handlers for the cnt accepted
      signals stacked in *buf.
    The caller must not be in sys critical section.
    The caller should have all sigs blocked; calling the handlers
      will unblock them as a side-effect.
    Note a thread switch can occur, or signal delivery may even
      result in a longjmp.
*/


/*
 * SlotData allocation
 */

extern PCR←ThPvt←SlotData *
PCR←ThPvt←SlotData←Alloc(void);
/*
    Allocate slot data and associated stack.
    Caller must not be in critical section.
*/


/*
 * Thread queueing routines
 *
 * Caller must be in sys critical section.
 */

extern PCR←ThPvt←SlotData *
PCR←ThPvt←SlotData←Activate(PCR←ThPvt←SlotData *);
/*
    Allocate slot data (or use space supplied) and link into system queues.
*/

extern void
PCR←ThPvt←SlotData←Deactivate(PCR←ThPvt←SlotData *tsd);
/*
    Deallocate slot data.
*/


extern PCR←Bool
PCR←ThPvt←TQ←IsEmpty(PCR←ThPvt←TQ *tq);

#define PCR←ThPvt←TQ←IsEmpty(tq)	((tq)->tq←tl == NIL)


extern PCR←Bool
PCR←ThPvt←MLQIsEmpty(PCR←Th←ML *ml);

#define PCR←ThPvt←MLQIsEmpty(ml) \
	PCR←ThPvt←TQ←IsEmpty( &( ((PCR←ThPvt←ML)(ml))->ml←tq ) )


extern PCR←Bool
PCR←ThPvt←CVQIsEmpty(PCR←Th←CV *cv);

#define PCR←ThPvt←CVQIsEmpty(cv) \
	PCR←ThPvt←TQ←IsEmpty( &( ((PCR←ThPvt←CV)(cv))->cv←tq ) )



extern void
PCR←ThPvt←AddTlRunQ(PCR←ThPvt←SlotData *tsd);
/*
    Add thread tsd to the tail of its associated run queue.
    Set scheduling state to ready.
    Request deferred resched if the run queue is higher priority
      than current thread.
*/

extern PCR←ThPvt←SlotData *
PCR←ThPvt←TQ←RemHd(PCR←ThPvt←TQ *tq);
/*
    Remove and return the head element of a (nonempty) queue.
    
*/

extern void
PCR←ThPvt←TQ←AddTl(PCR←ThPvt←TQ *tq, PCR←ThPvt←SlotData *tsd);
/*
    Add thread at tail of queue.
*/

extern void
PCR←ThPvt←TQ←AddHd(PCR←ThPvt←TQ *tq, PCR←ThPvt←SlotData *tsd);
/*
    Add thread at head of queue.
*/

extern void
PCR←ThPvt←TQ←Rem(PCR←ThPvt←TQ *tq, PCR←ThPvt←SlotData *tsd);
/*
    Remove thread from queue (which must contain it).
*/


/*
 * Synchronization primitive
 */

#if PCR←Arch←TAS

extern unsigned long
PCR←ThPvt←GetAndSet(unsigned long volatile *p);
/*
    Atomically fetch *p and set it nonzero.
*/

#endif



/*
 * Switching / coroutine jump primitives
 */

extern void PCR←ThPvt←CoroutineJump(
    volatile PCR←jmp←buf jbFrom,
    volatile PCR←jmp←buf jbTo
);
/*
    Coroutine jump between contexts specified by from and to.
*/


extern void PCR←ThPvt←InitForCoroutineJump(
    void (*proc)(void),
    void * stk,
    volatile PCR←jmp←buf jb
);
/*
    Initialize the jmp←buf so the next longjmp or coroutine jump
      will have the effect of calling (*proc)() using specified stk.
    The proc promises not to return.
    The stk area is presumed to be big enough.

*/


#endif /* ! ←←PCR←ThPvt←h */

/*
$Log$
*/