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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [kernel/] [current/] [src/] [sync/] [mutex.cxx] - Blame information for rev 819

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

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      sync/mutex.cxx
4
//
5
//      Mutex and condition variable implementation
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 Free Software Foundation, 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      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    nickg
43
// Contributors: nickg, jlarmour
44
// Date:         1999-02-17
45
// Purpose:      Mutex implementation
46
// Description:  This file contains the implementations of the mutex
47
//               and condition variable classes.
48
//
49
//####DESCRIPTIONEND####
50
//
51
//==========================================================================
52
 
53
#include <pkgconf/kernel.h>
54
 
55
#include <cyg/kernel/ktypes.h>         // base kernel types
56
#include <cyg/infra/cyg_trac.h>        // tracing macros
57
#include <cyg/infra/cyg_ass.h>         // assertion macros
58
#include <cyg/kernel/instrmnt.h>       // instrumentation
59
 
60
#include <cyg/kernel/mutex.hxx>        // our header
61
 
62
#include <cyg/kernel/thread.inl>       // thread inlines
63
#include <cyg/kernel/sched.inl>        // scheduler inlines
64
#include <cyg/kernel/clock.inl>        // clock inlines
65
 
66
// -------------------------------------------------------------------------
67
// Mutex protocol test macros.
68
// If the dynamic protocol option is enabled, then these generate appropriate
69
// tests on the protocol field. If there is no dynamic choice then they simply
70
// result in empty statements.
71
 
72
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
73
 
74
#define IF_PROTOCOL_INHERIT if( protocol == INHERIT )
75
#define IF_PROTOCOL_CEILING if( protocol == CEILING )
76
#define IF_PROTOCOL_ACTIVE  if( protocol != NONE )
77
 
78
#else
79
 
80
#define IF_PROTOCOL_INHERIT
81
#define IF_PROTOCOL_CEILING
82
#define IF_PROTOCOL_ACTIVE
83
 
84
#endif
85
 
86
// -------------------------------------------------------------------------
87
// Constructor
88
 
89
Cyg_Mutex::Cyg_Mutex()
90
{
91
    CYG_REPORT_FUNCTION();
92
 
93
    locked      = false;
94
    owner       = NULL;
95
 
96
#if defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT) && \
97
    defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC)
98
 
99
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_INHERIT
100
    protocol    = INHERIT;
101
#endif    
102
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_CEILING
103
    protocol    = CEILING;
104
    ceiling     = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY;
105
#endif    
106
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_NONE
107
    protocol    = NONE;
108
#endif
109
 
110
#else // not (DYNAMIC and DEFAULT defined)
111
 
112
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING    
113
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY
114
 
115
    // if there is a default priority ceiling defined, use that to initialize
116
    // the ceiling.
117
    ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY;
118
 
119
#else
120
 
121
    // Otherwise set it to zero.
122
    ceiling = 0;
123
 
124
#endif    
125
#endif
126
 
127
#endif // DYNAMIC and DEFAULT defined
128
 
129
    CYG_REPORT_RETURN();
130
}
131
 
132
// -------------------------------------------------------------------------
133
// Construct with defined protocol
134
 
135
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
136
 
137
Cyg_Mutex::Cyg_Mutex( cyg_protcol protocol_arg )
138
{
139
    CYG_REPORT_FUNCTION();
140
 
141
    locked      = false;
142
    owner       = NULL;
143
 
144
    protocol    = protocol_arg;
145
 
146
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING    
147
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY
148
 
149
    // if there is a default priority ceiling defined, use that to initialize
150
    // the ceiling.
151
    ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY;
152
 
153
#else
154
 
155
    // Otherwise set it to zero.
156
    ceiling = 0;
157
 
158
#endif    
159
#endif
160
 
161
    CYG_REPORT_RETURN();
162
}
163
 
164
#endif
165
 
166
// -------------------------------------------------------------------------
167
// Destructor
168
 
169
Cyg_Mutex::~Cyg_Mutex()
170
{
171
    CYG_REPORT_FUNCTION();
172
 
173
    CYG_ASSERT( owner == NULL, "Deleting mutex with owner");
174
    CYG_ASSERT( queue.empty(), "Deleting mutex with waiting threads");
175
    CYG_REPORT_RETURN();
176
}
177
 
