Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4973 right-hear 1
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
2
/* An implementation of select()
3
 
4
   Copyright 1995 by Morten Welinder
5
   This file maybe freely distributed and modified as long as the
6
   copyright notice remains.
7
 
8
   Notes: In a single process system as Dos this really boils down to
9
   something that can check whether a character from standard input
10
   is ready.  However, the code is organised in a way to make it easy
11
   to extend to multi process systems like WinNT and OS/2.  */
12
 
13
#include 
14
#include 
15
#include 
16
#include 
17
#include 
18
#include 
19
#include 
20
#include 
21
#include 
22
#include 
23
 
24
inline static int fp_output_ready(FILE *fp)
25
{
26
  return !ferror(fp);
27
}
28
 
29
/* This is as close as we get, I think.  For a file connected to a printer
30
   we could of course go ask the BIOS, but this should be enough.  */
31
 
32
inline static int fp_except_ready(FILE *fp)
33
{
34
  return ferror (fp);
35
}
36
 
37
inline static int fp_input_ready (FILE *fp)
38
{
39
  /* I think if there is something in the buffer, we should return
40
     ``ready'', even if some error was encountered.  Let him consume
41
     the buffered characters, *then* return ``not ready''.  */
42
  if (fp->_cnt)
43
    return 1;
44
 
45
  /* The `feof' part is only correct in a single-tasked environment.  */
46
  if (ferror (fp) || feof (fp))
47
    return 0;
48
 
49
  /* There is nothing in the buffer (perhaps because we read unbuffered).
50
     We don't know if we are ready.  Return ``ready'' anyway and let
51
     read() or write() tell the truth.  */
52
  return 1;
53
}
54
 
55
/* The Dos call 4407 always returns TRUE for disk files.  So the
56
   following really is meaningful for character devices only...  */
57
 
58
inline static int fd_output_ready(int fd)
59
{
60
 return 0;
61
}
62
 
63
inline static int fd_input_ready(int fd)
64
{
65
 return 0;
66
}
67
 
68
int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,
69
	struct timeval *timeout)
70
{
71
  int ready;
72
  fd_set oread, owrite, oexcept;
73
  struct timeval now, then;
74
 
75
  if (nfds > FD_SETSIZE)
76
  {
77
    errno = EINVAL;
78
    return -1;
79
  }
80
 
81
  FD_ZERO (&oread);
82
  FD_ZERO (&owrite);
83
  FD_ZERO (&oexcept);
84
  ready = 0;
85
 
86
  if (timeout)
87
  {
88
    if (timeout->tv_usec < 0)
89
    {
90
      errno = EINVAL;
91
      return -1;
92
    }
93
    gettimeofday (&now, 0);
94
    then.tv_usec = timeout->tv_usec + now.tv_usec;
95
    then.tv_sec = timeout->tv_sec + now.tv_sec + then.tv_usec / 1000000;
96
    then.tv_usec %= 1000000;
97
  }
98
 
99
  do {
100
    int i;
101
    int fd0 = 0;
102
    __file_rec *fr = __file_rec_list;
103
    FILE *fp;
104
 
105
    /* First, check the file handles with low-level DOS calls.  */
106
    for (i = 0; i < nfds; i++)
107
    {
108
      register int ioctl_result;
109
      __FSEXT_Function *func = __FSEXT_get_function(i);
110
      int fsext_ready = -1;
111
 
112
      if (func)
113
	func(__FSEXT_ready, &fsext_ready, &i);
114
 
115
      if (readfds && FD_ISSET (i, readfds))
116
      {
117
	if (fsext_ready != -1)
118
	{
119
	  if (fsext_ready & __FSEXT_ready_read)
120
	    ready++, FD_SET(i, &oread);
121
	}
122
        else if ((ioctl_result = fd_input_ready (i)) == -1)
123
          return -1;
124
        else if (ioctl_result)
125
          ready++, FD_SET (i, &oread);
126
      }
127
      if (writefds && FD_ISSET (i, writefds))
128
      {
129
        if (fsext_ready != -1)
130
	{
131
	  if (fsext_ready & __FSEXT_ready_write)
132
	    ready++, FD_SET(i, &owrite);
133
	}
134
        else if ((ioctl_result = fd_output_ready (i)) == -1)
135
          return -1;
136
        else if (ioctl_result)
137
          ready++, FD_SET (i, &owrite);
138
      }
139
      if (exceptfds && FD_ISSET (i, exceptfds))
140
      {
141
        if (fsext_ready != -1)
142
	{
143
	  if (fsext_ready & __FSEXT_ready_error)
144
	    ready++, FD_SET(i, &oexcept);
145
	}
146
      }
147
    }
148
 
149
    /* Now look at the table of FILE ptrs and reset the bits for file
150
       descriptors which we *thought* are ready, but for which the flags
151
       say they're NOT ready.  */
152
    for (i = 0; fr; i++)
153
    {
154
      if (i >= fd0 + fr->count) /* done with this subtable, go to next */
155
      {
156
	fd0 += fr->count;
157
	fr = fr->next;
158
      }
159
      if (fr)
160
      {
161
        fp = fr->files[i - fd0];
162
        if (fp->_flag)
163
        {
164
          int this_fd = fileno(fp);
165
 
166
          if (this_fd < nfds)
167
          {
168
            if (readfds && FD_ISSET (this_fd, readfds) &&
169
                FD_ISSET (this_fd, &oread) && !fp_input_ready (fp))
170
              ready--, FD_CLR (this_fd, &oread);
171
            if (writefds && FD_ISSET (this_fd, writefds) &&
172
                FD_ISSET (this_fd, &owrite) && !fp_output_ready (fp))
173
              ready--, FD_CLR (this_fd, &owrite);
174
 
175
            /* For exceptional conditions, ferror() is the only one
176
               which can tell us an exception is pending.  */
177
            if (exceptfds && FD_ISSET (this_fd, exceptfds) &&
178
                fp_except_ready (fp))
179
              ready++, FD_SET (this_fd, &oexcept);
180
          }
181
        }
182
      }
183
    }
184
 
185
    /* Exit if we found what we were waiting for.  */
186
    if (ready > 0)
187
    {
188
      if (readfds)
189
	*readfds = oread;
190
      if (writefds)
191
	*writefds = owrite;
192
      if (exceptfds)
193
	*exceptfds = oexcept;
194
      return ready;
195
    }
196
 
197
    /* Exit if we hit the time limit.  */
198
    if (timeout)
199
    {
200
      gettimeofday (&now, 0);
201
      if (now.tv_sec > then.tv_sec
202
	  || (now.tv_sec = then.tv_sec && now.tv_usec >= then.tv_usec))
203
	return 0;
204
    }
205
  } while (1);
206
}