1 #ifndef CYGONCE_KERNEL_THREAD_INL
2 #define CYGONCE_KERNEL_THREAD_INL
4 //==========================================================================
8 // Thread class inlines
10 //==========================================================================
11 //####ECOSGPLCOPYRIGHTBEGIN####
12 // -------------------------------------------
13 // This file is part of eCos, the Embedded Configurable Operating System.
14 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
15 // Copyright (C) 2003 Gary Thomas
17 // eCos is free software; you can redistribute it and/or modify it under
18 // the terms of the GNU General Public License as published by the Free
19 // Software Foundation; either version 2 or (at your option) any later version.
21 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
22 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 // You should have received a copy of the GNU General Public License along
27 // with eCos; if not, write to the Free Software Foundation, Inc.,
28 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
30 // As a special exception, if other files instantiate templates or use macros
31 // or inline functions from this file, or you compile this file and link it
32 // with other works to produce a work based on this file, this file does not
33 // by itself cause the resulting work to be covered by the GNU General Public
34 // License. However the source code for this file must still be made available
35 // in accordance with section (3) of the GNU General Public License.
37 // This exception does not invalidate any other reasons why a work based on
38 // this file might be covered by the GNU General Public License.
40 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
41 // at http://sources.redhat.com/ecos/ecos-license/
42 // -------------------------------------------
43 //####ECOSGPLCOPYRIGHTEND####
44 //==========================================================================
45 //#####DESCRIPTIONBEGIN####
48 // Contributors: nickg
50 // Purpose: Define inlines for thread classes
51 // Description: Inline implementations of various member functions defined
52 // in various Thread classes.
54 // #include <cyg/kernel/thread.hxx>
56 // #include <cyg/kernel/thread.inl>
60 //####DESCRIPTIONEND####
62 //==========================================================================
64 #include <cyg/kernel/thread.hxx>
65 #include <cyg/hal/hal_arch.h>
67 #include <cyg/kernel/clock.inl>
68 #include <cyg/infra/diag.h>
70 #ifndef CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE
71 #define CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE (0)
74 //==========================================================================
75 // Inlines for Cyg_HardwareThread
77 // -------------------------------------------------------------------------
78 // get the size/base of this thread's stack
81 Cyg_HardwareThread::get_stack_base()
83 return stack_base - CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE;
87 Cyg_HardwareThread::get_stack_size()
89 return stack_size + 2 * CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE;
92 // -------------------------------------------------------------------------
93 // Check the stack bounds of this thread:
94 #ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
95 inline void Cyg_HardwareThread::check_stack(void)
97 cyg_uint32 sig = (cyg_uint32)this;
98 cyg_uint32 *base = (cyg_uint32 *)get_stack_base();
99 cyg_uint32 *top = (cyg_uint32 *)(stack_base + stack_size);
102 CYG_INSTRUMENT_THREAD(CHECK_STACK, base, top );
104 CYG_ASSERT( 0 == ((sizeof(CYG_WORD)-1) & (cyg_uint32)base), "stack base not word aligned" );
105 CYG_ASSERT( 0 == ((sizeof(CYG_WORD)-1) & (cyg_uint32)top), "stack top not word aligned" );
107 CYG_ASSERT( (cyg_uint32)stack_ptr > (cyg_uint32)stack_base,
108 "Stack_ptr below base" );
109 CYG_ASSERT( (cyg_uint32)stack_ptr <= ((cyg_uint32)stack_base + stack_size),
110 "Stack_ptr above top" );
113 i < CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE/sizeof(cyg_uint32);
115 if ((sig ^ (i * 0x01010101)) != base[i]) {
116 char *reason = "Stack base corrupt";
117 diag_printf("%s - i: %d\n", reason, i);
118 diag_dump_buf(base, CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE);
121 if ((sig ^ (i * 0x10101010)) != top[i]) {
122 char *reason = "Stack top corrupt";
123 diag_printf("%s - i: %d\n", reason, i);
124 diag_dump_buf(top, CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE);
129 #ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
130 // we won't have added check data above the stack limit if it hasn't
132 if (stack_limit != stack_base) {
133 CYG_ADDRESS limit = stack_limit;
134 // the limit will be off by the check data size, so lets correct it
135 limit -= CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE;
137 // determine base of check data by rounding up to nearest word aligned
138 // address if not already aligned
139 cyg_uint32 *p = (cyg_uint32 *)((limit + 3) & ~3);
140 // i.e. + sizeof(cyg_uint32)-1) & ~(sizeof(cyg_uint32)-1);
143 i < CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE/sizeof(cyg_uint32);
145 if ((sig ^ (i * 0x01010101)) != p[i]) {
146 char *reason = "Gap between stack limit and base corrupt";
147 diag_printf("%s - i: %d\n", reason, i);
148 diag_dump_buf(p, CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE);
157 // -------------------------------------------------------------------------
158 // Measure the stack usage of the thread
159 #ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
160 inline cyg_uint32 Cyg_HardwareThread::measure_stack_usage(void)
162 #ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
163 CYG_WORD *base = (CYG_WORD *)stack_limit;
164 cyg_uint32 size = (stack_size - (stack_limit-stack_base))/sizeof(CYG_WORD);
166 CYG_WORD *base = (CYG_WORD *)stack_base;
167 cyg_uint32 size = stack_size/sizeof(CYG_WORD);
171 // Work up the stack comparing with the preset value
172 // We assume the stack grows downwards, hmm...
173 for (i=0; i<size; i++) {
174 if (base[i] != 0xDEADBEEF)
177 return (size - i)*sizeof(CYG_WORD);
181 // -------------------------------------------------------------------------
182 // Attach a stack to this thread. If there is a HAL defined macro to
183 // do this, then we use that, otherwise assume a falling stack.
184 inline void Cyg_HardwareThread::attach_stack(CYG_ADDRESS s_base, cyg_uint32 s_size)
186 #ifdef CYGNUM_HAL_STACK_SIZE_MINIMUM
187 CYG_ASSERT( s_size >= CYGNUM_HAL_STACK_SIZE_MINIMUM,
188 "Stack size too small");
191 #ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
193 cyg_uint32 sig = (cyg_uint32)this;
194 cyg_uint32 *base = (cyg_uint32 *)s_base;
195 cyg_uint32 *top = (cyg_uint32 *)(s_base + s_size -
196 CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE);
200 CYG_INSTRUMENT_THREAD(ATTACH_STACK, base, top );
202 CYG_ASSERT( NULL != base, "stack base non-NULL" );
203 CYG_ASSERT( 0 == ((sizeof(CYG_WORD)-1) & (cyg_uint32)base), "stack base alignment" );
204 CYG_ASSERT( 0 == ((sizeof(CYG_WORD)-1) & (cyg_uint32)top), "stack top alignment" );
207 i < CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE/sizeof(cyg_uint32);
209 base[i] = (sig ^ (i * 0x01010101));
210 top[i] = (sig ^ (i * 0x10101010));
212 // This check for overlap of the two signature areas also detects
213 // wrap round zero of the size in the unsigned subtraction below.
214 CYG_ASSERT( &base[i] < &top[0], "Stack is so small size wrapped" );
215 // Use this 'i' expression to round correctly to whole words.
216 s_base += i * sizeof(cyg_uint32);
217 s_size -= i * sizeof(cyg_uint32) * 2;
218 // This is a complete guess, the 256; the point is to assert early that
219 // this might go badly wrong. It would not detect wrap of unsigned size.
220 CYG_ASSERT( s_size >= 256,
221 "Stack size too small after allocating checking buffer");
224 #ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
226 CYG_WORD *base = (CYG_WORD *)s_base;
227 cyg_uint32 size = s_size/sizeof(CYG_WORD);
230 // initialize all of stack with known value - don't choose 0
231 // could do with pseudo value as above, but this way, checking
233 for (i=0; i<size; i++) {
234 base[i] = 0xDEADBEEF;
236 // Don't bother about the case when the stack isn't a multiple of
237 // CYG_WORD in size. Since it's at the top of the stack, it will
238 // almost certainly be overwritten the instant the thread starts
244 #ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
245 stack_limit = s_base;
248 #ifdef HAL_THREAD_ATTACH_STACK
250 HAL_THREAD_ATTACH_STACK(stack_ptr, stack_base, stack_size);
254 stack_ptr = stack_base + stack_size;
258 #ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
263 // -------------------------------------------------------------------------
265 inline Cyg_HardwareThread::Cyg_HardwareThread(
266 cyg_thread_entry *e_point, // entry point function
267 CYG_ADDRWORD e_data, // entry data
268 cyg_ucount32 s_size, // stack size, 0 = use default
269 CYG_ADDRESS s_base // stack base, NULL = allocate
272 entry_point = e_point;
274 #ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
278 attach_stack( s_base, s_size );
281 // -------------------------------------------------------------------------
283 #ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
285 // Return the current saved state for this thread.
286 inline HAL_SavedRegisters *Cyg_HardwareThread::get_saved_context()
288 HAL_SavedRegisters *regs;
289 if( saved_context != 0 ) regs = saved_context;
290 else HAL_THREAD_GET_SAVED_REGISTERS( stack_ptr, regs );
294 inline void Cyg_HardwareThread::set_saved_context(HAL_SavedRegisters *ctx)
301 // -------------------------------------------------------------------------
302 // (declare this inline before its first use)
304 inline cyg_uint16 Cyg_Thread::get_unique_id()
309 // -------------------------------------------------------------------------
310 // Initialize the context of this thread.
312 inline void Cyg_HardwareThread::init_context(Cyg_Thread *thread)
314 #ifdef CYGPKG_INFRA_DEBUG
315 cyg_uint32 threadid = thread->get_unique_id()*0x01010000;
317 cyg_uint32 threadid = 0x11110000;
319 HAL_THREAD_INIT_CONTEXT( stack_ptr, thread, thread_entry, threadid );
324 // -------------------------------------------------------------------------
325 // Save current thread's context and load that of the given next thread.
326 // This function is only really here for completeness, the
327 // kernel generally calls the HAL macros directly.
329 inline void Cyg_HardwareThread::switch_context(Cyg_HardwareThread *next)
331 HAL_THREAD_SWITCH_CONTEXT( &stack_ptr, &next->stack_ptr );
334 // -------------------------------------------------------------------------
335 // Get and set entry_data.
337 inline void Cyg_HardwareThread::set_entry_data( CYG_ADDRWORD data )
342 inline CYG_ADDRWORD Cyg_HardwareThread::get_entry_data()
347 // -------------------------------------------------------------------------
348 // Allocate some memory at the lower end of the stack
349 // by moving the stack limit pointer.
351 #ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
353 #ifndef CYGFUN_KERNEL_THREADS_STACK_CHECKING
354 // if stack checking, implementation is in thread.cxx
355 inline void *Cyg_HardwareThread::increment_stack_limit( cyg_ucount32 size )
357 void *ret = (void *)stack_limit;
364 Cyg_HardwareThread::get_stack_limit()
371 //==========================================================================
372 // Inlines for Cyg_Thread class
374 inline Cyg_Thread *Cyg_Thread::self()
376 return Cyg_Scheduler::get_current_thread();
379 // -------------------------------------------------------------------------
381 inline void Cyg_Thread::yield()
383 self()->Cyg_SchedThread::yield();
386 // -------------------------------------------------------------------------
389 Cyg_Thread::rotate_queue( cyg_priority pri )
391 self()->Cyg_SchedThread::rotate_queue( pri );
394 // -------------------------------------------------------------------------
397 Cyg_Thread::to_queue_head( void )
399 this->Cyg_SchedThread::to_queue_head();
402 // -------------------------------------------------------------------------
404 #ifdef CYGIMP_THREAD_PRIORITY
406 inline cyg_priority Cyg_Thread::get_priority()
408 #ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
410 // If we have an inherited priority, return our original
411 // priority rather than the current one.
413 if( priority_inherited ) return original_priority;
420 // Return the actual dispatching priority of the thread
421 // regardless of inheritance or scheduling concerns.
422 inline cyg_priority Cyg_Thread::get_current_priority()
429 // -------------------------------------------------------------------------
431 inline void Cyg_Thread::set_sleep_reason( cyg_reason reason)
433 self()->sleep_reason = reason;
434 self()->wake_reason = NONE;
437 // -------------------------------------------------------------------------
439 inline Cyg_Thread::cyg_reason Cyg_Thread::get_sleep_reason()
444 // -------------------------------------------------------------------------
446 inline void Cyg_Thread::set_wake_reason( cyg_reason reason )
449 wake_reason = reason;
452 // -------------------------------------------------------------------------
454 inline Cyg_Thread::cyg_reason Cyg_Thread::get_wake_reason()
459 // -------------------------------------------------------------------------
461 inline void Cyg_Thread::set_timer(
462 cyg_tick_count trigger,
466 #ifdef CYGFUN_KERNEL_THREADS_TIMER
467 self()->sleep_reason = reason;
468 self()->wake_reason = NONE;
469 self()->timer.initialize( trigger);
473 // -------------------------------------------------------------------------
475 inline void Cyg_Thread::clear_timer()
477 #ifdef CYGFUN_KERNEL_THREADS_TIMER
478 self()->timer.disable();
482 // -------------------------------------------------------------------------
484 #ifdef CYGVAR_KERNEL_THREADS_DATA
486 inline CYG_ADDRWORD Cyg_Thread::get_data( Cyg_Thread::cyg_data_index index )
488 CYG_ASSERT( index < CYGNUM_KERNEL_THREADS_DATA_MAX,
489 "Per thread data index out of bounds");
490 CYG_ASSERT( (thread_data_map & (1<<index)) == 0,
491 "Unallocated index used");
493 return self()->thread_data[index];
496 inline CYG_ADDRWORD *Cyg_Thread::get_data_ptr( Cyg_Thread::cyg_data_index index )
498 CYG_ASSERT( index < CYGNUM_KERNEL_THREADS_DATA_MAX,
499 "Per thread data index out of bounds");
500 CYG_ASSERT( (thread_data_map & (1<<index)) == 0,
501 "Unallocated index used");
503 return &(self()->thread_data[index]);
506 inline void Cyg_Thread::set_data( Cyg_Thread::cyg_data_index index,
509 CYG_ASSERT( index < CYGNUM_KERNEL_THREADS_DATA_MAX,
510 "Per thread data index out of bounds");
511 CYG_ASSERT( (thread_data_map & (1<<index)) == 0,
512 "Unallocated index used");
514 thread_data[index] = data;
519 // -------------------------------------------------------------------------
521 #ifdef CYGVAR_KERNEL_THREADS_NAME
523 inline char *Cyg_Thread::get_name()
530 // -------------------------------------------------------------------------
532 #ifdef CYGVAR_KERNEL_THREADS_LIST
534 inline Cyg_Thread *Cyg_Thread::get_list_head()
536 return thread_list?thread_list->list_next:0;
539 inline Cyg_Thread *Cyg_Thread::get_list_next()
541 return (this==thread_list)?0:list_next;
547 // -------------------------------------------------------------------------
549 #ifdef CYGPKG_KERNEL_EXCEPTIONS
551 inline void Cyg_Thread::register_exception(
552 cyg_code exception_number, // exception number
553 cyg_exception_handler handler, // handler function
554 CYG_ADDRWORD data, // data argument
555 cyg_exception_handler **old_handler, // handler function
556 CYG_ADDRWORD *old_data // data argument
559 self()->exception_control.register_exception(
568 inline void Cyg_Thread::deregister_exception(
569 cyg_code exception_number // exception number
572 self()->exception_control.deregister_exception(
579 //==========================================================================
580 // Inlines for Cyg_ThreadTimer class
582 // -------------------------------------------------------------------------
583 #if defined(CYGFUN_KERNEL_THREADS_TIMER) && defined(CYGVAR_KERNEL_COUNTERS_CLOCK)
585 inline Cyg_ThreadTimer::Cyg_ThreadTimer(
588 : Cyg_Alarm(Cyg_Clock::real_time_clock,
598 //==========================================================================
599 // Inlines for Cyg_ThreadQueue class
602 inline void Cyg_ThreadQueue::enqueue(Cyg_Thread *thread)
604 Cyg_ThreadQueue_Implementation::enqueue(thread);
607 // -------------------------------------------------------------------------
609 inline Cyg_Thread *Cyg_ThreadQueue::highpri()
611 return Cyg_ThreadQueue_Implementation::highpri();
614 // -------------------------------------------------------------------------
616 inline Cyg_Thread *Cyg_ThreadQueue::dequeue()
618 return Cyg_ThreadQueue_Implementation::dequeue();
621 // -------------------------------------------------------------------------
623 inline void Cyg_ThreadQueue::remove(Cyg_Thread *thread)
625 Cyg_ThreadQueue_Implementation::remove(thread);
628 // -------------------------------------------------------------------------
630 inline cyg_bool Cyg_ThreadQueue::empty()
632 return Cyg_ThreadQueue_Implementation::empty();
635 // -------------------------------------------------------------------------
637 #ifdef CYGPKG_KERNEL_THREADS_DESTRUCTORS
639 #ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
640 # include <cyg/kernel/sched.inl>
643 // Add and remove destructors. Returns true on success, false on failure.
645 Cyg_Thread::add_destructor( destructor_fn fn, CYG_ADDRWORD data )
648 #ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
649 Cyg_Scheduler::lock();
651 for (i=0; i<CYGNUM_KERNEL_THREADS_DESTRUCTORS; i++) {
652 if (NULL == destructors[i].fn) {
653 destructors[i].data = data;
654 destructors[i].fn = fn;
655 #ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
656 Cyg_Scheduler::unlock();
661 #ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
662 Cyg_Scheduler::unlock();
668 Cyg_Thread::rem_destructor( destructor_fn fn, CYG_ADDRWORD data )
671 #ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
672 Cyg_Scheduler::lock();
674 for (i=0; i<CYGNUM_KERNEL_THREADS_DESTRUCTORS; i++) {
675 if (destructors[i].fn == fn && destructors[i].data == data) {
676 destructors[i].fn = NULL;
677 #ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
678 Cyg_Scheduler::unlock();
683 #ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
684 Cyg_Scheduler::unlock();
690 // -------------------------------------------------------------------------
692 #endif // ifndef CYGONCE_KERNEL_THREAD_INL