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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [io/] [fileio/] [v2_0/] [src/] [select.cxx] - Blame information for rev 594

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
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 Red Hat, Inc.
12
// Copyright (C) 2002 Nick Garnett
13
//
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.
17
//
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
21
// for more details.
22
//
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.
26
//
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.
33
//
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.
36
//
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####
43
//
44
// Author(s):           nickg
45
// Contributors:        nickg
46
// Date:                2000-05-25
47
// Purpose:             Fileio select() support
48
// Description:         Support for select().
49
//                      
50
//              
51
//              
52
//
53
//####DESCRIPTIONEND####
54
//
55
//==========================================================================
56
 
57
#include <pkgconf/hal.h>
58
#include <pkgconf/kernel.h>
59
#include <pkgconf/io_fileio.h>
60
 
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
64
 
65
#include <stdarg.h>                    // for fcntl()
66
 
67
#include "fio.h"                       // Private header
68
 
69
#include <sys/select.h>                // select header
70
 
71
#include <cyg/kernel/sched.hxx>        // scheduler definitions
72
#include <cyg/kernel/thread.hxx>       // thread definitions
73
#include <cyg/kernel/mutex.hxx>        // mutex definitions
74
#include <cyg/kernel/clock.hxx>        // clock definitions
75
 
76
#include <cyg/kernel/sched.inl>
77
#include <cyg/kernel/thread.inl>
78
#include <cyg/kernel/clock.inl>
79
 
80
//==========================================================================
81
// File object locking
82
 
83
#define LOCK_FILE( fp ) cyg_file_lock( fp )
84
 
85
#define UNLOCK_FILE( fp ) cyg_file_unlock( fp )
86
 
87
//==========================================================================
88
// Local variables
89
 
90
// Mutex for serializing select processing. This essntially controls
91
// access to the contents of the selinfo structures embedded in the
92
// client system data structures.
93
static Cyg_Mutex select_mutex CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
94
 
95
// Condition variable where any thread that is waiting for a select to
96
// fire is suspended. Note that select is not intended to be a real time
97
// operation. Whenever any selectable event occurs, all selecting threads
98
// will be resumed. They must then rescan their selectees and resuspend if
99
// necessary.
100
static Cyg_Condition_Variable selwait( select_mutex ) CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
101
 
102
static volatile cyg_uint32 selwake_count = 0;
103
 
104
//==========================================================================
105
// Timeval to ticks conversion support
106
 
107
// Converters from sec and us to ticks
108
static struct Cyg_Clock::converter us_converter, sec_converter;
109
 
110
static cyg_bool converters_initialized = false;
111
 
112
externC cyg_tick_count cyg_timeval_to_ticks( const struct timeval *tv )
113
{
114
    if( !converters_initialized )
115
    {
116
        // Create the converters we need.
117
        Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000, &us_converter );
118
        Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000000000, &sec_converter );
119
 
120
        converters_initialized = true;
121
    }
122
 
123
    // Short circuit zero timeval
124
    if( tv->tv_sec == 0 && tv->tv_usec == 0 )
125
    {
126
        return 0;
127
    }
128
 
129
    // Convert the seconds field to ticks.
130
    cyg_tick_count ticks = Cyg_Clock::convert( tv->tv_sec, &sec_converter );
131
 
132
    // Convert the nanoseconds. This will round down to nearest whole tick.
133
    ticks += Cyg_Clock::convert( (cyg_tick_count)tv->tv_usec, &us_converter );
134
 
135
    return ticks;
136
}
137
 
138
//==========================================================================
139
// Select API function
140
 
141
static int
142
cyg_pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
143
           struct timeval *tv, const sigset_t *mask)
