chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Sapphire / sh / thread
1 ;
2 ; thread.sh
3 ;
4 ; Preemptive multitasking of idle threads
5 ;
6 ; © 1994-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's Sapphire library.
12 ;
13 ; Sapphire is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
16 ; any later version.
17 ;
18 ; Sapphire is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 ; GNU General Public License for more details.
22 ;
23 ; You should have received a copy of the GNU General Public License
24 ; along with Sapphire.  If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27 ;----- Overview -------------------------------------------------------------
28 ;
29 ; Functions provided:
30 ;
31 ;  thread_create
32 ;  thread_setPriority
33 ;  thread_setTimeSlice
34 ;  thread_destroy
35 ;  thread_suspend
36 ;  thread_resume
37 ;  thread_yield
38 ;  thread_createSem
39 ;  thread_destroySem
40 ;  thread_threaded
41 ;  thread_wait
42 ;  thread_signal
43 ;  thread_init
44 ;  thread_enterCrit
45 ;  thread_leaveCrit
46 ;  thread_errorHandler
47
48                 [       :LNOT::DEF:thread__dfn
49                 GBLL    thread__dfn
50
51 ; --- thread_create ---
52 ;
53 ; On entry:     R0 == size of stack to allocate, or 0 for a default
54 ;               R1 == pointer to thread routine
55 ;               R2 == workspace pointer to pass in R10
56 ;               R3 == workspace pointer to pass in R12
57 ;
58 ; On exit:      R0 == thread handle for the thread
59 ;               May return an error
60 ;
61 ; Use:          Creates a new thread running `in the background' (i.e. over
62 ;               idle events).
63 ;
64 ;               The thread is passed control with the registers R10 and R12
65 ;               set up from R1 and R2 passed to this routine and R13 pointing
66 ;               to the top of a stack chunk.  R0 on entry contains the
67 ;               thread's handle.  The thread is passed the scratchpad
68 ;               address (in R11).  The values of other registers are
69 ;               indeterminate and must not be relied upon.
70 ;
71 ;               The default stack size for a new thread is 1K, although this
72 ;               may change in future.
73 ;
74 ;               The thread may exit by calling thread_destroy or by
75 ;               returning in the normal way.
76
77                 IMPORT  thread_create
78
79 ; --- thread_setPriority ---
80 ;
81 ; On entry:     R0 == thread handle
82 ;               R1 == new priority to set
83 ;
84 ; On exit:      --
85 ;
86 ; Use:          Changes the priority of a thread.  The priority if a thread
87 ;               is a signed integer.  The highest priority thread is the one
88 ;               which runs.  If more than one thread has maximum priority,
89 ;               they are run in a cyclical order.
90
91                 IMPORT  thread_setPriority
92
93 ; --- thread_setTimeSlice ---
94 ;
95 ; On entry:     R0 == thread handle
96 ;               R1 == new timeslice size, in centiseconds
97 ;
98 ; On exit:      --
99 ;
100 ; Use:          Changes a thread's timeslice size.  Specify 0 to indicate
101 ;               that thread shouldn't be pre-empted.
102
103                 IMPORT  thread_setTimeSlice
104
105 ; --- thread_destroy ---
106 ;
107 ; On entry:     R0 == thread handle to destroy, if not executing a thread
108 ;
109 ; On exit:      --
110 ;
111 ; Use:          Destroys either the current thread or a thread with the
112 ;               the given handle if no thread is executing currently.  You
113 ;               can't destroy an arbitrary thread while running in one.
114 ;
115 ;               If a thread is waiting for a semaphore, it is removed from
116 ;               the waiting list.
117
118                 IMPORT  thread_destroy
119
120 ; --- thread_suspend ---
121 ;
122 ; On entry:     R0 == thread handle, or 0 for the current thread
123 ;
124 ; On exit:      --
125 ;
126 ; Use:          Suspends a thread's execution.  If a thread is currently
127 ;               running, that thread is suspended.  Otherwise, any thread
128 ;               may be suspended.
129 ;
130 ;               If the thread is currently claiming semaphores, the
131 ;               semaphores are not released, because we don't whether the
132 ;               system is in a fit state for this.
133 ;
134 ;               Thread suspensions are counted.  i.e. if you suspend a thread
135 ;               5 times, you have to resume it 5 times for it to become
136 ;               active again.
137
138                 IMPORT  thread_suspend
139
140 ; --- thread_resume ---
141 ;
142 ; On entry:     R0 == thread handle
143 ;
144 ; On exit:      --
145 ;
146 ; Use:          Allows a suspended thread to continue operations.  If you
147 ;               resume a thread more times than it has been suspended,
148 ;               any excess resumes are ignored.  You can't resume a thread
149 ;               to stop it being blocked by a semaphore.
150
151                 IMPORT  thread_resume
152
153 ; --- thread_yield ---
154 ;
155 ; On entry:     --
156 ;
157 ; On exit:      --
158 ;
159 ; Use:          Pauses the thread for a while.  You only need to use this
160 ;               call if you have stopped the current thread from being
161 ;               timesliced.
162
163                 IMPORT  thread_yield
164
165 ; --- thread_createSem ---
166 ;
167 ; On entry:     R0 == initial value for semaphore (0 for counter, 1 for
168 ;                     mutex)
169 ;
170 ; On exit:      R0 == semaphore handle and V clear if all went well
171 ;               R0 == pointer to error and V set if something went wrong
172 ;
173 ; Use:          Creates a semaphore with the given initial counter value.
174 ;
175 ;               The semaphore can be used to provide serialised access to
176 ;               a resource by initialising its value to 1 and performing the
177 ;               following:
178 ;
179 ;               thread_wait(mySemaphore)
180 ;               //
181 ;               // Do things with the resource
182 ;               //
183 ;               thread_signal(mySemaphore)
184 ;
185 ;               Or you can inform a thread that it has items in its input
186 ;               queue by having the following in the thread code:
187 ;
188 ;               while true
189 ;                 thread_wait(theSemaphore)
190 ;                 getFromQueue(myQueue,item)
191 ;                 process(item)
192 ;               endWhile
193 ;
194 ;               and when inserting queue items:
195 ;
196 ;               addToQueue(item)
197 ;               thread_signal(theSemaphore)
198 ;
199 ;               It is distinctly possible that input queue management will
200 ;               be introduced in a separate Sapphire module.
201
202                 IMPORT  thread_createSem
203
204 ; --- thread_destroySem ---
205 ;
206 ; On entry:     R0 == semaphore handle
207 ;
208 ; On exit:      --
209 ;
210 ; Use:          Destroys a semaphore when it's no use any more.  If threads
211 ;               are waiting for it, an error is generated.
212
213                 IMPORT  thread_destroySem
214
215 ; --- thread_threaded ---
216 ;
217 ; On entry:     --
218 ;
219 ; On exit:      CS if currently running a thread, CC otherwise
220 ;
221 ; Use:          Informs the caller whether a thread is currently executing.
222
223                 IMPORT  thread_threaded
224
225 ; --- thread_wait ---
226 ;
227 ; On entry:     R0 == semaphore handle
228 ;
229 ; On exit:      If successful, R0 preserved and V clear.
230 ;               If failed, R0 == pointer to error block and V set
231 ;
232 ; Use:          Waits on a sempahore.  The algorithm actually is as follows:
233 ;
234 ;               if semaphore.counter == 0 then
235 ;                 addToWaitingList(semaphore,currentThread)
236 ;                 suspend(currentThread)
237 ;               else
238 ;                 semaphore.counter -= 1
239 ;               endIf
240 ;
241 ;               See thread_createSem for suggestions on how to make use of
242 ;               semaphores.
243
244                 IMPORT  thread_wait
245
246 ; --- thread_signal ---
247 ;
248 ; On entry:     R0 == semaphore handle
249 ;
250 ; On exit:      --
251 ;
252 ; Use:          Increments a semaphore's counter if no threads are waiting
253 ;               for it, or releases a thread waiting for the semaphore.
254 ;
255 ;               The actual algorithm is shown below:
256 ;
257 ;               if semaphore.waitingList != 0 then
258 ;                 thread = removeFromWaitingList(semaphore)
259 ;                 unSuspend(thread)
260 ;               else
261 ;                 semaphore.counter += 1;
262 ;               endif
263 ;
264 ;               See thread_createSem for suggestions on how to make use of
265 ;               semaphores.
266
267                 IMPORT  thread_signal
268
269 ; --- thread_init ---
270 ;
271 ; On entry:     --
272 ;
273 ; On exit:      --
274 ;
275 ; Use:          Initialises the thread system for use.
276
277                 IMPORT  thread_init
278
279 ; --- thread_enterCrit ---
280 ;
281 ; On entry:     --
282 ;
283 ; On exit:      --
284 ;
285 ; Use:          Declares that the current thread is about to enter a
286 ;               critical section and must not be interrupted.
287
288                 IMPORT  thread_enterCrit
289
290 ; --- thread_leaveCrit ---
291 ;
292 ; On entry:     --
293 ;
294 ; On exit:      --
295 ;
296 ; Use:          Declares that the current thread has left the critical
297 ;               section and can be interrupted again.
298
299                 IMPORT  thread_leaveCrit
300
301 ; --- thread_errorHandler ---
302 ;
303 ; On entry:     R0 == pointer to routine to call
304 ;               R1 == R12 value to call with
305 ;               R2 == R13 value to call with
306 ;
307 ; On exit:      --
308 ;
309 ; Use:          Sets up the error handler for a thread.
310
311                 IMPORT  thread_errorHandler
312
313                 ]
314
315 ;----- That's all, folks ----------------------------------------------------
316
317                 END