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