1/*
2 * Copyright (c) 1982, 1986, 1989, 1993
3 *  The Regents of the University of California.  All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Portions copyright (c) 1999, 2000
11 * Intel Corporation.
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 *
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 *
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 *
25 * 3. All advertising materials mentioning features or use of this software
26 *    must display the following acknowledgement:
27 *
28 *    This product includes software developed by the University of
29 *    California, Berkeley, Intel Corporation, and its contributors.
30 *
31 * 4. Neither the name of University, Intel Corporation, or their respective
32 *    contributors may be used to endorse or promote products derived from
33 *    this software without specific prior written permission.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE REGENTS, INTEL CORPORATION AND
36 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
37 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
38 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS,
39 * INTEL CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
40 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
45 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 *
47 *  @(#)sys_generic.c 8.5 (Berkeley) 1/21/94
48 * $Id: select.c,v 1.1.1.1 2003/11/19 01:50:30 kyu3 Exp $
49 */
50#include <Library/UefiBootServicesTableLib.h>
51
52#include  <LibConfig.h>
53
54#include <stdlib.h>
55#include <unistd.h>
56#include <strings.h>
57#include <sys/poll.h>
58#include <sys/param.h>
59#include <sys/time.h>
60#ifndef KERNEL
61#define KERNEL
62#include <errno.h>
63#undef KERNEL
64#else
65#include <errno.h>
66#endif
67
68#ifdef  EFI_NT_EMULATOR
69#define _SELECT_DELAY_  10000
70#else
71#define _SELECT_DELAY_  1000
72#endif
73
74#define MAX_SLEEP_DELAY 0xfffffffe
75
76/** Sleep for the specified number of Microseconds.
77
78    Implements the usleep(3) function.
79
80    @param[in]    Microseconds    Number of microseconds to sleep.
81
82    @retval   0   Always returns zero.
83**/
84int
85usleep( useconds_t Microseconds )
86{
87  while ( MAX_SLEEP_DELAY < Microseconds ) {
88    gBS->Stall ( MAX_SLEEP_DELAY );
89    Microseconds -= MAX_SLEEP_DELAY;
90  }
91  gBS->Stall((UINTN)Microseconds );
92  return (0);
93}
94
95unsigned int
96sleep( unsigned int Seconds )
97{
98  return (usleep( (useconds_t)(Seconds * 1000000) ));
99}
100
101static int
102selscan(
103  fd_mask **ibits,
104  fd_mask **obits,
105  int nfd,
106  int *nselected
107  )
108{
109  int   msk;
110  int i;
111  int j;
112  int fd;
113  int n;
114  struct pollfd pfd;
115  int FdCount;
116  fd_mask   bits;
117  /* Note: backend also returns POLLHUP/POLLERR if appropriate. */
118  static int16_t  flag[3] = { POLLRDNORM, POLLWRNORM, POLLRDBAND };
119
120  for (msk = 0, n = 0; msk < 3; msk++) {
121    if (ibits[msk] == NULL)
122      continue;
123    for (i = 0; i < nfd; i += NFDBITS) {
124      bits = ibits[ msk ][ i / NFDBITS ];
125      while (( 0 != (j = ffs(bits))) && ((fd = i + --j) < nfd)) {
126        bits &= ~(1 << j);
127
128        pfd.fd = fd;
129        pfd.events = flag[msk];
130        pfd.revents = 0;
131        FdCount = poll ( &pfd, 1, 0 );
132        if ( -1 == FdCount ) {
133          return errno;
134        }
135        if ( 0 != FdCount ) {
136          obits[msk][(fd)/NFDBITS] |=
137            (1 << ((fd) % NFDBITS));
138          n++;
139          break;
140        }
141      }
142    }
143  }
144  *nselected = n;
145  return (0);
146}
147
148int
149select(
150  int nd,
151  fd_set  *in,
152  fd_set *ou,
153  fd_set *ex,
154  struct  timeval *tv
155  )
156{
157  fd_mask *ibits[3], *obits[3], *selbits, *sbp;
158  int error, forever, nselected;
159  u_int nbufbytes, ncpbytes, nfdbits;
160  int64_t timo;
161
162  if (nd < 0)
163    return (EINVAL);
164
165  /*
166   * Allocate just enough bits for the non-null fd_sets.  Use the
167   * preallocated auto buffer if possible.
168   */
169  nfdbits = roundup(nd, NFDBITS);
170  ncpbytes = nfdbits / NBBY;
171  nbufbytes = 0;
172  if (in != NULL)
173    nbufbytes += 2 * ncpbytes;
174  if (ou != NULL)
175    nbufbytes += 2 * ncpbytes;
176  if (ex != NULL)
177    nbufbytes += 2 * ncpbytes;
178  selbits = malloc(nbufbytes);
179
180  /*
181   * Assign pointers into the bit buffers and fetch the input bits.
182   * Put the output buffers together so that they can be bzeroed
183   * together.
184   */
185  sbp = selbits;
186#define getbits(name, x) \
187  do {                \
188    if (name == NULL)         \
189      ibits[x] = NULL;        \
190    else {              \
191      ibits[x] = sbp + nbufbytes / 2 / sizeof *sbp; \
192      obits[x] = sbp;         \
193      sbp += ncpbytes / sizeof *sbp;      \
194      bcopy(name, ibits[x], ncpbytes);    \
195    }             \
196  } while (0)
197  getbits(in, 0);
198  getbits(ou, 1);
199  getbits(ex, 2);
200#undef  getbits
201  if (nbufbytes != 0)
202    memset(selbits, 0, nbufbytes / 2);
203
204  if (tv) {
205    timo = tv->tv_usec + (tv->tv_sec * 1000000);
206    forever = 0;
207  } else {
208    timo = 0;
209    forever = 1;
210  }
211
212  /*
213   *  Poll for I/O events
214   */
215  nselected = 0;
216  do {
217    /*
218     *  Scan for pending I/O
219     */
220    error = selscan(ibits, obits, nd, &nselected);
221    if (error || nselected)
222      break;
223
224    /*
225     *  Adjust timeout is needed
226     */
227    if (timo)  {
228      /*
229       *  Give it a rest
230       */
231      usleep( _SELECT_DELAY_ );
232      timo -= _SELECT_DELAY_;
233    }
234
235  } while (timo > 0 || forever);
236
237  /* select is not restarted after signals... */
238  if (error == ERESTART)
239    error = EINTR;
240  else if (error == EWOULDBLOCK)
241    error = 0;
242
243#define putbits(name, x)  if (name) bcopy(obits[x], name, ncpbytes)
244  if (error == 0) {
245    putbits(in, 0);
246    putbits(ou, 1);
247    putbits(ex, 2);
248#undef putbits
249  } else {
250    errno = error;
251    nselected = -1;
252  }
253
254  free( selbits );
255  return ( nselected );
256}
257