144
{
145
    FILEIO_ENTRY();
146
 
147
    int error = ENOERR;
148
    int fd, mode, num;
149
    cyg_file *fp;
150
    fd_set in_res, out_res, ex_res;  // Result sets
151
    fd_set *selection[3], *result[3];
152
    cyg_tick_count ticks;
153
    int mode_type[] = {CYG_FREAD, CYG_FWRITE, 0};
154
    cyg_uint32 wake_count;
155
    sigset_t oldmask;
156
 
157
    FD_ZERO(&in_res);
158
    FD_ZERO(&out_res);
159
    FD_ZERO(&ex_res);
160
 
161
    // Set up sets
162
    selection[0] = in;   result[0] = &in_res;
163
    selection[1] = out;  result[1] = &out_res;
164
    selection[2] = ex;   result[2] = &ex_res;
165
 
166
    // Compute end time
167
    if (tv)
168
        ticks = cyg_timeval_to_ticks( tv );
169
    else ticks = 0;
170
 
171
    // Lock the mutex
172
    select_mutex.lock();
173
 
174
    // Scan sets for possible I/O until something found, timeout or error.
175
    while (!error)
176
    {
177
        wake_count = selwake_count;
178
 
179
        num = 0;  // Total file descriptors "ready"
180
        for (mode = 0;  !error && mode < 3;  mode++)
181
        {
182
            if (selection[mode]) {
183
                for (fd = 0;  !error && fd < nfd;  fd++)
184
                {
185
                    if (FD_ISSET(fd, selection[mode]))
186
                    {
187
                        fp = cyg_fp_get( fd );
188
                        if( fp == NULL )
189
                        {
190
                            error = EBADF;
191
                            break;
192
                        }
193
 
194
                        if ((*fp->f_ops->fo_select)(fp, mode_type[mode], 0))
195
                        {
196
                            FD_SET(fd, result[mode]);
197
                            num++;
198
                        }
199
 
200
                        cyg_fp_free( fp );
201
                    }
202
                }
203
            }
204
        }
205
 
206
        if (num)
207
        {
208
            // Found something, update user's sets
209
            if (in)  FD_COPY( &in_res, in );
210
            if (out) FD_COPY( &out_res, out );
211
            if (ex)  FD_COPY( &ex_res, ex );
212
            select_mutex.unlock();
213
            CYG_FILEIO_DELIVER_SIGNALS( mask );
214
            FILEIO_RETURN_VALUE(num);
215
        }
216
 
217
        Cyg_Scheduler::lock();
218
 
219
        // Switch to the supplied signal mask. This will permit delivery
220
        // of any signals that might terminate this select operation.
221
 
222
        CYG_FILEIO_SIGMASK_SET( mask, &oldmask );
223
 
224
        do
225
        {
226
 
227
            // We need to see if any signals have been posted while we
228
            // were testing all those files. The handlers will not
229
            // have run because we have ASRs inhibited but the signal
230
            // will have been set pending.
231
 
232
            if( CYG_FILEIO_SIGPENDING() )
233
            {
234
                // There are pending signals so we need to terminate
235
                // the select operation and return EINTR. Handlers for
236
                // the pending signals will be called just before we
237
                // return.
238
 
239
                error = EINTR;
240
                break;
241
            }
242
 
243
            if( wake_count == selwake_count )
244
            {
245
                // Nothing found, see if we want to wait
246
                if (tv)
247
                {
248
                    // Special case of "poll"
249
                    if (ticks == 0)
250
                    {
251
                        error = EAGAIN;
252
                        break;
253
                    }
254
 
255
                    ticks += Cyg_Clock::real_time_clock->current_value();
256
 
257
                    if( !selwait.wait( ticks ) )
258
                    {
259
                        // A non-standard wakeup, if the current time is equal to
260
                        // or past the timeout, return zero. Otherwise return
261
                        // EINTR, since we have been released.
262
 
263
                        if( Cyg_Clock::real_time_clock->current_value() >= ticks )
264
                        {
265
                            error = EAGAIN;
266
                            break;
267
                        }
268
                        else error = EINTR;
269
                    }
270
 
271
                    ticks -= Cyg_Clock::real_time_clock->current_value();
272
                }
273
                else
274
                {
275
                    // Wait forever (until something happens)
276
 
277
                    if( !selwait.wait() )
278
                        error = EINTR;
279
                }
280
            }
281
 
282
        } while(0);
283
 
284
        CYG_FILEIO_SIGMASK_SET( &oldmask, NULL );
285
 
286
        Cyg_Scheduler::unlock();
287
 
288
    } // while(!error)
289
 
290
    select_mutex.unlock();
291
 
292
    // If the error code is EAGAIN, this means that a timeout has
293
    // happened. We return zero in that case, rather than a proper
294
    // error code.
295
    // If the error code is EINTR, then a signal may be pending
296
    // delivery. Call back into the POSIX package to handle it.
297
 
298
    if( error == EAGAIN )
299
        FILEIO_RETURN_VALUE(0);
300
    else if( error == EINTR )
301
        CYG_FILEIO_DELIVER_SIGNALS( mask );
302
 
303
    FILEIO_RETURN(error);
304
}
305
 
