OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [io/] [fileio/] [current/] [src/] [select.cxx] - Blame information for rev 825

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      select.cxx
4
//
5
//      Fileio select() support
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):           nickg
43
// Contributors:        nickg
44
// Date:                2000-05-25
45
// Purpose:             Fileio select() support
46
// Description:         Support for select().
47
//                      
48
//              
49
//              
50
//
51
//####DESCRIPTIONEND####
52
//
53
//==========================================================================
54
 
55
#include <pkgconf/hal.h>
56
#include <pkgconf/kernel.h>
57
#include <pkgconf/io_fileio.h>
58
 
59
#include <cyg/kernel/ktypes.h>         // base kernel types
60
#include <cyg/infra/cyg_trac.h>        // tracing macros
61
#include <cyg/infra/cyg_ass.h>         // assertion macros
62
 
63
#include <stdarg.h>                    // for fcntl()
64
 
65
#include "fio.h"                       // Private header
66
 
67
#include <sys/select.h>                // select header
68
#include <sys/time.h>
69
 
70
#include <cyg/kernel/sched.hxx>        // scheduler definitions
71
#include <cyg/kernel/thread.hxx>       // thread definitions
72
#include <cyg/kernel/flag.hxx>         // flag definitions
73
#include <cyg/kernel/clock.hxx>        // clock definitions
74
 
75
#include <cyg/kernel/sched.inl>
76
#include <cyg/kernel/thread.inl>
77
#include <cyg/kernel/clock.inl>
78
 
79
//==========================================================================
80
// File object locking
81
 
82
#define LOCK_FILE( fp ) cyg_file_lock( fp )
83
 
84
#define UNLOCK_FILE( fp ) cyg_file_unlock( fp )
85
 
86
// Get a flag based on the thread's unique ID. Note: In a system with a large
87
// number of threads, the same flag may be used by more than one thread.
88
#define SELECT_WAIT_FLAG_GET() (1 << (Cyg_Thread::self()->get_unique_id() \
89
                                & (sizeof (Cyg_FlagValue) * NBBY - 1)))
90
 
91
//==========================================================================
92
// Local variables
93
 
94
static volatile cyg_uint32 selwake_count = 0;
95
 
96
// A flag is used to block a thread until data from the device is available. This
97
// prevents all threads from waking up at the same time and polling for changes.
98
// Each thread is allocated a flag bit via the SELECT_WAIT_FLAG_GET() macro when 
99
// the thread registers for selection via cyg_selrecord (). The flag is stored in
100
// the driver's select info block. Only those threads specified via the flags in 
101
// the select info are woken up by cyg_selwakeup (). 
102
// If there are more than 32 threads in the system, then there is a chance that
103
// cyg_selwakeup () may wake up more than one thread. Each thread then polls for
104
// changes.
105
static Cyg_Flag select_flag CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
106
 
107
//==========================================================================
108
// Timeval to ticks conversion support
109
 
110
// Converters from sec and us to ticks
111
static struct Cyg_Clock::converter us_converter, sec_converter;
112
 
113
static cyg_bool converters_initialized = false;
114
 
115
externC cyg_tick_count cyg_timeval_to_ticks( const struct timeval *tv )
116
{
117
    if( !converters_initialized )
118
    {
119
        // Create the converters we need.
120
        Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000, &us_converter );
121
        Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000000000, &sec_converter );
122
 
123
        converters_initialized = true;
124
    }
125
 
126
    // Short circuit zero timeval
127
    if( tv->tv_sec == 0 && tv->tv_usec == 0 )
128
    {
129
        return 0;
130
    }
131
 
132
    // Convert the seconds field to ticks.
133
    cyg_tick_count ticks = Cyg_Clock::convert( tv->tv_sec, &sec_converter );
134
 
135
    // Convert the nanoseconds. This will round down to nearest whole tick.
136
    ticks += Cyg_Clock::convert( (cyg_tick_count)tv->tv_usec, &us_converter );
137
 
138
    return ticks;
139
}
140
 
141
//==========================================================================
142
// Select API function
143
 
144
static int
145
cyg_pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
146
           struct timeval *tv, const sigset_t *mask)
