michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * This file implements _PR_MD_PR_POLL for OS/2. michael@0: */ michael@0: michael@0: #include /* For timeval. */ michael@0: michael@0: #include "primpl.h" michael@0: michael@0: #ifndef BSD_SELECT michael@0: /* Utility functions called when using OS/2 select */ michael@0: michael@0: PRBool IsSocketSet( PRInt32 osfd, int* socks, int start, int count ) michael@0: { michael@0: int i; michael@0: PRBool isSet = PR_FALSE; michael@0: michael@0: for( i = start; i < start+count; i++ ) michael@0: { michael@0: if( socks[i] == osfd ) michael@0: isSet = PR_TRUE; michael@0: } michael@0: michael@0: return isSet; michael@0: } michael@0: #endif michael@0: michael@0: PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) michael@0: { michael@0: #ifdef BSD_SELECT michael@0: fd_set rd, wt, ex; michael@0: #else michael@0: int rd, wt, ex; michael@0: int* socks; michael@0: unsigned long msecs; michael@0: int i, j; michael@0: #endif michael@0: PRFileDesc *bottom; michael@0: PRPollDesc *pd, *epd; michael@0: PRInt32 maxfd = -1, ready, err; michael@0: PRIntervalTime remaining, elapsed, start; michael@0: michael@0: #ifdef BSD_SELECT michael@0: struct timeval tv, *tvp = NULL; michael@0: michael@0: FD_ZERO(&rd); michael@0: FD_ZERO(&wt); michael@0: FD_ZERO(&ex); michael@0: #else michael@0: rd = 0; michael@0: wt = 0; michael@0: ex = 0; michael@0: socks = (int) PR_MALLOC( npds * 3 * sizeof(int) ); michael@0: michael@0: if (!socks) michael@0: { michael@0: PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); michael@0: return -1; michael@0: } michael@0: #endif michael@0: michael@0: ready = 0; michael@0: for (pd = pds, epd = pd + npds; pd < epd; pd++) michael@0: { michael@0: PRInt16 in_flags_read = 0, in_flags_write = 0; michael@0: PRInt16 out_flags_read = 0, out_flags_write = 0; michael@0: michael@0: if ((NULL != pd->fd) && (0 != pd->in_flags)) michael@0: { michael@0: if (pd->in_flags & PR_POLL_READ) michael@0: { michael@0: in_flags_read = (pd->fd->methods->poll)( michael@0: pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); michael@0: } michael@0: if (pd->in_flags & PR_POLL_WRITE) michael@0: { michael@0: in_flags_write = (pd->fd->methods->poll)( michael@0: pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); michael@0: } michael@0: if ((0 != (in_flags_read & out_flags_read)) || michael@0: (0 != (in_flags_write & out_flags_write))) michael@0: { michael@0: /* this one's ready right now */ michael@0: if (0 == ready) michael@0: { michael@0: /* michael@0: * We will have to return without calling the michael@0: * system poll/select function. So zero the michael@0: * out_flags fields of all the poll descriptors michael@0: * before this one. michael@0: */ michael@0: PRPollDesc *prev; michael@0: for (prev = pds; prev < pd; prev++) michael@0: { michael@0: prev->out_flags = 0; michael@0: } michael@0: } michael@0: ready += 1; michael@0: pd->out_flags = out_flags_read | out_flags_write; michael@0: } michael@0: else michael@0: { michael@0: pd->out_flags = 0; /* pre-condition */ michael@0: michael@0: /* make sure this is an NSPR supported stack */ michael@0: bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); michael@0: PR_ASSERT(NULL != bottom); /* what to do about that? */ michael@0: if ((NULL != bottom) && michael@0: (_PR_FILEDESC_OPEN == bottom->secret->state)) michael@0: { michael@0: if (0 == ready) michael@0: { michael@0: PRInt32 osfd = bottom->secret->md.osfd; michael@0: if (osfd > maxfd) michael@0: maxfd = osfd; michael@0: if (in_flags_read & PR_POLL_READ) michael@0: { michael@0: pd->out_flags |= _PR_POLL_READ_SYS_READ; michael@0: #ifdef BSD_SELECT michael@0: FD_SET(osfd, &rd); michael@0: #else michael@0: socks[rd] = osfd; michael@0: rd++; michael@0: #endif michael@0: } michael@0: if (in_flags_read & PR_POLL_WRITE) michael@0: { michael@0: pd->out_flags |= _PR_POLL_READ_SYS_WRITE; michael@0: #ifdef BSD_SELECT michael@0: FD_SET(osfd, &wt); michael@0: #else michael@0: socks[npds+wt] = osfd; michael@0: wt++; michael@0: #endif michael@0: } michael@0: if (in_flags_write & PR_POLL_READ) michael@0: { michael@0: pd->out_flags |= _PR_POLL_WRITE_SYS_READ; michael@0: #ifdef BSD_SELECT michael@0: FD_SET(osfd, &rd); michael@0: #else michael@0: socks[rd] = osfd; michael@0: rd++; michael@0: #endif michael@0: } michael@0: if (in_flags_write & PR_POLL_WRITE) michael@0: { michael@0: pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; michael@0: #ifdef BSD_SELECT michael@0: FD_SET(osfd, &wt); michael@0: #else michael@0: socks[npds+wt] = osfd; michael@0: wt++; michael@0: #endif michael@0: } michael@0: if (pd->in_flags & PR_POLL_EXCEPT) michael@0: { michael@0: #ifdef BSD_SELECT michael@0: FD_SET(osfd, &ex); michael@0: #else michael@0: socks[npds*2+ex] = osfd; michael@0: ex++; michael@0: #endif michael@0: } michael@0: } michael@0: } michael@0: else michael@0: { michael@0: if (0 == ready) michael@0: { michael@0: PRPollDesc *prev; michael@0: for (prev = pds; prev < pd; prev++) michael@0: { michael@0: prev->out_flags = 0; michael@0: } michael@0: } michael@0: ready += 1; /* this will cause an abrupt return */ michael@0: pd->out_flags = PR_POLL_NVAL; /* bogii */ michael@0: } michael@0: } michael@0: } michael@0: else michael@0: { michael@0: pd->out_flags = 0; michael@0: } michael@0: } michael@0: michael@0: if (0 != ready) michael@0: { michael@0: #ifndef BSD_SELECT michael@0: PR_Free(socks); michael@0: #endif michael@0: return ready; /* no need to block */ michael@0: } michael@0: michael@0: remaining = timeout; michael@0: start = PR_IntervalNow(); michael@0: michael@0: retry: michael@0: #ifdef BSD_SELECT michael@0: if (timeout != PR_INTERVAL_NO_TIMEOUT) michael@0: { michael@0: PRInt32 ticksPerSecond = PR_TicksPerSecond(); michael@0: tv.tv_sec = remaining / ticksPerSecond; michael@0: tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond ); michael@0: tvp = &tv; michael@0: } michael@0: michael@0: ready = bsdselect(maxfd + 1, &rd, &wt, &ex, tvp); michael@0: #else michael@0: switch (timeout) michael@0: { michael@0: case PR_INTERVAL_NO_WAIT: michael@0: msecs = 0; michael@0: break; michael@0: case PR_INTERVAL_NO_TIMEOUT: michael@0: msecs = -1; michael@0: break; michael@0: default: michael@0: msecs = PR_IntervalToMilliseconds(remaining); michael@0: } michael@0: michael@0: /* compact array */ michael@0: for( i = rd, j = npds; j < npds+wt; i++,j++ ) michael@0: socks[i] = socks[j]; michael@0: for( i = rd+wt, j = npds*2; j < npds*2+ex; i++,j++ ) michael@0: socks[i] = socks[j]; michael@0: michael@0: ready = os2_select(socks, rd, wt, ex, msecs); michael@0: #endif michael@0: michael@0: if (ready == -1 && errno == EINTR) michael@0: { michael@0: if (timeout == PR_INTERVAL_NO_TIMEOUT) michael@0: goto retry; michael@0: else michael@0: { michael@0: elapsed = (PRIntervalTime) (PR_IntervalNow() - start); michael@0: if (elapsed > timeout) michael@0: ready = 0; /* timed out */ michael@0: else michael@0: { michael@0: remaining = timeout - elapsed; michael@0: goto retry; michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* michael@0: ** Now to unravel the select sets back into the client's poll michael@0: ** descriptor list. Is this possibly an area for pissing away michael@0: ** a few cycles or what? michael@0: */ michael@0: if (ready > 0) michael@0: { michael@0: ready = 0; michael@0: for (pd = pds, epd = pd + npds; pd < epd; pd++) michael@0: { michael@0: PRInt16 out_flags = 0; michael@0: if ((NULL != pd->fd) && (0 != pd->in_flags)) michael@0: { michael@0: PRInt32 osfd; michael@0: bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); michael@0: PR_ASSERT(NULL != bottom); michael@0: michael@0: osfd = bottom->secret->md.osfd; michael@0: michael@0: #ifdef BSD_SELECT michael@0: if (FD_ISSET(osfd, &rd)) michael@0: #else michael@0: if( IsSocketSet(osfd, socks, 0, rd) ) michael@0: #endif michael@0: { michael@0: if (pd->out_flags & _PR_POLL_READ_SYS_READ) michael@0: out_flags |= PR_POLL_READ; michael@0: if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) michael@0: out_flags |= PR_POLL_WRITE; michael@0: } michael@0: michael@0: #ifdef BSD_SELECT michael@0: if (FD_ISSET(osfd, &wt)) michael@0: #else michael@0: if( IsSocketSet(osfd, socks, rd, wt) ) michael@0: #endif michael@0: { michael@0: if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) michael@0: out_flags |= PR_POLL_READ; michael@0: if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) michael@0: out_flags |= PR_POLL_WRITE; michael@0: } michael@0: michael@0: #ifdef BSD_SELECT michael@0: if (FD_ISSET(osfd, &ex)) michael@0: #else michael@0: if( IsSocketSet(osfd, socks, rd+wt, ex) ) michael@0: #endif michael@0: { michael@0: out_flags |= PR_POLL_EXCEPT; michael@0: } michael@0: } michael@0: pd->out_flags = out_flags; michael@0: if (out_flags) ready++; michael@0: } michael@0: PR_ASSERT(ready > 0); michael@0: } michael@0: else if (ready < 0) michael@0: { michael@0: err = _MD_ERRNO(); michael@0: if (err == EBADF) michael@0: { michael@0: /* Find the bad fds */ michael@0: int optval; michael@0: int optlen = sizeof(optval); michael@0: ready = 0; michael@0: for (pd = pds, epd = pd + npds; pd < epd; pd++) michael@0: { michael@0: pd->out_flags = 0; michael@0: if ((NULL != pd->fd) && (0 != pd->in_flags)) michael@0: { michael@0: bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); michael@0: if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, michael@0: SO_TYPE, (char *) &optval, &optlen) == -1) michael@0: { michael@0: PR_ASSERT(sock_errno() == ENOTSOCK); michael@0: if (sock_errno() == ENOTSOCK) michael@0: { michael@0: pd->out_flags = PR_POLL_NVAL; michael@0: ready++; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: PR_ASSERT(ready > 0); michael@0: } michael@0: else michael@0: _PR_MD_MAP_SELECT_ERROR(err); michael@0: } michael@0: michael@0: #ifndef BSD_SELECT michael@0: PR_Free(socks); michael@0: #endif michael@0: return ready; michael@0: } michael@0: