|
0
|
1 #ifndef CYGONCE_KERNEL_THREAD_HXX |
|
|
2 #define CYGONCE_KERNEL_THREAD_HXX |
|
|
3 |
|
|
4 //========================================================================== |
|
|
5 // |
|
|
6 // thread.hxx |
|
|
7 // |
|
|
8 // Thread class declarations |
|
|
9 // |
|
|
10 //========================================================================== |
|
|
11 //####COPYRIGHTBEGIN#### |
|
|
12 // |
|
|
13 // ------------------------------------------- |
|
|
14 // The contents of this file are subject to the Cygnus eCos Public License |
|
|
15 // Version 1.0 (the "License"); you may not use this file except in |
|
|
16 // compliance with the License. You may obtain a copy of the License at |
|
|
17 // http://sourceware.cygnus.com/ecos |
|
|
18 // |
|
|
19 // Software distributed under the License is distributed on an "AS IS" |
|
|
20 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
|
21 // License for the specific language governing rights and limitations under |
|
|
22 // the License. |
|
|
23 // |
|
|
24 // The Original Code is eCos - Embedded Cygnus Operating System, released |
|
|
25 // September 30, 1998. |
|
|
26 // |
|
|
27 // The Initial Developer of the Original Code is Cygnus. Portions created |
|
|
28 // by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved. |
|
|
29 // ------------------------------------------- |
|
|
30 // |
|
|
31 //####COPYRIGHTEND#### |
|
|
32 //========================================================================== |
|
|
33 //#####DESCRIPTIONBEGIN#### |
|
|
34 // |
|
|
35 // Author(s): nickg |
|
|
36 // Contributors: nickg |
|
|
37 // Date: 1997-09-09 |
|
|
38 // Purpose: Define Thread class interfaces |
|
|
39 // Description: The classes defined here collectively implement the |
|
|
40 // internal API used to create, configure and manage threads. |
|
|
41 // Usage: #include <cyg/kernel/thread.hxx> |
|
|
42 // |
|
|
43 //####DESCRIPTIONEND#### |
|
|
44 // |
|
|
45 //========================================================================== |
|
|
46 |
|
|
47 #include <cyg/kernel/ktypes.h> |
|
|
48 #include <cyg/infra/cyg_ass.h> // assertion macros |
|
|
49 #include <cyg/kernel/sched.hxx> |
|
|
50 #include <cyg/kernel/clock.hxx> |
|
|
51 #include <cyg/kernel/except.hxx> |
|
|
52 |
|
|
53 #include <cyg/hal/hal_arch.h> |
|
|
54 |
|
|
55 // ------------------------------------------------------------------------- |
|
|
56 // Miscellaneous types |
|
|
57 |
|
|
58 typedef void cyg_thread_entry(CYG_ADDRWORD data);// Thread entry point function |
|
|
59 |
|
|
60 // ------------------------------------------------------------------------- |
|
|
61 // Hardware thread interface. |
|
|
62 // The implementation of this class is provided by the HAL. |
|
|
63 |
|
|
64 class Cyg_HardwareThread |
|
|
65 { |
|
|
66 friend class Cyg_Scheduler; |
|
|
67 |
|
|
68 protected: |
|
|
69 |
|
|
70 CYG_ADDRESS stack_base; // pointer to base of stack area |
|
|
71 |
|
|
72 cyg_uint32 stack_size; // size of stack area in bytes |
|
|
73 |
|
|
74 #ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT |
|
|
75 CYG_ADDRESS stack_limit; // movable stack limit |
|
|
76 #endif |
|
|
77 |
|
|
78 CYG_ADDRESS stack_ptr; // pointer to saved state on stack |
|
|
79 |
|
|
80 cyg_thread_entry *entry_point; // main entry point (code pointer!) |
|
|
81 |
|
|
82 CYG_ADDRWORD entry_data; // entry point argument |
|
|
83 |
|
|
84 #ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT |
|
|
85 |
|
|
86 HAL_SavedRegisters *saved_context; // If non-zero, this points at a more |
|
|
87 // interesting context than stack_ptr. |
|
|
88 #endif |
|
|
89 |
|
|
90 Cyg_HardwareThread( |
|
|
91 cyg_thread_entry *entry_point, // entry point function |
|
|
92 CYG_ADDRWORD entry_data, // entry data |
|
|
93 cyg_ucount32 stack_size = 0, // stack size, 0 = use default |
|
|
94 CYG_ADDRESS stack_base = 0 // stack base, NULL = allocate |
|
|
95 ); |
|
|
96 |
|
|
97 // Thread entry point. This is where all threads begin execution. |
|
|
98 // This routine does a little housekeeping and then call the main |
|
|
99 // entry_point specified above. |
|
|
100 static void thread_entry(Cyg_Thread *thread); |
|
|
101 |
|
|
102 // Initialize the context of the thread to start execution at thread_entry |
|
|
103 void init_context( Cyg_Thread *thread ); |
|
|
104 |
|
|
105 // Save current thread's context and load that of the given next thread. |
|
|
106 void switch_context(Cyg_HardwareThread *next); |
|
|
107 |
|
|
108 // load this thread's context without saving current context |
|
|
109 void load_context(); |
|
|
110 |
|
|
111 // attach a stack to this thread |
|
|
112 void attach_stack(CYG_ADDRESS stack, cyg_uint32 stack_size); |
|
|
113 |
|
|
114 // detach the stack from this thread |
|
|
115 CYG_ADDRESS detach_stack(); |
|
|
116 |
|
|
117 // Adjust the thread's saved state to call the exception |
|
|
118 // handler when next executed. |
|
|
119 void prepare_exception ( |
|
|
120 cyg_exception_handler *exception_handler, |
|
|
121 CYG_ADDRWORD exception_data, |
|
|
122 cyg_code exception_number, |
|
|
123 CYG_ADDRWORD exception_info |
|
|
124 ); |
|
|
125 |
|
|
126 public: |
|
|
127 |
|
|
128 CYGDBG_DEFINE_CHECK_THIS |
|
|
129 |
|
|
130 // Get and set entry_data. |
|
|
131 |
|
|
132 void set_entry_data( CYG_ADDRWORD data ); |
|
|
133 |
|
|
134 CYG_ADDRWORD get_entry_data(); |
|
|
135 |
|
|
136 #ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT |
|
|
137 // Return the current saved state for this thread. |
|
|
138 HAL_SavedRegisters *get_saved_context(); |
|
|
139 |
|
|
140 // Set the saved context pointer. |
|
|
141 void set_saved_context(HAL_SavedRegisters *ctx); |
|
|
142 #endif |
|
|
143 |
|
|
144 // get the size/base of this thread's stack |
|
|
145 CYG_ADDRESS get_stack_base(); |
|
|
146 |
|
|
147 cyg_uint32 get_stack_size(); |
|
|
148 |
|
|
149 #ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT |
|
|
150 // Allocate some memory at the lower end of the stack |
|
|
151 // by moving the stack limit pointer. |
|
|
152 |
|
|
153 void *increment_stack_limit( cyg_ucount32 size); |
|
|
154 |
|
|
155 CYG_ADDRESS get_stack_limit(); |
|
|
156 #endif |
|
|
157 }; |
|
|
158 |
|
|
159 // ------------------------------------------------------------------------- |
|
|
160 // Per-thread timer support class. |
|
|
161 // This is only included when required. |
|
|
162 |
|
|
163 #ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
|
164 |
|
|
165 class Cyg_ThreadTimer |
|
|
166 : public Cyg_Alarm |
|
|
167 { |
|
|
168 friend class Cyg_Thread; |
|
|
169 |
|
|
170 // Pointer to current thread |
|
|
171 Cyg_Thread *thread; |
|
|
172 |
|
|
173 // Constructor |
|
|
174 Cyg_ThreadTimer( |
|
|
175 Cyg_Thread *thread |
|
|
176 ); |
|
|
177 |
|
|
178 // Alarm function |
|
|
179 static void alarm( Cyg_Alarm *alarm, CYG_ADDRWORD data); |
|
|
180 |
|
|
181 CYGDBG_DEFINE_CHECK_THIS |
|
|
182 |
|
|
183 }; |
|
|
184 |
|
|
185 #endif |
|
|
186 |
|
|
187 // ------------------------------------------------------------------------- |
|
|
188 // Main Thread class. |
|
|
189 // This provides the public API for controlling threads. |
|
|
190 |
|
|
191 class Cyg_Thread |
|
|
192 : public Cyg_HardwareThread, // provides hardware abstractions |
|
|
193 public Cyg_SchedThread // provides scheduling abstractions |
|
|
194 { |
|
|
195 friend class Cyg_Scheduler; |
|
|
196 friend void deliver_exception( CYG_WORD code, CYG_ADDRWORD data ); |
|
|
197 |
|
|
198 // The following definitions are used by all variants of the |
|
|
199 // basic thread object. |
|
|
200 |
|
|
201 public: |
|
|
202 enum { // Thread state values |
|
|
203 |
|
|
204 RUNNING = 0, // Thread is runnable or running |
|
|
205 SLEEPING = 1, // Thread is waiting for something to happen |
|
|
206 COUNTSLEEP = 2, // Sleep in counted manner |
|
|
207 SUSPENDED = 4, // Suspend count is non-zero |
|
|
208 CREATING = 8, // Thread is being created |
|
|
209 EXITED = 16, // Thread has exited |
|
|
210 |
|
|
211 // This is the set of bits that must be cleared by a generic |
|
|
212 // wake() or release(). |
|
|
213 SLEEPSET = (SLEEPING | COUNTSLEEP) |
|
|
214 }; |
|
|
215 |
|
|
216 private: |
|
|
217 // Current thread state, a logical OR of the above values. |
|
|
218 // Only if this word is zero can the thread execute. |
|
|
219 cyg_uint32 state; |
|
|
220 |
|
|
221 // Suspension counter, if > 0, the thread is suspended |
|
|
222 cyg_ucount32 suspend_count; |
|
|
223 |
|
|
224 // Wakeup counter, if > 0, sleep will not sleep, just decrement |
|
|
225 cyg_ucount32 wakeup_count; |
|
|
226 |
|
|
227 // A word of data used in syncronization object to communicate |
|
|
228 // information between sleepers and wakers. |
|
|
229 CYG_ADDRWORD wait_info; |
|
|
230 |
|
|
231 // Unique thread id assigned on creation |
|
|
232 cyg_uint16 unique_id; |
|
|
233 |
|
|
234 #ifdef CYGPKG_KERNEL_EXCEPTIONS |
|
|
235 |
|
|
236 // If exceptions are supported, define an exception control |
|
|
237 // object that will be used to manage and deliver them. If |
|
|
238 // exceptions are global there is a single static instance |
|
|
239 // of this object, if they are per-thread then there is one |
|
|
240 // for each thread. |
|
|
241 private: |
|
|
242 |
|
|
243 #ifdef CYGSEM_KERNEL_EXCEPTIONS_GLOBAL |
|
|
244 static |
|
|
245 #endif |
|
|
246 Cyg_Exception_Control exception_control; |
|
|
247 |
|
|
248 public: |
|
|
249 |
|
|
250 static void register_exception( |
|
|
251 cyg_code exception_number, // exception number |
|
|
252 cyg_exception_handler handler, // handler function |
|
|
253 CYG_ADDRWORD data, // data argument |
|
|
254 cyg_exception_handler **old_handler, // handler function |
|
|
255 CYG_ADDRWORD *old_data // data argument |
|
|
256 ); |
|
|
257 |
|
|
258 static void deregister_exception( |
|
|
259 cyg_code exception_number // exception number |
|
|
260 ); |
|
|
261 |
|
|
262 void deliver_exception( |
|
|
263 cyg_code exception_number, // exception being raised |
|
|
264 CYG_ADDRWORD exception_info // exception specific info |
|
|
265 ); |
|
|
266 |
|
|
267 #endif |
|
|
268 |
|
|
269 |
|
|
270 public: |
|
|
271 |
|
|
272 CYGDBG_DEFINE_CHECK_THIS |
|
|
273 |
|
|
274 // Constructor, Initialize the thread structure. The thread is |
|
|
275 // created in suspended state, and needs to be resumed to execute. |
|
|
276 // It is also started at some (configurable) default priority, which |
|
|
277 // may need to be changed before calling resume. |
|
|
278 |
|
|
279 Cyg_Thread ( |
|
|
280 cyg_thread_entry *entry, // entry point function |
|
|
281 CYG_ADDRWORD entry_data, // entry data |
|
|
282 cyg_ucount32 stack_size = 0, // stack size, 0 = use default |
|
|
283 CYG_ADDRESS stack_base = 0 // stack base, NULL = allocate |
|
|
284 ); |
|
|
285 |
|
|
286 Cyg_Thread ( |
|
|
287 CYG_ADDRWORD sched_info, // Scheduling parameter(s) |
|
|
288 cyg_thread_entry *entry, // entry point function |
|
|
289 CYG_ADDRWORD entry_data, // entry data |
|
|
290 char *name, // thread name |
|
|
291 CYG_ADDRESS stack_base = 0, // stack base, NULL = allocate |
|
|
292 cyg_ucount32 stack_size = 0 // stack size, 0 = use default |
|
|
293 ); |
|
|
294 |
|
|
295 // Re-initialize the thread back to it's initial state. |
|
|
296 void Cyg_Thread::reinitialize(); |
|
|
297 |
|
|
298 ~Cyg_Thread(); |
|
|
299 |
|
|
300 // The following are invoked implicitly on the current thread, |
|
|
301 // hence they are static member functions. |
|
|
302 |
|
|
303 static void sleep(); // Put thread to sleep |
|
|
304 |
|
|
305 static void counted_sleep();// Decrement counter or put |
|
|
306 // thread to sleep |
|
|
307 #ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
|
308 static void counted_sleep( cyg_tick_count delay ); |
|
|
309 // ...for delay ticks |
|
|
310 #endif |
|
|
311 |
|
|
312 static void exit(); // Terminate thread |
|
|
313 |
|
|
314 static void yield(); // Yield CPU to another thread |
|
|
315 |
|
|
316 #ifdef CYGSEM_KERNEL_SCHED_MLQUEUE |
|
|
317 static void rotate_queue( cyg_priority pri ); |
|
|
318 // Rotate that run queue |
|
|
319 #endif |
|
|
320 |
|
|
321 static Cyg_Thread *self(); // Return current thread |
|
|
322 |
|
|
323 |
|
|
324 // The following are called on threads other than the current one. |
|
|
325 |
|
|
326 void wake(); // Wake this thread from sleep. |
|
|
327 |
|
|
328 void counted_wake(); // Increment counter or wake thread |
|
|
329 cyg_uint32 cancel_counted_wake(); |
|
|
330 // Cancel counted wakeups for this |
|
|
331 // thread and return how many were |
|
|
332 // pending |
|
|
333 |
|
|
334 void suspend(); // Suspend this thread: increment counter and |
|
|
335 // deschedule. |
|
|
336 |
|
|
337 void resume(); // Resume this thread: decrement counter and |
|
|
338 // reschedule if counter is zero. |
|
|
339 |
|
|
340 void release(); // Release thread from sleep with BREAK |
|
|
341 // wake_reason. |
|
|
342 |
|
|
343 void kill(); // Kill this thread |
|
|
344 |
|
|
345 void force_resume(); // Resume this thread: set counter to zero. |
|
|
346 |
|
|
347 cyg_uint32 get_state(); // Return current thread state. |
|
|
348 |
|
|
349 |
|
|
350 // Accessor functions to set and get wait_info. |
|
|
351 |
|
|
352 void set_wait_info(CYG_ADDRWORD data); |
|
|
353 |
|
|
354 CYG_ADDRWORD get_wait_info(); |
|
|
355 |
|
|
356 // This part of the API is used if we have a clock and want |
|
|
357 // per-thread timers for doing delays and timeouts. |
|
|
358 |
|
|
359 // delay the given number of ticks |
|
|
360 void delay( cyg_tick_count delay ); |
|
|
361 |
|
|
362 |
|
|
363 enum cyg_reason // sleep/wakeup reason codes |
|
|
364 { |
|
|
365 NONE, // No recorded reason |
|
|
366 WAIT, // Wait with no timeout |
|
|
367 DELAY, // Simple time delay |
|
|
368 TIMEOUT, // Wait with timeout/timeout expired |
|
|
369 BREAK, // forced break out of sleep |
|
|
370 DESTRUCT, // wait object destroyed[note] |
|
|
371 EXIT, // forced termination |
|
|
372 DONE // Wait/delay complete |
|
|
373 }; |
|
|
374 // [note] NOT the thread, some object it was waiting on. |
|
|
375 // Thread destruction would first involve EXITing it. |
|
|
376 |
|
|
377 private: |
|
|
378 |
|
|
379 #ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
|
380 Cyg_ThreadTimer timer; // per-thread timer |
|
|
381 #endif |
|
|
382 |
|
|
383 cyg_reason sleep_reason; // reason for sleeping |
|
|
384 |
|
|
385 cyg_reason wake_reason; // reason for waking |
|
|
386 |
|
|
387 #ifdef CYGIMP_THREAD_PRIORITY |
|
|
388 |
|
|
389 public: |
|
|
390 |
|
|
391 // If the scheduler implements priorities, provide |
|
|
392 // functions to set and get it. |
|
|
393 |
|
|
394 void set_priority( cyg_priority pri ); |
|
|
395 |
|
|
396 cyg_priority get_priority(); |
|
|
397 |
|
|
398 // This returns the current dispatching priority of the |
|
|
399 // thread. This may differ from the result of get_priority() |
|
|
400 // in the presence of priority inheritance or certain |
|
|
401 // scheduling algorithms. |
|
|
402 cyg_priority get_current_priority(); |
|
|
403 |
|
|
404 #endif |
|
|
405 |
|
|
406 #ifdef CYGVAR_KERNEL_THREADS_DATA |
|
|
407 |
|
|
408 private: |
|
|
409 // Array of single word entries for each index. |
|
|
410 CYG_ADDRWORD thread_data[CYGNUM_KERNEL_THREADS_DATA_MAX]; |
|
|
411 |
|
|
412 // Map of free thread_data indexes. Each bit represents an index |
|
|
413 // and is 1 if that index is free, and 0 if it is in use. |
|
|
414 static cyg_ucount32 thread_data_map; |
|
|
415 |
|
|
416 public: |
|
|
417 |
|
|
418 static CYG_ADDRWORD get_data( cyg_ucount32 index ); |
|
|
419 |
|
|
420 static CYG_ADDRWORD *get_data_ptr( cyg_ucount32 index ); |
|
|
421 |
|
|
422 void set_data( cyg_ucount32 index, CYG_ADDRWORD data ); |
|
|
423 |
|
|
424 static cyg_ucount32 new_data_index(); |
|
|
425 |
|
|
426 static void free_data_index( cyg_ucount32 index ); |
|
|
427 |
|
|
428 #endif |
|
|
429 |
|
|
430 #ifdef CYGVAR_KERNEL_THREADS_NAME |
|
|
431 |
|
|
432 private: |
|
|
433 // An optional thread name string, for humans to read |
|
|
434 char *name; |
|
|
435 |
|
|
436 public: |
|
|
437 // function to get the name string |
|
|
438 char *get_name(); |
|
|
439 |
|
|
440 #endif |
|
|
441 |
|
|
442 |
|
|
443 #ifdef CYGVAR_KERNEL_THREADS_LIST |
|
|
444 |
|
|
445 // Housekeeping list that tracks all threads |
|
|
446 private: |
|
|
447 Cyg_Thread *list_next; |
|
|
448 static Cyg_Thread *thread_list; |
|
|
449 |
|
|
450 void add_to_list( void ); |
|
|
451 void remove_from_list( void ); |
|
|
452 public: |
|
|
453 |
|
|
454 static Cyg_Thread *get_list_head(); |
|
|
455 |
|
|
456 Cyg_Thread *get_list_next(); |
|
|
457 |
|
|
458 #endif |
|
|
459 |
|
|
460 public: |
|
|
461 |
|
|
462 // Set sleep reason to reason and wake reason to NONE |
|
|
463 static void set_sleep_reason( cyg_reason reason = WAIT); |
|
|
464 |
|
|
465 cyg_reason get_sleep_reason(); |
|
|
466 |
|
|
467 // Set the wakeup reason to the given value |
|
|
468 void set_wake_reason( cyg_reason reason = DONE); |
|
|
469 |
|
|
470 // Get current wake reason |
|
|
471 cyg_reason get_wake_reason(); |
|
|
472 |
|
|
473 static void set_timer( // Set timeout and sleep reason |
|
|
474 cyg_tick_count trigger, // Absolute wakeup time |
|
|
475 cyg_reason sleep_reason // reason for sleeping |
|
|
476 ); |
|
|
477 |
|
|
478 static void clear_timer(); // disable thread timer |
|
|
479 |
|
|
480 // Get a 16 bit unique id for this thread. This is |
|
|
481 // used in tracing and instrumentation to identify the |
|
|
482 // current thread. |
|
|
483 |
|
|
484 cyg_uint16 get_unique_id(); |
|
|
485 |
|
|
486 }; |
|
|
487 |
|
|
488 // ------------------------------------------------------------------------- |
|
|
489 // Thread Queue class. |
|
|
490 // This defines the main API for manipulating queues of threads. |
|
|
491 |
|
|
492 class Cyg_ThreadQueue |
|
|
493 : private Cyg_ThreadQueue_Implementation |
|
|
494 { |
|
|
495 |
|
|
496 public: |
|
|
497 |
|
|
498 CYGDBG_DEFINE_CHECK_THIS |
|
|
499 |
|
|
500 // API used by rest of kernel. |
|
|
501 |
|
|
502 // Add thread to queue |
|
|
503 void enqueue(Cyg_Thread *thread); |
|
|
504 |
|
|
505 // return first thread on queue |
|
|
506 Cyg_Thread *highpri(); |
|
|
507 |
|
|
508 // remove first thread on queue |
|
|
509 Cyg_Thread *dequeue(); |
|
|
510 |
|
|
511 // remove specified thread from queue |
|
|
512 void remove(Cyg_Thread *thread); |
|
|
513 |
|
|
514 // test if queue is empty |
|
|
515 cyg_bool empty(); |
|
|
516 |
|
|
517 }; |
|
|
518 |
|
|
519 // ------------------------------------------------------------------------- |
|
|
520 // Thread inlines |
|
|
521 |
|
|
522 // Return current thread state. |
|
|
523 inline cyg_uint32 Cyg_Thread::get_state() |
|
|
524 { |
|
|
525 return state; |
|
|
526 } |
|
|
527 |
|
|
528 inline void Cyg_Thread::set_wait_info(CYG_ADDRWORD data) |
|
|
529 { |
|
|
530 wait_info = data; |
|
|
531 } |
|
|
532 |
|
|
533 inline CYG_ADDRWORD Cyg_Thread::get_wait_info() |
|
|
534 { |
|
|
535 return wait_info; |
|
|
536 } |
|
|
537 |
|
|
538 // ------------------------------------------------------------------------- |
|
|
539 #endif // ifndef CYGONCE_KERNEL_THREAD_HXX |
|
|
540 // EOF thread.hxx |