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

$Date$
 *
 * Basic public type definitions for PCR threads
 *
 */


#ifndef	←←PCR←Th←h
#define ←←PCR←Th←h 1


#include <config/PCR←Arch.h>
#include <config/PCR←StdDefs.h>
#include <sig/PCR←Sig.h>
#include <th/PCR←ThTypes.h>


/*
 * Monitor Locks
 *
 * MLs are opaque but clients may allocate and initialize them.
 */

extern struct PCR←Th←MLRep const PCR←Th←ML←readonlyNull;

extern void
PCR←Th←ML←Init(PCR←Th←ML *ml);


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

extern struct PCR←Th←CVRep const PCR←Th←CV←readonlyNull;

extern void
PCR←Th←CV←Init(PCR←Th←CV *cv);


/*
 * Priority
 *
 * Client priorities must lie between userBackground and userForeground.
 */

extern const PCR←Th←Pri	PCR←Th←Pri←readonlyUserBackground;
extern const PCR←Th←Pri	PCR←Th←Pri←readonlyUserNormal;
extern const PCR←Th←Pri	PCR←Th←Pri←readonlyUserForeground;

extern const PCR←Th←Pri PCR←Th←Pri←readonlyStopped;
extern const PCR←Th←Pri PCR←Th←Pri←readonlyIdle;

/*
 *
 * Control of waiting primitives
 *
 */

/* timeout */

extern PCR←Msec
PCR←Th←WakeMsec(PCR←Msec interval);
/*
    Compute wakeup time (msec since boot or PCR←Msec←waitForever)
      from interval (or PCR←Msec←waitForever)
*/

extern PCR←Msec
PCR←Th←MsecSinceBoot(void);
/*
    Equivalent to PCR←Th←WakeMsec(0)
*/

extern PCR←Msec volatile PCR←SigGlue←msecSinceBoot;
#define PCR←Th←←MsecSinceBoot() PCR←SigGlue←msecSinceBoot
#define PCR←Th←MsecSinceBoot	PCR←Th←←MsecSinceBoot


/* sig mask */

#   define PCR←allSigsBlocked	(&PCR←sigset←t←readonlyFull)
#   define PCR←noSigsBlocked	(&PCR←sigset←t←readonlyEmpty)
#   define PCR←sigsBlockedUnchanged	NIL


/*********************************************************

    Public Procedures

/*********************************************************/


/*
 * Monitor entry/exit
 */

extern PCR←ERes
PCR←Th←ML←TestAndLock( PCR←Th←ML *ml,
        const PCR←sigset←t *sigMask, PCR←Msec wakeup );
/*
    Acquire lock.
    The existence of a pending signal (or arrival of a signal) not blocked
    by sigMask results in failure (EINTR).

    Success:
      (lock has been acquired, sigmask unchanged)
      PCR←ERes←okay
    Failure:
      (lock has not been acquired, sigmask unchanged)
      PCR←ETIMEDOUT
      EINTR

    NOTE: this differs from the Cedar semantics.  It is
      something of an experiment, but since we'll need
      to wrap this procedure for Cedar anyway ...
*/


extern void
PCR←Th←ML←Acquire(PCR←Th←ML *ml);
/*
    Equivalent to (but faster than)
        (void)PCR←Th←ML←TestAndLock( ml,
                PCR←allSigsBlocked, PCR←waitForever )
*/

extern PCR←ERes
PCR←Th←ML←Try(PCR←Th←ML *ml);
/*
    Equivalent to (but faster than)
        (void)PCR←Th←ML←TestAndLock( ml,
                PCR←sigsBlockedUnchanged, PCR←dontWait )
*/

extern void
PCR←Th←ML←Release(PCR←Th←ML *ml);
/*
    Release lock.
*/


/*
 * Condition wait/notify
 */

extern PCR←ERes
PCR←Th←CV←Wait( PCR←Th←CV *cv, PCR←Th←ML *ml,
        const PCR←sigset←t *sigMask, PCR←Msec wakeup );
/*
    Atomically release *ml (if not NIL) and
      - if cv has been sticky-notified, return PCR←ERes←okay immediately
      - otherwise wait for the cv to be notified.
    This is not an interruption point, but the existence of a pending
      signal (or arrival of a signal) not blocked by sigMask results
      in failure (EINTR).


    Success:
      PCR←ERes←okay
    Failure:
      PCR←ETIMEDOUT
      EINTR

    NOTE: this differs from the Cedar semantics, particularly
      in not ever re-acquiring the ml.  It is
      something of an experiment, but since we'll need
      to wrap this procedure for Cedar anyway ...
*/


extern void
PCR←Th←CV←Notify(
    PCR←Th←CV *cv
);
/*
    Notify cv.
*/


extern void
PCR←Th←CV←StickyNotify(
    PCR←Th←CV *cv
);
/*
    Do "sticky" notify of cv -- one notification will be remembered
      if it occurs before the corresponding wait.  This behavior
      is analogous to a binary semaphore.
*/


extern void
PCR←Th←CV←Reset(
    PCR←Th←CV *cv
);
/*
    Discard any remembered sticky notify on cv.
    It is okay to do this even if there are threads waiting on the condition.
*/


extern void
PCR←Th←CV←Broadcast(
    PCR←Th←CV *cv
);
/*
    Broadcast cv -- notify every thread currently waiting on it.
*/