178
// -------------------------------------------------------------------------
179
 
180
#ifdef CYGDBG_USE_ASSERTS
181
 
182
cyg_bool
183
Cyg_Mutex::check_this( cyg_assert_class_zeal zeal) const
184
{
185
//    CYG_REPORT_FUNCTION();
186
 
187
    // check that we have a non-NULL pointer first
188
    if( this == NULL ) return false;
189
 
190
    switch( zeal )
191
    {
192
    case cyg_system_test:
193
    case cyg_extreme:
194
    case cyg_thorough:
195
    case cyg_quick:
196
    case cyg_trivial:
197
        if(  locked && owner == NULL ) return false;
198
        if( !locked && owner != NULL ) return false;
199
    case cyg_none:
200
    default:
201
        break;
202
    };
203
 
204
    return true;
205
}
206
 
207
#endif
208
 
209
// -------------------------------------------------------------------------
210
// Lock and/or wait
211
 
212
cyg_bool
213
Cyg_Mutex::lock(void)
214
{
215
    CYG_REPORT_FUNCTYPE("returning %d");
216
 
217
    cyg_bool result = true;
218
    Cyg_Thread *self = Cyg_Thread::self();
219
 
220
    // Prevent preemption
221
    Cyg_Scheduler::lock();
222
 
223
    CYG_ASSERTCLASS( this, "Bad this pointer");
224
 
225
    CYG_INSTRUMENT_MUTEX(LOCK, this, 0);
226
 
227
    // Loop while the mutex is locked, sleeping each time around
228
    // the loop. This copes with the possibility of a higher priority
229
    // thread grabbing the mutex between the wakeup in unlock() and
230
    // this thread actually starting.
231
 
232
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
233
 
234
    IF_PROTOCOL_ACTIVE
235
        self->count_mutex();
236
 
237
#endif
238
 
239
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
240
 
241
    IF_PROTOCOL_CEILING
242
        self->set_priority_ceiling(ceiling);
243
 
244
#endif        
245
 
246
    while( locked && result )
247
    {
248
        CYG_ASSERT( self != owner, "Locking mutex I already own");
249
 
250
        self->set_sleep_reason( Cyg_Thread::WAIT );
251
 
252
        self->sleep();
253
 
254
        queue.enqueue( self );
255
 
256
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
257
 
258
        IF_PROTOCOL_INHERIT
259
            owner->inherit_priority(self);
260
 
261
#endif
262
 
263
        CYG_INSTRUMENT_MUTEX(WAIT, this, 0);
264
 
265
        // Allow other threads to run
266
        Cyg_Scheduler::reschedule();
267
 
268
        CYG_ASSERTCLASS( this, "Bad this pointer");
269
 
270
        switch( self->get_wake_reason() )
271
        {
272
        case Cyg_Thread::DESTRUCT:
273
        case Cyg_Thread::BREAK:
274
            result = false;
275
            break;
276
 
277
        case Cyg_Thread::EXIT:
278
            self->exit();
279
            break;
280
 
281
        default:
282
            break;
283
        }
284
 
285
    }
286
 
287
    if( result )
288
    {
289
        locked      = true;
290
        owner       = self;
291
 
292
        CYG_INSTRUMENT_MUTEX(LOCKED, this, 0);
293
    }
294
    else
295
    {
296
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
297
 
298
       IF_PROTOCOL_ACTIVE
299
           self->uncount_mutex();
300
 
301
#endif    
302
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
303
 
304
        IF_PROTOCOL_INHERIT
305
            self->disinherit_priority();
306
 
307
#endif
308
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
309
 
310
        IF_PROTOCOL_CEILING
311
            self->clear_priority_ceiling();
312
 
313
#endif
314
    }
315
 
316
    // Unlock the scheduler and maybe switch threads
317
    Cyg_Scheduler::unlock();
318
 
319
    CYG_ASSERTCLASS( this, "Bad this pointer");
320
 
321
    CYG_REPORT_RETVAL(result);
322
 
323
    return result;
324
}
325
 
326
// -------------------------------------------------------------------------
327
// Try to lock and return success
328
 
