mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-29 05:49:19 +00:00
239 lines
6.0 KiB
C
239 lines
6.0 KiB
C
/*
|
||
File: Sleep.c
|
||
|
||
Contains: Routines which facilitate sleeping processes.
|
||
|
||
Written by: Erich Ringewald
|
||
|
||
Copyright: © 1986-1992 by Apple Computer, Inc., all rights reserved.
|
||
|
||
Change History (most recent first):
|
||
|
||
<5> 3/23/92 JSM OSEvents.h is obsolete, use Events.h.
|
||
<4> 3/16/92 YK (for TSM) In clkint, If a physical event is not for the front
|
||
app, don’t switch to the front app.
|
||
<2> 11/27/90 DFH Removed unneeded parameter from cpu_resched.
|
||
<0> 3/13/86 ELR New Today.
|
||
|
||
*/
|
||
|
||
#include <types.h>
|
||
#include <memory.h>
|
||
#include <osutils.h>
|
||
#include <files.h>
|
||
#include <quickdraw.h>
|
||
#include <windows.h>
|
||
#include <menus.h>
|
||
#include <events.h>
|
||
#include <resources.h>
|
||
#include <retrace.h>
|
||
#include <segload.h>
|
||
|
||
#include "Glue.h"
|
||
#include "Lomem.h"
|
||
#include "Data.h"
|
||
#include "SysMisc.h"
|
||
#include "Puppet.h"
|
||
|
||
/* Some function prototypes that should be in (yet another) header file */
|
||
void RemoveFromStateList(PEntryPtr, PEntryPtr *);
|
||
void CancelSleep(PEntryPtr);
|
||
Boolean OSEventAvailForFront(short, EventRecord *);
|
||
|
||
/* Function prototypes internal to this file */
|
||
void RoustSleepers(void);
|
||
void PutOnSleepQueue(PEntryPtr, unsigned long);
|
||
void RoustSleepers(void);
|
||
|
||
/* PutOnSleepQueue. Put the specified process on the sleep queue with the designated
|
||
* sleep time.
|
||
*/
|
||
void
|
||
PutOnSleepQueue(PEntryPtr pProc, unsigned long sleepTime)
|
||
{
|
||
register PEntryPtr pPrev, pNext;
|
||
unsigned long thenTicks;
|
||
|
||
if (sleepTime == 0)
|
||
return;
|
||
|
||
/* Figure out time to wakeup. Pin overflow to highest TICKS value. */
|
||
thenTicks = TICKS + sleepTime;
|
||
if (thenTicks < sleepTime)
|
||
thenTicks = MAXVALUE;
|
||
|
||
/* reflect process state in PEntry */
|
||
pProc->p_state = PRSLEEPING;
|
||
pProc->p_wakeuptime = thenTicks;
|
||
|
||
/* Place process in the (ordered) sleep state list */
|
||
pPrev = nil;
|
||
pNext = pSleepingStateList;
|
||
while (pNext != nil)
|
||
{
|
||
unsigned long tempTicks;
|
||
|
||
if ( ((tempTicks = pNext->p_wakeuptime) != 0) && (tempTicks > thenTicks) )
|
||
break;
|
||
pPrev = pNext;
|
||
pNext = pNext->p_NextProcessInState;
|
||
}
|
||
|
||
/* Have insertion point. Fix up newcomer's links, then insert. */
|
||
assert((pProc != pPrev) && (pProc != pNext));
|
||
pProc->p_PrevProcessInState = pPrev;
|
||
pProc->p_NextProcessInState = pNext;
|
||
|
||
if (pPrev == nil)
|
||
pSleepingStateList = pProc;
|
||
else
|
||
pPrev->p_NextProcessInState = pProc;
|
||
|
||
if (pNext != nil)
|
||
pNext->p_PrevProcessInState = pProc;
|
||
}
|
||
|
||
/* SleepProcess. put the calling process to sleep. Call resched to arrange for
|
||
* another process to use the processor.
|
||
*/
|
||
pascal void
|
||
c_SleepProcess(u_long napTime)
|
||
{
|
||
PEntryPtr pCurr;
|
||
u_long olda5;
|
||
|
||
olda5 = ProcessMgrA5SimpleSetup();
|
||
|
||
/* can't sleep if not running */
|
||
pCurr = pCurrentProcess;
|
||
if ( (pCurr->p_state != PRRUN) &&
|
||
(pCurr->p_state != PRBACKRUN) )
|
||
{
|
||
A5SimpleRestore(olda5);
|
||
return;
|
||
}
|
||
|
||
/* can't sleep if coercing */
|
||
if (coercionState != CS_DONE)
|
||
{
|
||
A5SimpleRestore(olda5);
|
||
return;
|
||
}
|
||
|
||
PutOnSleepQueue(pCurr, napTime);
|
||
|
||
/* offer up the machine */
|
||
cpu_resched();
|
||
|
||
A5SimpleRestore(olda5);
|
||
}
|
||
|
||
/* clkint. This routine simulates processing on a clock interrupt. This is silly,
|
||
* and for now we call this thing from the idle loop.
|
||
*/
|
||
void
|
||
clkint(void)
|
||
{
|
||
EventRecord evtRec;
|
||
unsigned long olda5;
|
||
|
||
olda5 = ProcessMgrA5SimpleSetup();
|
||
|
||
/* See if anyone's time is up */
|
||
RoustSleepers();
|
||
|
||
/* Get frontmost app going if there's a physical event queued */
|
||
assert(coercionState == CS_DONE);
|
||
if ( (pFrontProcess->p_state == PRSLEEPING) && OSEventAvailForFront(pFrontProcess->p_eventmask, &evtRec) )
|
||
CancelSleep(pFrontProcess);
|
||
|
||
A5Restore(olda5);
|
||
}
|
||
|
||
/* PushOnStateList. Links process into head of given state list */
|
||
void
|
||
PushOnStateList(register PEntryPtr pProc, PEntryPtr *ppList)
|
||
{
|
||
PEntryPtr pFirstProc;
|
||
|
||
pFirstProc = *ppList;
|
||
pProc->p_NextProcessInState = pFirstProc;
|
||
pProc->p_PrevProcessInState = nil;
|
||
pFirstProc->p_PrevProcessInState = pProc;
|
||
*ppList = pProc;
|
||
}
|
||
|
||
/* RemoveFromStateList. Unlinks process from given state list */
|
||
void
|
||
RemoveFromStateList(register PEntryPtr pProc, PEntryPtr *ppList)
|
||
{
|
||
PEntryPtr pOtherProc;
|
||
|
||
if ((pOtherProc = pProc->p_PrevProcessInState) != nil)
|
||
pOtherProc->p_NextProcessInState = pProc->p_NextProcessInState;
|
||
else
|
||
*ppList = pProc->p_NextProcessInState;
|
||
|
||
if ((pOtherProc = pProc->p_NextProcessInState) != nil)
|
||
pOtherProc->p_PrevProcessInState = pProc->p_PrevProcessInState;
|
||
|
||
pProc->p_PrevProcessInState = nil;
|
||
pProc->p_NextProcessInState = nil;
|
||
}
|
||
|
||
/* RoustSleepers. This fellow is called by the 'clock interrupt'. It dequeues all
|
||
* members that have expired. The queue is ordered by p_wakeuptime, so normally
|
||
* we go no farther than a PEntry that should not be woken. The exception to this,
|
||
* of course, is when napOver == true, since that means that there are processes
|
||
* that are to be woken up prematurely (their p_wakeuptime == 0).
|
||
* NOTE: We turn interrupts off to protect this critical region against interference
|
||
* from WakeupProcess calls by interrupt routines.
|
||
*/
|
||
void
|
||
RoustSleepers(void)
|
||
{
|
||
register PEntryPtr pProc, pNextProc;
|
||
short ps;
|
||
|
||
ps = disable();
|
||
pProc = pSleepingStateList;
|
||
while (pProc != nil)
|
||
{
|
||
/* must get this now, since RemoveFromStateList() changes it */
|
||
pNextProc = pProc->p_NextProcessInState;
|
||
|
||
/* see if this guy should wake up now */
|
||
if (pProc->p_wakeuptime <= (unsigned long) TICKS)
|
||
{
|
||
RemoveFromStateList(pProc, &pSleepingStateList);
|
||
pProc->p_state = PRREADY;
|
||
}
|
||
else if (napOver == false)
|
||
break;
|
||
|
||
/* move on */
|
||
pProc = pNextProc;
|
||
}
|
||
|
||
napOver = false;
|
||
spl(ps);
|
||
}
|
||
|
||
/* CancelSleep. Ensures that pProc gets out of its current event call. */
|
||
void
|
||
CancelSleep(PEntryPtr pProc)
|
||
{
|
||
/* make sure the process is awake */
|
||
if (pProc->p_state == PRSLEEPING)
|
||
{
|
||
RemoveFromStateList(pProc, &pSleepingStateList);
|
||
pProc->p_state = PRREADY;
|
||
}
|
||
|
||
/* make sure the process stays awake. A zeroed p_wakeuptime means that the app
|
||
* will not go to sleep on the way out of its current event call. We must do this
|
||
* even if app is not asleep to begin with.
|
||
*/
|
||
pProc->p_wakeuptime = 0;
|
||
}
|