306
// -------------------------------------------------------------------------
307
// Select API function
308
 
309
__externC int
310
select(int nfd, fd_set *in, fd_set *out, fd_set *ex, struct timeval *tv)
311
{
312
        return cyg_pselect(nfd, in, out, ex, tv, NULL);
313
}
314
 
315
// -------------------------------------------------------------------------
316
// Pselect API function
317
//
318
// This is derived from the POSIX-200X specification.
319
 
320
#ifdef CYGPKG_POSIX
321
 
322
__externC int
323
pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
324
        const struct timespec *ts, const sigset_t *sigmask)
325
{
326
        struct timeval tv;
327
 
328
        if (ts != NULL)
329
        {
330
            tv.tv_sec = ts->tv_sec;
331
            tv.tv_usec = ts->tv_nsec/1000;
332
        }
333
 
334
        return cyg_pselect(nfd, in, out, ex, &tv, sigmask);
335
}
336
 
337
#endif
338
 
339
//==========================================================================
340
// Select support functions.
341
 
342
// -------------------------------------------------------------------------
343
// cyg_selinit() is used to initialize a selinfo structure
344
 
345
void cyg_selinit( struct CYG_SELINFO_TAG *sip )
346
{
347
    sip->si_info = 0;
348
    sip->si_thread = 0;
349
}
350
 
351
// -------------------------------------------------------------------------
352
// cyg_selrecord() is called when a client device needs to register
353
// the current thread for selection.
354
 
355
void cyg_selrecord( CYG_ADDRWORD info, struct CYG_SELINFO_TAG *sip )
356
{
357
    sip->si_info = info;
358
    sip->si_thread = (CYG_ADDRESS)Cyg_Thread::self();
359
}
360
 
361
// -------------------------------------------------------------------------
362
// cyg_selwakeup() is called when the client device matches the select
363
// criterion, and needs to wake up a selector.
364
 
365
void cyg_selwakeup( struct CYG_SELINFO_TAG *sip )
366
{
367
    // We don't actually use the si_info field of selinfo at present.
368
    // A potential use would be to select one of several selwait condition
369
    // variables to signal. However, that would only be necessary if we
370
    // end up having lots of threads in select.
371
 
372
    Cyg_Scheduler::lock();
373
 
374
    if( sip->si_thread != 0 )
375
    {
376
        // If the thread pointer is still present, this selection has
377
        // not been fired before. We just wake up all threads waiting,
378
        // regardless of whether they are waiting for this event or
379
        // not.  This avoids any race conditions, and is consistent
380
        // with the behaviour of the BSD kernel.
381
 
382
        sip->si_thread = 0;
383
        selwait.broadcast();
384
        selwake_count++;
385
 
386
    }
387
 
388
    Cyg_Scheduler::unlock();
389
}
390
 
391
// -------------------------------------------------------------------------
392
// EOF select.cxx

powered by: WebSVN 2.1.0

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