diff packages/io/fileio/current/src/select.cxx @ 410:064536ee7f68

* src/fio.h: Added macros to deal with signal handling. These will call into the POSIX package if it is present, but are null if it is not. * src/select.cxx: Renamed original select() to cyg_pselect() and added select() and pselect() routine from POSIX-200X to call it. Reorganized code a little and added calls to macros to deal with signal delivery and detection. * cdl/fileio.cdl: * tests/pselect.c: New test added to verify the signal masking and delivery behaviour of pselect(). * tests/select.c: Fixed up some printfs to make it a little tidier.
author nickg
date Mon, 11 Nov 2002 23:58:53 +0000
parents fc52fa818b5f
children 786e2e6e3c3d
line wrap: on
line diff
--- a/packages/io/fileio/current/src/select.cxx
+++ b/packages/io/fileio/current/src/select.cxx
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Nick Garnett
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -137,8 +138,9 @@ externC cyg_tick_count cyg_timeval_to_ti
 //==========================================================================
 // Select API function
 
-__externC int
-select(int nfd, fd_set *in, fd_set *out, fd_set *ex, struct timeval *tv)
+static int
+cyg_pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
+           struct timeval *tv, const sigset_t *mask)
 {
     FILEIO_ENTRY();
 
@@ -150,7 +152,8 @@ select(int nfd, fd_set *in, fd_set *out,
     cyg_tick_count ticks;
     int mode_type[] = {CYG_FREAD, CYG_FWRITE, 0};
     cyg_uint32 wake_count;
-    
+    sigset_t oldmask;
+
     FD_ZERO(&in_res);
     FD_ZERO(&out_res);
     FD_ZERO(&ex_res);
@@ -207,61 +210,132 @@ select(int nfd, fd_set *in, fd_set *out,
             if (out) FD_COPY( &out_res, out );
             if (ex)  FD_COPY( &ex_res, ex );
             select_mutex.unlock();
+            CYG_FILEIO_DELIVER_SIGNALS( mask );
             FILEIO_RETURN_VALUE(num);
         }
 
         Cyg_Scheduler::lock();
 
-        if( wake_count == selwake_count )
+        // Switch to the supplied signal mask. This will permit delivery
+        // of any signals that might terminate this select operation.
+        
+        CYG_FILEIO_SIGMASK_SET( mask, &oldmask );
+    
+        do
         {
-            // Nothing found, see if we want to wait
-            if (tv)
+
+            // We need to see if any signals have been posted while we
+            // were testing all those files. The handlers will not
+            // have run because we have ASRs inhibited but the signal
+            // will have been set pending.
+
+            if( CYG_FILEIO_SIGPENDING() )
             {
-                if (ticks == 0)
+                // There are pending signals so we need to terminate
+                // the select operation and return EINTR. Handlers for
+                // the pending signals will be called just before we
+                // return.
+
+                error = EINTR;
+                break;
+            }
+            
+            if( wake_count == selwake_count )
+            {
+                // Nothing found, see if we want to wait
+                if (tv)
                 {
                     // Special case of "poll"
-                    select_mutex.unlock();
-                    Cyg_Scheduler::unlock();
-                    FILEIO_RETURN_VALUE(0);
-                }
+                    if (ticks == 0)
+                    {
+                        error = EAGAIN;
+                        break;
+                    }
 
-                ticks += Cyg_Clock::real_time_clock->current_value();
+                    ticks += Cyg_Clock::real_time_clock->current_value();
                 
-                if( !selwait.wait( ticks ) )
-                {
-                    // A non-standard wakeup, if the current time is equal to
-                    // or past the timeout, return zero. Otherwise return
-                    // EINTR, since we have been released.
-
-                    if( Cyg_Clock::real_time_clock->current_value() >= ticks )
+                    if( !selwait.wait( ticks ) )
                     {
-                        select_mutex.unlock();
-                        Cyg_Scheduler::unlock();
-                        FILEIO_RETURN_VALUE(0);
+                        // A non-standard wakeup, if the current time is equal to
+                        // or past the timeout, return zero. Otherwise return
+                        // EINTR, since we have been released.
+
+                        if( Cyg_Clock::real_time_clock->current_value() >= ticks )
+                        {
+                            error = EAGAIN;
+                            break;
+                        }
+                        else error = EINTR;
                     }
-                    else error = EINTR;
+
+                    ticks -= Cyg_Clock::real_time_clock->current_value();
                 }
-
-                ticks -= Cyg_Clock::real_time_clock->current_value();
+                else
+                {
+                    // Wait forever (until something happens)
+            
+                    if( !selwait.wait() )
+                        error = EINTR;
+                }
             }
-            else
-            {
-                // Wait forever (until something happens)
-            
-                if( !selwait.wait() )
-                    error = EINTR;
-            }
-        }
+
+        } while(0);
 
+        CYG_FILEIO_SIGMASK_SET( &oldmask, NULL );
+        
         Cyg_Scheduler::unlock();
         
     } // while(!error)
 
     select_mutex.unlock();
  
+    // If the error code is EAGAIN, this means that a timeout has
+    // happened. We return zero in that case, rather than a proper
+    // error code.
+    // If the error code is EINTR, then a signal may be pending
+    // delivery. Call back into the POSIX package to handle it.
+    
+    if( error == EAGAIN )
+        FILEIO_RETURN_VALUE(0);
+    else if( error == EINTR )
+        CYG_FILEIO_DELIVER_SIGNALS( mask );
+
     FILEIO_RETURN(error);
 }
 
+// -------------------------------------------------------------------------
+// Select API function
+
+__externC int
+select(int nfd, fd_set *in, fd_set *out, fd_set *ex, struct timeval *tv)
+{
+	return cyg_pselect(nfd, in, out, ex, tv, NULL);
+}
+
+// -------------------------------------------------------------------------
+// Pselect API function
+//
+// This is derived from the POSIX-200X specification.
+
+#ifdef CYGPKG_POSIX
+
+__externC int
+pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
+	const struct timespec *ts, const sigset_t *sigmask)
+{
+	struct timeval tv;
+
+	if (ts != NULL)
+        {
+            tv.tv_sec = ts->tv_sec;
+            tv.tv_usec = ts->tv_nsec/1000;
+        }
+
+	return cyg_pselect(nfd, in, out, ex, &tv, sigmask);
+}
+
+#endif
+
 //==========================================================================
 // Select support functions.