/*
 * Thread manipulation
 */

extern PCR←Th←T *
(PCR←Th←CurrThread(void));
/*
    Return the current thread.
*/

extern PCR←Th←T *
(PCR←Th←Fork ( PCR←ProcPtr proc, PCR←Any data ));
/*
    Fork a thread running (*proc)(data).
    Return PCR←Th←T for child thread.
    If insufficient resources are available return NIL.
*/



extern PCR←ERes
PCR←Th←T←Join(
    PCR←Th←T *t,
    int *codep, PCR←Any *valp,
    const PCR←sigset←t *sigMask, PCR←Msec wakeup
);
/*
    JOIN with `t'.
    If codep != NIL, store exit code of t there.
    If valp != NIL, store exit val of t there.
      (See PCR←Exit below).
    A pending signal (or arrival of a signal) not blocked by sigMask
      results in failure (EINTR).

    Success:
      PCR←ERes←okay
    Failure:
      EFAULT or EINVAL -- t not a valid thread pointer;
      PCR←ETIMEDOUT
      EINTR

    NOTE: there may be multiple joiners with a thread.
*/



extern PCR←ERes
PCR←Th←Pause( const PCR←sigset←t *sigMask, PCR←Msec wakeup );
/*
    Pause until the specified wakeup time,
      or until a signal is delivered.
    This is not an interruption point, but the existence of a pending
      signal (or arrival of a signal) not blocked by sigMask results
      in failure (EINTR).
    Result is always "failure":
      PCR←ETIMEDOUT if timeout reached,
      EINTR signal pending/arrived.
*/


extern void
PCR←Th←Exit(int code, PCR←Any val);
/*
    Terminate current thread, passing code and val to any joiners
      (see PCR←Th←T←Join above).
    This unwinds the stack -- see PCR←ThUWProt.h
*/


extern PCR←ERes
PCR←Th←SetPri(
    const PCR←Th←Pri *pri,
    PCR←Th←Pri *old
);
/*
    Get/set scheduling priority.

    Success:
      (if pri != NIL priority of current thread changed to *pri)
      (if old != NIL old priority stored in *old)
      0

    NOTE: pri and old may be equal pointers -- *pri is retrieved
      before *old is stored.
*/


extern void
PCR←Th←T←YieldTo (
    PCR←Th←T *t
);
/*
    Yield processor to `t'
      (t invalid or NIL => let scheduler decide).
*/



/*
 * Signal handling
 */


extern PCR←ERes
PCR←Th←SetSigMask(
    const PCR←sigset←t *mask,
    PCR←sigset←t *old
);
/*
    If old != NIL, return current sigmask in *old.
    If mask != NIL, update sigmask from it.

    Success:
      PCR←ERes←okay
    Failure:
      EFAULT if mask or old not valid
*/



extern PCR←ERes
PCR←Th←SetSigAction(
    int sig,
    const PCR←Sig←Action *act,
    PCR←Sig←Action *old
);
/*
    If act != NIL, set signal action for specified signal in current thread.
    If old != NIL, store previous action there.
    Success:
      PCR←ERes←okay
    Failure:
      EINVAL -- bad signal number
      EFAULT -- bad act pointer
*/

extern PCR←ERes
PCR←Th←SetSigActions(
    const PCR←sigset←t * sigsp,
    const PCR←Sig←Action *act
);
/*
    Equivalent to an atomic loop of SetSigAction calls for each
      member of *sigsp.
*/


extern PCR←ERes
PCR←Th←T←SendSigs (
    PCR←Th←T *t,
    const PCR←sigset←t *sigs
);
/*
    Send specified signals to t.

    Success:
      0
    Failure:
      EFAULT or EINVAL if t not a valid thread pointer;
      ESRCH if t already finished.
*/


extern PCR←ERes
PCR←Th←T←SigsPending (
    PCR←Th←T *t,
    PCR←sigset←t /* result */ * pending 
);
/*
    Determine the set of signals pending for t.

    Success:
      PCR←ERes←okay.
    Failure:
      EFAULT or EINVAL if t not a valid thread pointer;
      EINVAL if signo not valid;
      ESRCH if t already finished.
*/


extern PCR←ERes
PCR←Th←T←CancelSigs (
    PCR←Th←T *t,
    const PCR←sigset←t *sigs
);
/*
    Cancel any of the specified signal requests for t.

    Success:
      PCR←ERes←okay
    Failure:
      EFAULT or EINVAL if t not a valid thread pointer;
      ESRCH if t already finished.
*/



/* stack size queries */

extern unsigned long
PCR←Th←GuessFrameBytes(void *p);
/*
    If p is address of first variable in caller's frame,
      return approximate size in bytes of caller's frame.
    If p is NIL,
      return approximate size in bytes of min-size frame.
*/

extern unsigned long
PCR←Th←GuessRemainingStackBytes(PCR←Th←T *t);
/*
    Guess approximate number of stack bytes remaining available
      to thread t (NIL => current thread).
*/

extern PCR←Bool
PCR←Th←EnoughStackBytes(unsigned long size);
/*
    Return PCR←Bool←true if at least size stack bytes are available
      to the current thread.
    This is the fastest way to do such a check for the current thread. 
*/

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

/*
$Log$
*/