summaryrefslogtreecommitdiff
path: root/cesar/ecos/packages/kernel/current/include/thread.hxx
blob: e191aa5ce441a3a7931f0193fbfb5fd4f2de7629 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
#ifndef CYGONCE_KERNEL_THREAD_HXX
#define CYGONCE_KERNEL_THREAD_HXX

//==========================================================================
//
//      thread.hxx
//
//      Thread class declarations
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):   nickg
// Contributors:        nickg
// Date:        1997-09-09
// Purpose:     Define Thread class interfaces
// Description: The classes defined here collectively implement the
//              internal API used to create, configure and manage threads.
// Usage:       #include <cyg/kernel/thread.hxx>
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <cyg/kernel/ktypes.h>
#include <cyg/infra/cyg_ass.h>         // assertion macros
#include <cyg/kernel/sched.hxx>
#include <cyg/kernel/clock.hxx>
#include <cyg/kernel/except.hxx>

#include <cyg/hal/hal_arch.h>

// -------------------------------------------------------------------------
// Miscellaneous types

typedef void cyg_thread_entry(CYG_ADDRWORD data);// Thread entry point function

// -------------------------------------------------------------------------
// Hardware thread interface.
// The implementation of this class is provided by the HAL.

class Cyg_HardwareThread
{
    friend class Cyg_Scheduler;

protected:

    CYG_ADDRESS         stack_base;     // pointer to base of stack area

    cyg_uint32          stack_size;     // size of stack area in bytes

#ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
    CYG_ADDRESS         stack_limit;    // movable stack limit
#endif    

    CYG_ADDRESS         stack_ptr;      // pointer to saved state on stack

    cyg_thread_entry    *entry_point;   // main entry point (code pointer!)

    CYG_ADDRWORD        entry_data;     // entry point argument

#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT

    HAL_SavedRegisters  *saved_context; // If non-zero, this points at a more
                                        // interesting context than stack_ptr.
#endif
    
    Cyg_HardwareThread(
        cyg_thread_entry        *entry_point,   // entry point function
        CYG_ADDRWORD            entry_data,     // entry data
        cyg_ucount32            stack_size = 0, // stack size, 0 = use default
        CYG_ADDRESS             stack_base = 0  // stack base, NULL = allocate
    );

    // Thread entry point. This is where all threads begin execution.
    // This routine does a little housekeeping and then call the main
    // entry_point specified above.
    static void thread_entry(Cyg_Thread *thread);

    // Initialize the context of the thread to start execution at thread_entry
    void    init_context( Cyg_Thread *thread );
    
    // Save current thread's context and load that of the given next thread.
    void    switch_context(Cyg_HardwareThread *next);

    // attach a stack to this thread
    void    attach_stack(CYG_ADDRESS stack, cyg_uint32 stack_size);

    // detach the stack from this thread
    CYG_ADDRESS detach_stack();

    // Adjust the thread's saved state to call the exception
    // handler when next executed.
    void    prepare_exception (
        cyg_exception_handler   *exception_handler,
        CYG_ADDRWORD            exception_data,
        cyg_code                exception_number,
        CYG_ADDRWORD            exception_info
        );

public:

    CYGDBG_DEFINE_CHECK_THIS    

    // Get and set entry_data.

    void set_entry_data( CYG_ADDRWORD data );

    CYG_ADDRWORD get_entry_data();

#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT    
    // Return the current saved state for this thread.
    HAL_SavedRegisters *get_saved_context();

    // Set the saved context pointer.
    void set_saved_context(HAL_SavedRegisters *ctx);
#endif

    // get the size/base of this thread's stack
    CYG_ADDRESS get_stack_base();

    cyg_uint32 get_stack_size();

#ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT    
    // Allocate some memory at the lower end of the stack
    // by moving the stack limit pointer.

    void *increment_stack_limit( cyg_ucount32 size);
    
    CYG_ADDRESS get_stack_limit();
#endif    

#ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING

