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 **/
84 int
usleep(useconds_t Microseconds)85 usleep( 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 
95 unsigned int
sleep(unsigned int Seconds)96 sleep( unsigned int Seconds )
97 {
98   return (usleep( (useconds_t)(Seconds * 1000000) ));
99 }
100 
101 static int
selscan(fd_mask ** ibits,fd_mask ** obits,int nfd,int * nselected)102 selscan(
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 
148 int
select(int nd,fd_set * in,fd_set * ou,fd_set * ex,struct timeval * tv)149 select(
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