diff -r -u5 -N -x CVS -x '*~' -x '.#*' clean/ecos/packages/io/fileio/current/ChangeLog devo/ecos/packages/io/fileio/current/ChangeLog --- clean/ecos/packages/io/fileio/current/ChangeLog 2004-03-29 06:19:42.000000000 -0700 +++ devo/ecos/packages/io/fileio/current/ChangeLog 2004-04-01 15:10:41.000000000 -0700 @@ -1,5 +1,14 @@ +2004-03-30 Alex Paulis and Cameron Taylor + + * include/fileio.h: Changed si_thread to si_waitFlag + * src/select.cxx: Improved efficiency: 1. Only threads waiting + on a selector are woken up in selwake. This is done by swapping + the condition variable for an event flag and registering threads + for wakeup in selrecord. 2. No mutex is now required. 3. Search + through the FD mask much streamlined. + 2004-03-25 Sebastien Couret * src/fd.cxx: Added CYG_ASSERT bound checking for file descriptor numbers (0 #include #include #include +#include #include // NULL, size_t #include #include #include @@ -394,11 +395,11 @@ // must be passed to cyg_selrecord() and cyg_selwakeup(). struct CYG_SELINFO_TAG { CYG_ADDRWORD si_info; // info passed through from fo_select() - CYG_ADDRESS si_thread; // selecting thread pointer + cyg_flag_value_t si_waitFlag; // select wait flags }; //----------------------------------------------------------------------------- // Select support functions. diff -r -u5 -N -x CVS -x '*~' -x '.#*' clean/ecos/packages/io/fileio/current/src/select.cxx devo/ecos/packages/io/fileio/current/src/select.cxx --- clean/ecos/packages/io/fileio/current/src/select.cxx 2004-01-06 23:45:28.000000000 -0700 +++ devo/ecos/packages/io/fileio/current/src/select.cxx 2004-04-01 15:54:42.000000000 -0700 @@ -68,11 +68,11 @@ #include // select header #include // scheduler definitions #include // thread definitions -#include // mutex definitions +#include // flag definitions #include // clock definitions #include #include #include @@ -82,27 +82,44 @@ #define LOCK_FILE( fp ) cyg_file_lock( fp ) #define UNLOCK_FILE( fp ) cyg_file_unlock( fp ) +// Get a flag based on the thread's unique ID. Note: In a system with a large +// number of threads, the same flag may be used by more than one thread. +#define SELECT_WAIT_FLAG_GET() (1 << (Cyg_Thread::self()->get_unique_id() \ + & (sizeof (Cyg_FlagValue) * NBBY - 1))) + +// Clear any bits in __p greater than __n +#define FD_ENFORCE(__n, __p) \ +{ \ + if ((__p)&&(__n < FD_SETSIZE)) { \ + unsigned int __i = __n/__NFDBITS; \ + (__p)->fds_bits[__i] &= \ + ~((-1) << (((__n - 1) % 32) + 1)); \ + while (__howmany(FD_SETSIZE,__NFDBITS) > ++__i){ \ + (__p)->fds_bits [__i] = 0; \ + } \ + } \ +} + //========================================================================== // Local variables -// Mutex for serializing select processing. This essntially controls -// access to the contents of the selinfo structures embedded in the -// client system data structures. -static Cyg_Mutex select_mutex CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS); - -// Condition variable where any thread that is waiting for a select to -// fire is suspended. Note that select is not intended to be a real time -// operation. Whenever any selectable event occurs, all selecting threads -// will be resumed. They must then rescan their selectees and resuspend if -// necessary. -static Cyg_Condition_Variable selwait( select_mutex ) CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS); - static volatile cyg_uint32 selwake_count = 0; +// A flag is used to block a thread until data from the device is available. This +// prevents all threads from waking up at the same time and polling for changes. +// Each thread is allocated a flag bit via the SELECT_WAIT_FLAG_GET() macro when +// the thread registers for selection via cyg_selrecord (). The flag is stored in +// the driver's select info block. Only those threads specified via the flags in +// the select info are woken up by cyg_selwakeup (). +// If there are more than 32 threads in the system, then there is a chance that +// cyg_selwakeup () may wake up more than one thread. Each thread then polls for +// changes. +static Cyg_Flag select_flag CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS); + //========================================================================== // Timeval to ticks conversion support // Converters from sec and us to ticks static struct Cyg_Clock::converter us_converter, sec_converter; @@ -150,56 +167,75 @@ fd_set in_res, out_res, ex_res; // Result sets fd_set *selection[3], *result[3]; cyg_tick_count ticks; int mode_type[] = {CYG_FREAD, CYG_FWRITE, 0}; cyg_uint32 wake_count; +#ifdef CYGPKG_POSIX sigset_t oldmask; +#endif + Cyg_FlagValue myFlag = SELECT_WAIT_FLAG_GET (); + int maxFdIndex = __howmany(nfd, __NFDBITS); // size of fd sets + + // Make sure the nfd < FD_SETSIZE, a value greater than FD_SETSIZE + // would break the results sets + if(nfd > FD_SETSIZE) + { + FILEIO_RETURN(EINVAL); + } FD_ZERO(&in_res); FD_ZERO(&out_res); FD_ZERO(&ex_res); + // clear any bits after nfd + FD_ENFORCE(nfd, in); + FD_ENFORCE(nfd, out); + FD_ENFORCE(nfd, ex); + // Set up sets selection[0] = in; result[0] = &in_res; selection[1] = out; result[1] = &out_res; selection[2] = ex; result[2] = &ex_res; // Compute end time if (tv) ticks = cyg_timeval_to_ticks( tv ); else ticks = 0; - // Lock the mutex - select_mutex.lock(); - // Scan sets for possible I/O until something found, timeout or error. while (!error) { wake_count = selwake_count; - + num = 0; // Total file descriptors "ready" for (mode = 0; !error && mode < 3; mode++) { - if (selection[mode]) { - for (fd = 0; !error && fd < nfd; fd++) + if (selection[mode]) + { + fd_mask *fds_bits = selection[mode]->fds_bits; + int index, fdbase; + for(index = 0, fdbase = 0; !error && index < maxFdIndex; index++, fdbase += __NFDBITS) { - if (FD_ISSET(fd, selection[mode])) + fd_mask mask = fds_bits[index]; + for(fd = fdbase; mask != 0; fd++, mask >>= 1) { - fp = cyg_fp_get( fd ); - if( fp == NULL ) - { - error = EBADF; - break; - } - - if ((*fp->f_ops->fo_select)(fp, mode_type[mode], 0)) + if(mask & 1) { - FD_SET(fd, result[mode]); - num++; + fp = cyg_fp_get( fd ); + if( fp == NULL ) + { + error = EBADF; + break; + } + + if ((*fp->f_ops->fo_select)(fp, mode_type[mode], 0)) + { + FD_SET(fd, result[mode]); + num++; + } + cyg_fp_free( fp ); } - - cyg_fp_free( fp ); } } } } @@ -207,11 +243,10 @@ { // Found something, update user's sets if (in) FD_COPY( &in_res, in ); 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(); @@ -252,11 +287,11 @@ break; } ticks += Cyg_Clock::real_time_clock->current_value(); - if( !selwait.wait( ticks ) ) + if( !select_flag.wait (myFlag, Cyg_Flag::OR, 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. @@ -271,12 +306,11 @@ ticks -= Cyg_Clock::real_time_clock->current_value(); } else { // Wait forever (until something happens) - - if( !selwait.wait() ) + if( !select_flag.wait (myFlag, Cyg_Flag::OR) ) error = EINTR; } } } while(0); @@ -285,12 +319,10 @@ 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. @@ -345,50 +377,42 @@ // cyg_selinit() is used to initialize a selinfo structure void cyg_selinit( struct CYG_SELINFO_TAG *sip ) { sip->si_info = 0; - sip->si_thread = 0; + sip->si_waitFlag = 0; } // ------------------------------------------------------------------------- // cyg_selrecord() is called when a client device needs to register -// the current thread for selection. - +// the current thread for selection. Save the flag that identifies the thread. void cyg_selrecord( CYG_ADDRWORD info, struct CYG_SELINFO_TAG *sip ) { sip->si_info = info; - sip->si_thread = (CYG_ADDRESS)Cyg_Thread::self(); + Cyg_Scheduler::lock(); + sip->si_waitFlag |= SELECT_WAIT_FLAG_GET (); + Cyg_Scheduler::unlock(); } // ------------------------------------------------------------------------- // cyg_selwakeup() is called when the client device matches the select -// criterion, and needs to wake up a selector. - +// criterion, and needs to wake up a thread. void cyg_selwakeup( struct CYG_SELINFO_TAG *sip ) { // We don't actually use the si_info field of selinfo at present. - // A potential use would be to select one of several selwait condition - // variables to signal. However, that would only be necessary if we - // end up having lots of threads in select. - Cyg_Scheduler::lock(); - if( sip->si_thread != 0 ) + if( sip->si_waitFlag != 0 ) { - // If the thread pointer is still present, this selection has - // not been fired before. We just wake up all threads waiting, - // regardless of whether they are waiting for this event or - // not. This avoids any race conditions, and is consistent - // with the behaviour of the BSD kernel. - - sip->si_thread = 0; - selwait.broadcast(); + // If the flag is still present, this selection has not fired before. + // Only wake up the threads waiting on the flags specified in si_waitFlag. + // There is no need to wake threads that are not waiting for this data. + select_flag.setbits (sip->si_waitFlag); + sip->si_waitFlag = 0; // clear all flags + select_flag.maskbits (sip->si_waitFlag); selwake_count++; - } - Cyg_Scheduler::unlock(); } // ------------------------------------------------------------------------- // EOF select.cxx diff -r -u5 -N -x CVS -x '*~' -x '.#*' clean/ecos/packages/isoinfra/current/ChangeLog devo/ecos/packages/isoinfra/current/ChangeLog --- clean/ecos/packages/isoinfra/current/ChangeLog 2004-03-15 08:20:22.000000000 -0700 +++ devo/ecos/packages/isoinfra/current/ChangeLog 2004-04-01 15:10:52.000000000 -0700 @@ -1,5 +1,10 @@ +2004-03-30 Alex Paulis and Cameron Taylor + + * include/sys/select.h: set FD_SETSIZE to CYGNUM_FILEIO_NFD + when appropriate. + 2004-03-12 Jonathan Larmour * cdl/isoinfra.cdl: Typo: CYGBLD_ISO_STDIO_FILEPOS -> CYGBLD_ISO_STDIO_FILEPOS_HEADER. diff -r -u5 -N -x CVS -x '*~' -x '.#*' clean/ecos/packages/isoinfra/current/include/sys/select.h devo/ecos/packages/isoinfra/current/include/sys/select.h --- clean/ecos/packages/isoinfra/current/include/sys/select.h 2004-01-06 23:45:13.000000000 -0700 +++ devo/ecos/packages/isoinfra/current/include/sys/select.h 2004-04-01 15:39:51.000000000 -0700 @@ -55,12 +55,18 @@ //====================================================================== */ /* CONFIGURATION */ +#include #include /* Configuration header */ +#ifdef CYGPKG_IO_FILEIO + #include + #define FD_SETSIZE CYGNUM_FILEIO_NFD +#endif + /* ------------------------------------------------------------------- */ #if !defined(_POSIX_SOURCE) #ifdef CYGINT_ISO_SELECT