OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [kernel/] [v2_0/] [src/] [common/] [thread.cxx] - Blame information for rev 565

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.