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