diff packages/kernel/current/src/sync/bin_sem.cxx @ 1062:e8b69d9c90a6

* cdl/kernel.cdl: Added tests/bin_sem3 to list of kernel tests. * include/sema.hxx: Added declaration for wait with timeout for Cyg_Binary_Semaphore. * include/instrmnt.h: Added instrumentation point for binary semaphore timeout. * src/sync/bin_sem.cxx: Added wait with time-out function to Cyg_Binary_Semaphore class. * src/sync/cnt_sem.cxx: Modified semantics slightly to claim an available semaphore even with a timeout in the past. This is in line with the new timed wait in bin_sem.cxx. * tests/bin_sem3.cxx: Created new test for timed wait binary semaphore.
author nickg
date Mon, 23 Jun 2003 18:09:59 +0000
parents d2c90368aeef
children 74dbf4c3f2e1
line wrap: on
line diff
--- a/packages/kernel/current/src/sync/bin_sem.cxx
+++ b/packages/kernel/current/src/sync/bin_sem.cxx
@@ -77,6 +77,7 @@ Cyg_Binary_Semaphore::Cyg_Binary_Semapho
 
 Cyg_Binary_Semaphore::~Cyg_Binary_Semaphore ( )
 {
+    CYG_ASSERT( queue.empty(), "Destroying semaphore with waiting threads");
 }
 
 // -------------------------------------------------------------------------
@@ -132,6 +133,84 @@ cyg_bool Cyg_Binary_Semaphore::wait()
 }
 
 // -------------------------------------------------------------------------
+// Wait until the state can be set false or timeout
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+cyg_bool
+Cyg_Binary_Semaphore::wait( cyg_tick_count timeout )
+{
+    cyg_bool result = true;
+    Cyg_Thread *self = Cyg_Thread::self();
+    
+    // Prevent preemption
+    Cyg_Scheduler::lock();
+
+    CYG_INSTRUMENT_BINSEM( CLAIM, this, state );
+        
+    // Set the timer _once_ outside the loop.
+    self->set_timer( timeout, Cyg_Thread::TIMEOUT  );
+
+    // If the timeout is in the past, the wake reason will have been
+    // set to something other than NONE already. If the semaphore is
+    // not available, set the result false to force an immediate
+    // return. If it is available, then go ahead and claim it.
+    
+    if( self->get_wake_reason() != Cyg_Thread::NONE && !state )
+        result = false;
+            
+    while ( !state && result ) {
+
+        // must reset the sleep reason every time
+        self->set_sleep_reason( Cyg_Thread::TIMEOUT );
+
+        self->sleep();
+
+        queue.enqueue( self );
+
+        CYG_INSTRUMENT_BINSEM( WAIT, this, 0 );
+
+        // Allow other threads to run
+        Cyg_Scheduler::reschedule();
+
+        CYG_INSTRUMENT_BINSEM( WOKE, this, state );
+
+        switch( self->get_wake_reason() )
+        {
+        case Cyg_Thread::TIMEOUT:
+            result = false;
+            CYG_INSTRUMENT_BINSEM( TIMEOUT, this, state);
+            break;
+            
+        case Cyg_Thread::DESTRUCT:
+        case Cyg_Thread::BREAK:
+            result = false;
+            break;
+            
+        case Cyg_Thread::EXIT:            
+            self->exit();
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    // Clear the timeout. It is irrelevant whether the alarm has
+    // actually gone off or not.
+    self->clear_timer();
+        
+    if( result ) state = false;
+
+    // Unlock the scheduler and maybe switch threads
+    Cyg_Scheduler::unlock();
+
+    return result;
+}
+
+#endif // CYGFUN_KERNEL_THREADS_TIMER
+
+// -------------------------------------------------------------------------
 
 cyg_bool Cyg_Binary_Semaphore::trywait()
 {