329
cyg_bool
330
Cyg_Mutex::trylock(void)
331
{
332
    CYG_REPORT_FUNCTYPE("returning %d");
333
 
334
    CYG_ASSERTCLASS( this, "Bad this pointer");
335
 
336
    cyg_bool result = true;
337
 
338
    // Prevent preemption
339
    Cyg_Scheduler::lock();
340
 
341
    // If the mutex is not locked, grab it
342
    // for ourself. Otherwise return failure.
343
    if( !locked )
344
    {
345
        Cyg_Thread *self = Cyg_Thread::self();
346
 
347
        locked  = true;
348
        owner   = self;
349
 
350
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
351
 
352
       IF_PROTOCOL_ACTIVE
353
            self->count_mutex();
354
 
355
#endif
356
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
357
 
358
        IF_PROTOCOL_CEILING
359
            self->set_priority_ceiling(ceiling);
360
 
361
#endif        
362
 
363
    }
364
    else result = false;
365
 
366
    CYG_INSTRUMENT_MUTEX(TRY, this, result);
367
 
368
    // Unlock the scheduler and maybe switch threads
369
    Cyg_Scheduler::unlock();
370
 
371
    CYG_REPORT_RETVAL(result);
372
    return result;
373
}
374
 
375
// -------------------------------------------------------------------------
376
// unlock
377
 
378
void
379
Cyg_Mutex::unlock(void)
380
{
381
    CYG_REPORT_FUNCTION();
382
 
383
    // Prevent preemption
384
    Cyg_Scheduler::lock();
385
 
386
    CYG_INSTRUMENT_MUTEX(UNLOCK, this, 0);
387
 
388
    CYG_ASSERTCLASS( this, "Bad this pointer");
389
    CYG_ASSERT( locked, "Unlock mutex that is not locked");
390
    CYG_ASSERT( owner == Cyg_Thread::self(), "Unlock mutex I do not own");
391
 
392
    if( !queue.empty() ) {
393
 
394
        // The queue is non-empty, so grab the next
395
        // thread from it and wake it up.
396
 
397
        Cyg_Thread *thread = queue.dequeue();
398
 
399
        CYG_ASSERTCLASS( thread, "Bad thread pointer");
400
 
401
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
402
 
403
        // Give the owner-to-be a chance to inherit from the remaining
404
        // queue or the relinquishing thread:
405
 
406
        IF_PROTOCOL_INHERIT
407
            thread->relay_priority(owner, &queue);
408
 
409
#endif
410
 
411
        thread->set_wake_reason( Cyg_Thread::DONE );
412
 
413
        thread->wake();
414
 
415
        CYG_INSTRUMENT_MUTEX(WAKE, this, thread);
416
 
417
    }
418
 
419
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
420
 
421
    IF_PROTOCOL_ACTIVE
422
        owner->uncount_mutex();
423
 
424
#endif    
425
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
426
 
427
    IF_PROTOCOL_INHERIT
428
        owner->disinherit_priority();
429
 
430
#endif
431
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
432
 
433
    IF_PROTOCOL_CEILING
434
        owner->clear_priority_ceiling();
435
 
436
#endif
437
 
438
    locked      = false;
439
    owner       = NULL;
440
 
441
    CYG_ASSERTCLASS( this, "Bad this pointer");
442
 
443
    // Unlock the scheduler and maybe switch threads
444
    Cyg_Scheduler::unlock();
445
 
446
    CYG_REPORT_RETURN();
447
}
448
 
449
// -------------------------------------------------------------------------
450
// Release all waiting threads.
451
 
452
void Cyg_Mutex::release()
453
{
454
    CYG_REPORT_FUNCTION();
455
 
456
    // Prevent preemption
457
    Cyg_Scheduler::lock();
458
 
459
    CYG_INSTRUMENT_MUTEX(RELEASE, this, 0);
460
 
461
    CYG_ASSERTCLASS( this, "Bad this pointer");
462
 
463
    while( !queue.empty() )
464
    {
465
        // The queue is non-empty, so grab each
466
        // thread from it and release it.
467
 
468
        Cyg_Thread *thread = queue.dequeue();
469
 
470
        CYG_ASSERTCLASS( thread, "Bad thread pointer");
471
 
472
        thread->release();
473
 
474
        CYG_INSTRUMENT_MUTEX(RELEASED, this, thread);
475
 
476
    }
477
 
478
    CYG_ASSERTCLASS( this, "Bad this pointer");
479
 
480
    // Unlock the scheduler and maybe switch threads
481
    Cyg_Scheduler::unlock();
482
 
483
    CYG_REPORT_RETURN();
484
}
485
 
