FreeBSD/Linux Kernel Cross Reference
sys/kern/rt_thread.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: rt_thread.c,v $
29 * Revision 2.2 93/11/17 17:20:03 dbg
30 * Renamed 'rt' or 'realtime' threads and timers to 'periodic'
31 * threads and timers (even though they can be used for nonperiodic
32 * threads).
33 * [93/11/16 dbg]
34 *
35 * Use thread_lock instead of ith_lock.
36 * [93/07/12 dbg]
37 *
38 * Handle starting timer better.
39 * [93/06/28 dbg]
40 *
41 * Changed thread_{get,set}_deadline_timer to
42 * thread_{get,set}_realtime_timers.
43 * [93/06/25 dbg]
44 *
45 * Use clock_read to read clock without locking.
46 * [93/06/18 dbg]
47 *
48 * machparam.h -> machspl.h
49 * [93/05/21 dbg]
50 *
51 * Conditionalize for MACH_RT.
52 * [93/05/17 dbg]
53 *
54 * Changed for flexible thread scheduling fields.
55 * [93/05/12 dbg]
56 *
57 * Added thread_get_deadline_timer, thread_set_deadline_timer.
58 * [93/04/15 dbg]
59 *
60 * Use sleep/wakeup instead of suspend/resume to wait for wakeup
61 * timer.
62 * [93/04/02 dbg]
63 *
64 * Moved thread_{get,set}_attributes here.
65 * [93/03/31 dbg]
66 *
67 * Merged into microkernel mainline.
68 *
69 * Checked time_specs to make sure they're valid
70 * [92/09/11 savage]
71 * Changed period and deadline to time_spec_t.
72 * [92/09/06 savage]
73 * Switched to use clock parameter instead of constant. Cleanup.
74 * [92/07/12 savage]
75 * Replaced rt_timers with more generic mach_timers
76 * [92/06/22 savage]
77 * Replaced wakeup queue with rt_timer mechanism
78 * [92/05/05 savage]
79 * Re-vamped :-)
80 * [92/02/22 savage]
81 * Created
82 * [90/06/28 tatsuo]
83 *
84 */
85 #include <mach_rt.h>
86
87 #include <mach/kern_return.h>
88 #include <mach/realtime_policy.h>
89 #include <mach/time_spec.h>
90
91 #include <ipc/ipc_object.h>
92 #include <ipc/ipc_port.h>
93
94 #include <kern/clock.h>
95 #include <kern/lock.h>
96 #include <kern/mach_param.h>
97 #include <kern/mach_timer.h>
98 #include <kern/rt_thread.h>
99 #include <kern/thread.h>
100 #include <kern/zalloc.h>
101
102 #include <vm/vm_kern.h>
103
104 #include <machine/machspl.h>
105
106 #if MACH_RT
107 /*
108 * Routine: thread_get_periodic_timers
109 * Purpose: gets the wakeup and deadline timers for a thread.
110 */
111 kern_return_t
112 thread_get_periodic_timers(
113 thread_t thread,
114 mach_timer_t *wakeup_timer_p, /* OUT */
115 mach_timer_t *deadline_timer_p)
116 {
117 mach_timer_t wakeup_timer, deadline_timer;
118
119 if (thread == THREAD_NULL)
120 return KERN_INVALID_ARGUMENT;
121
122 thread_lock(thread);
123 wakeup_timer = thread->rt_wakeup_timer;
124 mach_timer_reference(wakeup_timer);
125 deadline_timer = thread->rt_deadline_timer;
126 mach_timer_reference(deadline_timer);
127 thread_unlock(thread);
128
129 *wakeup_timer_p = wakeup_timer;
130 *deadline_timer_p = deadline_timer;
131
132 return KERN_SUCCESS;
133 }
134
135 /*
136 * Routine: thread_set_periodic_timers
137 * Purpose: sets the wakeup and deadline timers for a thread.
138 */
139 kern_return_t
140 thread_set_periodic_timers(
141 thread_t thread,
142 mach_timer_t new_wakeup_timer,
143 mach_timer_t new_deadline_timer)
144 {
145 mach_timer_t old_wakeup_timer;
146 mach_timer_t old_deadline_timer;
147
148 if (thread == THREAD_NULL)
149 return KERN_INVALID_ARGUMENT;
150
151 /*
152 * Make thread references to the new timers
153 * to keep them alive even if all send rights
154 * vanish.
155 */
156 if (!mach_timer_thread_reference(new_wakeup_timer)) {
157 /* dead already (?) */
158 return KERN_INVALID_ARGUMENT;
159 }
160 if (!mach_timer_thread_reference(new_deadline_timer)) {
161 mach_timer_thread_deallocate(new_wakeup_timer);
162 return KERN_INVALID_ARGUMENT;
163 }
164
165
166 /*
167 * Swap the old and new timers.
168 */
169 thread_lock(thread);
170 old_wakeup_timer = thread->rt_wakeup_timer;
171 thread->rt_wakeup_timer = new_wakeup_timer;
172 old_deadline_timer = thread->rt_deadline_timer;
173 thread->rt_deadline_timer = new_deadline_timer;
174 thread_unlock(thread);
175
176 /*
177 * Deallocate the thread-references to
178 * the old timers.
179 */
180 if (old_wakeup_timer != 0)
181 mach_timer_thread_deallocate(old_wakeup_timer);
182 if (old_deadline_timer != 0)
183 mach_timer_thread_deallocate(old_deadline_timer);
184
185 return KERN_SUCCESS;
186 }
187
188 /*
189 * Routine: periodic_thread_create
190 * Purpose: Creates a thread via thread_create, sets scheduling
191 * parameters, sets execution state, and then either
192 * thread_resumes the thread or enqueues it to be resumed
193 * later.
194 * Conditions: None
195 */
196 kern_return_t periodic_thread_create(
197 task_t parent_task,
198 mach_clock_t clock,
199 policy_param_realtime_t rt_attr,
200 ipc_port_t deadline_port,
201 int state_flavor,
202 thread_state_t state,
203 natural_t state_count,
204 thread_t *child_thread) /* out */
205 {
206 register
207 thread_t thread;
208 mach_timer_t wakeup_timer;
209 mach_timer_t deadline_timer;
210 int periodic;
211 kern_return_t ret;
212
213 if (parent_task == TASK_NULL || clock == 0)
214 return KERN_INVALID_ARGUMENT;
215
216 /*
217 * Are the time_specs legitimate?
218 */
219 if (!time_spec_valid(rt_attr.start_time) ||
220 !time_spec_valid(rt_attr.period) ||
221 !time_spec_valid(rt_attr.deadline))
222 {
223 return KERN_INVALID_VALUE;
224 }
225 if (rt_attr.start_when != START_TIME_ABSOLUTE &&
226 rt_attr.start_when != START_TIME_RELATIVE)
227 {
228 return KERN_INVALID_VALUE;
229 }
230
231 /*
232 * Convert zero period or deadline to infinity.
233 */
234 if (!time_spec_nonzero(rt_attr.period)) {
235 time_spec_set_infinite(rt_attr.period);
236 }
237 if (!time_spec_nonzero(rt_attr.deadline)) {
238 time_spec_set_infinite(rt_attr.deadline);
239 }
240
241 /*
242 * Create the thread.
243 */
244 {
245 thread_t temp_thread; /* to keep 'thread' in register */
246
247 ret = thread_create(parent_task, &temp_thread);
248 if (ret != KERN_SUCCESS)
249 return ret;
250
251 thread = temp_thread;
252 }
253
254 /*
255 * Set initial register state for the thread.
256 */
257 ret = thread_setstatus(thread, state_flavor, state, state_count);
258 if (ret != KERN_SUCCESS) {
259 (void) thread_terminate(thread);
260 return ret;
261 }
262
263 /*
264 * Create a wakeup timer for the thread.
265 */
266 ret = timer_create(clock, &wakeup_timer);
267 if (ret != KERN_SUCCESS) {
268 (void) thread_terminate(thread);
269 thread_deallocate(thread);
270 return ret;
271 }
272
273 /*
274 * Create a deadline timer for the thread.
275 */
276 ret = timer_create(clock, &deadline_timer);
277 if (ret != KERN_SUCCESS) {
278 (void) timer_terminate(wakeup_timer);
279 (void) thread_terminate(thread);
280 thread_deallocate(thread);
281 return ret;
282 }
283
284 /*
285 * Calculate the absolute start time, so that
286 * the wakeup and deadline timers are consistent.
287 * Give it to thread_set_policy_param.
288 */
289 if (rt_attr.start_when == START_TIME_RELATIVE) {
290 time_spec_t cur_time;
291 clock_read(cur_time, clock);
292 time_spec_add(rt_attr.start_time, cur_time);
293 rt_attr.start_when = START_TIME_ABSOLUTE;
294 }
295
296 /*
297 * Set the scheduling policy and attributes for
298 * the thread. Do this before registering the
299 * timers for the thread, so that the timers
300 * can be set later (with the wakeup-thread
301 * and deadline port).
302 */
303 ret = thread_set_policy_param(thread,
304 FALSE,
305 (natural_t *)&rt_attr,
306 POLICY_PARAM_REALTIME_COUNT);
307 if (ret != KERN_SUCCESS) {
308 (void) thread_terminate(thread);
309 return ret;
310 }
311
312 /*
313 * Register the timers with the thread.
314 */
315 (void) thread_set_periodic_timers(thread,
316 wakeup_timer,
317 deadline_timer);
318
319 /*
320 * Set the 'periodic' flag for the timers.
321 */
322 if (time_spec_infinite(rt_attr.period))
323 periodic = 0; /* not periodic */
324 else
325 periodic = TIMER_PERIODIC; /* periodic thread */
326
327 /*
328 * Set the wakeup timer for the starting time
329 * of the thread, and make it periodic if thread
330 * is periodic.
331 */
332 ret = timer_sleep_periodic(wakeup_timer,
333 rt_attr.start_time,
334 rt_attr.period,
335 thread,
336 TIMER_ABSOLUTE | periodic);
337 if (ret != KERN_SUCCESS) {
338 (void) thread_terminate(thread);
339 return ret;
340 }
341
342 /*
343 * Set the deadline timer, if the thread has
344 * a deadline.
345 */
346 if (!time_spec_infinite(rt_attr.deadline)) {
347 time_spec_t deadline_time;
348
349 deadline_time = rt_attr.start_time;
350 time_spec_add(deadline_time, rt_attr.deadline);
351 ret = timer_arm(deadline_timer,
352 deadline_time,
353 rt_attr.period,
354 deadline_port,
355 THREAD_NULL,
356 TIMER_THREAD_SUSPEND | TIMER_ABSOLUTE | periodic);
357 if (ret != KERN_SUCCESS) {
358 /*
359 * Bad parameter to time?
360 */
361 (void) thread_terminate(thread);
362 return ret;
363 }
364 }
365
366 /*
367 * Resume the thread. If it has a delayed start,
368 * it will be waiting for the wakeup timer.
369 */
370 (void) thread_resume(thread);
371
372 /*
373 * Return the child thread.
374 */
375 *child_thread = thread;
376 return KERN_SUCCESS;
377 }
378
379
380 /*
381 * Routine: periodic_thread_restart
382 * Purpose: Resets timers and execution state for periodic threads.
383 * This routine is usually only called via fiddling with
384 * the user stack and is never invoked directly.
385 * Conditions: None
386 */
387 kern_return_t periodic_thread_restart(
388 thread_t thread)
389 {
390 mach_timer_t wakeup_timer;
391 mach_timer_t deadline_timer;
392
393 if (thread == THREAD_NULL)
394 return KERN_INVALID_ARGUMENT;
395
396 /*
397 * Thread must have wakeup and deadline timers
398 */
399 deadline_timer = thread->rt_deadline_timer;
400 wakeup_timer = thread->rt_wakeup_timer;
401 if (deadline_timer == 0 || wakeup_timer == 0)
402 return KERN_INVALID_ARGUMENT;
403
404 /*
405 * Cancel the current iteration of the deadline timer.
406 * If the thread is periodic, this resets the deadline
407 * timer to the deadline for the thread`s next
408 * execution period.
409 */
410
411 (void) timer_cancel(deadline_timer, TIMER_PERIODIC);
412
413 /*
414 * If the thread is not periodic, terminate it.
415 *
416 * XXX locking on timer
417 */
418 if ((wakeup_timer->tm_flags & TELT_PERIODIC) == 0) {
419 return thread_terminate(thread);
420 }
421
422 /*
423 * Periodic thread. Wait for the next
424 * expiration of the wakeup timer.
425 */
426 timer_wait(wakeup_timer, thread);
427
428 /*
429 * Thread is now waiting for timer.
430 * If it is the current thread, block to
431 * wait for timer.
432 *
433 * If thread is NOT the current thread, it better
434 * be suspended...
435 */
436 if (thread == current_thread()) {
437 thread_block(CONTINUE_NULL);
438 }
439
440 return KERN_SUCCESS;
441 }
442
443 #else /* MACH_RT */
444
445 /*
446 * Periodic thread interfaces are not implemented, and all
447 * return KERN_FAILURE.
448 */
449 kern_return_t
450 thread_get_periodic_timers(
451 thread_t thread,
452 mach_timer_t *wakeup_timer_p, /* OUT */
453 mach_timer_t *deadline_timer_p)
454 {
455 return KERN_FAILURE;
456 }
457
458 kern_return_t
459 thread_set_periodic_timers(
460 thread_t thread,
461 mach_timer_t new_wakeup_timer,
462 mach_timer_t new_deadline_timer)
463 {
464 return KERN_FAILURE;
465 }
466
467 kern_return_t periodic_thread_create(
468 task_t parent_task,
469 mach_clock_t clock,
470 policy_param_realtime_t rt_attr,
471 ipc_port_t deadline_port,
472 int state_flavor,
473 thread_state_t state,
474 natural_t state_count,
475 thread_t *child_thread) /* out */
476 {
477 return KERN_FAILURE;
478 }
479
480 kern_return_t periodic_thread_restart(
481 thread_t thread)
482 {
483 return KERN_FAILURE;
484 }
485
486 #endif /* MACH_RT */
Cache object: 1627cc90d8132f76284d8e635be4cf59
|