    inline void check_stack(void);

#endif
#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT

    inline cyg_uint32 measure_stack_usage(void);

#endif
};

// -------------------------------------------------------------------------
// Per-thread timer support class.
// This is only included when required.

#ifdef CYGFUN_KERNEL_THREADS_TIMER

class Cyg_ThreadTimer
    : public Cyg_Alarm
{
    friend class Cyg_Thread;

    // Pointer to current thread
    Cyg_Thread          *thread;

    // Constructor
    Cyg_ThreadTimer(
        Cyg_Thread      *thread
        );

    // Alarm function
    static void alarm( Cyg_Alarm *alarm, CYG_ADDRWORD data);

    CYGDBG_DEFINE_CHECK_THIS

};

#endif

// -------------------------------------------------------------------------
// Main Thread class.
// This provides the public API for controlling threads.

class Cyg_Thread
    : public Cyg_HardwareThread,       // provides hardware abstractions
      public Cyg_SchedThread           // provides scheduling abstractions
{
    friend class Cyg_Scheduler;
    friend void deliver_exception( CYG_WORD code, CYG_ADDRWORD data );
    
    // The following definitions are used by all variants of the
    // basic thread object.

public:    
    enum {                       // Thread state values
        
        RUNNING    = 0,          // Thread is runnable or running
        SLEEPING   = 1,          // Thread is waiting for something to happen
        COUNTSLEEP = 2,          // Sleep in counted manner
        SUSPENDED  = 4,          // Suspend count is non-zero
        CREATING   = 8,          // Thread is being created
        EXITED     = 16,         // Thread has exited

        // This is the set of bits that must be cleared by a generic
        // wake() or release().
        SLEEPSET   = (SLEEPING | COUNTSLEEP)
    };
    
private:
    // Current thread state, a logical OR of the above values.
    // Only if this word is zero can the thread execute.
    cyg_uint32                  state;      

    // Suspension counter, if > 0, the thread is suspended
    cyg_ucount32                suspend_count;

    // Wakeup counter, if > 0, sleep will not sleep, just decrement
    cyg_ucount32                wakeup_count;

    // A word of data used in syncronization object to communicate
    // information between sleepers and wakers.
    CYG_ADDRWORD                wait_info;
    
    // Unique thread id assigned on creation
    cyg_uint16                  unique_id;

#ifdef CYGPKG_KERNEL_EXCEPTIONS

    // If exceptions are supported, define an exception control
    // object that will be used to manage and deliver them. If
    // exceptions are global there is a single static instance
    // of this object, if they are per-thread then there is one
    // for each thread.
private:

#ifdef CYGSEM_KERNEL_EXCEPTIONS_GLOBAL
    static
#endif
    Cyg_Exception_Control       exception_control;

public:

    static void register_exception(
        cyg_code                exception_number,       // exception number
        cyg_exception_handler   handler,                // handler function
        CYG_ADDRWORD            data,                   // data argument
        cyg_exception_handler   **old_handler,          // handler function
        CYG_ADDRWORD            *old_data               // data argument
        );

    static void deregister_exception(
        cyg_code                exception_number        // exception number
        );
    
    void deliver_exception(
        cyg_code            exception_number,       // exception being raised
        CYG_ADDRWORD        exception_info          // exception specific info
        );

#endif

    
public:

    CYGDBG_DEFINE_CHECK_THIS
    
    // Constructor, Initialize the thread structure. The thread is
    // created in suspended state, and needs to be resumed to execute.
    // It is also started at some (configurable) default priority, which
    // may need to be changed before calling resume.
    
    Cyg_Thread (
        cyg_thread_entry        *entry,         // entry point function
        CYG_ADDRWORD            entry_data,     // entry data
        cyg_ucount32            stack_size = 0, // stack size, 0 = use default
        CYG_ADDRESS             stack_base = 0  // stack base, NULL = allocate
        );

    Cyg_Thread (
        CYG_ADDRWORD            sched_info,     // Scheduling parameter(s)
        cyg_thread_entry        *entry,         // entry point function
        CYG_ADDRWORD            entry_data,     // entry data
        char                    *name,          // thread name
        CYG_ADDRESS             stack_base = 0, // stack base, NULL = allocate
        cyg_ucount32            stack_size = 0  // stack size, 0 = use default
        );

    // Re-initialize the thread back to it's initial state.
    void reinitialize();
    
    ~Cyg_Thread();
    
    // The following are invoked implicitly on the current thread,
    // hence they are static member functions.

    static void         sleep();        // Put thread to sleep

    static void         counted_sleep();// Decrement counter or put
                                        // thread to sleep
#ifdef CYGFUN_KERNEL_THREADS_TIMER
    static void         counted_sleep( cyg_tick_count delay );
                                        // ...for delay ticks
#endif
    
    static void         exit();         // Terminate thread

    static void         yield();        // Yield CPU to another thread

    static void         rotate_queue( cyg_priority pri );
                                        // Rotate that run queue

    void                to_queue_head( void );
                                        // Move to the head of its queue
                                        // (not necessarily a scheduler q)

    static Cyg_Thread   *self();        // Return current thread

        
    // The following are called on threads other than the current one.

    void                wake();         // Wake this thread from sleep.

    void                counted_wake(); // Increment counter or wake thread
    cyg_uint32          cancel_counted_wake();
                                        // Cancel counted wakeups for this
                                        // thread and return how many were
                                        // pending

    void                suspend();      // Suspend this thread: increment counter and
                                        // deschedule.
    
    void                resume();       // Resume this thread: decrement counter and
                                        // reschedule if counter is zero.

    void                release();      // Release thread from sleep with BREAK
                                        // wake_reason.
    
    void                kill();         // Kill this thread
    
    void                force_resume(); // Resume this thread: set counter to zero.

    cyg_uint32          get_state();    // Return current thread state.


    // Accessor functions to set and get wait_info.
    
    void                set_wait_info(CYG_ADDRWORD data);

    CYG_ADDRWORD        get_wait_info();
    
    // This part of the API is used if we have a clock and want
    // per-thread timers for doing delays and timeouts.

    // delay the given number of ticks
    void delay( cyg_tick_count delay );
        

    enum cyg_reason                     // sleep/wakeup reason codes
    {
        NONE,                           // No recorded reason
        WAIT,                           // Wait with no timeout
        DELAY,                          // Simple time delay
        TIMEOUT,                        // Wait with timeout/timeout expired
        BREAK,                          // forced break out of sleep
        DESTRUCT,                       // wait object destroyed[note]
        EXIT,                           // forced termination
        DONE                            // Wait/delay complete
    };
    // [note] NOT the thread, some object it was waiting on.
    //        Thread destruction would first involve EXITing it.
    
private:

#ifdef CYGFUN_KERNEL_THREADS_TIMER
    Cyg_ThreadTimer     timer;          // per-thread timer
#endif

    cyg_reason          sleep_reason;   // reason for sleeping

    cyg_reason          wake_reason;    // reason for waking
    
#ifdef CYGIMP_THREAD_PRIORITY

public:

    // If the scheduler implements priorities, provide
    // functions to set and get it.
    
    void set_priority( cyg_priority pri );

    cyg_priority get_priority();

    // This returns the current dispatching priority of the
    // thread. This may differ from the result of get_priority()
    // in the presence of priority inheritance or certain
    // scheduling algorithms.
    cyg_priority get_current_priority();    
    
#endif

#ifdef CYGVAR_KERNEL_THREADS_DATA

private:
    // Array of single word entries for each index. 
    CYG_ADDRWORD        thread_data[CYGNUM_KERNEL_THREADS_DATA_MAX];

    // Map of free thread_data indexes. Each bit represents an index
    // and is 1 if that index is free, and 0 if it is in use.
    static cyg_ucount32        thread_data_map;

public:
    
    typedef cyg_count32 cyg_data_index;

    static CYG_ADDRWORD get_data( cyg_data_index index );

    static CYG_ADDRWORD *get_data_ptr( cyg_data_index index );

    void                set_data( cyg_data_index index, CYG_ADDRWORD data );

    // returns -1 if no more indexes available
    static cyg_data_index new_data_index();

    static void         free_data_index( cyg_data_index index );

#endif

#ifdef CYGPKG_KERNEL_THREADS_DESTRUCTORS

    // thread destructors, called on thread exit.
private:
    typedef void (*destructor_fn)(CYG_ADDRWORD);
    struct Cyg_Destructor_Entry {
        destructor_fn fn;
        CYG_ADDRWORD data;
    };
#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
    static 
#endif
    Cyg_Destructor_Entry destructors[ CYGNUM_KERNEL_THREADS_DESTRUCTORS ];
public:
 
    // Add and remove destructors. Returns true on success, false on failure.
#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
    static 
#endif
    cyg_bool     add_destructor( destructor_fn fn, CYG_ADDRWORD data );
#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
    static 
#endif
    cyg_bool     rem_destructor( destructor_fn fn, CYG_ADDRWORD data );
#endif

#ifdef CYGVAR_KERNEL_THREADS_NAME

private:
    // An optional thread name string, for humans to read
    char                        *name;

public:    
    // function to get the name string
    char                        *get_name();
    
#endif
    

#ifdef CYGVAR_KERNEL_THREADS_LIST

        // Housekeeping list that tracks all threads
private:
    Cyg_Thread                  *list_next;
    static Cyg_Thread           *thread_list;

    void                        add_to_list(      void );
    void                        remove_from_list( void );
public:

    static Cyg_Thread           *get_list_head();
    
    Cyg_Thread                  *get_list_next();
    
#endif
    
public:
    
    // Set sleep reason to reason and wake reason to NONE
    static void set_sleep_reason( cyg_reason reason = WAIT);

    cyg_reason get_sleep_reason();
    
    // Set the wakeup reason to the given value
    void set_wake_reason( cyg_reason reason = DONE);

    // Get current wake reason
    cyg_reason get_wake_reason();

    static void set_timer(              // Set timeout and sleep reason
        cyg_tick_count  trigger,        // Absolute wakeup time
        cyg_reason      sleep_reason    // reason for sleeping
        );

    static void clear_timer();          // disable thread timer

    // Get a 16 bit unique id for this thread. This is
    // used in tracing and instrumentation to identify the
    // current thread.
    
    cyg_uint16 get_unique_id();
        
};

// -------------------------------------------------------------------------
// Thread Queue class.
// This defines the main API for manipulating queues of threads.

class Cyg_ThreadQueue
    : public Cyg_ThreadQueue_Implementation
{
    
public:

    CYGDBG_DEFINE_CHECK_THIS
    
    // API used by rest of kernel.
    
                        // Add thread to queue
    void                enqueue(Cyg_Thread *thread);

                        // return first thread on queue
    Cyg_Thread          *highpri();

                        // remove first thread on queue    
    Cyg_Thread          *dequeue();

                        // remove specified thread from queue    
    void                remove(Cyg_Thread *thread);

                        // test if queue is empty
    inline cyg_bool     empty();
    
};

// -------------------------------------------------------------------------
// Thread inlines

// Return current thread state.
inline cyg_uint32 Cyg_Thread::get_state()
{
    return state;
}

inline void Cyg_Thread::set_wait_info(CYG_ADDRWORD data)
{
    wait_info = data;
}

inline CYG_ADDRWORD Cyg_Thread::get_wait_info()
{
    return wait_info;
}

// -------------------------------------------------------------------------
#endif // ifndef CYGONCE_KERNEL_THREAD_HXX
// EOF thread.hxx