486
// -------------------------------------------------------------------------
487
// Set ceiling priority for priority ceiling protocol
488
 
489
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
490
 
491
void Cyg_Mutex::set_ceiling( cyg_priority priority )
492
{
493
    CYG_REPORT_FUNCTION();
494
 
495
//    CYG_ASSERT( priority >=  CYG_THREAD_MAX_PRIORITY, "Priority out of range");
496
//    CYG_ASSERT( priority <=  CYG_THREAD_MIN_PRIORITY, "Priority out of range");
497
 
498
    // Prevent preemption
499
    Cyg_Scheduler::lock();
500
 
501
    ceiling = priority;
502
 
503
    // Unlock the scheduler
504
    Cyg_Scheduler::unlock();
505
 
506
    CYG_REPORT_RETURN();
507
}
508
 
509
#endif
510
 
511
// -------------------------------------------------------------------------
512
// Set priority inversion protocol
513
 
514
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
515
void Cyg_Mutex::set_protocol( cyg_protcol new_protocol )
516
{
517
    CYG_REPORT_FUNCTION();
518
 
519
    // Prevent preemption
520
    Cyg_Scheduler::lock();
521
 
522
    protocol = new_protocol;
523
 
524
    // Unlock the scheduler
525
    Cyg_Scheduler::unlock();
526
 
527
    CYG_REPORT_RETURN();
528
}
529
 
530
#endif
531
 
532
 
533
//==========================================================================
534
// Condition variables
535
 
536
Cyg_Condition_Variable::Cyg_Condition_Variable(
537
    Cyg_Mutex   &mx                // linked mutex
538
    )
539
{
540
    CYG_REPORT_FUNCTION();
541
 
542
    mutex       = &mx;
543
 
544
    CYG_ASSERTCLASS( mutex, "Invalid mutex argument");
545
 
546
    CYG_REPORT_RETURN();
547
}
548
 
549
Cyg_Condition_Variable::Cyg_Condition_Variable()
550
{
551
    CYG_REPORT_FUNCTION();
552
 
553
    mutex       = NULL;
554
 
555
    CYG_REPORT_RETURN();
556
}
557
 
558
// -------------------------------------------------------------------------
559
// Destructor
560
 
561
Cyg_Condition_Variable::~Cyg_Condition_Variable()
562
{
563
    CYG_REPORT_FUNCTION();
564
 
565
    CYG_ASSERT( queue.empty(), "Deleting condvar with waiting threads");
566
 
567
    CYG_REPORT_RETURN();
568
}
569
 
570
// -------------------------------------------------------------------------
571
 
572
#ifdef CYGDBG_USE_ASSERTS
573
 
574
cyg_bool
575
Cyg_Condition_Variable::check_this( cyg_assert_class_zeal zeal) const
576
{
577
    bool result = true;
578
 
579
    CYG_REPORT_FUNCTYPE("returning %d");
580
    CYG_REPORT_FUNCARG1("zeal = %d", zeal);
581
 
582
    // check that we have a non-NULL pointer first
583
    if( this == NULL )
584
        result = false;
585
    else {
586
 
587
        switch( zeal )
588
        {
589
        case cyg_system_test:
590
        case cyg_extreme:
591
        case cyg_thorough:
592
            if( mutex != NULL && !mutex->check_this(zeal) )
593
                result = false;
594
        case cyg_quick:
595
        case cyg_trivial:
596
        case cyg_none:
597
        default:
598
            break;
599
        }
600
    }
601
 
602
    CYG_REPORT_RETVAL(result);
603
    return result;
604
}
605
 
606
#endif
607
 
608
// -------------------------------------------------------------------------
609
// Wait for condition to be true    
610
// Note: if this function is entered with the scheduler locked (e.g. to
611
// suspend DSR processing) then there is no need to take the lock.  Also
612
// in this case, exit with the scheduler locked, which allows this function
613
// to be used in a totally thread-safe manner.
614
 
