1 //==========================================================================
5 // Fileio select() support
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 // Copyright (C) 2002 Nick Garnett
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
45 // Contributors: nickg
47 // Purpose: Fileio select() support
48 // Description: Support for select().
53 //####DESCRIPTIONEND####
55 //==========================================================================
57 #include <pkgconf/hal.h>
58 #include <pkgconf/kernel.h>
59 #include <pkgconf/io_fileio.h>
61 #include <cyg/kernel/ktypes.h> // base kernel types
62 #include <cyg/infra/cyg_trac.h> // tracing macros
63 #include <cyg/infra/cyg_ass.h> // assertion macros
65 #include <stdarg.h> // for fcntl()
67 #include "fio.h" // Private header
69 #include <sys/select.h> // select header
72 #include <cyg/kernel/sched.hxx> // scheduler definitions
73 #include <cyg/kernel/thread.hxx> // thread definitions
74 #include <cyg/kernel/flag.hxx> // flag definitions
75 #include <cyg/kernel/clock.hxx> // clock definitions
77 #include <cyg/kernel/sched.inl>
78 #include <cyg/kernel/thread.inl>
79 #include <cyg/kernel/clock.inl>
81 //==========================================================================
82 // File object locking
84 #define LOCK_FILE( fp ) cyg_file_lock( fp )
86 #define UNLOCK_FILE( fp ) cyg_file_unlock( fp )
88 // Get a flag based on the thread's unique ID. Note: In a system with a large
89 // number of threads, the same flag may be used by more than one thread.
90 #define SELECT_WAIT_FLAG_GET() (1 << (Cyg_Thread::self()->get_unique_id() \
91 & (sizeof (Cyg_FlagValue) * NBBY - 1)))
93 //==========================================================================
96 static volatile cyg_uint32 selwake_count = 0;
98 // A flag is used to block a thread until data from the device is available. This
99 // prevents all threads from waking up at the same time and polling for changes.
100 // Each thread is allocated a flag bit via the SELECT_WAIT_FLAG_GET() macro when
101 // the thread registers for selection via cyg_selrecord (). The flag is stored in
102 // the driver's select info block. Only those threads specified via the flags in
103 // the select info are woken up by cyg_selwakeup ().
104 // If there are more than 32 threads in the system, then there is a chance that
105 // cyg_selwakeup () may wake up more than one thread. Each thread then polls for
107 static Cyg_Flag select_flag CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
109 //==========================================================================
110 // Timeval to ticks conversion support
112 // Converters from sec and us to ticks
113 static struct Cyg_Clock::converter us_converter, sec_converter;
115 static cyg_bool converters_initialized = false;
117 externC cyg_tick_count cyg_timeval_to_ticks( const struct timeval *tv )
119 if( !converters_initialized )
121 // Create the converters we need.
122 Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000, &us_converter );
123 Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000000000, &sec_converter );
125 converters_initialized = true;
128 // Short circuit zero timeval
129 if( tv->tv_sec == 0 && tv->tv_usec == 0 )
134 // Convert the seconds field to ticks.
135 cyg_tick_count ticks = Cyg_Clock::convert( tv->tv_sec, &sec_converter );
137 // Convert the nanoseconds. This will round down to nearest whole tick.
138 ticks += Cyg_Clock::convert( (cyg_tick_count)tv->tv_usec, &us_converter );
143 //==========================================================================
144 // Select API function
147 cyg_pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
148 struct timeval *tv, const sigset_t *mask)
155 fd_set in_res, out_res, ex_res; // Result sets
156 fd_set *selection[3], *result[3];
157 cyg_tick_count ticks;
158 int mode_type[] = {CYG_FREAD, CYG_FWRITE, 0};
159 cyg_uint32 wake_count;
162 Cyg_FlagValue myFlag = SELECT_WAIT_FLAG_GET ();
163 int maxFdIndex = __howmany(nfd, __NFDBITS); // size of fd sets
165 // Make sure the nfd < FD_SETSIZE, a value greater than FD_SETSIZE
166 // would break the results sets
169 FILEIO_RETURN(EINVAL);
177 selection[0] = in; result[0] = &in_res;
178 selection[1] = out; result[1] = &out_res;
179 selection[2] = ex; result[2] = &ex_res;
183 ticks = cyg_timeval_to_ticks( tv );
186 // Scan sets for possible I/O until something found, timeout or error.
189 wake_count = selwake_count;
191 num = 0; // Total file descriptors "ready"
192 for (mode = 0; !error && mode < 3; mode++)
196 fd_mask *fds_bits = selection[mode]->fds_bits;
198 for(index = 0, fdbase = 0; !error && index < maxFdIndex; index++, fdbase += __NFDBITS)
200 fd_mask mask = fds_bits[index];
201 for(fd = fdbase; mask != 0; fd++, mask >>= 1)
205 fp = cyg_fp_get( fd );
212 if ((*fp->f_ops->fo_select)(fp, mode_type[mode], 0))
214 FD_SET(fd, result[mode]);
229 // Found something, update user's sets
230 if (in) FD_COPY( &in_res, in );
231 if (out) FD_COPY( &out_res, out );
232 if (ex) FD_COPY( &ex_res, ex );
233 CYG_FILEIO_DELIVER_SIGNALS( mask );
234 FILEIO_RETURN_VALUE(num);
237 Cyg_Scheduler::lock();
239 // Switch to the supplied signal mask. This will permit delivery
240 // of any signals that might terminate this select operation.
242 CYG_FILEIO_SIGMASK_SET( mask, &oldmask );
247 // We need to see if any signals have been posted while we
248 // were testing all those files. The handlers will not
249 // have run because we have ASRs inhibited but the signal
250 // will have been set pending.
252 if( CYG_FILEIO_SIGPENDING() )
254 // There are pending signals so we need to terminate
255 // the select operation and return EINTR. Handlers for
256 // the pending signals will be called just before we
263 if( wake_count == selwake_count )
265 // Nothing found, see if we want to wait
268 // Special case of "poll"
275 ticks += Cyg_Clock::real_time_clock->current_value();
277 if( !select_flag.wait (myFlag, Cyg_Flag::OR, ticks) )
279 // A non-standard wakeup, if the current time is equal to
280 // or past the timeout, return zero. Otherwise return
281 // EINTR, since we have been released.
283 if( Cyg_Clock::real_time_clock->current_value() >= ticks )
291 ticks -= Cyg_Clock::real_time_clock->current_value();
295 // Wait forever (until something happens)
296 if( !select_flag.wait (myFlag, Cyg_Flag::OR) )
303 CYG_FILEIO_SIGMASK_SET( &oldmask, NULL );
305 Cyg_Scheduler::unlock();
309 // If the error code is EAGAIN, this means that a timeout has
310 // happened. We return zero in that case, rather than a proper
312 // If the error code is EINTR, then a signal may be pending
313 // delivery. Call back into the POSIX package to handle it.
315 if( error == EAGAIN )
316 FILEIO_RETURN_VALUE(0);
317 else if( error == EINTR )
318 CYG_FILEIO_DELIVER_SIGNALS( mask );
320 FILEIO_RETURN(error);
323 // -------------------------------------------------------------------------
324 // Select API function
327 select(int nfd, fd_set *in, fd_set *out, fd_set *ex, struct timeval *tv)
329 return cyg_pselect(nfd, in, out, ex, tv, NULL);
332 // -------------------------------------------------------------------------
333 // Pselect API function
335 // This is derived from the POSIX-200X specification.
338 pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
339 const struct timespec *ts, const sigset_t *sigmask)
343 #ifndef CYGPKG_POSIX_SIGNALS
344 CYG_ASSERT( sigmask == NULL,
345 "pselect called with non-null sigmask without POSIX signal support"
351 tv.tv_sec = ts->tv_sec;
352 tv.tv_usec = ts->tv_nsec/1000;
355 return cyg_pselect(nfd, in, out, ex, ts ? &tv : NULL, sigmask);
358 //==========================================================================
359 // Select support functions.
361 // -------------------------------------------------------------------------
362 // cyg_selinit() is used to initialize a selinfo structure
364 void cyg_selinit( struct CYG_SELINFO_TAG *sip )
367 sip->si_waitFlag = 0;
370 // -------------------------------------------------------------------------
371 // cyg_selrecord() is called when a client device needs to register
372 // the current thread for selection. Save the flag that identifies the thread.
373 void cyg_selrecord( CYG_ADDRWORD info, struct CYG_SELINFO_TAG *sip )
376 Cyg_Scheduler::lock();
377 sip->si_waitFlag |= SELECT_WAIT_FLAG_GET ();
378 Cyg_Scheduler::unlock();
381 // -------------------------------------------------------------------------
382 // cyg_selwakeup() is called when the client device matches the select
383 // criterion, and needs to wake up a thread.
384 void cyg_selwakeup( struct CYG_SELINFO_TAG *sip )
386 // We don't actually use the si_info field of selinfo at present.
387 Cyg_Scheduler::lock();
389 if( sip->si_waitFlag != 0 )
391 // If the flag is still present, this selection has not fired before.
392 // Only wake up the threads waiting on the flags specified in si_waitFlag.
393 // There is no need to wake threads that are not waiting for this data.
394 select_flag.setbits (sip->si_waitFlag);
395 sip->si_waitFlag = 0; // clear all flags
396 select_flag.maskbits (sip->si_waitFlag);
399 Cyg_Scheduler::unlock();
402 // -------------------------------------------------------------------------