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 / p3 / Thread.c < prev    next >
Text File  |  2006-04-17  |  15KB  |  423 lines

  1. code Thread
  2.  
  3.   -- Harry Porter  --  January 10, 2005
  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.       idleThread.Init ("IdleThread")
  23.       idleThread.Fork (IdleFunction, 0)
  24.       Seti ()
  25.     endFunction
  26.  
  27. -----------------------------  IdleFunction  ---------------------------------
  28.  
  29.   function IdleFunction (arg: int)
  30.     --
  31.     -- This is the "idle thread", a kernel thread which ensures that the ready
  32.     -- list is never empty.  The idle thread constantly yields to other threads
  33.     -- in an infinite loop.  However, before yielding, it first checks to see if
  34.     -- there are other threads.  If there are no other threads, the idle thread
  35.     -- will execute the "wait" instruction.  The "wait" instruction will enable
  36.     -- interrupts and halt CPU execution until the next interrupt arrives.
  37.     --
  38.       var ignore: int
  39.       print ("Initializing Idle Process...\n")
  40.       while true
  41.         ignore = SetInterruptsTo (DISABLED)
  42.         if readyList.IsEmpty ()
  43.           Wait ()
  44.         else
  45.           currentThread.Yield ()
  46.         endIf
  47.       endWhile
  48.     endFunction
  49.  
  50. -----------------------------  Run  ---------------------------------
  51.  
  52.   function Run (nextThread: ptr to Thread)
  53.     --
  54.     -- Begin executing the thread "nextThread", which has already
  55.     -- been removed from the readyList.  The current thread will
  56.     -- be suspended; we assume that its status has already been
  57.     -- changed to READY or BLOCKED.  We assume that interrupts are
  58.     -- DISABLED when called.
  59.     --
  60.     -- This routine is called only from "Thread.Yield" and "Thread.Sleep".
  61.     --
  62.       var prevThread, th: ptr to Thread
  63.       prevThread = currentThread
  64.       prevThread.CheckOverflow ()
  65.       currentThread = nextThread
  66.       nextThread.status = RUNNING
  67.       --print ("SWITCHING from ")
  68.       --print (prevThread.name)
  69.       --print (" to ")
  70.       --print (nextThread.name)
  71.       --print ("\n")
  72.       Switch (prevThread, nextThread)
  73.       --print ("After SWITCH, back in thread ")
  74.       --print (currentThread.name)
  75.       --print ("\n")
  76.       while ! threadsToBeDestroyed.IsEmpty ()
  77.         th = threadsToBeDestroyed.Remove()
  78.         th.status = UNUSED
  79.       endWhile
  80.     endFunction
  81.  
  82. -----------------------------  PrintReadyList  ---------------------------------
  83.  
  84.   function PrintReadyList ()
  85.     --
  86.     -- This routine prints the readyList.  It disables interrupts during the
  87.     -- printing to guarantee that the readyList won't change while it is
  88.     -- being printed, which could cause disaster in this routine!
  89.     --
  90.     var oldStatus: int
  91.       oldStatus = SetInterruptsTo (DISABLED)
  92.         print ("Here is the ready list:\n")
  93.         readyList.ApplyToEach (ThreadPrint)
  94.       oldStatus = SetInterruptsTo (oldStatus)
  95.     endFunction
  96.  
  97. -----------------------------  ThreadStart  ---------------------------------
  98.  
  99.   function ThreadStart ()
  100.     --
  101.     -- This is the first high-level code each thread will execute, and it will
  102.     -- be executed just before the thread function is invoked.  This function
  103.     -- will start all new threads off with interrupts enabled.
  104.     --
  105.       var
  106.         junk: int
  107.       -- print ("ThreadStart...\n")
  108.       junk = SetInterruptsTo (ENABLED)
  109.     endFunction
  110.  
  111. -----------------------------  ThreadFinish  ---------------------------------
  112.  
  113.   function ThreadFinish ()
  114.     --
  115.     -- As the last thing to do in this thread, we want to clean up
  116.     -- and reclaim the Thread object.  This method is called as the
  117.     -- last thing the thread does; this is the normal way for a thread
  118.     -- to die.  However, since the thread is still running in this,
  119.     -- we can't actually do the clean up.  So we just make a note
  120.     -- that it is pending.  After the next thread starts (in method "Run")
  121.     -- we'll finish the job.
  122.     --
  123.       var junk: int
  124.       junk = SetInterruptsTo (DISABLED)
  125.       -- print ("Finishing ")
  126.       -- print (currentThread.name)
  127.       -- print ("\n")
  128.       threadsToBeDestroyed.AddToEnd (currentThread)
  129.       currentThread.Sleep ()
  130.       -- Execution will never reach the next instruction
  131.       debug
  132.     endFunction
  133.  
  134. -----------------------------  FatalError  ---------------------------------
  135.  
  136.   function FatalError (errorMessage: ptr to array of char)
  137.     --
  138.     -- Print out the name of the current thread and the given error message.
  139.     -- Then abort execution.
  140.     --
  141.       var
  142.         junk: int
  143.       junk = SetInterruptsTo (DISABLED)
  144.       print ("\nFATAL ERROR")
  145.       if currentThread    -- If case errors occur before thread initialization
  146.         print (" in ")
  147.         print (currentThread.name)
  148.       endIf
  149.       print (": \"")
  150.       print (errorMessage)
  151.       print ("\" -- TERMINATING!\n")
  152.       RuntimeExit ()
  153.     endFunction
  154.  
  155. -----------------------------  SetInterruptsTo  ---------------------------------
  156.  
  157.   function SetInterruptsTo (newStatus: int) returns int
  158.     --
  159.     -- This routine is passed a status (DISABLED or ENABLED).  It
  160.     -- returns the previous interrupt status and sets the interrupt
  161.     -- status to "newStatus".
  162.     --
  163.     -- Since this routine reads and modifies a shared variable
  164.     -- (currentInterruptStatus), there is a danger of this routine
  165.     -- being re-entered.  Therefore, it momentarily will disable
  166.     -- interrupts, to ensure a valid update to this variable.
  167.     --
  168.       var
  169.         oldStat: int
  170.       Cleari ()
  171.       oldStat = currentInterruptStatus
  172.       if newStatus == ENABLED
  173.         currentInterruptStatus = ENABLED
  174.         Seti ()
  175.       else
  176.         currentInterruptStatus = DISABLED
  177.         Cleari ()
  178.       endIf
  179.       return oldStat
  180.     endFunction
  181.  
  182. -----------------------------  TimerInterruptHandler  ---------------------------------
  183.  
  184.   function TimerInterruptHandler ()
  185.     --
  186.     -- This routine is called when a timer interrupt occurs.  Upon entry,
  187.     -- interrupts are DISABLED.  Upon return, execution will return to
  188.     -- the interrupted process, which necessarily had interrupts ENABLED.
  189.     --
  190.     -- (If you wish to turn time-slicing off, simply diasable the call
  191.     -- to "Yield" in the code below.  Threads will then execute until they
  192.     -- call "Yield" explicitly, or indirectly via, e.g., "Fork", etc.)
  193.     --
  194.       currentInterruptStatus = DISABLED
  195.       -- printChar ('_')
  196.       currentThread.Yield ()
  197.       currentInterruptStatus = ENABLED
  198.     endFunction
  199.  
  200. -----------------------------  ThreadPrint  ---------------------------------
  201.  
  202.   function ThreadPrint (t: ptr to Thread)
  203.     --
  204.     -- This function prints a single line giving the name of thread "t",
  205.     -- its status, and the address of the Thread object itself (which may be
  206.     -- helpful in disnguishing Threads when the name is not helpful).
  207.     --
  208.       var
  209.         oldStatus: int = SetInterruptsTo (DISABLED)
  210.       print ("  Thread \"")
  211.       print (t.name)
  212.       print ("\"    status=")
  213.       switch t.status
  214.         case JUST_CREATED:
  215.           print ("JUST_CREATED")
  216.           break
  217.         case READY:
  218.           print ("READY")
  219.           break
  220.         case RUNNING:
  221.           print ("RUNNING")
  222.           break
  223.         case BLOCKED:
  224.           print ("BLOCKED")
  225.           break
  226.         case UNUSED:
  227.           print ("UNUSED")
  228.           break
  229.         default:
  230.           FatalError ("Bad status in Thread")
  231.       endSwitch
  232.       print ("    (addr of Thread object: ")
  233.       printHex (t asInteger)
  234.       print (")")
  235.       nl ()
  236.       -- t.Print ()
  237.       oldStatus = SetInterruptsTo (oldStatus)
  238.     endFunction
  239.  
  240. -----------------------------  Thread  ---------------------------------
  241.  
  242.   behavior Thread
  243.  
  244.       ----------  Thread . Init  ----------
  245.  
  246.       method Init (n: String)
  247.         --
  248.         -- Initialize this Thread object, but do not schedule it for
  249.         -- execution yet.
  250.         --
  251.           name = n
  252.           status = JUST_CREATED
  253.           -- The next line initializes the systemStack array, without filling it in.
  254.           *((& systemStack) asPtrTo int) = SYSTEM_STACK_SIZE
  255.           systemStack [0] = STACK_SENTINEL
  256.           systemStack [SYSTEM_STACK_SIZE-1] = STACK_SENTINEL
  257.           stackTop = & (systemStack[SYSTEM_STACK_SIZE-1])
  258.           regs = new array of int { 13 of 0 }
  259.         endMethod
  260.  
  261.       ----------  Thread . Fork  ----------
  262.  
  263.       method Fork (fun: ptr to function (int), arg: int)
  264.         --
  265.         -- This method will schedule this thread for execution; in other words
  266.         -- it will make it ready to run by adding it to the "ready queue."  This
  267.         -- method is passed a function and a single integer argument.  When the
  268.         -- thread runs, the thread will execute this function on that argument
  269.         -- and then termiante.  This method will return after scheduling this
  270.         -- thread.
  271.         --
  272.           var
  273.             oldIntStat, junk: int
  274.           oldIntStat = SetInterruptsTo (DISABLED)
  275.           -- print ("Forking thread...\n")
  276.           regs [0] = fun asInteger      -- Set r2 = ptr to function
  277.           regs [1] = arg                -- Set r3 = argument
  278.           stackTop = stackTop - 4
  279.           *(stackTop asPtrTo int) = ThreadStartUp asInteger
  280.           status = READY
  281.           readyList.AddToEnd (self)
  282.           junk = SetInterruptsTo (oldIntStat)
  283.         endMethod
  284.  
  285.       ----------  Thread . Yield  ----------
  286.  
  287.       method Yield ()
  288.         --
  289.         -- This method should only be invoked on the current thread.  The
  290.         -- current thread may yield the processor to other threads by
  291.         -- executing:
  292.         --       currentThread.Yield ()
  293.         -- This method may be invoked with or without interrupts enabled.
  294.         -- Upon return, the interrupts will be in the same state; however
  295.         -- since other threads are given a chance to run and they may allow
  296.         -- interrupts, interrupts handlers may have been invoked before
  297.         -- this method returns.
  298.         --
  299.           var
  300.             nextTh: ptr to Thread
  301.             oldIntStat, junk: int
  302.           -- ASSERT:
  303.               if self != currentThread
  304.                 FatalError ("In Yield, self != currentThread")
  305.               endIf
  306.           oldIntStat = SetInterruptsTo (DISABLED)
  307.           -- print ("Yielding ")
  308.           -- print (name)
  309.           -- print ("\n")
  310.           nextTh = readyList.Remove ()
  311.           if nextTh
  312.             -- print ("About to run ")
  313.             -- print (nextTh.name)
  314.             -- print ("\n")
  315.             if status == BLOCKED
  316.               FatalError ("Status of current thread should be READY or RUNNING")
  317.             endIf
  318.             status = READY
  319.             readyList.AddToEnd (self)
  320.             Run (nextTh)
  321.           endIf
  322.           junk = SetInterruptsTo (oldIntStat)
  323.         endMethod
  324.  
  325.       ----------  Thread . Sleep  ----------
  326.  
  327.       method Sleep ()
  328.         --
  329.         -- This method should only be invoked on the current thread.  It
  330.         -- will set the status of the current thread to BLCOKED and will
  331.         -- will switch to executing another thread.  It is assumed that
  332.         --     (1) Interrupts are disabled before calling this routine, and
  333.         --     (2) The current thread has been placed on some other wait
  334.         --         list (e.g., for a Semaphore) or else the thread will
  335.         --         never get scheduled again.
  336.         --
  337.           var nextTh: ptr to Thread
  338.           -- ASSERT:
  339.               if currentInterruptStatus != DISABLED
  340.                 FatalError ("In Sleep, currentInterruptStatus != DISABLED")
  341.               endIf
  342.           -- ASSERT:
  343.               if self != currentThread
  344.                 FatalError ("In Sleep, self != currentThread")
  345.               endIf
  346.           -- print ("Sleeping ")
  347.           -- print (name)
  348.           -- print ("\n")
  349.           status = BLOCKED
  350.           nextTh = readyList.Remove ()
  351.           if nextTh == null
  352.             FatalError ("Ready list should always contain the idle thread")
  353.           endIf
  354.           Run (nextTh)
  355.         endMethod
  356.  
  357.       ----------  Thread . CheckOverflow  ----------
  358.  
  359.       method CheckOverflow ()
  360.         --
  361.         -- This method checks to see if this thread has overflowed its
  362.         -- pre-alloted stack space.  WARNING: the approach taken here is only
  363.         -- guaranteed to work "with high probability".
  364.         --
  365.           if systemStack[0] != STACK_SENTINEL
  366.             FatalError ("System stack overflow detected!")
  367.           elseIf systemStack[SYSTEM_STACK_SIZE-1] != STACK_SENTINEL
  368.             FatalError ("System stack underflow detected!")
  369.           endIf
  370.         endMethod
  371.  
  372.       ----------  Thread . Print  ----------
  373.  
  374.       method Print ()
  375.         --
  376.         -- Print this object.
  377.         --
  378.           var i: int
  379.               oldStatus: int
  380.           oldStatus = SetInterruptsTo (DISABLED)
  381.           print ("  Thread \"")
  382.           print (name)
  383.           print ("\"    (addr of Thread object: ")
  384.           printHex (self asInteger)
  385.           print (")\n")
  386.           print ("    machine state:\n")
  387.           for i = 0 to 12
  388.             print ("      r")
  389.             printInt (i+2)
  390.             print (": ")
  391.             printHex (regs[i])
  392.             print ("   ")
  393.             printInt (regs[i])
  394.             print ("\n")
  395.           endFor
  396.           printHexVar ("    stackTop", stackTop asInteger)
  397.           printHexVar ("    stack starting addr", (& systemStack[0]) asInteger)
  398.           switch status
  399.             case JUST_CREATED:
  400.               print ("    status = JUST_CREATED\n")
  401.               break
  402.             case READY:
  403.               print ("    status = READY\n")
  404.               break
  405.             case RUNNING:
  406.               print ("    status = RUNNING\n")
  407.               break
  408.             case BLOCKED:
  409.               print ("    status = BLOCKED\n")
  410.               break
  411.             case UNUSED:
  412.               print ("    status = UNUSED\n")
  413.               break
  414.             default:
  415.               FatalError ("Bad status in Thread")
  416.           endSwitch
  417.           oldStatus = SetInterruptsTo (oldStatus)
  418.       endMethod
  419.  
  420.   endBehavior
  421.  
  422. endCode
  423.