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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [kernel/] [v2_0/] [src/] [sync/] [mutex.cxx] - Blame information for rev 208

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

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

powered by: WebSVN 2.1.0

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