615
cyg_bool
616
Cyg_Condition_Variable::wait_inner( Cyg_Mutex *mx )
617
{
618
    CYG_REPORT_FUNCTION();
619
 
620
    cyg_bool result = true;
621
    Cyg_Thread *self = Cyg_Thread::self();
622
 
623
    Cyg_Scheduler::lock();
624
 
625
    CYG_ASSERTCLASS( this, "Bad this pointer");
626
    CYG_ASSERTCLASS( mx, "Corrupt mutex");
627
    CYG_ASSERTCLASS( self, "Bad self thread");
628
 
629
    CYG_INSTRUMENT_CONDVAR(WAIT, this, 0);
630
 
631
    mx->unlock();
632
 
633
    self->set_sleep_reason( Cyg_Thread::WAIT );
634
 
635
    self->sleep();
636
 
637
    queue.enqueue( self );
638
 
639
    // Avoid calling ASRs during the following unlock.
640
    self->set_asr_inhibit();
641
 
642
    // Unlock the scheduler and switch threads
643
    Cyg_Scheduler::unlock_reschedule();
644
 
645
    // Allow ASRs again
646
    self->clear_asr_inhibit();
647
 
648
    CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason());
649
 
650
    CYG_ASSERTCLASS( this, "Bad this pointer");
651
    CYG_ASSERTCLASS( mx, "Corrupt mutex");
652
 
653
    switch( self->get_wake_reason() )
654
    {
655
    case Cyg_Thread::DESTRUCT:          // which, the cv or the mutex?
656
    case Cyg_Thread::BREAK:
657
        result = false;
658
        break;
659
 
660
    case Cyg_Thread::EXIT:
661
        self->exit();
662
        break;
663
 
664
    default:
665
        break;
666
    }
667
 
668
    // When we awake, we must re-acquire the mutex.  Note that while
669
    // it is essential to release the mutex and queue on the CV
670
    // atomically relative to other threads, to avoid races, it is not
671
    // necessary for us to re-acquire the mutex in the same atomic
672
    // action. Hence we can do it after unlocking the scheduler.
673
    // We need to loop here in case the thread is released while waiting
674
    // for the mutex. It is essential that we exit this function with the
675
    // mutex claimed.
676
 
677
    while ( !mx->lock() )
678
        continue;
679
 
680
    CYG_ASSERTCLASS( this, "Bad this pointer");
681
    CYG_ASSERTCLASS( mx, "Corrupt mutex");
682
    CYG_ASSERT( mx->owner == self, "Not mutex owner");
683
 
684
    CYG_REPORT_RETURN();
685
 
686
    return result;
687
}
688
 
689
// -------------------------------------------------------------------------
690
// Wake one thread
691
 
692
void
693
Cyg_Condition_Variable::signal(void)
694
{
695
    CYG_REPORT_FUNCTION();
696
 
697
    CYG_ASSERTCLASS( this, "Bad this pointer");
698
 
699
    // Prevent preemption
700
    Cyg_Scheduler::lock();
701
 
702
    CYG_INSTRUMENT_CONDVAR(SIGNAL, this, 0);
703
 
704
    if( !queue.empty() )
705
    {
706
        // The queue is non-empty, so grab the next
707
        // thread from it and wake it up.
708
 
709
        Cyg_Thread *thread = queue.dequeue();
710
 
711
        CYG_ASSERTCLASS( thread, "Bad thread pointer");
712
 
713
        thread->set_wake_reason( Cyg_Thread::DONE );
714
 
715
        thread->wake();
716
 
717
        CYG_INSTRUMENT_CONDVAR(WAKE, this, thread);
718
 
719
    }
720
 
721
    CYG_ASSERTCLASS( this, "Bad this pointer");
722
 
723
    // Unlock the scheduler and maybe switch threads
724
    Cyg_Scheduler::unlock();
725
 
726
    CYG_REPORT_RETURN();
727
}
728
 
729
// -------------------------------------------------------------------------
730
// Set cond true, wake all threads
731
 
