; ; thread.sh ; ; Preemptive multitasking of idle threads ; ; © 1994-1998 Straylight ; ;----- Licensing note ------------------------------------------------------- ; ; This file is part of Straylight's Sapphire library. ; ; Sapphire is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2, or (at your option) ; any later version. ; ; Sapphire is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with Sapphire. If not, write to the Free Software Foundation, ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ;----- Overview ------------------------------------------------------------- ; ; Functions provided: ; ; thread_create ; thread_setPriority ; thread_setTimeSlice ; thread_destroy ; thread_suspend ; thread_resume ; thread_yield ; thread_createSem ; thread_destroySem ; thread_threaded ; thread_wait ; thread_signal ; thread_init ; thread_enterCrit ; thread_leaveCrit ; thread_errorHandler [ :LNOT::DEF:thread__dfn GBLL thread__dfn ; --- thread_create --- ; ; On entry: R0 == size of stack to allocate, or 0 for a default ; R1 == pointer to thread routine ; R2 == workspace pointer to pass in R10 ; R3 == workspace pointer to pass in R12 ; ; On exit: R0 == thread handle for the thread ; May return an error ; ; Use: Creates a new thread running `in the background' (i.e. over ; idle events). ; ; The thread is passed control with the registers R10 and R12 ; set up from R1 and R2 passed to this routine and R13 pointing ; to the top of a stack chunk. R0 on entry contains the ; thread's handle. The thread is passed the scratchpad ; address (in R11). The values of other registers are ; indeterminate and must not be relied upon. ; ; The default stack size for a new thread is 1K, although this ; may change in future. ; ; The thread may exit by calling thread_destroy or by ; returning in the normal way. IMPORT thread_create ; --- thread_setPriority --- ; ; On entry: R0 == thread handle ; R1 == new priority to set ; ; On exit: -- ; ; Use: Changes the priority of a thread. The priority if a thread ; is a signed integer. The highest priority thread is the one ; which runs. If more than one thread has maximum priority, ; they are run in a cyclical order. IMPORT thread_setPriority ; --- thread_setTimeSlice --- ; ; On entry: R0 == thread handle ; R1 == new timeslice size, in centiseconds ; ; On exit: -- ; ; Use: Changes a thread's timeslice size. Specify 0 to indicate ; that thread shouldn't be pre-empted. IMPORT thread_setTimeSlice ; --- thread_destroy --- ; ; On entry: R0 == thread handle to destroy, if not executing a thread ; ; On exit: -- ; ; Use: Destroys either the current thread or a thread with the ; the given handle if no thread is executing currently. You ; can't destroy an arbitrary thread while running in one. ; ; If a thread is waiting for a semaphore, it is removed from ; the waiting list. IMPORT thread_destroy ; --- thread_suspend --- ; ; On entry: R0 == thread handle, or 0 for the current thread ; ; On exit: -- ; ; Use: Suspends a thread's execution. If a thread is currently ; running, that thread is suspended. Otherwise, any thread ; may be suspended. ; ; If the thread is currently claiming semaphores, the ; semaphores are not released, because we don't whether the ; system is in a fit state for this. ; ; Thread suspensions are counted. i.e. if you suspend a thread ; 5 times, you have to resume it 5 times for it to become ; active again. IMPORT thread_suspend ; --- thread_resume --- ; ; On entry: R0 == thread handle ; ; On exit: -- ; ; Use: Allows a suspended thread to continue operations. If you ; resume a thread more times than it has been suspended, ; any excess resumes are ignored. You can't resume a thread ; to stop it being blocked by a semaphore. IMPORT thread_resume ; --- thread_yield --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Pauses the thread for a while. You only need to use this ; call if you have stopped the current thread from being ; timesliced. IMPORT thread_yield ; --- thread_createSem --- ; ; On entry: R0 == initial value for semaphore (0 for counter, 1 for ; mutex) ; ; On exit: R0 == semaphore handle and V clear if all went well ; R0 == pointer to error and V set if something went wrong ; ; Use: Creates a semaphore with the given initial counter value. ; ; The semaphore can be used to provide serialised access to ; a resource by initialising its value to 1 and performing the ; following: ; ; thread_wait(mySemaphore) ; // ; // Do things with the resource ; // ; thread_signal(mySemaphore) ; ; Or you can inform a thread that it has items in its input ; queue by having the following in the thread code: ; ; while true ; thread_wait(theSemaphore) ; getFromQueue(myQueue,item) ; process(item) ; endWhile ; ; and when inserting queue items: ; ; addToQueue(item) ; thread_signal(theSemaphore) ; ; It is distinctly possible that input queue management will ; be introduced in a separate Sapphire module. IMPORT thread_createSem ; --- thread_destroySem --- ; ; On entry: R0 == semaphore handle ; ; On exit: -- ; ; Use: Destroys a semaphore when it's no use any more. If threads ; are waiting for it, an error is generated. IMPORT thread_destroySem ; --- thread_threaded --- ; ; On entry: -- ; ; On exit: CS if currently running a thread, CC otherwise ; ; Use: Informs the caller whether a thread is currently executing. IMPORT thread_threaded ; --- thread_wait --- ; ; On entry: R0 == semaphore handle ; ; On exit: If successful, R0 preserved and V clear. ; If failed, R0 == pointer to error block and V set ; ; Use: Waits on a sempahore. The algorithm actually is as follows: ; ; if semaphore.counter == 0 then ; addToWaitingList(semaphore,currentThread) ; suspend(currentThread) ; else ; semaphore.counter -= 1 ; endIf ; ; See thread_createSem for suggestions on how to make use of ; semaphores. IMPORT thread_wait ; --- thread_signal --- ; ; On entry: R0 == semaphore handle ; ; On exit: -- ; ; Use: Increments a semaphore's counter if no threads are waiting ; for it, or releases a thread waiting for the semaphore. ; ; The actual algorithm is shown below: ; ; if semaphore.waitingList != 0 then ; thread = removeFromWaitingList(semaphore) ; unSuspend(thread) ; else ; semaphore.counter += 1; ; endif ; ; See thread_createSem for suggestions on how to make use of ; semaphores. IMPORT thread_signal ; --- thread_init --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Initialises the thread system for use. IMPORT thread_init ; --- thread_enterCrit --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Declares that the current thread is about to enter a ; critical section and must not be interrupted. IMPORT thread_enterCrit ; --- thread_leaveCrit --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Declares that the current thread has left the critical ; section and can be interrupted again. IMPORT thread_leaveCrit ; --- thread_errorHandler --- ; ; On entry: R0 == pointer to routine to call ; R1 == R12 value to call with ; R2 == R13 value to call with ; ; On exit: -- ; ; Use: Sets up the error handler for a thread. IMPORT thread_errorHandler ] ;----- That's all, folks ---------------------------------------------------- END