home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.pdx.edu / 2014.02.ftp.ee.pdx.edu.tar / ftp.ee.pdx.edu / pub / users / Harry / Blitz / OSProject / p4 / Kernel.c < prev    next >
Text File  |  2009-04-09  |  57KB  |  1,673 lines

  1. code Kernel
  2.  
  3.   -- <PUT YOUR NAME HERE>
  4.  
  5. -----------------------------  InitializeScheduler  ---------------------------------
  6.  
  7.   function InitializeScheduler ()
  8.     --
  9.     -- This routine assumes that we are in System mode.  It sets up the
  10.     -- thread scheduler and turns the executing program into "main-thread".
  11.     -- After exit, we can execute "Yield", "Fork", etc.  Upon return, the
  12.     -- main-thread will be executing with interrupts enabled.
  13.     --
  14.       Cleari ()
  15.       print ("Initializing Thread Scheduler...\n")
  16.       readyList = new List [Thread]
  17.       threadsToBeDestroyed = new List [Thread]
  18.       mainThread = new Thread
  19.       mainThread.Init ("main-thread")
  20.       mainThread.status = RUNNING
  21.       idleThread = new Thread
  22.       idleThread.Init ("idle-thread")
  23.       idleThread.Fork (IdleFunction, 0)
  24.       currentThread = & mainThread
  25.       FatalError = FatalError_ThreadVersion       -- Use a routine which prints threadname
  26.       currentInterruptStatus = ENABLED
  27.       Seti ()
  28.     endFunction
  29.  
  30. -----------------------------  IdleFunction  ---------------------------------
  31.  
  32.   function IdleFunction (arg: int)
  33.     --
  34.     -- This is the "idle thread", a kernel thread which ensures that the ready
  35.     -- list is never empty.  The idle thread constantly yields to other threads
  36.     -- in an infinite loop.  However, before yielding, it first checks to see if
  37.     -- there are other threads.  If there are no other threads, the idle thread
  38.     -- will execute the "wait" instruction.  The "wait" instruction will enable
  39.     -- interrupts and halt CPU execution until the next interrupt arrives.
  40.     --
  41.       var junk: int
  42.       while true
  43.         junk = SetInterruptsTo (DISABLED)
  44.         if readyList.IsEmpty ()
  45.           Wait ()
  46.         else
  47.           currentThread.Yield ()
  48.         endIf
  49.       endWhile
  50.     endFunction
  51.  
  52. -----------------------------  Run  ---------------------------------
  53.  
  54.   function Run (nextThread: ptr to Thread)
  55.     --
  56.     -- Begin executing the thread "nextThread", which has already
  57.     -- been removed from the readyList.  The current thread will
  58.     -- be suspended; we assume that its status has already been
  59.     -- changed to READY or BLOCKED.  We assume that interrupts are
  60.     -- DISABLED when called.
  61.     --
  62.     -- This routine is called only from "Thread.Yield" and "Thread.Sleep".
  63.     --
  64.     -- It is allowable for nextThread to be currentThread.
  65.     --
  66.       var prevThread, th: ptr to Thread
  67.       prevThread = currentThread
  68.       prevThread.CheckOverflow ()
  69.       -- If the previous thread was using the USER registers, save them.
  70.       if prevThread.isUserThread
  71.         SaveUserRegs (&prevThread.userRegs[0])
  72.       endIf
  73.       currentThread = nextThread
  74.       nextThread.status = RUNNING
  75.       --print ("SWITCHING from ")
  76.       --print (prevThread.name)
  77.       --print (" to ")
  78.       --print (nextThread.name)
  79.       --print ("\n")
  80.       Switch (prevThread, nextThread)
  81.       --print ("After SWITCH, back in thread ")
  82.       --print (currentThread.name)
  83.       --print ("\n")
  84.       while ! threadsToBeDestroyed.IsEmpty ()
  85.         th = threadsToBeDestroyed.Remove()
  86.         threadManager.FreeThread (th)
  87.       endWhile
  88.       -- If the new thread uses the USER registers, restore them.
  89.       if currentThread.isUserThread
  90.         RestoreUserRegs (¤tThread.userRegs[0])
  91.         currentThread.myProcess.addrSpace.SetToThisPageTable ()
  92.       endIf
  93.     endFunction
  94.  
  95. -----------------------------  PrintReadyList  ---------------------------------
  96.  
  97.   function PrintReadyList ()
  98.     --
  99.     -- This routine prints the readyList.  It disables interrupts during the
  100.     -- printing to guarantee that the readyList won't change while it is
  101.     -- being printed, which could cause disaster in this routine!
  102.     --
  103.     var oldStatus: int
  104.       oldStatus = SetInterruptsTo (DISABLED)
  105.       print ("Here is the ready list:\n")
  106.       readyList.ApplyToEach (ThreadPrintShort)
  107.       oldStatus = SetInterruptsTo (oldStatus)
  108.     endFunction
  109.  
  110. -----------------------------  ThreadStartMain  ---------------------------------
  111.  
  112.   function ThreadStartMain ()
  113.     --
  114.     -- This function is called from the assembly language routine "ThreadStart".
  115.     -- It is the first KPL code each thread will execute, and it will
  116.     -- invoke the thread's "main" function, with interrupts enabled.  If the "main"
  117.     -- function ever returns, this function will terminate this thread.  This
  118.     -- function will never return.
  119.     --
  120.       var
  121.         junk: int
  122.         mainFun: ptr to function (int)
  123.       -- print ("ThreadStartMain...\n")
  124.       junk = SetInterruptsTo (ENABLED)
  125.       mainFun = currentThread.initialFunction
  126.       mainFun (currentThread.initialArgument)
  127.       ThreadFinish ()
  128.       FatalError ("ThreadFinish should never return")
  129.     endFunction
  130.  
  131. -----------------------------  ThreadFinish  ---------------------------------
  132.  
  133.   function ThreadFinish ()
  134.     --
  135.     -- As the last thing to do in this thread, we want to clean up
  136.     -- and reclaim the Thread object.  This method is called as the
  137.     -- last thing the thread does; this is the normal way for a thread
  138.     -- to die.  However, since the thread is still running in this,
  139.     -- we can't actually do the clean up.  So we just make a note
  140.     -- that it is pending.  After the next thread starts (in method "Run")
  141.     -- we'll finish the job.
  142.     --
  143.       var junk: int
  144.       junk = SetInterruptsTo (DISABLED)
  145.       -- print ("Finishing ")
  146.       -- print (currentThread.name)
  147.       -- print ("\n")
  148.       threadsToBeDestroyed.AddToEnd (currentThread)
  149.       currentThread.Sleep ()
  150.       -- Execution will never reach the next instruction
  151.       FatalError ("This thread will never run again")
  152.     endFunction
  153.  
  154. -----------------------------  FatalError_ThreadVersion  -----------------------
  155.  
  156.   function FatalError_ThreadVersion (errorMessage: ptr to array of char)
  157.     --
  158.     -- This function will print out the name of the current thread and
  159.     -- the given error message.  Then it will call "RuntimeExit" to
  160.     -- shutdown the system.
  161.     --
  162.       var
  163.         junk: int
  164.       junk = SetInterruptsTo (DISABLED)
  165.       print ("\nFATAL ERROR")
  166.       if currentThread    -- In case errors occur before thread initialization
  167.         print (" in ")
  168.         print (currentThread.name)
  169.       endIf
  170.       print (": \"")
  171.       print (errorMessage)
  172.       print ("\" -- TERMINATING!\n\n")
  173.       print ("(To find out where execution was when the problem arose, type 'st' at the emulator prompt.)\n")
  174.       RuntimeExit ()
  175.     endFunction
  176.  
  177. -----------------------------  SetInterruptsTo  ---------------------------------
  178.  
  179.   function SetInterruptsTo (newStatus: int) returns int
  180.     --
  181.     -- This routine is passed a status (DISABLED or ENABLED).  It
  182.     -- returns the previous interrupt status and sets the interrupt
  183.     -- status to "newStatus".
  184.     --
  185.     -- Since this routine reads and modifies a shared variable
  186.     -- (currentInterruptStatus), there is a danger of this routine
  187.     -- being re-entered.  Therefore, it momentarily will disable
  188.     -- interrupts, to ensure a valid update to this variable.
  189.     --
  190.       var
  191.         oldStat: int
  192.       Cleari ()
  193.       oldStat = currentInterruptStatus
  194.       if newStatus == ENABLED
  195.         currentInterruptStatus = ENABLED
  196.         Seti ()
  197.       else
  198.         currentInterruptStatus = DISABLED
  199.         Cleari ()
  200.       endIf
  201.       return oldStat
  202.     endFunction
  203.  
  204. -----------------------------  Semaphore  ---------------------------------
  205.  
  206.   behavior Semaphore
  207.     -- This class provides the following methods:
  208.     --    Up()  ...also known as "V" or "Signal"...
  209.     --         Increment the semaphore count.  Wake up a thread if
  210.     --         there are any waiting.  This operation always executes
  211.     --         quickly and will not suspend the thread.
  212.     --    Down()   ...also known as "P" or "Wait"...
  213.     --         Decrement the semaphore count.  If the count would go
  214.     --         negative, wait for some other thread to do an Up()
  215.     --         first.  Conceptually, the count will never go negative.
  216.     --    Init(initialCount)
  217.     --         Each semaphore must be initialized.  Normally, you should
  218.     --         invoke this method, providing an 'initialCount' of zero.
  219.     --         If the semaphore is initialized with 0, then a Down()
  220.     --         operation before any Up() will wait for the first
  221.     --         Up().  If initialized with i, then it is as if i Up()
  222.     --         operations have been performed already.
  223.     --
  224.     -- NOTE: The user should never look at a semaphore's count since the value
  225.     -- retrieved may be out-of-date, due to other threads performing Up() or
  226.     -- Down() operations since the retrieval of the count.
  227.  
  228.       ----------  Semaphore . Init  ----------
  229.  
  230.       method Init (initialCount: int)
  231.           if initialCount < 0
  232.             FatalError ("Semaphore created with initialCount < 0")
  233.           endIf
  234.           count = initialCount
  235.           waitingThreads = new List [Thread]
  236.         endMethod
  237.  
  238.       ----------  Semaphore . Up  ----------
  239.  
  240.       method Up ()
  241.           var
  242.             oldIntStat: int
  243.             t: ptr to Thread
  244.           oldIntStat = SetInterruptsTo (DISABLED)
  245.           if count == 0x7fffffff
  246.             FatalError ("Semaphore count overflowed during 'Up' operation")
  247.           endIf
  248.           count = count + 1
  249.           if count <= 0
  250.             t = waitingThreads.Remove ()
  251.             t.status = READY
  252.             readyList.AddToEnd (t)
  253.           endIf
  254.           oldIntStat = SetInterruptsTo (oldIntStat)
  255.         endMethod
  256.  
  257.       ----------  Semaphore . Down  ----------
  258.  
  259.       method Down ()
  260.           var
  261.             oldIntStat: int
  262.           oldIntStat = SetInterruptsTo (DISABLED)
  263.           if count == 0x80000000
  264.             FatalError ("Semaphore count underflowed during 'Down' operation")
  265.           endIf
  266.           count = count - 1
  267.           if count < 0
  268.             waitingThreads.AddToEnd (currentThread)
  269.             currentThread.Sleep ()
  270.           endIf
  271.           oldIntStat = SetInterruptsTo (oldIntStat)
  272.         endMethod
  273.  
  274.   endBehavior
  275.  
  276. -----------------------------  Mutex  ---------------------------------
  277.  
  278.   behavior Mutex
  279.     -- This class provides the following methods:
  280.     --    Lock()
  281.     --         Acquire the mutex if free, otherwise wait until the mutex is
  282.     --         free and then get it.
  283.     --    Unlock()
  284.     --         Release the mutex.  If other threads are waiting, then
  285.     --         wake up the oldest one and give it the lock.
  286.     --    Init()
  287.     --         Each mutex must be initialized.
  288.     --    IsHeldByCurrentThread()
  289.     --         Return TRUE iff the current (invoking) thread holds a lock
  290.     --         on the mutex.
  291.  
  292.        -----------  Mutex . Init  -----------
  293.  
  294.        method Init ()
  295.            waitingThreads = new List [Thread]
  296.          endMethod
  297.  
  298.        -----------  Mutex . Lock  -----------
  299.  
  300.        method Lock ()
  301.            var
  302.              oldIntStat: int
  303.            if heldBy == currentThread
  304.              FatalError ("Attempt to lock a mutex by a thread already holding it")
  305.            endIf
  306.            oldIntStat = SetInterruptsTo (DISABLED)
  307.            if !heldBy
  308.              heldBy = currentThread
  309.            else
  310.              waitingThreads.AddToEnd (currentThread)
  311.              currentThread.Sleep ()
  312.            endIf
  313.            oldIntStat = SetInterruptsTo (oldIntStat)
  314.          endMethod
  315.  
  316.        -----------  Mutex . Unlock  -----------
  317.  
  318.        method Unlock ()
  319.            var
  320.              oldIntStat: int
  321.              t: ptr to Thread
  322.            if heldBy != currentThread
  323.              FatalError ("Attempt to unlock a mutex by a thread not holding it")
  324.            endIf
  325.            oldIntStat = SetInterruptsTo (DISABLED)
  326.            t = waitingThreads.Remove ()
  327.            if t
  328.              t.status = READY
  329.              readyList.AddToEnd (t)
  330.              heldBy = t
  331.            else
  332.              heldBy = null
  333.            endIf
  334.            oldIntStat = SetInterruptsTo (oldIntStat)
  335.          endMethod
  336.  
  337.        -----------  Mutex . IsHeldByCurrentThread  -----------
  338.  
  339.        method IsHeldByCurrentThread () returns bool
  340.            return heldBy == currentThread
  341.          endMethod
  342.  
  343.   endBehavior
  344.  
  345. -----------------------------  Condition  ---------------------------------
  346.  
  347.   behavior Condition
  348.     -- This class is used to implement monitors.  Each monitor will have a
  349.     -- mutex lock and one or more condition variables.  The lock ensures that
  350.     -- only one process at a time may execute code in the monitor.  Within the
  351.     -- monitor code, a thread can execute Wait() and Signal() operations
  352.     -- on the condition variables to make sure certain condions are met.
  353.     --
  354.     -- The condition variables here implement "Mesa-style" semantics, which
  355.     -- means that in the time between a Signal() operation and the awakening
  356.     -- and execution of the corrsponding waiting thread, other threads may
  357.     -- have snuck in and run.  The waiting thread should always re-check the
  358.     -- data to ensure that the condition which was signalled is still true.
  359.     --
  360.     -- This class provides the following methods:
  361.     --    Wait(mutex)
  362.     --         This method assumes the mutex has alreasy been locked.
  363.     --         It unlocks it, and goes to sleep waiting for a signal on
  364.     --         this condition.  When the signal is received, this method
  365.     --         re-awakens, re-locks the mutex, and returns.
  366.     --    Signal(mutex)
  367.     --         If there are any threads waiting on this condition, this
  368.     --         method will wake up the oldest and schedule it to run.
  369.     --         However, since this thread holds the mutex and never unlocks
  370.     --         it, the newly awakened thread will be forced to wait before
  371.     --         it can re-acquire the mutex and resume execution.
  372.     --    Broadcast(mutex)
  373.     --         This method is like Signal() except that it wakes up all
  374.     --         threads waiting on this condition, not just the next one.
  375.     --    Init()
  376.     --         Each condition must be initialized.
  377.  
  378.       ----------  Condition . Init  ----------
  379.  
  380.       method Init ()
  381.           waitingThreads = new List [Thread]
  382.         endMethod
  383.  
  384.       ----------  Condition . Wait  ----------
  385.  
  386.       method Wait (mutex: ptr to Mutex)
  387.           var
  388.             oldIntStat: int
  389.           if ! mutex.IsHeldByCurrentThread ()
  390.             FatalError ("Attempt to wait on condition when mutex is not held")
  391.           endIf
  392.           oldIntStat = SetInterruptsTo (DISABLED)
  393.           mutex.Unlock ()
  394.           waitingThreads.AddToEnd (currentThread)
  395.           currentThread.Sleep ()
  396.           mutex.Lock ()
  397.           oldIntStat = SetInterruptsTo (oldIntStat)
  398.         endMethod
  399.  
  400.       ----------  Condition . Signal  ----------
  401.  
  402.       method Signal (mutex: ptr to Mutex)
  403.           var
  404.             oldIntStat: int
  405.             t: ptr to Thread
  406.           if ! mutex.IsHeldByCurrentThread ()
  407.             FatalError ("Attempt to signal a condition when mutex is not held")
  408.           endIf
  409.           oldIntStat = SetInterruptsTo (DISABLED)
  410.           t = waitingThreads.Remove ()
  411.           if t
  412.             t.status = READY
  413.             readyList.AddToEnd (t)
  414.           endIf
  415.           oldIntStat = SetInterruptsTo (oldIntStat)
  416.         endMethod
  417.  
  418.       ----------  Condition . Broadcast  ----------
  419.  
  420.       method Broadcast (mutex: ptr to Mutex)
  421.           var
  422.             oldIntStat: int
  423.             t: ptr to Thread
  424.           if ! mutex.IsHeldByCurrentThread ()
  425.             FatalError ("Attempt to broadcast a condition when lock is not held")
  426.           endIf
  427.           oldIntStat = SetInterruptsTo (DISABLED)
  428.           while true
  429.             t = waitingThreads.Remove ()
  430.             if t == null
  431.               break
  432.             endIf
  433.             t.status = READY
  434.             readyList.AddToEnd (t)
  435.           endWhile
  436.           oldIntStat = SetInterruptsTo (oldIntStat)
  437.         endMethod
  438.  
  439.   endBehavior
  440.  
  441. -----------------------------  Thread  ---------------------------------
  442.  
  443.   behavior Thread
  444.  
  445.       ----------  Thread . Init  ----------
  446.  
  447.       method Init (n: String)
  448.         --
  449.         -- Initialize this Thread object, but do not schedule it for
  450.         -- execution yet.
  451.         --
  452.           name = n
  453.           status = JUST_CREATED
  454.           -- The next line initializes the systemStack array, without filling it in.
  455.           *((& systemStack) asPtrTo int) = SYSTEM_STACK_SIZE
  456.           systemStack [0] = STACK_SENTINEL
  457.           systemStack [SYSTEM_STACK_SIZE-1] = STACK_SENTINEL
  458.           stackTop = & (systemStack[SYSTEM_STACK_SIZE-1])
  459.           regs = new array of int { 13 of 0 }
  460.           isUserThread = false
  461.           userRegs = new array of int { 15 of 0 }
  462.         endMethod
  463.  
  464.       ----------  Thread . Fork  ----------
  465.  
  466.       method Fork (fun: ptr to function (int), arg: int)
  467.         --
  468.         -- This method will schedule this thread for execution; in other words
  469.         -- it will make it ready to run by adding it to the "ready queue."  This
  470.         -- method is passed a function and a single integer argument.  When the
  471.         -- thread runs, the thread will execute this function on that argument
  472.         -- and then termiante.  This method will return after scheduling this
  473.         -- thread.
  474.         --
  475.           var
  476.             oldIntStat, junk: int
  477.           oldIntStat = SetInterruptsTo (DISABLED)
  478.           -- print ("Forking thread...\n")
  479.           initialFunction = fun
  480.           initialArgument = arg
  481.           stackTop = stackTop - 4
  482.           *(stackTop asPtrTo int) = ThreadStartUp asInteger
  483.           status = READY
  484.           readyList.AddToEnd (self)
  485.           junk = SetInterruptsTo (oldIntStat)
  486.         endMethod
  487.  
  488.       ----------  Thread . Yield  ----------
  489.  
  490.       method Yield ()
  491.         --
  492.         -- This method should only be invoked on the current thread.  The
  493.         -- current thread may yield the processor to other threads by
  494.         -- executing:
  495.         --       currentThread.Yield ()
  496.         -- This method may be invoked with or without interrupts enabled.
  497.         -- Upon return, the interrupts will be in the same state; however
  498.         -- since other threads are given a chance to run and they may allow
  499.         -- interrupts, interrupts handlers may have been invoked before
  500.         -- this method returns.
  501.         --
  502.           var
  503.             nextTh: ptr to Thread
  504.             oldIntStat, junk: int
  505.           -- ASSERT:
  506.               if self != currentThread
  507.                 FatalError ("In Yield, self != currentThread")
  508.               endIf
  509.           oldIntStat = SetInterruptsTo (DISABLED)
  510.           -- print ("Yielding ")
  511.           -- print (name)
  512.           -- print ("\n")
  513.           nextTh = readyList.Remove ()
  514.           if nextTh
  515.             -- print ("About to run ")
  516.             -- print (nextTh.name)
  517.             -- print ("\n")
  518.             if status == BLOCKED
  519.               FatalError ("Status of current thread should be READY or RUNNING")
  520.             endIf
  521.             status = READY
  522.             readyList.AddToEnd (self)
  523.             Run (nextTh)
  524.           endIf
  525.           junk = SetInterruptsTo (oldIntStat)
  526.         endMethod
  527.  
  528.       ----------  Thread . Sleep  ----------
  529.  
  530.       method Sleep ()
  531.         --
  532.         -- This method should only be invoked on the current thread.  It
  533.         -- will set the status of the current thread to BLCOKED and will
  534.         -- will switch to executing another thread.  It is assumed that
  535.         --     (1) Interrupts are disabled before calling this routine, and
  536.         --     (2) The current thread has been placed on some other wait
  537.         --         list (e.g., for a Semaphore) or else the thread will
  538.         --         never get scheduled again.
  539.         --
  540.           var nextTh: ptr to Thread
  541.           -- ASSERT:
  542.               if currentInterruptStatus != DISABLED
  543.                 FatalError ("In Sleep, currentInterruptStatus != DISABLED")
  544.               endIf
  545.           -- ASSERT:
  546.               if self != currentThread
  547.                 FatalError ("In Sleep, self != currentThread")
  548.               endIf
  549.           -- print ("Sleeping ")
  550.           -- print (name)
  551.           -- print ("\n")
  552.           status = BLOCKED
  553.           nextTh = readyList.Remove ()
  554.           if nextTh == null
  555.             FatalError ("Ready list should always contain the idle thread")
  556.           endIf
  557.           Run (nextTh)
  558.         endMethod
  559.  
  560.       ----------  Thread . CheckOverflow  ----------
  561.  
  562.       method CheckOverflow ()
  563.         --
  564.         -- This method checks to see if this thread has overflowed its
  565.         -- pre-alloted stack space.  WARNING: the approach taken here is only
  566.         -- guaranteed to work "with high probability".
  567.         --
  568.           if systemStack[0] != STACK_SENTINEL
  569.             FatalError ("System stack overflow detected!")
  570.           elseIf systemStack[SYSTEM_STACK_SIZE-1] != STACK_SENTINEL
  571.             FatalError ("System stack underflow detected!")
  572.           endIf
  573.         endMethod
  574.  
  575.       ----------  Thread . Print  ----------
  576.  
  577.       method Print ()
  578.         --
  579.         -- Print this object.
  580.         --
  581.           var i: int
  582.               oldStatus: int
  583.           oldStatus = SetInterruptsTo (DISABLED)
  584.           print ("  Thread \"")
  585.           print (name)
  586.           print ("\"    (addr of Thread object: ")
  587.           printHex (self asInteger)
  588.           print (")\n")
  589.           print ("    machine state:\n")
  590.           for i = 0 to 12
  591.             print ("      r")
  592.             printInt (i+2)
  593.             print (": ")
  594.             printHex (regs[i])
  595.             print ("   ")
  596.             printInt (regs[i])
  597.             print ("\n")
  598.           endFor
  599.           printHexVar ("    stackTop", stackTop asInteger)
  600.           printHexVar ("    stack starting addr", (& systemStack[0]) asInteger)
  601.           switch status
  602.             case JUST_CREATED:
  603.               print ("    status = JUST_CREATED\n")
  604.               break
  605.             case READY:
  606.               print ("    status = READY\n")
  607.               break
  608.             case RUNNING:
  609.               print ("    status = RUNNING\n")
  610.               break
  611.             case BLOCKED:
  612.               print ("    status = BLOCKED\n")
  613.               break
  614.             case UNUSED:
  615.               print ("    status = UNUSED\n")
  616.               break
  617.             default:
  618.               FatalError ("Bad status in Thread")
  619.           endSwitch
  620.           print ("    is user thread: ")
  621.           printBool (isUserThread)
  622.           nl ()
  623.           print ("    user registers:\n")
  624.           for i = 0 to 14
  625.             print ("      r")
  626.             printInt (i+1)
  627.             print (": ")
  628.             printHex (userRegs[i])
  629.             print ("   ")
  630.             printInt (userRegs[i])
  631.             print ("\n")
  632.           endFor
  633.           oldStatus = SetInterruptsTo (oldStatus)
  634.         endMethod
  635.  
  636.   endBehavior
  637.  
  638. -----------------------------  ThreadPrintShort  ---------------------------------
  639.  
  640.   function ThreadPrintShort (t: ptr to Thread)
  641.     --
  642.     -- This function prints a single line giving the name of thread "t",
  643.     -- its status, and the address of the Thread object itself (which may be
  644.     -- helpful in distinguishing Threads when the name is not helpful).
  645.     --
  646.       var
  647.         oldStatus: int = SetInterruptsTo (DISABLED)
  648.       if !t
  649.         print ("NULL\n")
  650.         return
  651.       endIf
  652.       print ("  Thread \"")
  653.       print (t.name)
  654.       print ("\"    status=")
  655.       switch t.status
  656.         case JUST_CREATED:
  657.           print ("JUST_CREATED")
  658.           break
  659.         case READY:
  660.           print ("READY")
  661.           break
  662.         case RUNNING:
  663.           print ("RUNNING")
  664.           break
  665.         case BLOCKED:
  666.           print ("BLOCKED")
  667.           break
  668.         case UNUSED:
  669.           print ("UNUSED")
  670.           break
  671.         default:
  672.           FatalError ("Bad status in Thread")
  673.       endSwitch
  674.       print ("    (addr of Thread object: ")
  675.       printHex (t asInteger)
  676.       print (")")
  677.       nl ()
  678.       -- t.Print ()
  679.       oldStatus = SetInterruptsTo (oldStatus)
  680.     endFunction
  681.  
  682. -----------------------------  ThreadManager  ---------------------------------
  683.  
  684.   behavior ThreadManager
  685.  
  686.       ----------  ThreadManager . Init  ----------
  687.  
  688.       method Init ()
  689.         --
  690.         -- This method is called once at kernel startup time to initialize
  691.         -- the one and only "ThreadManager" object.
  692.         -- 
  693.           print ("Initializing Thread Manager...\n")
  694.           -- NOT IMPLEMENTED
  695.         endMethod
  696.  
  697.       ----------  ThreadManager . Print  ----------
  698.  
  699.       method Print ()
  700.         -- 
  701.         -- Print each thread.  Since we look at the freeList, this
  702.         -- routine disables interrupts so the printout will be a
  703.         -- consistent snapshot of things.
  704.         -- 
  705.         var i, oldStatus: int
  706.           oldStatus = SetInterruptsTo (DISABLED)
  707.           print ("Here is the thread table...\n")
  708.           for i = 0 to MAX_NUMBER_OF_PROCESSES-1
  709.             print ("  ")
  710.             printInt (i)
  711.             print (":")
  712.             ThreadPrintShort (&threadTable[i])
  713.           endFor
  714.           print ("Here is the FREE list of Threads:\n   ")
  715.           freeList.ApplyToEach (PrintObjectAddr)
  716.           nl ()
  717.           oldStatus = SetInterruptsTo (oldStatus)
  718.         endMethod
  719.  
  720.       ----------  ThreadManager . GetANewThread  ----------
  721.  
  722.       method GetANewThread () returns ptr to Thread
  723.         -- 
  724.         -- This method returns a new Thread; it will wait
  725.         -- until one is available.
  726.         -- 
  727.           -- NOT IMPLEMENTED
  728.           return null
  729.         endMethod
  730.  
  731.       ----------  ThreadManager . FreeThread  ----------
  732.  
  733.       method FreeThread (th: ptr to Thread)
  734.         -- 
  735.         -- This method is passed a ptr to a Thread;  It moves it
  736.         -- to the FREE list.
  737.         -- 
  738.           -- NOT IMPLEMENTED
  739.         endMethod
  740.  
  741.     endBehavior
  742.  
  743. --------------------------  ProcessControlBlock  ------------------------------
  744.  
  745.   behavior ProcessControlBlock
  746.  
  747.       ----------  ProcessControlBlock . Init  ----------
  748.       --
  749.       -- This method is called once for every PCB at startup time.
  750.       --
  751.       method Init ()
  752.           pid = -1
  753.           status = FREE
  754.           addrSpace = new AddrSpace
  755.           addrSpace.Init ()
  756. -- Uncomment this code later...
  757. /*
  758.           fileDescriptor = new array of ptr to OpenFile
  759.                       { MAX_FILES_PER_PROCESS of null }
  760. */
  761.         endMethod
  762.  
  763.       ----------  ProcessControlBlock . Print  ----------
  764.  
  765.       method Print ()
  766.         --
  767.         -- Print this ProcessControlBlock using several lines.
  768.         --
  769.         -- var i: int
  770.           self.PrintShort ()
  771.           addrSpace.Print ()
  772.           print ("    myThread = ")
  773.           ThreadPrintShort (myThread)
  774. -- Uncomment this code later...
  775. /*
  776.           print ("    File Descriptors:\n")
  777.           for i = 0 to MAX_FILES_PER_PROCESS-1
  778.             if fileDescriptor[i]
  779.               fileDescriptor[i].Print ()
  780.             endIf
  781.           endFor
  782. */
  783.           nl ()
  784.         endMethod
  785.  
  786.       ----------  ProcessControlBlock . PrintShort  ----------
  787.  
  788.       method PrintShort ()
  789.         --
  790.         -- Print this ProcessControlBlock on one line.
  791.         --
  792.           print ("  ProcessControlBlock   (addr=")
  793.           printHex (self asInteger)
  794.           print (")   pid=")
  795.           printInt (pid)
  796.           print (", status=")
  797.           if status == ACTIVE
  798.             print ("ACTIVE")
  799.           elseIf status == ZOMBIE
  800.             print ("ZOMBIE")
  801.           elseIf status == FREE
  802.             print ("FREE")
  803.           else
  804.             FatalError ("Bad status in ProcessControlBlock")
  805.           endIf
  806.           print (", parentsPid=")
  807.           printInt (parentsPid)
  808.           print (", exitStatus=")
  809.           printInt (exitStatus)
  810.           nl ()
  811.         endMethod
  812.  
  813.     endBehavior
  814.  
  815. -----------------------------  ProcessManager  ---------------------------------
  816.  
  817.   behavior ProcessManager
  818.  
  819.       ----------  ProcessManager . Init  ----------
  820.  
  821.       method Init ()
  822.         --
  823.         -- This method is called once at kernel startup time to initialize
  824.         -- the one and only "processManager" object.  
  825.         --
  826.         -- NOT IMPLEMENTED
  827.         endMethod
  828.  
  829.       ----------  ProcessManager . Print  ----------
  830.  
  831.       method Print ()
  832.         -- 
  833.         -- Print all processes.  Since we look at the freeList, this
  834.         -- routine disables interrupts so the printout will be a
  835.         -- consistent snapshot of things.
  836.         -- 
  837.         var i, oldStatus: int
  838.           oldStatus = SetInterruptsTo (DISABLED)
  839.           print ("Here is the process table...\n")
  840.           for i = 0 to MAX_NUMBER_OF_PROCESSES-1
  841.             print ("  ")
  842.             printInt (i)
  843.             print (":")
  844.             processTable[i].Print ()
  845.           endFor
  846.           print ("Here is the FREE list of ProcessControlBlocks:\n   ")
  847.           freeList.ApplyToEach (PrintObjectAddr)
  848.           nl ()
  849.           oldStatus = SetInterruptsTo (oldStatus)
  850.         endMethod
  851.  
  852.       ----------  ProcessManager . PrintShort  ----------
  853.  
  854.       method PrintShort ()
  855.         -- 
  856.         -- Print all processes.  Since we look at the freeList, this
  857.         -- routine disables interrupts so the printout will be a
  858.         -- consistent snapshot of things.
  859.         -- 
  860.         var i, oldStatus: int
  861.           oldStatus = SetInterruptsTo (DISABLED)
  862.           print ("Here is the process table...\n")
  863.           for i = 0 to MAX_NUMBER_OF_PROCESSES-1
  864.             print ("  ")
  865.             printInt (i)
  866.             processTable[i].PrintShort ()
  867.           endFor
  868.           print ("Here is the FREE list of ProcessControlBlocks:\n   ")
  869.           freeList.ApplyToEach (PrintObjectAddr)
  870.           nl ()
  871.           oldStatus = SetInterruptsTo (oldStatus)
  872.         endMethod
  873.  
  874.       ----------  ProcessManager . GetANewProcess  ----------
  875.  
  876.       method GetANewProcess () returns ptr to ProcessControlBlock
  877.         --
  878.         -- This method returns a new ProcessControlBlock; it will wait
  879.         -- until one is available.
  880.         --
  881.           -- NOT IMPLEMENTED
  882.           return null
  883.         endMethod
  884.  
  885.       ----------  ProcessManager . FreeProcess  ----------
  886.  
  887.       method FreeProcess (p: ptr to ProcessControlBlock)
  888.         --
  889.         -- This method is passed a ptr to a Process;  It moves it
  890.         -- to the FREE list.
  891.         --
  892.           -- NOT IMPLEMENTED
  893.         endMethod
  894.  
  895.  
  896.     endBehavior
  897.  
  898. -----------------------------  PrintObjectAddr  ---------------------------------
  899.  
  900.   function PrintObjectAddr (p: ptr to Object)
  901.     --
  902.     -- Print the address of the given object.
  903.     --
  904.       printHex (p asInteger)
  905.       printChar (' ')
  906.     endFunction
  907.  
  908. -----------------------------  ProcessFinish  --------------------------
  909.  
  910.   function ProcessFinish (exitStatus: int)
  911.     --
  912.     -- This routine is called when a process is to be terminated.  It will
  913.     -- free the resources held by this process and will terminate the
  914.     -- current thread.
  915.     --
  916.       FatalError ("ProcessFinish is not implemented")
  917.     endFunction
  918.  
  919. -----------------------------  FrameManager  ---------------------------------
  920.  
  921.   behavior FrameManager
  922.  
  923.       ----------  FrameManager . Init  ----------
  924.  
  925.       method Init ()
  926.         --
  927.         -- This method is called once at kernel startup time to initialize
  928.         -- the one and only "frameManager" object.  
  929.         --
  930.         var i: int
  931.           print ("Initializing Frame Manager...\n")
  932.           framesInUse = new BitMap
  933.           framesInUse.Init (NUMBER_OF_PHYSICAL_PAGE_FRAMES)
  934.           numberFreeFrames = NUMBER_OF_PHYSICAL_PAGE_FRAMES
  935.           frameManagerLock = new Mutex
  936.           frameManagerLock.Init ()
  937.           newFramesAvailable = new Condition
  938.           newFramesAvailable.Init ()
  939.           -- Check that the area to be used for paging contains zeros.
  940.           -- The BLITZ emulator will initialize physical memory to zero, so
  941.           -- if by chance the size of the kernel has gotten so large that
  942.           -- it runs into the area reserved for pages, we will detect it.
  943.           -- Note: this test is not 100%, but is included nonetheless.
  944.           for i = PHYSICAL_ADDRESS_OF_FIRST_PAGE_FRAME
  945.                    to PHYSICAL_ADDRESS_OF_FIRST_PAGE_FRAME+300
  946.                    by 4
  947.             if 0 != *(i asPtrTo int)
  948.               FatalError ("Kernel code size appears to have grown too large and is overflowing into the frame region")
  949.             endIf
  950.           endFor
  951.         endMethod
  952.  
  953.       ----------  FrameManager . Print  ----------
  954.  
  955.       method Print ()
  956.         --
  957.         -- Print which frames are allocated and how many are free.
  958.         --
  959.           frameManagerLock.Lock ()
  960.           print ("FRAME MANAGER:\n")
  961.           printIntVar ("  numberFreeFrames", numberFreeFrames)
  962.           print ("  Here are the frames in use: \n    ")
  963.           framesInUse.Print ()
  964.           frameManagerLock.Unlock ()
  965.         endMethod
  966.  
  967.       ----------  FrameManager . GetAFrame  ----------
  968.  
  969.       method GetAFrame () returns int
  970.         --
  971.         -- Allocate a single frame and return its physical address.  If no frames
  972.         -- are currently available, wait until the request can be completed.
  973.         --
  974.           var f, frameAddr: int
  975.  
  976.           -- Acquire exclusive access to the frameManager data structure...
  977.           frameManagerLock.Lock ()
  978.  
  979.           -- Wait until we have enough free frames to entirely satisfy the request...
  980.           while numberFreeFrames < 1
  981.             newFramesAvailable.Wait (&frameManagerLock)
  982.           endWhile
  983.  
  984.           -- Find a free frame and allocate it...
  985.           f = framesInUse.FindZeroAndSet ()
  986.           numberFreeFrames = numberFreeFrames - 1
  987.  
  988.           -- Unlock...
  989.           frameManagerLock.Unlock ()
  990.  
  991.           -- Compute and return the physical address of the frame...
  992.           frameAddr = PHYSICAL_ADDRESS_OF_FIRST_PAGE_FRAME + (f * PAGE_SIZE)
  993.           -- printHexVar ("GetAFrame returning frameAddr", frameAddr)
  994.           return frameAddr
  995.         endMethod
  996.  
  997.       ----------  FrameManager . GetNewFrames  ----------
  998.  
  999.       method GetNewFrames (aPageTable: ptr to AddrSpace, numFramesNeeded: int)
  1000.           -- NOT IMPLEMENTED
  1001.         endMethod
  1002.  
  1003.       ----------  FrameManager . ReturnAllFrames  ----------
  1004.  
  1005.       method ReturnAllFrames (aPageTable: ptr to AddrSpace)
  1006.           -- NOT IMPLEMENTED
  1007.         endMethod
  1008.  
  1009.     endBehavior
  1010.  
  1011. -----------------------------  AddrSpace  ---------------------------------
  1012.  
  1013.   behavior AddrSpace
  1014.  
  1015.       ----------  AddrSpace . Init  ----------
  1016.  
  1017.       method Init ()
  1018.         --
  1019.         -- Initialize this object.
  1020.         --
  1021.           numberOfPages = 0
  1022.           pageTable = new array of int { MAX_PAGES_PER_VIRT_SPACE of 0x00000003 }
  1023.         endMethod
  1024.  
  1025.       ----------  AddrSpace . Print  ----------
  1026.  
  1027.       method Print ()
  1028.         --
  1029.         -- Print this object.
  1030.         --
  1031.           var i: int
  1032.           print ("        addr        entry          Logical    Physical   Undefined Bits  Dirty  Referenced  Writeable  Valid\n")
  1033.           print ("     ==========   ==========     ==========  ==========  ==============  =====  ==========  =========  =====\n")
  1034.           for i = 0 to numberOfPages-1
  1035.             print ("     ")
  1036.             printHex ((&pageTable[i]) asInteger)
  1037.             print (":  ")
  1038.             printHex (pageTable[i])
  1039.             print ("     ")
  1040.             printHex (i * PAGE_SIZE)   -- Logical address
  1041.             print ("  ")
  1042.             printHex (self.ExtractFrameAddr (i))       -- Physical address
  1043.             print ("    ")
  1044.             if self.ExtractUndefinedBits (i) != 0
  1045.               printHex (self.ExtractUndefinedBits (i))
  1046.             else
  1047.               print ("          ")
  1048.             endIf
  1049.             print ("     ")
  1050.             if self.IsDirty (i)
  1051.               print ("YES")
  1052.             else
  1053.               print ("   ")
  1054.             endIf
  1055.             print ("      ")
  1056.             if self.IsReferenced (i)
  1057.               print ("YES")
  1058.             else
  1059.               print ("   ")
  1060.             endIf
  1061.             print ("         ")
  1062.             if self.IsWritable (i)
  1063.               print ("YES")
  1064.             else
  1065.               print ("   ")
  1066.             endIf
  1067.             print ("      ")
  1068.             if self.IsValid (i)
  1069.               print ("YES")
  1070.             else
  1071.               print ("   ")
  1072.             endIf
  1073.             nl ()
  1074.           endFor
  1075.         endMethod
  1076.  
  1077.       ----------  AddrSpace . ExtractFrameAddr  ----------
  1078.  
  1079.       method ExtractFrameAddr (entry: int) returns int
  1080.         --
  1081.         -- Return the physical address of the frame in the selected page
  1082.         -- table entry.
  1083.         --
  1084.           return (pageTable[entry] & 0xffffe000) 
  1085.         endMethod
  1086.  
  1087.       ----------  AddrSpace . ExtractUndefinedBits  ----------
  1088.  
  1089.       method ExtractUndefinedBits (entry: int) returns int
  1090.         --
  1091.         -- Return the undefined bits in the selected page table entry.
  1092.         --
  1093.           return (pageTable[entry] & 0x00001ff0) 
  1094.         endMethod
  1095.  
  1096.       ----------  AddrSpace . SetFrameAddr  ----------
  1097.  
  1098.       method SetFrameAddr (entry: int, frameAddr: int)
  1099.         --
  1100.         -- Set the physical address of the frame in the selected page
  1101.         -- table entry to the value of the argument "frameAddr".
  1102.         --
  1103.           pageTable[entry] = (pageTable[entry] & 0x00001fff) | frameAddr
  1104.         endMethod
  1105.  
  1106.       ----------  AddrSpace . IsDirty  ----------
  1107.  
  1108.       method IsDirty (entry: int) returns bool
  1109.         --
  1110.         -- Return true if the selected page table entry is marked "dirty".
  1111.         --
  1112.           return (pageTable[entry] & 0x00000008) != 0
  1113.         endMethod
  1114.  
  1115.       ----------  AddrSpace . IsReferenced  ----------
  1116.  
  1117.       method IsReferenced (entry: int) returns bool
  1118.         --
  1119.         -- Return true if the selected page table entry is marked "referenced".
  1120.         --
  1121.           return (pageTable[entry] & 0x00000004) != 0
  1122.         endMethod
  1123.  
  1124.       ----------  AddrSpace . IsWritable  ----------
  1125.  
  1126.       method IsWritable (entry: int) returns bool
  1127.         --
  1128.         -- Return true if the selected page table entry is marked "writable".
  1129.         --
  1130.           return (pageTable[entry] & 0x00000002) != 0
  1131.         endMethod
  1132.  
  1133.       ----------  AddrSpace . IsValid  ----------
  1134.  
  1135.       method IsValid (entry: int) returns bool
  1136.         --
  1137.         -- Return true if the selected page table entry is marked "valid".
  1138.         --
  1139.           return (pageTable[entry] & 0x00000001) != 0
  1140.         endMethod
  1141.  
  1142.       ----------  AddrSpace . SetDirty  ----------
  1143.  
  1144.       method SetDirty (entry: int)
  1145.         --
  1146.         -- Set the selected page table entry's "dirty" bit to 1.
  1147.         --
  1148.           pageTable[entry] = pageTable[entry] | 0x00000008
  1149.         endMethod
  1150.  
  1151.       ----------  AddrSpace . SetReferenced  ----------
  1152.  
  1153.       method SetReferenced (entry: int)
  1154.         --
  1155.         -- Set the selected page table entry's "referenced" bit to 1.
  1156.         --
  1157.           pageTable[entry] = pageTable[entry] | 0x00000004
  1158.         endMethod
  1159.  
  1160.       ----------  AddrSpace . SetWritable  ----------
  1161.  
  1162.       method SetWritable (entry: int)
  1163.         --
  1164.         -- Set the selected page table entry's "writable" bit to 1.
  1165.         --
  1166.           pageTable[entry] = pageTable[entry] | 0x00000002
  1167.         endMethod
  1168.  
  1169.       ----------  AddrSpace . SetValid  ----------
  1170.  
  1171.       method SetValid (entry: int)
  1172.         --
  1173.         -- Set the selected page table entry's "valid" bit to 1.
  1174.         --
  1175.           pageTable[entry] = pageTable[entry] | 0x00000001
  1176.         endMethod
  1177.  
  1178.       ----------  AddrSpace . ClearDirty  ----------
  1179.  
  1180.       method ClearDirty (entry: int)
  1181.         --
  1182.         -- Clear the selected page table entry's "dirty" bit.
  1183.         --
  1184.           pageTable[entry] = pageTable[entry] & ! 0x00000008
  1185.         endMethod
  1186.  
  1187.       ----------  AddrSpace . ClearReferenced  ----------
  1188.  
  1189.       method ClearReferenced (entry: int)
  1190.         --
  1191.         -- Clear the selected page table entry's "referenced" bit.
  1192.         --
  1193.           pageTable[entry] = pageTable[entry] & ! 0x00000004
  1194.         endMethod
  1195.  
  1196.       ----------  AddrSpace . ClearWritable  ----------
  1197.  
  1198.       method ClearWritable (entry: int)
  1199.         --
  1200.         -- Clear the selected page table entry's "writable" bit.
  1201.         --
  1202.           pageTable[entry] = pageTable[entry] & ! 0x00000002
  1203.         endMethod
  1204.  
  1205.       ----------  AddrSpace . ClearValid  ----------
  1206.  
  1207.       method ClearValid (entry: int)
  1208.         --
  1209.         -- Clear the selected page table entry's "valid" bit.
  1210.         --
  1211.           pageTable[entry] = pageTable[entry] & ! 0x00000001
  1212.         endMethod
  1213.  
  1214.       ----------  AddrSpace . SetToThisPageTable  ----------
  1215.  
  1216.       method SetToThisPageTable ()
  1217.         --
  1218.         -- This method sets the page table registers in the CPU to
  1219.         -- point to this page table.  Later, when paging is enabled,
  1220.         -- this will become the active virtual address space.
  1221.         --
  1222.           LoadPageTableRegs ((& pageTable[0]) asInteger, numberOfPages*4)
  1223.         endMethod
  1224.  
  1225.       ----------  AddrSpace . CopyBytesFromVirtual  ----------
  1226.  
  1227.       method CopyBytesFromVirtual (kernelAddr, virtAddr, numBytes: int)
  1228.                     returns int
  1229.         --
  1230.         -- This method copies data from a user's virtual address space
  1231.         -- to somewhere in the kernel space.  We assume that the
  1232.         -- pages of the virtual address space are resident in
  1233.         -- physical page frames.  This routine returns the number of bytes
  1234.         -- that were copied; if there was any problem with the virtual
  1235.         -- addressed data, it returns -1.
  1236.         --
  1237.           var copiedSoFar, virtPage, offset, fromAddr: int
  1238.           -- print ("CopyBytesFromVirtual called...\n")
  1239.           -- printHexVar ("  kernelAddr", kernelAddr)
  1240.           -- printHexVar ("  virtAddr", virtAddr)
  1241.           -- printIntVar ("  numBytes", numBytes)
  1242.           if numBytes == 0
  1243.             return 0
  1244.           elseIf numBytes < 0
  1245.             return -1
  1246.           endIf
  1247.           virtPage = virtAddr / PAGE_SIZE
  1248.           offset = virtAddr % PAGE_SIZE
  1249.           -- printHexVar ("  virtPage", virtPage)
  1250.           -- printHexVar ("  offset", offset)
  1251.           while true
  1252.             if virtPage >= numberOfPages
  1253.               print ("  Virtual page number is too large!!!\n")
  1254.               return -1
  1255.             endIf
  1256.             if ! self.IsValid (virtPage)
  1257.               print ("  Virtual page is not marked VALID!!!\n")
  1258.               return -1
  1259.             endIf
  1260.             fromAddr = self.ExtractFrameAddr (virtPage) + offset
  1261.             -- printHexVar ("  Copying bytes from physcial addr", fromAddr)
  1262.             while offset < PAGE_SIZE
  1263.               -- printHexVar ("  Copying a byte to physcial addr", kernelAddr)
  1264.               -- printChar (* (fromAddr asPtrTo char))
  1265.               * (kernelAddr asPtrTo char) = * (fromAddr asPtrTo char)
  1266.               offset = offset + 1
  1267.               kernelAddr = kernelAddr + 1
  1268.               fromAddr = fromAddr + 1
  1269.               copiedSoFar = copiedSoFar + 1
  1270.               if copiedSoFar == numBytes
  1271.                 return copiedSoFar
  1272.               endIf
  1273.             endWhile
  1274.             virtPage = virtPage + 1
  1275.             offset = 0
  1276.           endWhile
  1277.         endMethod
  1278.  
  1279.       ----------  AddrSpace . CopyBytesToVirtual  ----------
  1280.  
  1281.       method CopyBytesToVirtual (virtAddr, kernelAddr, numBytes: int)
  1282.                     returns int
  1283.         --
  1284.         -- This method copies data from the kernel's address space to
  1285.         -- somewhere in the virtual address space.  We assume that the
  1286.         -- pages of the virtual address space are resident in physical
  1287.         -- page frames.  This routine returns the number of bytes
  1288.         -- that were copied; if there was any problem with the virtual
  1289.         -- addressed data, it returns -1.
  1290.         --
  1291.           var copiedSoFar, virtPage, offset, destAddr: int
  1292.           if numBytes == 0
  1293.             return 0
  1294.           elseIf numBytes < 0
  1295.             return -1
  1296.           endIf
  1297.           virtPage = virtAddr / PAGE_SIZE
  1298.           offset = virtAddr % PAGE_SIZE
  1299.           while true
  1300.             if (virtPage >= numberOfPages) ||
  1301.                (! self.IsValid (virtPage)) ||
  1302.                (! self.IsWritable (virtPage))
  1303.               return -1
  1304.             endIf
  1305.             destAddr = self.ExtractFrameAddr (virtPage) + offset
  1306.             while offset < PAGE_SIZE
  1307.               * (destAddr asPtrTo char) = * (kernelAddr asPtrTo char)
  1308.               offset = offset + 1
  1309.               kernelAddr = kernelAddr + 1
  1310.               destAddr = destAddr + 1
  1311.               copiedSoFar = copiedSoFar + 1
  1312.               if copiedSoFar == numBytes
  1313.                 return copiedSoFar
  1314.               endIf
  1315.             endWhile
  1316.             virtPage = virtPage + 1
  1317.             offset = 0
  1318.           endWhile
  1319.         endMethod
  1320.  
  1321.       ----------  AddrSpace . GetStringFromVirtual  ----------
  1322.  
  1323.       method GetStringFromVirtual (kernelAddr: String, virtAddr, maxSize: int) returns int
  1324.         --
  1325.         -- This method is used to copy a String from virtual space into
  1326.         -- a given physical address in the kernel.  The "kernelAddr" should be
  1327.         -- a pointer to an "array of char" in the kernel's code.  This method
  1328.         -- copies up to "maxSize" characters from approriate page frame to this
  1329.         -- to the target array in the kernel.
  1330.         --
  1331.         -- Note: This method resets the "arraySize" word in the target.  It is
  1332.         -- assumed that the target array has enough space; no checking is done.
  1333.         -- The caller should supply a "maxSize" telling how many characters may
  1334.         -- be safely copied.
  1335.         --
  1336.         -- If there are problems, then -1 is returned.  Possible problems:
  1337.         --       The source array has more than "maxSize" elements
  1338.         --       The source page is invalid or out of range
  1339.         -- If all okay, then the number of characters copied is returned.
  1340.         --
  1341.           var sourceSize: int
  1342.           -- print ("GetStringFromVirtual called...\n")
  1343.           -- printHexVar ("  kernelAddr", kernelAddr asInteger)
  1344.           -- printHexVar ("  virtAddr", virtAddr)
  1345.           -- printIntVar ("  maxSize", maxSize)
  1346.           -- Begin by fetching the source size
  1347.           if self.CopyBytesFromVirtual ((&sourceSize) asInteger,
  1348.                                         virtAddr,
  1349.                                         4) < 4
  1350.             return -1
  1351.           endIf
  1352.           -- printIntVar ("  sourceSize", sourceSize)
  1353.           -- Make sure the source size is okay
  1354.           if sourceSize > maxSize
  1355.             return -1
  1356.           endIf
  1357.           -- Change the size of the destination array
  1358.           * (kernelAddr asPtrTo int) = sourceSize
  1359.           -- Next, get the characters
  1360.           return self.CopyBytesFromVirtual (kernelAddr asInteger + 4,
  1361.                                             virtAddr + 4,
  1362.                                             sourceSize)
  1363.         endMethod
  1364.  
  1365.     endBehavior
  1366.  
  1367. -----------------------------  TimerInterruptHandler  ---------------------------------
  1368.  
  1369.   function TimerInterruptHandler ()
  1370.     --
  1371.     -- This routine is called when a timer interrupt occurs.  Upon entry,
  1372.     -- interrupts are DISABLED.  Upon return, execution will return to
  1373.     -- the interrupted process, which necessarily had interrupts ENABLED.
  1374.     --
  1375.     -- (If you wish to turn time-slicing off, simply disable the call
  1376.     -- to "Yield" in the code below.  Threads will then execute until they
  1377.     -- call "Yield" explicitly, or until they call "Sleep".)
  1378.     --
  1379.       currentInterruptStatus = DISABLED
  1380.       -- printChar ('_')
  1381.       currentThread.Yield ()
  1382.       currentInterruptStatus = ENABLED
  1383.     endFunction
  1384.  
  1385. -----------------------------  DiskInterruptHandler  --------------------------
  1386.  
  1387.   function DiskInterruptHandler ()
  1388.     --
  1389.     -- This routine is called when a disk interrupt occurs.  It will
  1390.     -- signal the "semToSignalOnCompletion" Semaphore and return to
  1391.     -- the interrupted thread.
  1392.     --
  1393.     -- This is an interrupt handler.  As such, interrupts will be DISABLED
  1394.     -- for the duration of its execution.
  1395.     --
  1396. -- Uncomment this code later...
  1397.       FatalError ("DISK INTERRUPTS NOT EXPECTED IN PROJECT 4")
  1398. /*
  1399.       currentInterruptStatus = DISABLED
  1400.       -- print ("DiskInterruptHandler invoked!\n")
  1401.       if diskDriver.semToSignalOnCompletion
  1402.         diskDriver.semToSignalOnCompletion.Up()
  1403.       endIf
  1404. */
  1405.     endFunction
  1406.  
  1407. -----------------------------  SerialInterruptHandler  --------------------------
  1408.  
  1409.   function SerialInterruptHandler ()
  1410.     --
  1411.     -- This routine is called when a serial interrupt occurs.  It will
  1412.     -- signal the "semToSignalOnCompletion" Semaphore and return to
  1413.     -- the interrupted thread.
  1414.     --
  1415.     -- This is an interrupt handler.  As such, interrupts will be DISABLED
  1416.     -- for the duration of its execution.
  1417.     --
  1418.       currentInterruptStatus = DISABLED
  1419.       -- NOT IMPLEMENTED
  1420.     endFunction
  1421. -----------------------------  IllegalInstructionHandler  --------------------------
  1422.  
  1423.   function IllegalInstructionHandler ()
  1424.     --
  1425.     -- This routine is called when an IllegalInstruction exception occurs.  Upon entry,
  1426.     -- interrupts are DISABLED.  We should not return to the code that had
  1427.     -- the exception.
  1428.     --
  1429.       currentInterruptStatus = DISABLED
  1430.       ErrorInUserProcess ("An IllegalInstruction exception has occured while in user mode")
  1431.     endFunction
  1432.  
  1433. -----------------------------  ArithmeticExceptionHandler  --------------------------
  1434.  
  1435.   function ArithmeticExceptionHandler ()
  1436.     --
  1437.     -- This routine is called when an ArithmeticException occurs.  Upon entry,
  1438.     -- interrupts are DISABLED.  We should not return to the code that had
  1439.     -- the exception.
  1440.     --
  1441.       currentInterruptStatus = DISABLED
  1442.       ErrorInUserProcess ("An ArithmeticException exception has occured while in user mode")
  1443.     endFunction
  1444.  
  1445. -----------------------------  AddressExceptionHandler  --------------------------
  1446.  
  1447.   function AddressExceptionHandler ()
  1448.     --
  1449.     -- This routine is called when an AddressException occurs.  Upon entry,
  1450.     -- interrupts are DISABLED.  We should not return to the code that had
  1451.     -- the exception.
  1452.     --
  1453.       currentInterruptStatus = DISABLED
  1454.       ErrorInUserProcess ("An AddressException exception has occured while in user mode")
  1455.     endFunction
  1456.  
  1457. -----------------------------  PageInvalidExceptionHandler  --------------------------
  1458.  
  1459.   function PageInvalidExceptionHandler ()
  1460.     --
  1461.     -- This routine is called when a PageInvalidException occurs.  Upon entry,
  1462.     -- interrupts are DISABLED.  For now, we simply print a message and abort
  1463.     -- the thread.
  1464.     --
  1465.       currentInterruptStatus = DISABLED
  1466.       ErrorInUserProcess ("A PageInvalidException exception has occured while in user mode")
  1467.     endFunction
  1468.  
  1469. -----------------------------  PageReadonlyExceptionHandler  --------------------------
  1470.  
  1471.   function PageReadonlyExceptionHandler ()
  1472.     --
  1473.     -- This routine is called when a PageReadonlyException occurs.  Upon entry,
  1474.     -- interrupts are DISABLED.  For now, we simply print a message and abort
  1475.     -- the thread.
  1476.     --
  1477.       currentInterruptStatus = DISABLED
  1478.       ErrorInUserProcess ("A PageReadonlyException exception has occured while in user mode")
  1479.     endFunction
  1480.  
  1481. -----------------------------  PrivilegedInstructionHandler  --------------------------
  1482.  
  1483.   function PrivilegedInstructionHandler ()
  1484.     --
  1485.     -- This routine is called when a PrivilegedInstruction exception occurs.  Upon entry,
  1486.     -- interrupts are DISABLED.  We should not return to the code that had
  1487.     -- the exception.
  1488.     --
  1489.       currentInterruptStatus = DISABLED
  1490.       ErrorInUserProcess ("A PrivilegedInstruction exception has occured while in user mode")
  1491.     endFunction
  1492.  
  1493. -----------------------------  AlignmentExceptionHandler  --------------------------
  1494.  
  1495.   function AlignmentExceptionHandler ()
  1496.     --
  1497.     -- This routine is called when an AlignmentException occurs.  Upon entry,
  1498.     -- interrupts are DISABLED.  We should not return to the code that had
  1499.     -- the exception.
  1500.     --
  1501.       currentInterruptStatus = DISABLED
  1502.       ErrorInUserProcess ("An AlignmentException exception has occured while in user mode")
  1503.     endFunction
  1504.  
  1505. -----------------------------  ErrorInUserProcess  --------------------------
  1506.  
  1507.   function ErrorInUserProcess (errorMessage: String)
  1508.     --
  1509.     -- This routine is called when an error has occurred in a user-level
  1510.     -- process.  It prints the error message and terminates the process.
  1511.     --
  1512.       print ("\n**********  ")
  1513.       print (errorMessage)
  1514.       print ("  **********\n\n")
  1515.  
  1516.       -- Print some information about the offending process...
  1517.       if currentThread.myProcess
  1518.         currentThread.myProcess.Print ()
  1519.       else
  1520.         print ("  ERROR: currentThread.myProcess is null\n\n")
  1521.       endIf
  1522.       currentThread.Print ()
  1523.  
  1524.       -- Uncomment the following for even more information...
  1525.       -- threadManager.Print ()
  1526.       -- processManager.Print ()
  1527.  
  1528.       ProcessFinish (-1)
  1529.     endFunction
  1530.  
  1531. -----------------------------  SyscallTrapHandler  --------------------------
  1532.  
  1533.   function SyscallTrapHandler (syscallCodeNum, arg1, arg2, arg3, arg4: int) returns int
  1534.     --
  1535.     -- This routine is called when a syscall trap occurs.  Upon entry, interrupts
  1536.     -- will be DISABLED, paging is disabled, and we will be running in System mode.
  1537.     -- Upon return, execution will return to the user mode portion of this
  1538.     -- thread, which will have had interrupts ENABLED.
  1539.     --
  1540.       currentInterruptStatus = DISABLED
  1541.       /*****
  1542.       print ("Within SyscallTrapHandler: syscallCodeNum=")
  1543.       printInt (syscallCodeNum)
  1544.       print (", arg1=")
  1545.       printInt (arg1)
  1546.       print (", arg2=")
  1547.       printInt (arg2)
  1548.       print (", arg3=")
  1549.       printInt (arg3)
  1550.       print (", arg4=")
  1551.       printInt (arg4)
  1552.       nl ()
  1553.       *****/
  1554.       switch syscallCodeNum
  1555.         case SYSCALL_FORK:
  1556.           return Handle_Sys_Fork ()
  1557.         case SYSCALL_YIELD:
  1558.           Handle_Sys_Yield ()
  1559.           return 0
  1560.         case SYSCALL_EXEC:
  1561.           return Handle_Sys_Exec (arg1 asPtrTo array of char)
  1562.         case SYSCALL_JOIN:
  1563.           return Handle_Sys_Join (arg1)
  1564.         case SYSCALL_EXIT:
  1565.           Handle_Sys_Exit (arg1)
  1566.           return 0
  1567.         case SYSCALL_CREATE:
  1568.           return Handle_Sys_Create (arg1 asPtrTo array of char)
  1569.         case SYSCALL_OPEN:
  1570.           return Handle_Sys_Open (arg1 asPtrTo array of char)
  1571.         case SYSCALL_READ:
  1572.           return Handle_Sys_Read (arg1, arg2 asPtrTo char, arg3)
  1573.         case SYSCALL_WRITE:
  1574.           return Handle_Sys_Write (arg1, arg2 asPtrTo char, arg3)
  1575.         case SYSCALL_SEEK:
  1576.           return Handle_Sys_Seek (arg1, arg2)
  1577.         case SYSCALL_CLOSE:
  1578.           Handle_Sys_Close (arg1)
  1579.           return 0
  1580.         case SYSCALL_SHUTDOWN:
  1581.           Handle_Sys_Shutdown ()
  1582.           return 0
  1583.         default:
  1584.           print ("Syscall code = ")
  1585.           printInt (syscallCodeNum)
  1586.           nl ()
  1587.           FatalError ("Unknown syscall code from user thread")
  1588.       endSwitch
  1589.       return 0
  1590.     endFunction
  1591.  
  1592. -----------------------------  Handle_Sys_Exit  ---------------------------------
  1593.  
  1594.   function Handle_Sys_Exit (returnStatus: int)
  1595.       -- NOT IMPLEMENTED
  1596.     endFunction
  1597.  
  1598. -----------------------------  Handle_Sys_Shutdown  ---------------------------------
  1599.  
  1600.   function Handle_Sys_Shutdown ()
  1601.       -- NOT IMPLEMENTED
  1602.     endFunction
  1603.  
  1604. -----------------------------  Handle_Sys_Yield  ---------------------------------
  1605.  
  1606.   function Handle_Sys_Yield ()
  1607.       -- NOT IMPLEMENTED
  1608.     endFunction
  1609.  
  1610. -----------------------------  Handle_Sys_Fork  ---------------------------------
  1611.  
  1612.   function Handle_Sys_Fork () returns int
  1613.       -- NOT IMPLEMENTED
  1614.       return 0
  1615.     endFunction
  1616.  
  1617. -----------------------------  Handle_Sys_Join  ---------------------------------
  1618.  
  1619.   function Handle_Sys_Join (processID: int) returns int
  1620.       -- NOT IMPLEMENTED
  1621.       return 0
  1622.     endFunction
  1623.  
  1624. -----------------------------  Handle_Sys_Exec  ---------------------------------
  1625.  
  1626.   function Handle_Sys_Exec (filename: ptr to array of char) returns int
  1627.       -- NOT IMPLEMENTED
  1628.       return 0
  1629.     endFunction
  1630.  
  1631. -----------------------------  Handle_Sys_Create  ---------------------------------
  1632.  
  1633.   function Handle_Sys_Create (filename: ptr to array of char) returns int
  1634.       -- NOT IMPLEMENTED
  1635.       return 0
  1636.     endFunction
  1637.  
  1638. -----------------------------  Handle_Sys_Open  ---------------------------------
  1639.  
  1640.   function Handle_Sys_Open (filename: ptr to array of char) returns int
  1641.       -- NOT IMPLEMENTED
  1642.       return 0
  1643.     endFunction
  1644.  
  1645. -----------------------------  Handle_Sys_Read  ---------------------------------
  1646.  
  1647.   function Handle_Sys_Read (fileDesc: int, buffer: ptr to char, sizeInBytes: int) returns int
  1648.       -- NOT IMPLEMENTED
  1649.       return 0
  1650.     endFunction
  1651.  
  1652. -----------------------------  Handle_Sys_Write  ---------------------------------
  1653.  
  1654.   function Handle_Sys_Write (fileDesc: int, buffer: ptr to char, sizeInBytes: int) returns int
  1655.       -- NOT IMPLEMENTED
  1656.       return 0
  1657.     endFunction
  1658.  
  1659. -----------------------------  Handle_Sys_Seek  ---------------------------------
  1660.  
  1661.   function Handle_Sys_Seek (fileDesc: int, newCurrentPos: int) returns int
  1662.       -- NOT IMPLEMENTED
  1663.       return 0
  1664.     endFunction
  1665.  
  1666. -----------------------------  Handle_Sys_Close  ---------------------------------
  1667.  
  1668.   function Handle_Sys_Close (fileDesc: int)
  1669.       -- NOT IMPLEMENTED
  1670.     endFunction
  1671.  
  1672. endCode
  1673.