Upload Tizen:Base source
[toolchains/nspr.git] / mozilla / nsprpub / pr / src / md / os2 / os2poll.c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is the Netscape Portable Runtime (NSPR).
16  *
17  * The Initial Developer of the Original Code is
18  * Netscape Communications Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 1998-2000
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either the GNU General Public License Version 2 or later (the "GPL"), or
26  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the MPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the MPL, the GPL or the LGPL.
35  *
36  * ***** END LICENSE BLOCK ***** */
37
38 /*
39  * This file implements _PR_MD_PR_POLL for OS/2.
40  */
41
42 #include <sys/time.h> /* For timeval. */
43
44 #include "primpl.h"
45
46 #ifndef BSD_SELECT
47 /* Utility functions called when using OS/2 select */
48
49 PRBool IsSocketSet( PRInt32 osfd, int* socks, int start, int count )
50 {
51   int i;
52   PRBool isSet = PR_FALSE;
53
54   for( i = start; i < start+count; i++ )
55   {
56     if( socks[i] == osfd )
57       isSet = PR_TRUE;
58   }
59   
60   return isSet; 
61 }
62 #endif
63
64 PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
65 {
66 #ifdef BSD_SELECT
67     fd_set rd, wt, ex;
68 #else
69     int rd, wt, ex;
70     int* socks;
71     unsigned long msecs;
72     int i, j;
73 #endif
74     PRFileDesc *bottom;
75     PRPollDesc *pd, *epd;
76     PRInt32 maxfd = -1, ready, err;
77     PRIntervalTime remaining, elapsed, start;
78
79 #ifdef BSD_SELECT
80     struct timeval tv, *tvp = NULL;
81
82     FD_ZERO(&rd);
83     FD_ZERO(&wt);
84     FD_ZERO(&ex);
85 #else
86     rd = 0;
87     wt = 0;
88     ex = 0;
89     socks = (int) PR_MALLOC( npds * 3 * sizeof(int) );
90     
91     if (!socks)
92     {
93         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
94         return -1;
95     }
96 #endif
97
98     ready = 0;
99     for (pd = pds, epd = pd + npds; pd < epd; pd++)
100     {
101         PRInt16 in_flags_read = 0, in_flags_write = 0;
102         PRInt16 out_flags_read = 0, out_flags_write = 0;
103
104         if ((NULL != pd->fd) && (0 != pd->in_flags))
105         {
106             if (pd->in_flags & PR_POLL_READ)
107             {
108                 in_flags_read = (pd->fd->methods->poll)(
109                     pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read);
110             }
111             if (pd->in_flags & PR_POLL_WRITE)
112             {
113                 in_flags_write = (pd->fd->methods->poll)(
114                     pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write);
115             }
116             if ((0 != (in_flags_read & out_flags_read)) ||
117                 (0 != (in_flags_write & out_flags_write)))
118             {
119                 /* this one's ready right now */
120                 if (0 == ready)
121                 {
122                     /*
123                      * We will have to return without calling the
124                      * system poll/select function.  So zero the
125                      * out_flags fields of all the poll descriptors
126                      * before this one.
127                      */
128                     PRPollDesc *prev;
129                     for (prev = pds; prev < pd; prev++)
130                     {
131                         prev->out_flags = 0;
132                     }
133                 }
134                 ready += 1;
135                 pd->out_flags = out_flags_read | out_flags_write;
136             }
137             else
138             {
139                 pd->out_flags = 0;  /* pre-condition */
140
141                 /* make sure this is an NSPR supported stack */
142                 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
143                 PR_ASSERT(NULL != bottom);  /* what to do about that? */
144                 if ((NULL != bottom) &&
145                     (_PR_FILEDESC_OPEN == bottom->secret->state))
146                 {
147                     if (0 == ready)
148                     {
149                         PRInt32 osfd = bottom->secret->md.osfd;
150                         if (osfd > maxfd) 
151                             maxfd = osfd;
152                         if (in_flags_read & PR_POLL_READ)
153                         {
154                             pd->out_flags |= _PR_POLL_READ_SYS_READ;
155 #ifdef BSD_SELECT
156                             FD_SET(osfd, &rd);
157 #else
158                             socks[rd] = osfd;
159                             rd++;              
160 #endif
161                         }
162                         if (in_flags_read & PR_POLL_WRITE)
163                         {
164                             pd->out_flags |= _PR_POLL_READ_SYS_WRITE;
165 #ifdef BSD_SELECT
166                             FD_SET(osfd, &wt);
167 #else
168                             socks[npds+wt] = osfd;
169                             wt++;              
170 #endif
171                         }
172                         if (in_flags_write & PR_POLL_READ)
173                         {
174                             pd->out_flags |= _PR_POLL_WRITE_SYS_READ;
175 #ifdef BSD_SELECT
176                             FD_SET(osfd, &rd);
177 #else
178                             socks[rd] = osfd;
179                             rd++;              
180 #endif
181                         }
182                         if (in_flags_write & PR_POLL_WRITE)
183                         {
184                             pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE;
185 #ifdef BSD_SELECT
186                             FD_SET(osfd, &wt);
187 #else
188                             socks[npds+wt] = osfd;
189                             wt++;              
190 #endif
191                         }
192                         if (pd->in_flags & PR_POLL_EXCEPT)
193                         {
194 #ifdef BSD_SELECT
195                             FD_SET(osfd, &ex);
196 #else
197                             socks[npds*2+ex] = osfd;
198                             ex++;
199 #endif
200                         }
201                     }
202                 }
203                 else
204                 {
205                     if (0 == ready)
206                     {
207                         PRPollDesc *prev;
208                         for (prev = pds; prev < pd; prev++)
209                         {
210                             prev->out_flags = 0;
211                         }
212                     }
213                     ready += 1;  /* this will cause an abrupt return */
214                     pd->out_flags = PR_POLL_NVAL;  /* bogii */
215                 }
216             }
217         }
218         else
219         {
220             pd->out_flags = 0;
221         }
222     }
223
224     if (0 != ready)
225     {
226 #ifndef BSD_SELECT
227         PR_Free(socks);
228 #endif
229         return ready;  /* no need to block */
230     }
231
232     remaining = timeout;
233     start = PR_IntervalNow();
234
235 retry:
236 #ifdef BSD_SELECT
237     if (timeout != PR_INTERVAL_NO_TIMEOUT)
238     {
239         PRInt32 ticksPerSecond = PR_TicksPerSecond();
240         tv.tv_sec = remaining / ticksPerSecond;
241         tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond );
242         tvp = &tv;
243     }
244
245     ready = bsdselect(maxfd + 1, &rd, &wt, &ex, tvp);
246 #else
247     switch (timeout)
248     {
249         case PR_INTERVAL_NO_WAIT:
250             msecs = 0;
251             break;
252         case PR_INTERVAL_NO_TIMEOUT:
253             msecs = -1;
254             break;
255         default:
256             msecs = PR_IntervalToMilliseconds(remaining);
257     }
258
259      /* compact array */
260     for( i = rd, j = npds; j < npds+wt; i++,j++ )
261         socks[i] = socks[j];
262     for( i = rd+wt, j = npds*2; j < npds*2+ex; i++,j++ )
263         socks[i] = socks[j];
264     
265     ready = os2_select(socks, rd, wt, ex, msecs);
266 #endif
267
268     if (ready == -1 && errno == EINTR)
269     {
270         if (timeout == PR_INTERVAL_NO_TIMEOUT)
271             goto retry;
272         else
273         {
274             elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
275             if (elapsed > timeout)
276                 ready = 0;  /* timed out */
277             else
278             {
279                 remaining = timeout - elapsed;
280                 goto retry;
281             }
282         }
283     }
284
285     /*
286     ** Now to unravel the select sets back into the client's poll
287     ** descriptor list. Is this possibly an area for pissing away
288     ** a few cycles or what?
289     */
290     if (ready > 0)
291     {
292         ready = 0;
293         for (pd = pds, epd = pd + npds; pd < epd; pd++)
294         {
295             PRInt16 out_flags = 0;
296             if ((NULL != pd->fd) && (0 != pd->in_flags))
297             {
298                 PRInt32 osfd;
299                 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
300                 PR_ASSERT(NULL != bottom);
301
302                 osfd = bottom->secret->md.osfd;
303
304 #ifdef BSD_SELECT
305                 if (FD_ISSET(osfd, &rd))
306 #else
307                 if( IsSocketSet(osfd, socks, 0, rd) )        
308 #endif
309                 {
310                     if (pd->out_flags & _PR_POLL_READ_SYS_READ)
311                         out_flags |= PR_POLL_READ;
312                     if (pd->out_flags & _PR_POLL_WRITE_SYS_READ)
313                         out_flags |= PR_POLL_WRITE;
314                 } 
315
316 #ifdef BSD_SELECT
317                 if (FD_ISSET(osfd, &wt))
318 #else
319                 if( IsSocketSet(osfd, socks, rd, wt) )        
320 #endif
321                 {
322                     if (pd->out_flags & _PR_POLL_READ_SYS_WRITE)
323                         out_flags |= PR_POLL_READ;
324                     if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE)
325                         out_flags |= PR_POLL_WRITE;
326                 } 
327
328 #ifdef BSD_SELECT
329                 if (FD_ISSET(osfd, &ex))
330 #else
331                 if( IsSocketSet(osfd, socks, rd+wt, ex) )        
332 #endif
333                 {
334                     out_flags |= PR_POLL_EXCEPT;
335                 }
336             }
337             pd->out_flags = out_flags;
338             if (out_flags) ready++;
339         }
340         PR_ASSERT(ready > 0);
341     }
342     else if (ready < 0)
343     {
344         err = _MD_ERRNO();
345         if (err == EBADF)
346         {
347             /* Find the bad fds */
348             int optval;
349             int optlen = sizeof(optval);
350             ready = 0;
351             for (pd = pds, epd = pd + npds; pd < epd; pd++)
352             {
353                 pd->out_flags = 0;
354                 if ((NULL != pd->fd) && (0 != pd->in_flags))
355                 {
356                     bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
357                     if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET,
358                         SO_TYPE, (char *) &optval, &optlen) == -1)
359                     {
360                         PR_ASSERT(sock_errno() == ENOTSOCK);
361                         if (sock_errno() == ENOTSOCK)
362                         {
363                             pd->out_flags = PR_POLL_NVAL;
364                             ready++;
365                         }
366                     }
367                 }
368             }
369             PR_ASSERT(ready > 0);
370         }
371         else
372             _PR_MD_MAP_SELECT_ERROR(err);
373     }
374
375 #ifndef BSD_SELECT
376     PR_Free(socks);
377 #endif
378     return ready;
379 }
380