732
void
733
Cyg_Condition_Variable::broadcast(void)
734
{
735
    CYG_REPORT_FUNCTION();
736
 
737
    CYG_ASSERTCLASS( this, "Bad this pointer");
738
 
739
    // Prevent preemption
740
    Cyg_Scheduler::lock();
741
 
742
    CYG_INSTRUMENT_CONDVAR(BROADCAST, this, 0);
743
 
744
    // Grab all the threads from the queue and let them
745
    // go.
746
 
747
    while( !queue.empty() )
748
    {
749
        Cyg_Thread *thread = queue.dequeue();
750
 
751
        CYG_ASSERTCLASS( thread, "Bad thread pointer");
752
 
753
        thread->set_wake_reason( Cyg_Thread::DONE );
754
 
755
        thread->wake();
756
 
757
        CYG_INSTRUMENT_CONDVAR(WAKE, this, thread);
758
    }
759
 
760
    CYG_ASSERTCLASS( this, "Bad this pointer");
761
 
762
    // Unlock the scheduler and maybe switch threads
763
    Cyg_Scheduler::unlock();
764
 
765
    CYG_REPORT_RETURN();
766
}
767
 
768
// -------------------------------------------------------------------------
769
// Optional timed wait on a CV
770
 
771
#if defined(CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT)
772
 
773
cyg_bool
774
Cyg_Condition_Variable::wait_inner( Cyg_Mutex *mx, cyg_tick_count timeout )
775
{
776
    CYG_REPORT_FUNCTYPE("returning %d");
777
    CYG_REPORT_FUNCARG1("timeout = %d", timeout);
778
 
779
    CYG_ASSERTCLASS( this, "Bad this pointer");
780
    CYG_ASSERTCLASS( mx, "Corrupt mutex");
781
 
782
    cyg_bool result = true;
783
 
784
    Cyg_Thread *self = Cyg_Thread::self();
785
 
786
    CYG_ASSERTCLASS( self, "Bad self thread");
787
 
788
    // Prevent preemption
789
    Cyg_Scheduler::lock();
790
 
791
    CYG_INSTRUMENT_CONDVAR(TIMED_WAIT, this, 0 );
792
 
793
    mx->unlock();
794
 
795
    // The ordering of sleep() and set_timer() here are
796
    // important. If the timeout is in the past, the thread
797
    // will be woken up immediately and will not sleep.
798
 
799
    self->sleep();
800
 
801
    // Set the timer and sleep reason
802
    self->set_timer( timeout, Cyg_Thread::TIMEOUT );
803
 
804
    // Only enqueue if the timeout has not already fired.
805
    if( self->get_wake_reason() == Cyg_Thread::NONE )
806
        queue.enqueue( self );
807
 
808
    // Avoid calling ASRs during the following unlock.
809
    self->set_asr_inhibit();
810
 
811
    // Unlock the scheduler and switch threads
812
    Cyg_Scheduler::unlock_reschedule();
813
 
814
    // Allow ASRs again
815
    self->clear_asr_inhibit();
816
 
817
    CYG_ASSERTCLASS( this, "Bad this pointer");
818
    CYG_ASSERTCLASS( mx, "Corrupt mutex");
819
 
820
    self->clear_timer();
821
 
822
    CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason());
823
 
824
    switch( self->get_wake_reason() )
825
    {
826
    case Cyg_Thread::TIMEOUT:
827
    case Cyg_Thread::DESTRUCT:          // which, the cv or the mutex?
828
    case Cyg_Thread::BREAK:
829
        result = false;
830
        break;
831
 
832
    case Cyg_Thread::EXIT:
833
        self->exit();
834
        break;
835
 
836
    default:
837
        break;
838
    }
839
 
840
 
841
    // When we awake, we must re-acquire the mutex.  Note that while
842
    // it is essential to release the mutex and queue on the CV
843
    // atomically relative to other threads, to avoid races, it is not
844
    // necessary for us to re-acquire the mutex in the same atomic
845
    // action. Hence we can do it after unlocking the scheduler.
846
 
847
    while ( !mx->lock() )
848
        continue;
849
 
850
    CYG_ASSERTCLASS( this, "Bad this pointer");
851
    CYG_ASSERTCLASS( mx, "Corrupt mutex");
852
 
853
    CYG_REPORT_RETVAL(result);
854
 
855
    return result;
856
}
857
 
858
#endif
859
 
860
 
861
// -------------------------------------------------------------------------
862
// EOF sync/mutex.cxx

powered by: WebSVN 2.1.0

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