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
71 #include <cyg/kernel/sched.hxx> // scheduler definitions
72 #include <cyg/kernel/thread.hxx> // thread definitions
73 #include <cyg/kernel/flag.hxx> // flag definitions
74 #include <cyg/kernel/clock.hxx> // clock definitions
76 #include <cyg/kernel/sched.inl>
77 #include <cyg/kernel/thread.inl>
78 #include <cyg/kernel/clock.inl>
80 //==========================================================================
81 // File object locking
83 #define LOCK_FILE( fp ) cyg_file_lock( fp )
85 #define UNLOCK_FILE( fp ) cyg_file_unlock( fp )
87 // Get a flag based on the thread's unique ID. Note: In a system with a large
88 // number of threads, the same flag may be used by more than one thread.
89 #define SELECT_WAIT_FLAG_GET() (1 << (Cyg_Thread::self()->get_unique_id() \
90 & (sizeof (Cyg_FlagValue) * NBBY - 1)))
92 //==========================================================================
95 static volatile cyg_uint32 selwake_count = 0;
97 // A flag is used to block a thread until data from the device is available. This
98 // prevents all threads from waking up at the same time and polling for changes.
99 // Each thread is allocated a flag bit via the SELECT_WAIT_FLAG_GET() macro when
100 // the thread registers for selection via cyg_selrecord (). The flag is stored in
101 // the driver's select info block. Only those threads specified via the flags in
102 // the select info are woken up by cyg_selwakeup ().
103 // If there are more than 32 threads in the system, then there is a chance that
104 // cyg_selwakeup () may wake up more than one thread. Each thread then polls for
106 static Cyg_Flag select_flag CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
108 //==========================================================================
109 // Timeval to ticks conversion support
111 // Converters from sec and us to ticks
112 static struct Cyg_Clock::converter us_converter, sec_converter;
114 static cyg_bool converters_initialized = false;
116 externC cyg_tick_count cyg_timeval_to_ticks( const struct timeval *tv )
118 if( !converters_initialized )
120 // Create the converters we need.
121 Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000, &us_converter );
122 Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000000000, &sec_converter );
124 converters_initialized = true;
127 // Short circuit zero timeval
128 if( tv->tv_sec == 0 && tv->tv_usec == 0 )
133 // Convert the seconds field to ticks.
134 cyg_tick_count ticks = Cyg_Clock::convert( tv->tv_sec, &sec_converter );
136 // Convert the nanoseconds. This will round down to nearest whole tick.
137 ticks += Cyg_Clock::convert( (cyg_tick_count)tv->tv_usec, &us_converter );
142 //==========================================================================
143 // Select API function
146 cyg_pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
147 struct timeval *tv, const sigset_t *mask)
154 fd_set in_res, out_res, ex_res; // Result sets
155 fd_set *selection[3], *result[3];
156 cyg_tick_count ticks;
157 int mode_type[] = {CYG_FREAD, CYG_FWRITE, 0};
158 cyg_uint32 wake_count;
161 Cyg_FlagValue myFlag = SELECT_WAIT_FLAG_GET ();
162 int maxFdIndex = __howmany(nfd, __NFDBITS); // size of fd sets
164 // Make sure the nfd < FD_SETSIZE, a value greater than FD_SETSIZE
165 // would break the results sets
168 FILEIO_RETURN(EINVAL);
176 selection[0] = in; result[0] = &in_res;
177 selection[1] = out; result[1] = &out_res;
178 selection[2] = ex; result[2] = &ex_res;
182 ticks = cyg_timeval_to_ticks( tv );
185 // Scan sets for possible I/O until something found, timeout or error.
188 wake_count = selwake_count;
190 num = 0; // Total file descriptors "ready"
191 for (mode = 0; !error && mode < 3; mode++)
195 fd_mask *fds_bits = selection[mode]->fds_bits;
197 for(index = 0, fdbase = 0; !error && index < maxFdIndex; index++, fdbase += __NFDBITS)
199 fd_mask mask = fds_bits[index];
200 for(fd = fdbase; mask != 0; fd++, mask >>= 1)
204 fp = cyg_fp_get( fd );
211 if ((*fp->f_ops->fo_select)(fp, mode_type[mode], 0))
213 FD_SET(fd, result[mode]);
228 // Found something, update user's sets
229 if (in) FD_COPY( &in_res, in );
230 if (out) FD_COPY( &out_res, out );
231 if (ex) FD_COPY( &ex_res, ex );
232 CYG_FILEIO_DELIVER_SIGNALS( mask );
233 FILEIO_RETURN_VALUE(num);
236 Cyg_Scheduler::lock();
238 // Switch to the supplied signal mask. This will permit delivery
239 // of any signals that might terminate this select operation.
241 CYG_FILEIO_SIGMASK_SET( mask, &oldmask );
246 // We need to see if any signals have been posted while we
247 // were testing all those files. The handlers will not
248 // have run because we have ASRs inhibited but the signal
249 // will have been set pending.
251 if( CYG_FILEIO_SIGPENDING() )
253 // There are pending signals so we need to terminate
254 // the select operation and return EINTR. Handlers for
255 // the pending signals will be called just before we
262 if( wake_count == selwake_count )
264 // Nothing found, see if we want to wait
267 // Special case of "poll"
274 ticks += Cyg_Clock::real_time_clock->current_value();
276 if( !select_flag.wait (myFlag, Cyg_Flag::OR, ticks) )
278 // A non-standard wakeup, if the current time is equal to
279 // or past the timeout, return zero. Otherwise return
280 // EINTR, since we have been released.
282 if( Cyg_Clock::real_time_clock->current_value() >= ticks )
290 ticks -= Cyg_Clock::real_time_clock->current_value();
294 // Wait forever (until something happens)
295 if( !select_flag.wait (myFlag, Cyg_Flag::OR) )
302 CYG_FILEIO_SIGMASK_SET( &oldmask, NULL );
304 Cyg_Scheduler::unlock();
308 // If the error code is EAGAIN, this means that a timeout has
309 // happened. We return zero in that case, rather than a proper
311 // If the error code is EINTR, then a signal may be pending
312 // delivery. Call back into the POSIX package to handle it.
314 if( error == EAGAIN )
315 FILEIO_RETURN_VALUE(0);
316 else if( error == EINTR )
317 CYG_FILEIO_DELIVER_SIGNALS( mask );
319 FILEIO_RETURN(error);
322 // -------------------------------------------------------------------------
323 // Select API function
326 select(int nfd, fd_set *in, fd_set *out, fd_set *ex, struct timeval *tv)
328 return cyg_pselect(nfd, in, out, ex, tv, NULL);
331 // -------------------------------------------------------------------------
332 // Pselect API function
334 // This is derived from the POSIX-200X specification.
337 pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
338 const struct timespec *ts, const sigset_t *sigmask)
342 #ifndef CYGPKG_POSIX_SIGNALS
343 CYG_ASSERT( sigmask == NULL,
344 "pselect called with non-null sigmask without POSIX signal support"
350 tv.tv_sec = ts->tv_sec;
351 tv.tv_usec = ts->tv_nsec/1000;
354 return cyg_pselect(nfd, in, out, ex, ts ? &tv : NULL, sigmask);
357 //==========================================================================
358 // Select support functions.
360 // -------------------------------------------------------------------------
361 // cyg_selinit() is used to initialize a selinfo structure
363 void cyg_selinit( struct CYG_SELINFO_TAG *sip )
366 sip->si_waitFlag = 0;
369 // -------------------------------------------------------------------------
370 // cyg_selrecord() is called when a client device needs to register
371 // the current thread for selection. Save the flag that identifies the thread.
372 void cyg_selrecord( CYG_ADDRWORD info, struct CYG_SELINFO_TAG *sip )
375 Cyg_Scheduler::lock();
376 sip->si_waitFlag |= SELECT_WAIT_FLAG_GET ();
377 Cyg_Scheduler::unlock();
380 // -------------------------------------------------------------------------
381 // cyg_selwakeup() is called when the client device matches the select
382 // criterion, and needs to wake up a thread.
383 void cyg_selwakeup( struct CYG_SELINFO_TAG *sip )
385 // We don't actually use the si_info field of selinfo at present.
386 Cyg_Scheduler::lock();
388 if( sip->si_waitFlag != 0 )
390 // If the flag is still present, this selection has not fired before.
391 // Only wake up the threads waiting on the flags specified in si_waitFlag.
392 // There is no need to wake threads that are not waiting for this data.
393 select_flag.setbits (sip->si_waitFlag);
394 sip->si_waitFlag = 0; // clear all flags
395 select_flag.maskbits (sip->si_waitFlag);
398 Cyg_Scheduler::unlock();
401 // -------------------------------------------------------------------------