147
{
148
    FILEIO_ENTRY();
149
 
150
    int error = ENOERR;
151
    int fd, mode, num;
152
    cyg_file *fp;
153
    fd_set in_res, out_res, ex_res;  // Result sets
154
    fd_set *selection[3], *result[3];
155
    cyg_tick_count ticks;
156
    int mode_type[] = {CYG_FREAD, CYG_FWRITE, 0};
157
    cyg_uint32 wake_count;
158
    sigset_t oldmask;
159
 
160
    Cyg_FlagValue myFlag = SELECT_WAIT_FLAG_GET ();
161
    int    maxFdIndex = __howmany(nfd, __NFDBITS); // size of fd sets
162
 
163
    // Make sure the nfd < FD_SETSIZE, a value greater than FD_SETSIZE 
164
    // would break the results sets
165
    if(nfd > FD_SETSIZE)
166
    {
167
        FILEIO_RETURN(EINVAL);
168
    }
169
 
170
    FD_ZERO(&in_res);
171
    FD_ZERO(&out_res);
172
    FD_ZERO(&ex_res);
173
 
174
    // Set up sets
175
    selection[0] = in;   result[0] = &in_res;
176
    selection[1] = out;  result[1] = &out_res;
177
    selection[2] = ex;   result[2] = &ex_res;
178
 
179
    // Compute end time
180
    if (tv)
181
        ticks = cyg_timeval_to_ticks( tv );
182
    else ticks = 0;
183
 
184
    // Scan sets for possible I/O until something found, timeout or error.
185
    while (!error)
186
    {
187
        wake_count = selwake_count;
188
 
189
        num = 0;  // Total file descriptors "ready"
190
        for (mode = 0;  !error && mode < 3;  mode++)
191
        {
192
            if (selection[mode])
193
            {
194
                fd_mask *fds_bits = selection[mode]->fds_bits;
195
                int      index, fdbase;
196
                for(index = 0, fdbase = 0; !error && index < maxFdIndex; index++, fdbase += __NFDBITS)
197
                {
198
                    fd_mask mask = fds_bits[index];
199
                    for(fd = fdbase; mask != 0; fd++, mask >>= 1)
200
                    {
201
                        if(mask & 1)
202
                        {
203
                            fp = cyg_fp_get( fd );
204
                            if( fp == NULL )
205
                            {
206
                                error = EBADF;
207
                                break;
208
                            }
209
 
210
                            if ((*fp->f_ops->fo_select)(fp, mode_type[mode], 0))
211
                            {
212
                                FD_SET(fd, result[mode]);
213
                                num++;
214
                            }
215
                            cyg_fp_free( fp );
216
                        }
217
                    }
218
                }
219
            }
220
        }
221
 
222
        if (error)
223
            break;
224
 
225
        if (num)
226
        {
227
            // Found something, update user's sets
228
            if (in)  FD_COPY( &in_res, in );
229
            if (out) FD_COPY( &out_res, out );
230
            if (ex)  FD_COPY( &ex_res, ex );
231
            CYG_FILEIO_DELIVER_SIGNALS( mask );
232
            FILEIO_RETURN_VALUE(num);
233
        }
234
 
235
        Cyg_Scheduler::lock();
236
 
237
        // Switch to the supplied signal mask. This will permit delivery
238
        // of any signals that might terminate this select operation.
239
 
240
        CYG_FILEIO_SIGMASK_SET( mask, &oldmask );
241
 
242
        do
243
        {
244
 
245
            // We need to see if any signals have been posted while we
246
            // were testing all those files. The handlers will not
247
            // have run because we have ASRs inhibited but the signal
248
            // will have been set pending.
249
 
250
            if( CYG_FILEIO_SIGPENDING() )
251
            {
252
                // There are pending signals so we need to terminate
253
                // the select operation and return EINTR. Handlers for
254
                // the pending signals will be called just before we
255
                // return.
256
 
257
                error = EINTR;
258
                break;
259
            }
260
 
261
            if( wake_count == selwake_count )
262
            {
263
                // Nothing found, see if we want to wait
264
                if (tv)
265
                {
266
                    // Special case of "poll"
267
                    if (ticks == 0)
268
                    {
269
                        error = EAGAIN;
270
                        break;
271
                    }
272
 
273
                    ticks += Cyg_Clock::real_time_clock->current_value();
274
 
275
                    if( !select_flag.wait (myFlag, Cyg_Flag::OR, ticks) )
276
                    {
277
                        // A non-standard wakeup, if the current time is equal to
278
                        // or past the timeout, return zero. Otherwise return
279
                        // EINTR, since we have been released.
280
 
281
                        if( Cyg_Clock::real_time_clock->current_value() >= ticks )
282
                        {
283
                            error = EAGAIN;
284
                            break;
285
                        }
286
                        else error = EINTR;
287
                    }
288
 
289
                    ticks -= Cyg_Clock::real_time_clock->current_value();
290
                }
291
                else
292
                {
293
                    // Wait forever (until something happens)
294
                    if( !select_flag.wait (myFlag, Cyg_Flag::OR) )
295
                        error = EINTR;
296
                }
297
            }
298
 
299
        } while(0);
300
 
301
        CYG_FILEIO_SIGMASK_SET( &oldmask, NULL );
302
 
303
        Cyg_Scheduler::unlock();
304
 
305
    } // while(!error)
306
 
307
    // If the error code is EAGAIN, this means that a timeout has
308
    // happened. We return zero in that case, rather than a proper
309
    // error code.
310
    // If the error code is EINTR, then a signal may be pending
311
    // delivery. Call back into the POSIX package to handle it.
312
 
313
    if( error == EAGAIN )
314
        FILEIO_RETURN_VALUE(0);
315
    else if( error == EINTR )
316
        CYG_FILEIO_DELIVER_SIGNALS( mask );
317
 
318
    FILEIO_RETURN(error);
319
}
320
 
