|
0
|
1 //========================================================================== |
|
|
2 // |
|
2
|
3 // common/thread.cxx |
|
0
|
4 // |
|
2
|
5 // Thread class implementations |
|
0
|
6 // |
|
|
7 //========================================================================== |
|
|
8 //####COPYRIGHTBEGIN#### |
|
|
9 // |
|
|
10 // ------------------------------------------- |
|
|
11 // The contents of this file are subject to the Cygnus eCos Public License |
|
|
12 // Version 1.0 (the "License"); you may not use this file except in |
|
|
13 // compliance with the License. You may obtain a copy of the License at |
|
|
14 // http://sourceware.cygnus.com/ecos |
|
|
15 // |
|
|
16 // Software distributed under the License is distributed on an "AS IS" |
|
|
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
|
18 // License for the specific language governing rights and limitations under |
|
|
19 // the License. |
|
|
20 // |
|
|
21 // The Original Code is eCos - Embedded Cygnus Operating System, released |
|
|
22 // September 30, 1998. |
|
|
23 // |
|
|
24 // The Initial Developer of the Original Code is Cygnus. Portions created |
|
2
|
25 // by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. |
|
0
|
26 // ------------------------------------------- |
|
|
27 // |
|
|
28 //####COPYRIGHTEND#### |
|
|
29 //========================================================================== |
|
|
30 //#####DESCRIPTIONBEGIN#### |
|
|
31 // |
|
2
|
32 // Author(s): nickg |
|
|
33 // Contributors: nickg |
|
|
34 // Date: 1997-09-15 |
|
|
35 // Purpose: Thread class implementation |
|
|
36 // Description: This file contains the definitions of the thread class |
|
0
|
37 // member functions that are common to all thread implementations. |
|
|
38 // |
|
|
39 //####DESCRIPTIONEND#### |
|
|
40 // |
|
|
41 //========================================================================== |
|
|
42 |
|
|
43 #include <pkgconf/kernel.h> // kernel configuration file |
|
|
44 |
|
2
|
45 #include <cyg/hal/hal_arch.h> // HAL_REORDER_BARRIER & |
|
|
46 // CYGNUM_HAL_STACK_SIZE_TYPICAL |
|
|
47 |
|
0
|
48 #include <cyg/kernel/ktypes.h> // base kernel types |
|
|
49 #include <cyg/infra/cyg_trac.h> // tracing macros |
|
|
50 #include <cyg/infra/cyg_ass.h> // assertion macros |
|
|
51 #include <cyg/kernel/instrmnt.h> // instrumentation |
|
|
52 |
|
|
53 #include <cyg/kernel/thread.hxx> // our header |
|
|
54 |
|
|
55 #include <cyg/kernel/intr.hxx> // Interrupt support |
|
|
56 |
|
|
57 #include <cyg/kernel/thread.inl> // thread inlines |
|
|
58 #include <cyg/kernel/sched.inl> // scheduler inlines |
|
|
59 #include <cyg/kernel/clock.inl> // clock inlines |
|
|
60 |
|
|
61 // ========================================================================= |
|
|
62 // Cyg_HardwareThread members |
|
|
63 |
|
|
64 // ------------------------------------------------------------------------- |
|
|
65 // Thread entry point. |
|
|
66 // This is inserted as the PC value in all initial thread contexts. |
|
|
67 // It does some housekeeping and then calls the real entry point. |
|
|
68 |
|
|
69 void |
|
|
70 Cyg_HardwareThread::thread_entry( Cyg_Thread *thread ) |
|
|
71 { |
|
|
72 CYG_REPORT_FUNCTION(); |
|
|
73 |
|
|
74 Cyg_Scheduler::scheduler.need_reschedule = false; // finished rescheduling |
|
|
75 Cyg_Scheduler::scheduler.current_thread = thread; // restore current thread pointer |
|
|
76 |
|
|
77 #ifdef CYGSEM_KERNEL_SCHED_TIMESLICE |
|
|
78 // Reset the timeslice counter so that this thread gets a full |
|
|
79 // quantum. |
|
|
80 Cyg_Scheduler::reset_timeslice_count(); |
|
|
81 #endif |
|
|
82 |
|
|
83 // Zero the lock |
|
2
|
84 HAL_REORDER_BARRIER (); // Prevent the compiler from moving |
|
|
85 Cyg_Scheduler::sched_lock = 0; // the assignment into the code above. |
|
|
86 HAL_REORDER_BARRIER(); |
|
0
|
87 |
|
|
88 // Call entry point in a loop. |
|
|
89 |
|
|
90 for(;;) |
|
|
91 { |
|
|
92 thread->entry_point(thread->entry_data); |
|
|
93 thread->exit(); |
|
|
94 } |
|
|
95 } |
|
|
96 |
|
|
97 // ========================================================================= |
|
|
98 // Cyg_Thread members |
|
|
99 |
|
|
100 // ------------------------------------------------------------------------- |
|
|
101 // Statics and thread list functions |
|
|
102 |
|
|
103 #ifdef CYGVAR_KERNEL_THREADS_LIST |
|
|
104 |
|
|
105 // List of all extant threads |
|
|
106 Cyg_Thread *Cyg_Thread::thread_list = 0; |
|
|
107 |
|
|
108 inline void |
|
|
109 Cyg_Thread::add_to_list( void ) |
|
|
110 { |
|
|
111 // Add thread to housekeeping list |
|
|
112 Cyg_Scheduler::lock(); |
|
|
113 |
|
|
114 if( thread_list == 0 ) |
|
|
115 list_next = this; |
|
|
116 else { |
|
|
117 Cyg_Thread *prev = thread_list; |
|
|
118 do { |
|
|
119 if ( this == prev ) |
|
|
120 break; // found it already! |
|
|
121 prev = prev->list_next; |
|
|
122 } while ( prev != thread_list ); |
|
|
123 if ( this != prev ) { |
|
|
124 // insert it in the list: |
|
|
125 list_next = thread_list->list_next; |
|
|
126 thread_list->list_next = this; |
|
|
127 } |
|
|
128 } |
|
|
129 thread_list = this; |
|
|
130 |
|
|
131 Cyg_Scheduler::unlock(); |
|
|
132 } |
|
|
133 |
|
|
134 inline void |
|
|
135 Cyg_Thread::remove_from_list( void ) |
|
|
136 { |
|
|
137 // remove thread from housekeeping list |
|
|
138 Cyg_Scheduler::lock(); |
|
|
139 |
|
|
140 Cyg_Thread *prev = thread_list; |
|
|
141 |
|
|
142 do { |
|
|
143 if( prev->list_next == this ) { |
|
|
144 prev->list_next = list_next; |
|
|
145 if( thread_list == this ) |
|
|
146 thread_list = list_next; |
|
|
147 break; |
|
|
148 } |
|
|
149 prev = prev->list_next; |
|
|
150 } while ( prev != thread_list ); |
|
|
151 |
|
|
152 Cyg_Scheduler::unlock(); |
|
|
153 } |
|
|
154 |
|
|
155 #endif |
|
|
156 |
|
|
157 static cyg_uint16 next_unique_id = 1; |
|
|
158 |
|
|
159 // ------------------------------------------------------------------------- |
|
|
160 // Magic new operator to allow the thread constructor to be |
|
|
161 // recalled. |
|
|
162 |
|
|
163 inline void * |
|
|
164 operator new(size_t size, Cyg_Thread *ptr) |
|
|
165 { return (void *)ptr; }; |
|
|
166 |
|
|
167 // Constructor |
|
|
168 |
|
|
169 Cyg_Thread::Cyg_Thread( |
|
|
170 CYG_ADDRWORD sched_info, // Scheduling parameter(s) |
|
|
171 cyg_thread_entry *entry, // entry point function |
|
|
172 CYG_ADDRWORD entry_data, // entry data |
|
|
173 char *name_arg, // thread name cookie |
|
|
174 CYG_ADDRESS stack_base, // stack base, NULL = allocate |
|
|
175 cyg_ucount32 stack_size // stack size, 0 = use default |
|
|
176 ) |
|
|
177 : Cyg_HardwareThread(entry, entry_data, stack_size, stack_base), |
|
|
178 Cyg_SchedThread(this, sched_info) |
|
|
179 #ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
|
180 ,timer(this) |
|
|
181 #endif |
|
|
182 { |
|
|
183 CYG_REPORT_FUNCTION(); |
|
|
184 |
|
|
185 // Start the thread in suspended state. |
|
|
186 state = SUSPENDED; |
|
|
187 suspend_count = 1; |
|
|
188 |
|
|
189 // Initialize sleep_reason which is used by kill, release |
|
|
190 sleep_reason = NONE; |
|
|
191 wake_reason = NONE; |
|
|
192 |
|
|
193 // Assign a 16 bit id to the thread. |
|
|
194 unique_id = next_unique_id++; |
|
|
195 |
|
|
196 #ifdef CYGVAR_KERNEL_THREADS_DATA |
|
|
197 // Zero all per-thread data entries. |
|
|
198 for( int i = 0; i < CYGNUM_KERNEL_THREADS_DATA_MAX; i++ ) |
|
|
199 thread_data[i] = 0; |
|
|
200 #endif |
|
|
201 #ifdef CYGVAR_KERNEL_THREADS_NAME |
|
|
202 name = name_arg; |
|
|
203 #endif |
|
|
204 #ifdef CYGVAR_KERNEL_THREADS_LIST |
|
|
205 // Add thread to housekeeping list |
|
|
206 add_to_list(); |
|
|
207 #endif |
|
|
208 |
|
|
209 Cyg_Scheduler::scheduler.register_thread(this); |
|
|
210 |
|
|
211 init_context(this); |
|
|
212 |
|
|
213 CYG_REPORT_RETURN(); |
|
|
214 } |
|
|
215 |
|
|
216 |
|
|
217 // ------------------------------------------------------------------------- |
|
|
218 // Re-initialize this thread. |
|
|
219 // We do this by re-invoking the constructor with the original |
|
|
220 // arguments, which are still available in the object. |
|
|
221 |
|
|
222 void |
|
|
223 Cyg_Thread::reinitialize() |
|
|
224 { |
|
|
225 CYG_REPORT_FUNCTION(); |
|
|
226 |
|
|
227 CYG_ASSERTCLASS( this, "Bad thread"); |
|
|
228 CYG_ASSERT( this != Cyg_Scheduler::get_current_thread(), |
|
|
229 "Attempt to reinitialize current thread"); |
|
|
230 CYG_ASSERT( get_current_queue() == NULL , "Thread is still on a queue"); |
|
|
231 |
|
|
232 #ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
|
233 // Clear the timeout. It is irrelevant whether there was |
|
|
234 // actually a timeout pending. |
|
|
235 timer.disable(); |
|
|
236 #endif |
|
|
237 |
|
|
238 // Ensure the scheduler has let go of us. |
|
|
239 Cyg_Scheduler::scheduler.deregister_thread(this); |
|
|
240 |
|
|
241 cyg_priority pri = get_priority(); |
|
|
242 #ifdef CYGVAR_KERNEL_THREADS_NAME |
|
|
243 char * name_arg = name; |
|
|
244 #else |
|
|
245 char * name_arg = NULL; |
|
|
246 #endif |
|
|
247 |
|
|
248 new(this) Cyg_Thread( pri, |
|
|
249 entry_point, entry_data, |
|
|
250 name_arg, |
|
|
251 stack_base, stack_size ); |
|
|
252 // the constructor re-registers the thread with the scheduler. |
|
|
253 |
|
|
254 CYG_ASSERTCLASS( this, "Thread corrupted by reinitialize"); |
|
|
255 |
|
|
256 CYG_REPORT_RETURN(); |
|
|
257 } |
|
|
258 |
|
|
259 // ------------------------------------------------------------------------- |
|
|
260 // Destructor. |
|
|
261 |
|
|
262 Cyg_Thread::~Cyg_Thread() |
|
|
263 { |
|
|
264 CYG_REPORT_FUNCTION(); |
|
|
265 |
|
|
266 Cyg_Scheduler::scheduler.deregister_thread(this); |
|
|
267 |
|
|
268 #ifdef CYGVAR_KERNEL_THREADS_LIST |
|
|
269 // Remove thread from housekeeping list. |
|
|
270 remove_from_list(); |
|
|
271 #endif |
|
|
272 |
|
|
273 CYG_REPORT_RETURN(); |
|
|
274 } |
|
|
275 |
|
|
276 // ------------------------------------------------------------------------- |
|
|
277 // Thread consistency checker. |
|
|
278 |
|
|
279 #ifdef CYGDBG_USE_ASSERTS |
|
|
280 |
|
|
281 bool |
|
2
|
282 Cyg_Thread::check_this( cyg_assert_class_zeal zeal) const |
|
0
|
283 { |
|
|
284 // CYG_REPORT_FUNCTION(); |
|
|
285 |
|
|
286 // check that we have a non-NULL pointer first |
|
|
287 if( this == NULL ) return false; |
|
|
288 |
|
|
289 switch( zeal ) |
|
|
290 { |
|
|
291 case cyg_system_test: |
|
|
292 case cyg_extreme: |
|
|
293 case cyg_thorough: |
|
|
294 if( (state & SUSPENDED) && (suspend_count == 0) ) return false; |
|
|
295 case cyg_quick: |
|
2
|
296 // Check that the stackpointer is within its limits. |
|
|
297 // Note: This does not check the current stackpointer value |
|
|
298 // of the executing thread. |
|
|
299 if( (stack_ptr > (stack_base + stack_size)) || |
|
|
300 (stack_ptr < stack_base) ) return false; |
|
0
|
301 case cyg_trivial: |
|
|
302 case cyg_none: |
|
|
303 default: |
|
|
304 break; |
|
|
305 }; |
|
|
306 |
|
|
307 return true; |
|
|
308 } |
|
|
309 |
|
|
310 #endif |
|
|
311 |
|
|
312 // ------------------------------------------------------------------------- |
|
|
313 // Put the thread to sleep. |
|
|
314 // This can only be called by the current thread on itself, hence |
|
|
315 // it is a static function. |
|
|
316 |
|
|
317 void |
|
|
318 Cyg_Thread::sleep() |
|
|
319 { |
|
|
320 CYG_REPORT_FUNCTION(); |
|
|
321 |
|
|
322 Cyg_Thread *current = Cyg_Scheduler::get_current_thread(); |
|
|
323 |
|
|
324 CYG_ASSERTCLASS( current, "Bad current thread" ); |
|
|
325 |
|
|
326 CYG_INSTRUMENT_THREAD(SLEEP,current,0); |
|
|
327 |
|
|
328 // Prevent preemption |
|
|
329 Cyg_Scheduler::lock(); |
|
|
330 |
|
|
331 // If running, remove from run qs |
|
|
332 if ( current->state == RUNNING ) |
|
|
333 Cyg_Scheduler::scheduler.rem_thread(current); |
|
|
334 |
|
|
335 // Set the state |
|
|
336 current->state |= SLEEPING; |
|
|
337 |
|
|
338 // Unlock the scheduler and switch threads |
|
|
339 Cyg_Scheduler::unlock(); |
|
|
340 |
|
|
341 CYG_REPORT_RETURN(); |
|
|
342 } |
|
|
343 |
|
|
344 // ------------------------------------------------------------------------- |
|
|
345 // Awaken the thread from sleep. |
|
|
346 |
|
|
347 void |
|
|
348 Cyg_Thread::wake() |
|
|
349 { |
|
|
350 CYG_REPORT_FUNCTION(); |
|
|
351 |
|
|
352 CYG_INSTRUMENT_THREAD(WAKE,this,Cyg_Scheduler::current_thread); |
|
|
353 |
|
|
354 // Prevent preemption |
|
|
355 Cyg_Scheduler::lock(); |
|
|
356 |
|
|
357 if( 0 != (state & SLEEPSET) ) |
|
|
358 { |
|
|
359 // Set the state |
|
|
360 state &= ~SLEEPSET; |
|
|
361 |
|
|
362 // remove from any queue we were on |
|
|
363 remove(); |
|
|
364 |
|
|
365 // If the thread is now runnable, return it to run queue |
|
|
366 if( state == RUNNING ) |
|
|
367 Cyg_Scheduler::scheduler.add_thread(this); |
|
|
368 |
|
|
369 } |
|
|
370 |
|
|
371 // Unlock the scheduler and maybe switch threads |
|
|
372 Cyg_Scheduler::unlock(); |
|
|
373 |
|
|
374 CYG_REPORT_RETURN(); |
|
|
375 } |
|
|
376 |
|
|
377 // ------------------------------------------------------------------------- |
|
|
378 // Put the thread to sleep, with wakeup count. |
|
|
379 // This can only be called by the current thread on itself, hence |
|
|
380 // it is a static function. |
|
|
381 |
|
|
382 void |
|
|
383 Cyg_Thread::counted_sleep() |
|
|
384 { |
|
|
385 CYG_REPORT_FUNCTION(); |
|
|
386 |
|
|
387 Cyg_Thread *current = Cyg_Scheduler::get_current_thread(); |
|
|
388 |
|
|
389 CYG_ASSERTCLASS( current, "Bad current thread" ); |
|
|
390 |
|
|
391 CYG_INSTRUMENT_THREAD(SLEEP,current,0); |
|
|
392 |
|
|
393 // Prevent preemption |
|
|
394 Cyg_Scheduler::lock(); |
|
|
395 |
|
|
396 if ( 0 == current->wakeup_count ) { |
|
|
397 set_sleep_reason( Cyg_Thread::WAIT ); |
|
|
398 current->sleep(); // prepare to sleep |
|
|
399 current->state |= COUNTSLEEP; // Set the state |
|
|
400 } |
|
|
401 else |
|
|
402 // there is a queued wakeup, do not sleep |
|
|
403 current->wakeup_count--; |
|
|
404 |
|
|
405 // Unlock the scheduler and switch threads |
|
|
406 Cyg_Scheduler::unlock(); |
|
|
407 |
|
|
408 // and deal with anything we must do when we return |
|
|
409 switch( current->wake_reason ) { |
|
|
410 case DESTRUCT: |
|
|
411 case EXIT: |
|
|
412 current->exit(); |
|
|
413 break; |
|
|
414 |
|
|
415 default: |
|
|
416 break; |
|
|
417 } |
|
|
418 |
|
|
419 CYG_REPORT_RETURN(); |
|
|
420 } |
|
|
421 |
|
|
422 // ------------------------------------------------------------------------- |
|
|
423 // Put the thread to sleep for a delay, with wakeup count. |
|
|
424 // This can only be called by the current thread on itself, hence |
|
|
425 // it is a static function. |
|
|
426 |
|
|
427 #ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
|
428 void |
|
|
429 Cyg_Thread::counted_sleep( cyg_tick_count delay ) |
|
|
430 { |
|
|
431 CYG_REPORT_FUNCTION(); |
|
|
432 |
|
|
433 Cyg_Thread *current = Cyg_Scheduler::get_current_thread(); |
|
|
434 |
|
|
435 CYG_ASSERTCLASS( current, "Bad current thread" ); |
|
|
436 |
|
|
437 CYG_INSTRUMENT_THREAD(SLEEP,current,0); |
|
|
438 |
|
|
439 // Prevent preemption |
|
|
440 Cyg_Scheduler::lock(); |
|
|
441 |
|
|
442 if ( 0 == current->wakeup_count ) { |
|
|
443 |
|
|
444 // Set the timer (once outside any waiting loop.) |
|
|
445 set_timer( Cyg_Clock::real_time_clock->current_value()+delay, |
|
|
446 Cyg_Thread::TIMEOUT ); |
|
|
447 |
|
|
448 // If the timeout is in the past, the wake reason will have been |
|
|
449 // set to something other than NONE already. |
|
|
450 |
|
|
451 if( current->get_wake_reason() == Cyg_Thread::NONE ) |
|
|
452 { |
|
|
453 set_sleep_reason( Cyg_Thread::TIMEOUT ); |
|
|
454 current->sleep(); // prepare to sleep |
|
|
455 current->state |= COUNTSLEEP; // Set the state |
|
|
456 |
|
|
457 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, |
|
|
458 "Called with non-zero scheduler lock"); |
|
|
459 |
|
|
460 Cyg_Scheduler::unlock(); |
|
|
461 Cyg_Scheduler::lock(); |
|
|
462 |
|
|
463 // clear the timer; if it actually fired, no worries. |
|
|
464 clear_timer(); |
|
|
465 } |
|
|
466 } |
|
|
467 else |
|
|
468 // there is a queued wakeup, do not sleep |
|
|
469 current->wakeup_count--; |
|
|
470 |
|
|
471 // Unlock the scheduler and switch threads |
|
|
472 Cyg_Scheduler::unlock(); |
|
|
473 |
|
|
474 // and deal with anything we must do when we return |
|
|
475 switch( current->wake_reason ) { |
|
|
476 case DESTRUCT: |
|
|
477 case EXIT: |
|
|
478 current->exit(); |
|
|
479 break; |
|
|
480 |
|
|
481 default: |
|
|
482 break; |
|
|
483 } |
|
|
484 |
|
|
485 CYG_REPORT_RETURN(); |
|
|
486 } |
|
|
487 #endif |
|
|
488 |
|
|
489 // ------------------------------------------------------------------------- |
|
|
490 // Awaken the thread from sleep. |
|
|
491 |
|
|
492 void |
|
|
493 Cyg_Thread::counted_wake() |
|
|
494 { |
|
|
495 CYG_REPORT_FUNCTION(); |
|
|
496 |
|
|
497 CYG_INSTRUMENT_THREAD(WAKE,this,Cyg_Scheduler::current_thread); |
|
|
498 |
|
|
499 // Prevent preemption |
|
|
500 Cyg_Scheduler::lock(); |
|
|
501 |
|
|
502 if ( 0 == (state & COUNTSLEEP) ) // already awake, or waiting: |
|
|
503 wakeup_count++; // not in a counted sleep anyway. |
|
|
504 else { |
|
|
505 sleep_reason = NONE; |
|
|
506 wake_reason = DONE; |
|
|
507 wake(); // and awaken the thread |
|
|
508 } |
|
|
509 |
|
|
510 #ifdef CYGNUM_KERNEL_MAX_COUNTED_WAKE_COUNT_ASSERT |
|
|
511 CYG_ASSERT( CYGNUM_KERNEL_MAX_COUNTED_WAKE_COUNT_ASSERT > wakeup_count, |
|
|
512 "wakeup_count overflow" ); |
|
|
513 #endif |
|
|
514 |
|
|
515 // Unlock the scheduler and maybe switch threads |
|
|
516 Cyg_Scheduler::unlock(); |
|
|
517 |
|
|
518 CYG_REPORT_RETURN(); |
|
|
519 } |
|
|
520 |
|
|
521 // ------------------------------------------------------------------------- |
|
|
522 // Cancel wakeups for this thread and return how many were pending |
|
|
523 cyg_uint32 |
|
|
524 Cyg_Thread::cancel_counted_wake() |
|
|
525 { |
|
|
526 CYG_REPORT_FUNCTION(); |
|
|
527 |
|
|
528 CYG_INSTRUMENT_THREAD(WAKE,this,Cyg_Scheduler::current_thread); |
|
|
529 |
|
|
530 // Prevent preemption |
|
|
531 Cyg_Scheduler::lock(); |
|
|
532 |
|
|
533 cyg_uint32 result = wakeup_count; |
|
|
534 wakeup_count = 0; |
|
|
535 |
|
|
536 // Unlock the scheduler |
|
|
537 Cyg_Scheduler::unlock(); |
|
|
538 |
|
|
539 CYG_REPORT_RETVAL( result ); |
|
|
540 return result; |
|
|
541 } |
|
|
542 |
|
|
543 // ------------------------------------------------------------------------- |
|
|
544 // Suspend thread. Increment suspend count and deschedule thread |
|
|
545 // if still running. |
|
|
546 |
|
|
547 void |
|
|
548 Cyg_Thread::suspend() |
|
|
549 { |
|
|
550 CYG_REPORT_FUNCTION(); |
|
|
551 |
|
|
552 CYG_INSTRUMENT_THREAD(SUSPEND,this,Cyg_Scheduler::current_thread); |
|
|
553 |
|
|
554 // Prevent preemption |
|
|
555 Cyg_Scheduler::lock(); |
|
|
556 |
|
|
557 suspend_count++; |
|
|
558 |
|
|
559 #ifdef CYGNUM_KERNEL_MAX_SUSPEND_COUNT_ASSERT |
|
|
560 CYG_ASSERT( CYGNUM_KERNEL_MAX_SUSPEND_COUNT_ASSERT > suspend_count, |
|
|
561 "suspend_count overflow" ); |
|
|
562 #endif |
|
|
563 |
|
|
564 // If running, remove from run qs |
|
|
565 if( state == RUNNING ) |
|
|
566 Cyg_Scheduler::scheduler.rem_thread(this); |
|
|
567 |
|
|
568 // Set the state |
|
|
569 state |= SUSPENDED; |
|
|
570 |
|
|
571 // Unlock the scheduler and maybe switch threads |
|
|
572 Cyg_Scheduler::unlock(); |
|
|
573 |
|
|
574 CYG_REPORT_RETURN(); |
|
|
575 } |
|
|
576 |
|
|
577 // ------------------------------------------------------------------------- |
|
|
578 // Resume thread. Decrement suspend count and reschedule if it |
|
|
579 // is zero. |
|
|
580 |
|
|
581 void |
|
|
582 Cyg_Thread::resume() |
|
|
583 { |
|
|
584 CYG_REPORT_FUNCTION(); |
|
|
585 |
|
|
586 CYG_INSTRUMENT_THREAD(RESUME,this,Cyg_Scheduler::current_thread); |
|
|
587 |
|
|
588 // Prevent preemption |
|
|
589 Cyg_Scheduler::lock(); |
|
|
590 |
|
|
591 // If we are about to zero the count, clear the state bit and |
|
|
592 // reschedule the thread if possible. |
|
|
593 |
|
|
594 if( suspend_count == 1 ) |
|
|
595 { |
|
|
596 suspend_count = 0; |
|
|
597 |
|
|
598 CYG_ASSERT( (state & SUSPENDED) != 0, "SUSPENDED bit not set" ); |
|
|
599 |
|
|
600 // Set the state |
|
|
601 state &= ~SUSPENDED; |
|
|
602 |
|
|
603 // Return thread to scheduler if runnable |
|
|
604 if( state == RUNNING ) |
|
|
605 Cyg_Scheduler::scheduler.add_thread(this); |
|
|
606 } |
|
|
607 else |
|
|
608 if( suspend_count > 0 ) |
|
|
609 suspend_count--; |
|
|
610 // else ignore attempt to resume |
|
|
611 |
|
|
612 // Unlock the scheduler and maybe switch threads |
|
|
613 Cyg_Scheduler::unlock(); |
|
|
614 CYG_REPORT_RETURN(); |
|
|
615 } |
|
|
616 |
|
|
617 // ------------------------------------------------------------------------- |
|
|
618 // Forced Resume thread. Zero suspend count and reschedule... |
|
|
619 |
|
|
620 void |
|
|
621 Cyg_Thread::force_resume() |
|
|
622 { |
|
|
623 CYG_REPORT_FUNCTION(); |
|
|
624 |
|
|
625 CYG_INSTRUMENT_THREAD(RESUME,this,Cyg_Scheduler::current_thread); |
|
|
626 |
|
|
627 // Prevent preemption |
|
|
628 Cyg_Scheduler::lock(); |
|
|
629 |
|
|
630 // If we are about to zero the count, clear the state bit and |
|
|
631 // reschedule the thread if possible. |
|
|
632 |
|
|
633 if ( 0 < suspend_count ) { |
|
|
634 suspend_count = 0; |
|
|
635 |
|
|
636 CYG_ASSERT( (state & SUSPENDED) != 0, "SUSPENDED bit not set" ); |
|
|
637 |
|
|
638 // Set the state |
|
|
639 state &= ~SUSPENDED; |
|
|
640 |
|
|
641 // Return thread to scheduler if runnable |
|
|
642 if( state == RUNNING ) |
|
|
643 Cyg_Scheduler::scheduler.add_thread(this); |
|
|
644 } |
|
|
645 |
|
|
646 // Unlock the scheduler and maybe switch threads |
|
|
647 Cyg_Scheduler::unlock(); |
|
|
648 CYG_REPORT_RETURN(); |
|
|
649 } |
|
|
650 |
|
|
651 // ------------------------------------------------------------------------- |
|
|
652 // Force thread to wake up from a sleep with a wake_reason of |
|
|
653 // BREAK. It is the responsibility of the woken thread to detect |
|
|
654 // the release() and do the right thing. |
|
|
655 |
|
|
656 void |
|
|
657 Cyg_Thread::release() |
|
|
658 { |
|
|
659 CYG_REPORT_FUNCTION(); |
|
|
660 // Prevent preemption |
|
|
661 Cyg_Scheduler::lock(); |
|
|
662 |
|
|
663 // If the thread is in any of the sleep states, set the |
|
|
664 // wake reason and wake it up. |
|
|
665 |
|
|
666 switch( sleep_reason ) |
|
|
667 { |
|
|
668 |
|
|
669 case NONE: |
|
|
670 // The thread is not sleeping for any reason, do nothing. |
|
|
671 // drop through... |
|
|
672 |
|
|
673 case DESTRUCT: |
|
|
674 case BREAK: |
|
|
675 case EXIT: |
|
|
676 case DONE: |
|
|
677 // Do nothing in any of these cases. They are here to |
|
|
678 // keep the compiler happy. |
|
|
679 |
|
|
680 Cyg_Scheduler::unlock(); |
|
|
681 CYG_REPORT_RETURN(); |
|
|
682 return; |
|
|
683 |
|
|
684 case WAIT: |
|
|
685 // The thread was waiting for some sync object to do |
|
|
686 // something. |
|
|
687 // drop through... |
|
|
688 |
|
|
689 case TIMEOUT: |
|
|
690 // The thread was waiting on a sync object with a timeout. |
|
|
691 // drop through... |
|
|
692 |
|
|
693 case DELAY: |
|
|
694 // The thread was simply delaying, unless it has been |
|
|
695 // woken up for some other reason, wake it now. |
|
|
696 sleep_reason = NONE; |
|
|
697 wake_reason = BREAK; |
|
|
698 break; |
|
|
699 } |
|
|
700 |
|
|
701 wake(); |
|
|
702 |
|
|
703 // Allow preemption |
|
|
704 Cyg_Scheduler::unlock(); |
|
|
705 |
|
|
706 CYG_REPORT_RETURN(); |
|
|
707 } |
|
|
708 |
|
|
709 // ------------------------------------------------------------------------- |
|
|
710 // Exit thread. This puts the thread into EXITED state. |
|
|
711 |
|
|
712 void |
|
|
713 Cyg_Thread::exit() |
|
|
714 { |
|
|
715 // The thread should never return from this function. |
|
|
716 |
|
|
717 Cyg_Thread *self = Cyg_Thread::self(); |
|
|
718 |
|
|
719 Cyg_Scheduler::lock(); |
|
|
720 |
|
|
721 // clear the timer; if there was none, no worries. |
|
|
722 clear_timer(); |
|
|
723 |
|
|
724 self->state = EXITED; |
|
|
725 |
|
|
726 Cyg_Scheduler::scheduler.rem_thread(self); |
|
|
727 |
|
|
728 // Un-nest any scheduler locks we have until we |
|
|
729 // suspend. |
|
|
730 for( ;; ) Cyg_Scheduler::unlock(); |
|
|
731 } |
|
|
732 |
|
|
733 // ------------------------------------------------------------------------- |
|
|
734 // Kill thread. Force the thread into EXITED state externally, or |
|
|
735 // make it wake up and call exit(). |
|
|
736 |
|
|
737 void |
|
|
738 Cyg_Thread::kill() |
|
|
739 { |
|
|
740 CYG_REPORT_FUNCTION(); |
|
|
741 // If this is called by the current thread on itself, |
|
|
742 // just call exit(), which is what he should have done |
|
|
743 // in the first place. |
|
|
744 if( this == Cyg_Scheduler::get_current_thread() ) |
|
|
745 exit(); |
|
|
746 |
|
|
747 // Prevent preemption |
|
|
748 Cyg_Scheduler::lock(); |
|
|
749 |
|
|
750 // We are killing someone else. Find out what state he is |
|
|
751 // in and force him to wakeup and call exit(). |
|
|
752 |
|
|
753 force_resume(); // this is necessary for when |
|
|
754 // he is asleep AND suspended. |
|
|
755 #ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
|
756 timer.disable(); // and make sure the timer |
|
|
757 // does not persist. |
|
|
758 #endif |
|
|
759 |
|
|
760 switch( sleep_reason ) |
|
|
761 { |
|
|
762 |
|
|
763 case NONE: |
|
|
764 // The thread is not sleeping for any reason, it must be |
|
|
765 // on a run queue. |
|
|
766 // We can safely deschedule and set its state. |
|
|
767 if( state == RUNNING ) Cyg_Scheduler::scheduler.rem_thread(this); |
|
|
768 state = EXITED; |
|
|
769 break; |
|
|
770 |
|
|
771 case DESTRUCT: |
|
|
772 case BREAK: |
|
|
773 case EXIT: |
|
|
774 case DONE: |
|
|
775 // Do nothing in any of these cases. They are here to |
|
|
776 // keep the compiler happy. |
|
|
777 |
|
|
778 Cyg_Scheduler::unlock(); |
|
|
779 CYG_REPORT_RETURN(); |
|
|
780 return; |
|
|
781 |
|
|
782 case WAIT: |
|
|
783 // The thread was waiting for some sync object to do |
|
|
784 // something. |
|
|
785 // drop through... |
|
|
786 |
|
|
787 case TIMEOUT: |
|
|
788 // The thread was waiting on a sync object with a timeout. |
|
|
789 // drop through... |
|
|
790 |
|
|
791 case DELAY: |
|
|
792 // The thread was simply delaying, unless it has been |
|
|
793 // woken up for some other reason, wake it now. |
|
|
794 sleep_reason = NONE; |
|
|
795 wake_reason = EXIT; |
|
|
796 break; |
|
|
797 } |
|
|
798 |
|
|
799 wake(); |
|
|
800 |
|
|
801 // Allow preemption |
|
|
802 Cyg_Scheduler::unlock(); |
|
|
803 CYG_REPORT_RETURN(); |
|
|
804 } |
|
|
805 |
|
|
806 // ------------------------------------------------------------------------- |
|
|
807 // Set thread priority |
|
|
808 |
|
|
809 #ifdef CYGIMP_THREAD_PRIORITY |
|
|
810 |
|
|
811 void |
|
|
812 Cyg_Thread::set_priority( cyg_priority new_priority ) |
|
|
813 { |
|
|
814 CYG_REPORT_FUNCTION(); |
|
|
815 |
|
|
816 // CYG_ASSERT( new_priority >= CYG_THREAD_MAX_PRIORITY, "Priority out of range"); |
|
|
817 // CYG_ASSERT( new_priority <= CYG_THREAD_MIN_PRIORITY, "Priority out of range"); |
|
|
818 |
|
|
819 CYG_INSTRUMENT_THREAD(PRIORITY,this,priority); |
|
|
820 |
|
|
821 // Prevent preemption |
|
|
822 Cyg_Scheduler::lock(); |
|
|
823 |
|
|
824 Cyg_ThreadQueue *queue = NULL; |
|
|
825 |
|
|
826 // If running, remove from run qs |
|
|
827 if( state == RUNNING ) |
|
|
828 Cyg_Scheduler::scheduler.rem_thread(this); |
|
|
829 else if( state & SLEEPING ) |
|
|
830 { |
|
|
831 // Remove thread from current queue. |
|
|
832 queue = get_current_queue(); |
|
|
833 // if indeed we are on a queue |
|
|
834 if ( NULL != queue ) { |
|
|
835 CYG_CHECK_DATA_PTR(queue, "Bad queue pointer"); |
|
|
836 remove(); |
|
|
837 } |
|
|
838 } |
|
|
839 |
|
|
840 Cyg_Scheduler::scheduler.deregister_thread(this); |
|
|
841 |
|
|
842 #if CYG_SCHED_UNIQUE_PRIORITIES |
|
|
843 |
|
|
844 // Check that there are no other threads at this priority. |
|
|
845 // If so, leave is as it is. |
|
|
846 |
|
|
847 CYG_ASSERT( Cyg_Scheduler::scheduler.unique(new_priority), "Priority not unique"); |
|
|
848 |
|
|
849 if( Cyg_Scheduler::scheduler.unique(new_priority) ) |
|
|
850 priority = new_priority; |
|
|
851 |
|
|
852 #else // !CYG_SCHED_UNIQUE_PRIORITIES |
|
|
853 |
|
|
854 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE_SIMPLE |
|
|
855 |
|
|
856 // When we have priority inheritance, we must update the original |
|
|
857 // priority and not the inherited one. If the new priority is |
|
|
858 // better than the current inherited one, then use that |
|
|
859 // immediately. We remain in inherited state to avoid problems |
|
|
860 // with multiple mutex inheritances. |
|
|
861 |
|
|
862 if( priority_inherited ) |
|
|
863 { |
|
|
864 original_priority = new_priority; |
|
|
865 if( priority > new_priority ) priority = new_priority; |
|
|
866 } |
|
|
867 else priority = new_priority; |
|
|
868 |
|
|
869 #else |
|
|
870 |
|
|
871 priority = new_priority; |
|
|
872 |
|
|
873 #endif |
|
|
874 |
|
|
875 #endif // CYG_SCHED_UNIQUE_PRIORITIES |
|
|
876 |
|
|
877 Cyg_Scheduler::scheduler.register_thread(this); |
|
|
878 |
|
|
879 // Return thread to scheduler if runnable |
|
|
880 if( state == RUNNING ) |
|
|
881 Cyg_Scheduler::scheduler.add_thread(this); |
|
|
882 else if ( state & SLEEPING ) |
|
|
883 { |
|
|
884 // return to current queue |
|
|
885 // if indeed we are on a queue |
|
|
886 if ( NULL != queue ) { |
|
|
887 CYG_CHECK_DATA_PTR(queue, "Bad queue pointer"); |
|
|
888 queue->enqueue(this); |
|
|
889 } |
|
|
890 } |
|
|
891 |
|
|
892 // If the current thread is being reprioritized, set the |
|
|
893 // reschedule flag to ensure that it gets rescheduled if |
|
|
894 // necessary. (Strictly we only need to do this if the new |
|
|
895 // priority is less than that of some other runnable thread, in |
|
|
896 // practice checking that is as expensive as what the scheduler |
|
|
897 // will do anyway). |
|
|
898 |
|
|
899 if( this == Cyg_Scheduler::get_current_thread() ) |
|
|
900 Cyg_Scheduler::need_reschedule = true; |
|
|
901 |
|
|
902 // Unlock the scheduler and maybe switch threads |
|
|
903 Cyg_Scheduler::unlock(); |
|
|
904 CYG_REPORT_RETURN(); |
|
|
905 } |
|
|
906 |
|
|
907 #endif |
|
|
908 |
|
|
909 |
|
|
910 // ------------------------------------------------------------------------- |
|
|
911 // Thread delay function |
|
|
912 |
|
|
913 void |
|
|
914 Cyg_Thread::delay( cyg_tick_count delay) |
|
|
915 { |
|
|
916 CYG_REPORT_FUNCTION(); |
|
|
917 |
|
2
|
918 #ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
0
|
919 |
|
|
920 CYG_INSTRUMENT_THREAD(DELAY,this,delay); |
|
|
921 |
|
|
922 // Prevent preemption |
|
|
923 Cyg_Scheduler::lock(); |
|
|
924 |
|
|
925 sleep(); |
|
|
926 |
|
|
927 set_timer( Cyg_Clock::real_time_clock->current_value()+delay, DELAY ); |
|
|
928 |
|
|
929 // Unlock the scheduler and maybe switch threads |
|
|
930 Cyg_Scheduler::unlock(); |
|
|
931 |
|
|
932 // Clear the timeout. It is irrelevant whether the alarm has |
|
|
933 // actually gone off or not. |
|
|
934 clear_timer(); |
|
|
935 |
|
|
936 // and deal with anything else we must do when we return |
|
|
937 switch( wake_reason ) { |
|
|
938 case DESTRUCT: |
|
|
939 case EXIT: |
|
|
940 exit(); |
|
|
941 break; |
|
|
942 |
|
|
943 default: |
|
|
944 break; |
|
|
945 } |
|
|
946 #endif |
|
|
947 CYG_REPORT_RETURN(); |
|
|
948 } |
|
|
949 |
|
|
950 // ------------------------------------------------------------------------- |
|
|
951 // |
|
|
952 |
|
|
953 #ifdef CYGPKG_KERNEL_EXCEPTIONS |
|
|
954 |
|
|
955 void |
|
|
956 Cyg_Thread::deliver_exception( |
|
|
957 cyg_code exception_number, // exception being raised |
|
|
958 CYG_ADDRWORD exception_info // exception specific info |
|
|
959 ) |
|
|
960 { |
|
|
961 if( this == Cyg_Scheduler::get_current_thread() ) |
|
|
962 { |
|
|
963 // Delivering to current thread, probably as a result |
|
|
964 // of a real hardware exception. Simply invoke the appropriate |
|
|
965 // handler. |
|
|
966 |
|
|
967 exception_control.deliver_exception( exception_number, exception_info ); |
|
|
968 } |
|
|
969 #ifdef CYGIMP_EXCEPTION_ASYNC |
|
|
970 else |
|
|
971 { |
|
|
972 // Delivering to another thread, probably as a result of one thread |
|
|
973 // invoking this function on another thread. Adjust the other thread's |
|
|
974 // state to make it execute the exception routine when it next runs. |
|
|
975 |
|
|
976 // At present there is an unresolved problem here. We do not know what |
|
|
977 // state the destination thread is in. It may not be a suitable point at |
|
|
978 // which to invoke an exception routine. In most cases the exception |
|
|
979 // routine will be run in the scheduler thread switch code, where the world is |
|
|
980 // in an inconsistent state. We really need to run the routine at the |
|
|
981 // end of unlock_inner(). However this would add extra code to the scheduler, |
|
|
982 // and require a way of storing pending exceptions. So for now this option is |
|
|
983 // disabled and not yet implemented, it may never be. |
|
|
984 |
|
|
985 } |
|
|
986 #endif |
|
|
987 } |
|
|
988 |
|
|
989 #endif |
|
|
990 |
|
|
991 // ------------------------------------------------------------------------- |
|
|
992 // Per-thread data support |
|
|
993 |
|
|
994 #ifdef CYGVAR_KERNEL_THREADS_DATA |
|
|
995 |
|
|
996 // Set the data map bits for each free slot in the data array. |
|
|
997 cyg_ucount32 Cyg_Thread::thread_data_map = (~CYGNUM_KERNEL_THREADS_DATA_ALL) & |
|
|
998 ((1<<CYGNUM_KERNEL_THREADS_DATA_MAX)-1); |
|
|
999 |
|
|
1000 cyg_ucount32 |
|
|
1001 Cyg_Thread::new_data_index() |
|
|
1002 { |
|
|
1003 Cyg_Scheduler::lock(); |
|
|
1004 |
|
|
1005 cyg_ucount32 index; |
|
|
1006 |
|
|
1007 CYG_ASSERT( thread_data_map != 0 , "No more thread data indexes"); |
|
|
1008 |
|
|
1009 // find ls set bit |
|
|
1010 HAL_LSBIT_INDEX( index, thread_data_map ); |
|
|
1011 |
|
|
1012 // clear the bit |
|
|
1013 thread_data_map &= ~(1<<index); |
|
|
1014 |
|
|
1015 Cyg_Scheduler::unlock(); |
|
|
1016 |
|
|
1017 return index; |
|
|
1018 } |
|
|
1019 |
|
|
1020 void Cyg_Thread::free_data_index( cyg_ucount32 index ) |
|
|
1021 { |
|
|
1022 Cyg_Scheduler::lock(); |
|
|
1023 |
|
|
1024 thread_data_map |= (1<<index); |
|
|
1025 |
|
|
1026 Cyg_Scheduler::unlock(); |
|
|
1027 } |
|
|
1028 |
|
|
1029 |
|
|
1030 #endif |
|
|
1031 |
|
|
1032 // ========================================================================= |
|
|
1033 // Cyg_ThreadTimer member functions |
|
|
1034 |
|
|
1035 // ------------------------------------------------------------------------- |
|
|
1036 // Timer alarm function. Inspect the sleep_reason and if necessary wake |
|
|
1037 // up the thread with an appropriate wake_reason. |
|
|
1038 |
|
|
1039 #ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
|
1040 |
|
|
1041 void |
|
|
1042 Cyg_ThreadTimer::alarm( |
|
|
1043 Cyg_Alarm *alarm, |
|
|
1044 CYG_ADDRWORD data |
|
|
1045 ) |
|
|
1046 { |
|
|
1047 CYG_REPORT_FUNCTION(); |
|
|
1048 |
|
|
1049 Cyg_ThreadTimer *self = (Cyg_ThreadTimer *)data; |
|
|
1050 Cyg_Thread *thread = self->thread; |
|
|
1051 |
|
|
1052 CYG_INSTRUMENT_THREAD(ALARM, 0, 0); |
|
|
1053 |
|
|
1054 Cyg_Scheduler::lock(); |
|
|
1055 |
|
|
1056 Cyg_Thread::cyg_reason sleep_reason = thread->get_sleep_reason(); |
|
|
1057 |
|
|
1058 switch( sleep_reason ) { |
|
|
1059 |
|
|
1060 case Cyg_Thread::DESTRUCT: |
|
|
1061 case Cyg_Thread::BREAK: |
|
|
1062 case Cyg_Thread::EXIT: |
|
|
1063 case Cyg_Thread::NONE: |
|
|
1064 case Cyg_Thread::WAIT: |
|
|
1065 case Cyg_Thread::DONE: |
|
|
1066 // Do nothing in any of these cases. Most are here to |
|
|
1067 // keep the compiler happy. |
|
|
1068 Cyg_Scheduler::unlock(); |
|
|
1069 CYG_REPORT_RETURN(); |
|
|
1070 return; |
|
|
1071 |
|
|
1072 case Cyg_Thread::DELAY: |
|
|
1073 // The thread was simply delaying, unless it has been |
|
|
1074 // woken up for some other reason, wake it now. |
|
|
1075 thread->set_wake_reason(Cyg_Thread::DONE); |
|
|
1076 break; |
|
|
1077 |
|
|
1078 case Cyg_Thread::TIMEOUT: |
|
|
1079 // The thread has timed out, set the wake reason to |
|
|
1080 // TIMEOUT and restart. |
|
|
1081 thread->set_wake_reason(Cyg_Thread::TIMEOUT); |
|
|
1082 break; |
|
|
1083 } |
|
|
1084 |
|
|
1085 thread->wake(); |
|
|
1086 |
|
|
1087 Cyg_Scheduler::unlock(); |
|
|
1088 CYG_REPORT_RETURN(); |
|
|
1089 } |
|
|
1090 |
|
|
1091 #endif |
|
|
1092 |
|
|
1093 // ========================================================================= |
|
|
1094 // The Idle thread |
|
|
1095 // The idle thread is implemented as a single instance of the |
|
|
1096 // Cyg_IdleThread class. This is so that it can be initialized before |
|
|
1097 // main in a static constructor. |
|
|
1098 |
|
|
1099 // ------------------------------------------------------------------------- |
|
|
1100 // Data definitions |
|
|
1101 |
|
|
1102 // stack |
|
2
|
1103 #ifdef CYGNUM_HAL_STACK_SIZE_MINIMUM |
|
|
1104 # ifdef CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE |
|
|
1105 # if CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE < CYGNUM_HAL_STACK_SIZE_MINIMUM |
|
0
|
1106 |
|
2
|
1107 // then override the configured stack size |
|
|
1108 # undef CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE |
|
|
1109 # define CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUM |
|
|
1110 |
|
|
1111 # endif // CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE < CYGNUM_HAL_STACK_SIZE_MINIMUM |
|
|
1112 # endif // CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE |
|
|
1113 #endif // CYGNUM_HAL_STACK_SIZE_MINIMUM |
|
|
1114 |
|
|
1115 static char idle_thread_stack[CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE]; |
|
0
|
1116 |
|
|
1117 // Loop counter for debugging/housekeeping |
|
|
1118 cyg_uint32 idle_thread_loops = 1; |
|
|
1119 |
|
|
1120 // ------------------------------------------------------------------------- |
|
|
1121 // Idle thread code. |
|
|
1122 |
|
|
1123 void |
|
|
1124 idle_thread_main( CYG_ADDRESS data ) |
|
|
1125 { |
|
|
1126 CYG_REPORT_FUNCTION(); |
|
|
1127 |
|
|
1128 for(;;) |
|
|
1129 { |
|
|
1130 idle_thread_loops++; |
|
|
1131 |
|
|
1132 HAL_IDLE_THREAD_ACTION(idle_thread_loops); |
|
|
1133 |
|
|
1134 #if 0 |
|
|
1135 // For testing, it is useful to be able to fake |
|
|
1136 // clock interrupts in the idle thread. |
|
|
1137 |
|
|
1138 Cyg_Clock::real_time_clock->tick(); |
|
|
1139 #endif |
|
|
1140 #ifdef CYGIMP_IDLE_THREAD_YIELD |
|
|
1141 // In single priority and non-preemptive systems, |
|
|
1142 // the idle thread should yield repeatedly to |
|
|
1143 // other threads. |
|
|
1144 Cyg_Thread::yield(); |
|
|
1145 #endif |
|
|
1146 } |
|
|
1147 } |
|
|
1148 |
|
|
1149 // ------------------------------------------------------------------------- |
|
|
1150 // Idle thread class |
|
|
1151 |
|
|
1152 class Cyg_IdleThread : public Cyg_Thread |
|
|
1153 { |
|
|
1154 public: |
|
|
1155 Cyg_IdleThread( |
|
|
1156 cyg_thread_entry *entry, // entry point function |
|
|
1157 CYG_ADDRWORD entry_data, // entry data |
|
|
1158 cyg_ucount32 stack_size = 0, // stack size, 0 = use default |
|
|
1159 CYG_ADDRESS stack_base = 0 // stack base, NULL = allocate |
|
|
1160 ); |
|
|
1161 |
|
|
1162 }; |
|
|
1163 |
|
|
1164 // ------------------------------------------------------------------------- |
|
|
1165 // Idle threads constructor |
|
|
1166 |
|
|
1167 Cyg_IdleThread::Cyg_IdleThread( |
|
|
1168 cyg_thread_entry *entry, // entry point function |
|
|
1169 CYG_ADDRWORD entry_data, // entry data |
|
|
1170 cyg_ucount32 stack_size, // stack size, 0 = use default |
|
|
1171 CYG_ADDRESS stack_base // stack base, NULL = allocate |
|
|
1172 ) |
|
|
1173 : Cyg_Thread( CYG_THREAD_MIN_PRIORITY, |
|
|
1174 entry, |
|
|
1175 entry_data, |
|
|
1176 "Idle Thread", |
|
|
1177 stack_base, |
|
|
1178 stack_size) |
|
|
1179 { |
|
|
1180 CYG_REPORT_FUNCTION(); |
|
|
1181 |
|
|
1182 resume(); |
|
|
1183 CYG_REPORT_RETURN(); |
|
|
1184 } |
|
|
1185 |
|
|
1186 // ------------------------------------------------------------------------- |
|
|
1187 // Instantiate the idle thread |
|
|
1188 |
|
|
1189 Cyg_IdleThread idle_thread CYG_INIT_PRIORITY( IDLE_THREAD ) = |
|
|
1190 Cyg_IdleThread( idle_thread_main, |
|
|
1191 0, |
|
|
1192 CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE, |
|
|
1193 CYG_ADDRESS(idle_thread_stack) |
|
|
1194 ); |
|
|
1195 |
|
|
1196 |
|
|
1197 // ------------------------------------------------------------------------- |
|
|
1198 // EOF common/thread.cxx |