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