Back to index

lightning-sunbird  0.9+nobinonly
os2poll.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * This file implements _PR_MD_PR_POLL for OS/2.
00040  */
00041 
00042 #ifdef XP_OS2_EMX
00043  #include <sys/time.h> /* For timeval. */
00044 #endif
00045 
00046 #include "primpl.h"
00047 
00048 #ifndef BSD_SELECT
00049 /* Utility functions called when using OS/2 select */
00050 
00051 PRBool IsSocketSet( PRInt32 osfd, int* socks, int start, int count )
00052 {
00053   int i;
00054   PRBool isSet = PR_FALSE;
00055 
00056   for( i = start; i < start+count; i++ )
00057   {
00058     if( socks[i] == osfd )
00059       isSet = PR_TRUE;
00060   }
00061   
00062   return isSet; 
00063 }
00064 #endif
00065 
00066 PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
00067 {
00068 #ifdef BSD_SELECT
00069     fd_set rd, wt, ex;
00070 #else
00071     int rd, wt, ex;
00072     int* socks;
00073     unsigned long msecs;
00074     int i, j;
00075 #endif
00076     PRFileDesc *bottom;
00077     PRPollDesc *pd, *epd;
00078     PRInt32 maxfd = -1, ready, err;
00079     PRIntervalTime remaining, elapsed, start;
00080 
00081 #ifdef BSD_SELECT
00082     struct timeval tv, *tvp = NULL;
00083 
00084     FD_ZERO(&rd);
00085     FD_ZERO(&wt);
00086     FD_ZERO(&ex);
00087 #else
00088     rd = 0;
00089     wt = 0;
00090     ex = 0;
00091     socks = (int) PR_MALLOC( npds * 3 * sizeof(int) );
00092     
00093     if (!socks)
00094     {
00095         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00096         return -1;
00097     }
00098 #endif
00099 
00100     ready = 0;
00101     for (pd = pds, epd = pd + npds; pd < epd; pd++)
00102     {
00103         PRInt16 in_flags_read = 0, in_flags_write = 0;
00104         PRInt16 out_flags_read = 0, out_flags_write = 0;
00105 
00106         if ((NULL != pd->fd) && (0 != pd->in_flags))
00107         {
00108             if (pd->in_flags & PR_POLL_READ)
00109             {
00110                 in_flags_read = (pd->fd->methods->poll)(
00111                     pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read);
00112             }
00113             if (pd->in_flags & PR_POLL_WRITE)
00114             {
00115                 in_flags_write = (pd->fd->methods->poll)(
00116                     pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write);
00117             }
00118             if ((0 != (in_flags_read & out_flags_read)) ||
00119                 (0 != (in_flags_write & out_flags_write)))
00120             {
00121                 /* this one's ready right now */
00122                 if (0 == ready)
00123                 {
00124                     /*
00125                      * We will have to return without calling the
00126                      * system poll/select function.  So zero the
00127                      * out_flags fields of all the poll descriptors
00128                      * before this one.
00129                      */
00130                     PRPollDesc *prev;
00131                     for (prev = pds; prev < pd; prev++)
00132                     {
00133                         prev->out_flags = 0;
00134                     }
00135                 }
00136                 ready += 1;
00137                 pd->out_flags = out_flags_read | out_flags_write;
00138             }
00139             else
00140             {
00141                 pd->out_flags = 0;  /* pre-condition */
00142 
00143                 /* make sure this is an NSPR supported stack */
00144                 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
00145                 PR_ASSERT(NULL != bottom);  /* what to do about that? */
00146                 if ((NULL != bottom) &&
00147                     (_PR_FILEDESC_OPEN == bottom->secret->state))
00148                 {
00149                     if (0 == ready)
00150                     {
00151                         PRInt32 osfd = bottom->secret->md.osfd;
00152                         if (osfd > maxfd) 
00153                             maxfd = osfd;
00154                         if (in_flags_read & PR_POLL_READ)
00155                         {
00156                             pd->out_flags |= _PR_POLL_READ_SYS_READ;
00157 #ifdef BSD_SELECT
00158                             FD_SET(osfd, &rd);
00159 #else
00160                             socks[rd] = osfd;
00161                             rd++;              
00162 #endif
00163                         }
00164                         if (in_flags_read & PR_POLL_WRITE)
00165                         {
00166                             pd->out_flags |= _PR_POLL_READ_SYS_WRITE;
00167 #ifdef BSD_SELECT
00168                             FD_SET(osfd, &wt);
00169 #else
00170                             socks[npds+wt] = osfd;
00171                             wt++;              
00172 #endif
00173                         }
00174                         if (in_flags_write & PR_POLL_READ)
00175                         {
00176                             pd->out_flags |= _PR_POLL_WRITE_SYS_READ;
00177 #ifdef BSD_SELECT
00178                             FD_SET(osfd, &rd);
00179 #else
00180                             socks[rd] = osfd;
00181                             rd++;              
00182 #endif
00183                         }
00184                         if (in_flags_write & PR_POLL_WRITE)
00185                         {
00186                             pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE;
00187 #ifdef BSD_SELECT
00188                             FD_SET(osfd, &wt);
00189 #else
00190                             socks[npds+wt] = osfd;
00191                             wt++;              
00192 #endif
00193                         }
00194                         if (pd->in_flags & PR_POLL_EXCEPT)
00195                         {
00196 #ifdef BSD_SELECT
00197                             FD_SET(osfd, &ex);
00198 #else
00199                             socks[npds*2+ex] = osfd;
00200                             ex++;
00201 #endif
00202                         }
00203                     }
00204                 }
00205                 else
00206                 {
00207                     if (0 == ready)
00208                     {
00209                         PRPollDesc *prev;
00210                         for (prev = pds; prev < pd; prev++)
00211                         {
00212                             prev->out_flags = 0;
00213                         }
00214                     }
00215                     ready += 1;  /* this will cause an abrupt return */
00216                     pd->out_flags = PR_POLL_NVAL;  /* bogii */
00217                 }
00218             }
00219         }
00220         else
00221         {
00222             pd->out_flags = 0;
00223         }
00224     }
00225 
00226     if (0 != ready)
00227     {
00228 #ifndef BSD_SELECT
00229         PR_Free(socks);
00230 #endif
00231         return ready;  /* no need to block */
00232     }
00233 
00234     remaining = timeout;
00235     start = PR_IntervalNow();
00236 
00237 retry:
00238 #ifdef BSD_SELECT
00239     if (timeout != PR_INTERVAL_NO_TIMEOUT)
00240     {
00241         PRInt32 ticksPerSecond = PR_TicksPerSecond();
00242         tv.tv_sec = remaining / ticksPerSecond;
00243         tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond );
00244         tvp = &tv;
00245     }
00246 
00247     ready = bsdselect(maxfd + 1, &rd, &wt, &ex, tvp);
00248 #else
00249     switch (timeout)
00250     {
00251         case PR_INTERVAL_NO_WAIT:
00252             msecs = 0;
00253             break;
00254         case PR_INTERVAL_NO_TIMEOUT:
00255             msecs = -1;
00256             break;
00257         default:
00258             msecs = PR_IntervalToMilliseconds(remaining);
00259     }
00260 
00261      /* compact array */
00262     for( i = rd, j = npds; j < npds+wt; i++,j++ )
00263         socks[i] = socks[j];
00264     for( i = rd+wt, j = npds*2; j < npds*2+ex; i++,j++ )
00265         socks[i] = socks[j];
00266     
00267     ready = os2_select(socks, rd, wt, ex, msecs);
00268 #endif
00269 
00270     if (ready == -1 && errno == EINTR)
00271     {
00272         if (timeout == PR_INTERVAL_NO_TIMEOUT)
00273             goto retry;
00274         else
00275         {
00276             elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
00277             if (elapsed > timeout)
00278                 ready = 0;  /* timed out */
00279             else
00280             {
00281                 remaining = timeout - elapsed;
00282                 goto retry;
00283             }
00284         }
00285     }
00286 
00287     /*
00288     ** Now to unravel the select sets back into the client's poll
00289     ** descriptor list. Is this possibly an area for pissing away
00290     ** a few cycles or what?
00291     */
00292     if (ready > 0)
00293     {
00294         ready = 0;
00295         for (pd = pds, epd = pd + npds; pd < epd; pd++)
00296         {
00297             PRInt16 out_flags = 0;
00298             if ((NULL != pd->fd) && (0 != pd->in_flags))
00299             {
00300                 PRInt32 osfd;
00301                 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
00302                 PR_ASSERT(NULL != bottom);
00303 
00304                 osfd = bottom->secret->md.osfd;
00305 
00306 #ifdef BSD_SELECT
00307                 if (FD_ISSET(osfd, &rd))
00308 #else
00309                 if( IsSocketSet(osfd, socks, 0, rd) )        
00310 #endif
00311                 {
00312                     if (pd->out_flags & _PR_POLL_READ_SYS_READ)
00313                         out_flags |= PR_POLL_READ;
00314                     if (pd->out_flags & _PR_POLL_WRITE_SYS_READ)
00315                         out_flags |= PR_POLL_WRITE;
00316                 } 
00317 
00318 #ifdef BSD_SELECT
00319                 if (FD_ISSET(osfd, &wt))
00320 #else
00321                 if( IsSocketSet(osfd, socks, rd, wt) )        
00322 #endif
00323                 {
00324                     if (pd->out_flags & _PR_POLL_READ_SYS_WRITE)
00325                         out_flags |= PR_POLL_READ;
00326                     if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE)
00327                         out_flags |= PR_POLL_WRITE;
00328                 } 
00329 
00330 #ifdef BSD_SELECT
00331                 if (FD_ISSET(osfd, &ex))
00332 #else
00333                 if( IsSocketSet(osfd, socks, rd+wt, ex) )        
00334 #endif
00335                 {
00336                     out_flags |= PR_POLL_EXCEPT;
00337                 }
00338             }
00339             pd->out_flags = out_flags;
00340             if (out_flags) ready++;
00341         }
00342         PR_ASSERT(ready > 0);
00343     }
00344     else if (ready < 0)
00345     {
00346         err = _MD_ERRNO();
00347         if (err == EBADF)
00348         {
00349             /* Find the bad fds */
00350             int optval;
00351             int optlen = sizeof(optval);
00352             ready = 0;
00353             for (pd = pds, epd = pd + npds; pd < epd; pd++)
00354             {
00355                 pd->out_flags = 0;
00356                 if ((NULL != pd->fd) && (0 != pd->in_flags))
00357                 {
00358                     bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
00359                     if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET,
00360                         SO_TYPE, (char *) &optval, &optlen) == -1)
00361                     {
00362                         PR_ASSERT(sock_errno() == ENOTSOCK);
00363                         if (sock_errno() == ENOTSOCK)
00364                         {
00365                             pd->out_flags = PR_POLL_NVAL;
00366                             ready++;
00367                         }
00368                     }
00369                 }
00370             }
00371             PR_ASSERT(ready > 0);
00372         }
00373         else
00374             _PR_MD_MAP_SELECT_ERROR(err);
00375     }
00376 
00377 #ifndef BSD_SELECT
00378     PR_Free(socks);
00379 #endif
00380     return ready;
00381 }
00382