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