321
// -------------------------------------------------------------------------
322
// Select API function
323
 
324
__externC int
325
select(int nfd, fd_set *in, fd_set *out, fd_set *ex, struct timeval *tv)
326
{
327
        return cyg_pselect(nfd, in, out, ex, tv, NULL);
328
}
329
 
330
// -------------------------------------------------------------------------
331
// Pselect API function
332
//
333
// This is derived from the POSIX-200X specification.
334
 
335
__externC int
336
pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
337
        const struct timespec *ts, const sigset_t *sigmask)
338
{
339
        struct timeval tv;
340
 
341
#ifndef CYGPKG_POSIX_SIGNALS
342
        CYG_ASSERT( sigmask == NULL,
343
                    "pselect called with non-null sigmask without POSIX signal support"
344
                    );
345
#endif
346
 
347
        if (ts != NULL)
348
        {
349
            tv.tv_sec = ts->tv_sec;
350
            tv.tv_usec = ts->tv_nsec/1000;
351
        }
352
 
353
        return cyg_pselect(nfd, in, out, ex, ts ? &tv : NULL, sigmask);
354
}
355
 
356
//==========================================================================
357
// Select support functions.
358
 
359
// -------------------------------------------------------------------------
360
// cyg_selinit() is used to initialize a selinfo structure
361
 
362
void cyg_selinit( struct CYG_SELINFO_TAG *sip )
363
{
364
    sip->si_info = 0;
365
    sip->si_waitFlag = 0;
366
}
367
 
368
// -------------------------------------------------------------------------
369
// cyg_selrecord() is called when a client device needs to register
370
// the current thread for selection. Save the flag that identifies the thread. 
371
void cyg_selrecord( CYG_ADDRWORD info, struct CYG_SELINFO_TAG *sip )
372
{
373
    sip->si_info = info;
374
    Cyg_Scheduler::lock();
375
    sip->si_waitFlag |= SELECT_WAIT_FLAG_GET ();
376
    Cyg_Scheduler::unlock();
377
}
378
 
379
// -------------------------------------------------------------------------
380
// cyg_selwakeup() is called when the client device matches the select
381
// criterion, and needs to wake up a thread.
382
void cyg_selwakeup( struct CYG_SELINFO_TAG *sip )
383
{
384
    // We don't actually use the si_info field of selinfo at present.
385
    Cyg_Scheduler::lock();
386
 
387
    if( sip->si_waitFlag != 0 )
388
    {
389
        // If the flag is still present, this selection has not fired before. 
390
        // Only wake up the threads waiting on the flags specified in si_waitFlag. 
391
        // There is no need to wake threads that are not waiting for this data.
392
        select_flag.setbits (sip->si_waitFlag);
393
        sip->si_waitFlag = 0;     // clear all flags
394
        select_flag.maskbits (sip->si_waitFlag);
395
        selwake_count++;
396
    }
397
    Cyg_Scheduler::unlock();
398
}
399
 
400
// -------------------------------------------------------------------------
401
// EOF select.cxx

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.