Back to index

lightning-sunbird  0.9+nobinonly
w16sock.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 #include "primpl.h"
00039 
00040 static  int winsockNotPresent = 0;
00041 
00042 void
00043 _PR_MD_INIT_IO()
00044 {
00045     int rv;
00046     
00047     WORD WSAVersion = 0x0101;
00048     WSADATA WSAData;
00049 
00050     rv = WSAStartup( WSAVersion, &WSAData );
00051     if ( rv != 0 )
00052     {
00053         _PR_MD_MAP_WSASTARTUP_ERROR(WSAGetLastError());
00054         winsockNotPresent = 1;
00055     }
00056     return;
00057 }
00058 
00059 void
00060 _PR_MD_CLEANUP_BEFORE_EXIT(void)
00061 {
00062     int rv;
00063     int err;
00064     
00065     rv = WSACleanup();
00066     if ( rv == SOCKET_ERROR )
00067     {
00068         err = WSAGetLastError();
00069         PR_ASSERT(0);
00070     }
00071     return;
00072 } /* end _PR_MD_CLEANUP_BEFORE_EXIT() */
00073 
00074 /* --- SOCKET IO --------------------------------------------------------- */
00075 
00076 PRStatus 
00077 _MD_WindowsGetHostName(char *name, PRUint32 namelen)
00078 {
00079     PRIntn  rv;
00080     PRInt32 syserror;
00081     
00082     rv = gethostname(name, (PRInt32) namelen);
00083     if (0 == rv) {
00084         return PR_SUCCESS;
00085     }
00086     syserror = WSAGetLastError();
00087     PR_ASSERT(WSANOTINITIALISED != syserror);
00088     _PR_MD_MAP_GETHOSTNAME_ERROR(syserror);
00089     return PR_FAILURE;
00090 }
00091 
00092 
00093 PRInt32
00094 _PR_MD_SOCKET(int af, int type, int flags)
00095 {
00096     SOCKET      sock;
00097     PRUint32    one = 1;
00098     PRInt32     rv;
00099     PRInt32     err;
00100 
00101     if ( winsockNotPresent )
00102         return( (PRInt32)INVALID_SOCKET );
00103 
00104     sock = socket(af, type, flags);
00105 
00106     if (sock == INVALID_SOCKET ) 
00107     {
00108         int rv = GetLastError();
00109         closesocket(sock);
00110         _PR_MD_MAP_SOCKET_ERROR(rv);
00111         return (PRInt32)INVALID_SOCKET;
00112     }
00113 
00114     /*
00115     ** Make the socket Non-Blocking
00116     */
00117     rv = ioctlsocket( sock, FIONBIO, &one);
00118     if ( rv != 0 )
00119     {
00120         err = WSAGetLastError();
00121         return -1;
00122     }
00123 
00124     return (PRInt32)sock;
00125 }
00126 
00127 
00128 PRInt32
00129 _PR_MD_SOCKETAVAILABLE(PRFileDesc *fd)
00130 {
00131     PRUint32 result;
00132 
00133     if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) {
00134         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError());
00135         return -1;
00136     }
00137     return result;
00138 }
00139 
00140 
00141 /*
00142 ** _MD_CloseSocket() -- Close a socket
00143 **
00144 */
00145 PRInt32
00146 _PR_MD_CLOSE_SOCKET(PRInt32 osfd)
00147 {
00148     PRInt32 rv;
00149 
00150     rv = closesocket((SOCKET) osfd );
00151     if (rv < 0)
00152         _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError());
00153 
00154     return rv;
00155 }
00156 
00157 PRInt32 _PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog)
00158 {
00159     int rv, err;
00160 
00161        rv = listen(fd->secret->md.osfd, backlog);
00162        if ( rv == SOCKET_ERROR ) {
00163               _PR_MD_MAP_LISTEN_ERROR(WSAGetLastError());
00164         return(-1);
00165        }
00166        return(rv);
00167 }
00168 
00169 PRInt32
00170 _PR_MD_ACCEPT(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen,
00171        PRIntervalTime timeout )
00172 {
00173     PRInt32 osfd = fd->secret->md.osfd;
00174     PRThread    *me = _PR_MD_CURRENT_THREAD();
00175     PRInt32     err;
00176     PRIntn      rv;
00177 
00178     MD_ASSERTINT( *addrlen );    
00179 
00180     while ((rv = (SOCKET)accept(osfd, (struct sockaddr *) addr,
00181                                         (int *)addrlen)) == INVALID_SOCKET ) {
00182         err = WSAGetLastError();
00183               if ( err == WSAEWOULDBLOCK ) {
00184                      if (fd->secret->nonblocking) {
00185                             break;
00186                      }
00187             if (_PR_WaitForFD(osfd, PR_POLL_READ, timeout) == 0) {
00188                 if ( _PR_PENDING_INTERRUPT(me))
00189                 {
00190                     me->flags &= ~_PR_INTERRUPT;
00191                     PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00192                 } else
00193                 {
00194                     PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00195                 }
00196                 rv = -1;
00197                 goto done;
00198             } else if (_PR_PENDING_INTERRUPT(me)) {
00199                 me->flags &= ~_PR_INTERRUPT;
00200                 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00201                 rv = -1;
00202                 goto done;
00203             }
00204         } else if ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){
00205             continue;
00206         } else {
00207             break;
00208         }
00209     }
00210     if (rv < 0) {
00211         _PR_MD_MAP_ACCEPT_ERROR(err);
00212     }
00213 done:
00214     if ( rv == INVALID_SOCKET )
00215         return(-1 );
00216     else
00217         return(rv);
00218 } /* end _MD_Accept() */
00219 
00220 
00221 PRInt32
00222 _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, 
00223                PRIntervalTime timeout)
00224 {
00225     PRInt32 osfd = fd->secret->md.osfd;
00226     PRThread *me = _PR_MD_CURRENT_THREAD();
00227     PRInt32 rv, err;
00228 
00229     while ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) {
00230         err = WSAGetLastError();
00231         if (err == WSAEISCONN) {
00232             rv = 0;
00233             break;
00234         }
00235         /* for winsock1.1, it reports EALREADY as EINVAL */
00236               if ((err == WSAEWOULDBLOCK)
00237             ||(err == WSAEALREADY) 
00238             || (err = WSAEINVAL)) {
00239                      if (fd->secret->nonblocking) {
00240                             break;
00241                      }
00242             if (_PR_WaitForFD(osfd, PR_POLL_WRITE, timeout) == 0) {
00243                 if ( _PR_PENDING_INTERRUPT(me))
00244                 {
00245                     me->flags &= ~_PR_INTERRUPT;
00246                     PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00247                 } else
00248                 {
00249                     PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00250                 }
00251                 rv = -1;
00252                 goto done;
00253             } else if (_PR_PENDING_INTERRUPT(me)) {
00254                 me->flags &= ~_PR_INTERRUPT;
00255                 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00256                 rv = -1;
00257                 goto done;
00258             }
00259         } else if ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){
00260             continue;
00261         } else {
00262             break;
00263         }
00264     }
00265 
00266     if (rv < 0) {
00267         _PR_MD_MAP_CONNECT_ERROR(err);
00268     }
00269 done:
00270     return rv;
00271 }
00272 
00273 PRInt32
00274 _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
00275 {
00276     PRInt32 rv;
00277     int one = 1;
00278 
00279     rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen);
00280 
00281     if (rv == SOCKET_ERROR)  {
00282         _PR_MD_MAP_BIND_ERROR(WSAGetLastError());
00283         return -1;
00284     }
00285 
00286     return 0;
00287 }
00288 
00289 
00290 PRInt32
00291 _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, 
00292             PRIntervalTime timeout)
00293 {
00294     PRInt32 osfd = fd->secret->md.osfd;
00295     PRThread *me = _PR_MD_CURRENT_THREAD();
00296     PRInt32 rv, err;
00297 
00298     while ((rv = recv(osfd,buf,amount,flags)) == -1) {
00299         err = WSAGetLastError();
00300               if ( err == WSAEWOULDBLOCK ) {
00301                      if (fd->secret->nonblocking) {
00302                             break;
00303                      }
00304             if (_PR_WaitForFD(osfd, PR_POLL_READ, timeout) == 0) {
00305                 if ( _PR_PENDING_INTERRUPT(me))
00306                 {
00307                     me->flags &= ~_PR_INTERRUPT;
00308                     PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00309                 } else
00310                 {
00311                     PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00312                 }
00313                 rv = -1;
00314                 goto done;
00315             } else if (_PR_PENDING_INTERRUPT(me)) {
00316                 me->flags &= ~_PR_INTERRUPT;
00317                 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00318                 rv = -1;
00319                 goto done;
00320             }
00321         } else if ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){
00322             continue;
00323         } else {
00324             break;
00325         }
00326     }
00327     if (rv < 0) {
00328         _PR_MD_MAP_RECV_ERROR(err);
00329     }
00330 done:
00331     return(rv);
00332 }
00333 
00334 PRInt32
00335 _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
00336             PRIntervalTime timeout)
00337 {
00338     PRInt32 osfd = fd->secret->md.osfd;
00339     PRThread *me = _PR_MD_CURRENT_THREAD();
00340     PRInt32 rv, err;
00341 
00342     while ((rv = send(osfd,buf,amount,flags)) == -1) {
00343         err = WSAGetLastError();
00344               if ( err == WSAEWOULDBLOCK ) {
00345                      if (fd->secret->nonblocking) {
00346                             break;
00347                      }
00348             if (_PR_WaitForFD(osfd, PR_POLL_WRITE, timeout) == 0) {
00349                 if ( _PR_PENDING_INTERRUPT(me))
00350                 {
00351                     me->flags &= ~_PR_INTERRUPT;
00352                     PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00353                 } else
00354                 {
00355                     PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00356                 }
00357                 rv = -1;
00358                 goto done;
00359             } else if (_PR_PENDING_INTERRUPT(me)) {
00360                 me->flags &= ~_PR_INTERRUPT;
00361                 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00362                 rv = -1;
00363                 goto done;
00364             }
00365         } else if ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){
00366             continue;
00367         } else {
00368             break;
00369         }
00370     }
00371     if (rv < 0) {
00372         _PR_MD_MAP_SEND_ERROR(err);
00373     }
00374 done:
00375     return rv;
00376 }
00377 
00378 PRInt32
00379 _PR_MD_SENDTO(PRFileDesc*fd, const void *buf, PRInt32 amount, PRIntn flags,
00380               const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
00381 {
00382     PRInt32 osfd = fd->secret->md.osfd;
00383     PRThread *me = _PR_MD_CURRENT_THREAD();
00384     PRInt32 rv, err;
00385 
00386     while ((rv = sendto(osfd, buf, amount, flags,
00387             (struct sockaddr *) addr, addrlen)) == -1) {
00388         err = WSAGetLastError();
00389               if ( err == WSAEWOULDBLOCK ) {
00390                      if (fd->secret->nonblocking) {
00391                             break;
00392                      }
00393             if (_PR_WaitForFD(osfd, PR_POLL_WRITE, timeout) == 0) {
00394                 if ( _PR_PENDING_INTERRUPT(me))
00395                 {
00396                     me->flags &= ~_PR_INTERRUPT;
00397                     PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00398                 } else
00399                 {
00400                     PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00401                 }
00402                 rv = -1;
00403                 goto done;
00404             } else if (_PR_PENDING_INTERRUPT(me)) {
00405                 me->flags &= ~_PR_INTERRUPT;
00406                 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00407                 rv = -1;
00408                 goto done;
00409             }
00410         } else if ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){
00411             continue;
00412         } else {
00413             break;
00414         }
00415     }
00416     if (rv < 0) {
00417         _PR_MD_MAP_SENDTO_ERROR(err);
00418     }
00419 done:
00420     return rv;
00421 }
00422 
00423 PRInt32
00424 _PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
00425                 PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
00426 {
00427     PRInt32 osfd = fd->secret->md.osfd;
00428     PRThread *me = _PR_MD_CURRENT_THREAD();
00429     PRInt32 rv, err;
00430 
00431     while ((*addrlen = PR_NETADDR_SIZE(addr)),
00432                 ((rv = recvfrom(osfd, buf, amount, flags,
00433                 (struct sockaddr FAR *) addr,(int FAR *)addrlen)) == -1)) {
00434         err = WSAGetLastError();
00435               if ( err == WSAEWOULDBLOCK ) {
00436                      if (fd->secret->nonblocking) {
00437                             break;
00438                      }
00439             if (_PR_WaitForFD(osfd, PR_POLL_READ, timeout) == 0) {
00440                 if ( _PR_PENDING_INTERRUPT(me))
00441                 {
00442                     me->flags &= ~_PR_INTERRUPT;
00443                     PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00444                 } else
00445                 {
00446                     PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00447                 }
00448                 rv = -1;
00449                 goto done;
00450             } else if (_PR_PENDING_INTERRUPT(me)) {
00451                 me->flags &= ~_PR_INTERRUPT;
00452                 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00453                 rv = -1;
00454                 goto done;
00455             }
00456         } else if ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){
00457             continue;
00458         } else {
00459             break;
00460         }
00461     }
00462     if (rv < 0) {
00463         _PR_MD_MAP_RECVFROM_ERROR(err);
00464     }
00465 done:
00466     return(rv);
00467 }
00468 
00469 PRInt32
00470 _PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
00471 {
00472     int index;
00473     int sent = 0;
00474     int rv;
00475 
00476     for (index=0; index < iov_size; index++) 
00477     {
00478 
00479 /*
00480  * XXX To be fixed
00481  * should call PR_Send
00482  */
00483 
00484         rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout);
00485         if (rv > 0) 
00486             sent += rv;
00487         if ( rv != iov[index].iov_len ) 
00488         {
00489             if (sent <= 0)
00490                 return -1;
00491             return -1;
00492         }
00493     }
00494     return sent;
00495 }
00496 
00497 PRInt32
00498 _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how)
00499 {
00500 PRInt32 rv;
00501 
00502     rv = shutdown(fd->secret->md.osfd, how);
00503     if (rv < 0)
00504         _PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError());
00505     return rv;
00506 }
00507 
00508 PRStatus
00509 _PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
00510 {
00511     PRInt32 rv;
00512 
00513     rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, (int *)len);
00514     if (rv==0)
00515         return PR_SUCCESS;
00516     else {
00517         _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError());
00518         return PR_FAILURE;
00519     }
00520 }
00521 
00522 PRStatus
00523 _PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
00524 {
00525     PRInt32 rv;
00526 
00527     rv = getpeername((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, (int*)len);
00528     if (rv==0)
00529         return PR_SUCCESS;
00530     else {
00531         _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError());
00532         return PR_FAILURE;
00533     }
00534 }
00535 
00536 PRStatus
00537 _PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
00538 {
00539     PRInt32 rv;
00540 
00541     rv = getsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, (int*)optlen);
00542     if (rv==0)
00543         return PR_SUCCESS;
00544     else {
00545         _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
00546         return PR_FAILURE;
00547     }
00548 }
00549 
00550 PRStatus
00551 _PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
00552 {
00553     PRInt32 rv;
00554 
00555     rv = setsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen);
00556     if (rv==0)
00557         return PR_SUCCESS;
00558     else {
00559         _PR_MD_MAP_SETSOCKOPT_ERROR(WSAGetLastError());
00560         return PR_FAILURE;
00561     }
00562 }
00563 
00564 void
00565 _PR_MD_MAKE_NONBLOCK(PRFileDesc *f)
00566 {
00567     return; // do nothing!
00568 }
00569 
00570 /*
00571 ** Wait for I/O on a single descriptor.
00572  *
00573  * return 0, if timed-out, else return 1
00574 */
00575 PRInt32
00576 _PR_WaitForFD(PRInt32 osfd, PRUintn how, PRIntervalTime timeout)
00577 {
00578     _PRWin16PollDesc *pd;
00579     PRPollQueue      *pq;
00580     PRIntn is;
00581     PRInt32 rv = 1;
00582     PRThread *me = _PR_MD_CURRENT_THREAD();
00583 
00584     PR_ASSERT(!(me->flags & _PR_IDLE_THREAD));
00585 
00586     pd = &me->md.thr_pd;
00587     pq = &me->md.thr_pq;
00588     if (timeout == PR_INTERVAL_NO_WAIT) return 0;
00589 
00590     pd->osfd = osfd;
00591     pd->in_flags = how;
00592     pd->out_flags = 0;
00593 
00594     pq->pds = pd;
00595     pq->npds = 1;
00596 
00597     _PR_INTSOFF(is);
00598     _PR_MD_IOQ_LOCK();
00599     _PR_THREAD_LOCK(me);
00600 
00601        if (_PR_PENDING_INTERRUPT(me)) {
00602        _PR_THREAD_UNLOCK(me);
00603        _PR_MD_IOQ_UNLOCK();
00604               return 0;
00605        }
00606 
00607     pq->thr = me;
00608     pq->on_ioq = PR_TRUE;
00609     pq->timeout = timeout;
00610     _PR_ADD_TO_IOQ((*pq), me->cpu);
00611     if (how == PR_POLL_READ) {
00612         FD_SET(osfd, &_PR_FD_READ_SET(me->cpu));
00613         (_PR_FD_READ_CNT(me->cpu))[osfd]++;
00614     } else if (how == PR_POLL_WRITE) {
00615         FD_SET(osfd, &_PR_FD_WRITE_SET(me->cpu));
00616         (_PR_FD_WRITE_CNT(me->cpu))[osfd]++;
00617     } else {
00618         FD_SET(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
00619         (_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]++;
00620     }
00621     if (_PR_IOQ_MAX_OSFD(me->cpu) < osfd)
00622         _PR_IOQ_MAX_OSFD(me->cpu) = osfd;
00623     if (_PR_IOQ_TIMEOUT(me->cpu) > timeout)
00624         _PR_IOQ_TIMEOUT(me->cpu) = timeout;
00625         
00626     _PR_THREAD_LOCK(me);
00627 
00628     _PR_SLEEPQ_LOCK(me->cpu);
00629     _PR_ADD_SLEEPQ(me, timeout);
00630     me->state = _PR_IO_WAIT;
00631     me->io_pending = PR_TRUE;
00632     me->io_suspended = PR_FALSE;
00633     _PR_SLEEPQ_UNLOCK(me->cpu);
00634     _PR_THREAD_UNLOCK(me);
00635     _PR_MD_IOQ_UNLOCK();
00636 
00637     _PR_MD_WAIT(me, timeout);
00638     me->io_pending = PR_FALSE;
00639     me->io_suspended = PR_FALSE;
00640 
00641     /*
00642     ** If we timed out the pollq might still be on the ioq. Remove it
00643     ** before continuing.
00644     */
00645     if (pq->on_ioq) {
00646         _PR_INTSOFF(is);
00647         _PR_MD_IOQ_LOCK();
00648     /*
00649      * Need to check pq.on_ioq again
00650      */
00651         if (pq->on_ioq) {
00652             PR_REMOVE_LINK(&pq->links);
00653             if (how == PR_POLL_READ) {
00654                 if ((--(_PR_FD_READ_CNT(me->cpu))[osfd]) == 0)
00655                     FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu));
00656             
00657             } else if (how == PR_POLL_WRITE) {
00658                 if ((--(_PR_FD_WRITE_CNT(me->cpu))[osfd]) == 0)
00659                     FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu));
00660             } else {
00661                 if ((--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]) == 0)
00662                     FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
00663             }
00664         }
00665         _PR_MD_IOQ_UNLOCK();
00666         rv = 0;
00667     }
00668     _PR_FAST_INTSON(is);
00669    return(rv);
00670 }
00671 
00672 /*
00673  * Unblock threads waiting for I/O
00674  *    used when interrupting threads
00675  *
00676  * NOTE: The thread lock should held when this function is called.
00677  * On return, the thread lock is released.
00678  */
00679 void _PR_Unblock_IO_Wait(PRThread *thr)
00680 {
00681     int pri = thr->priority;
00682     _PRCPU *cpu = thr->cpu;
00683  
00684     PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ));
00685     _PR_SLEEPQ_LOCK(cpu);
00686     _PR_DEL_SLEEPQ(thr, PR_TRUE);
00687     _PR_SLEEPQ_UNLOCK(cpu);
00688 
00689     PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD));
00690     thr->state = _PR_RUNNABLE;
00691     _PR_RUNQ_LOCK(cpu);
00692     _PR_ADD_RUNQ(thr, cpu, pri);
00693     _PR_RUNQ_UNLOCK(cpu);
00694     _PR_THREAD_UNLOCK(thr);
00695     _PR_MD_WAKEUP_WAITER(thr);
00696 }
00697 
00698 /*
00699 ** Scan through io queue and find any bad fd's that triggered the error
00700 ** from _MD_SELECT
00701 */
00702 static void FindBadFDs(void)
00703 {
00704     PRCList *q;
00705     PRThread *me = _MD_CURRENT_THREAD();
00706     int sockOpt;
00707     int sockOptLen = sizeof(sockOpt);
00708 
00709     PR_ASSERT(!_PR_IS_NATIVE_THREAD(me));
00710     q = (_PR_IOQ(me->cpu)).next;
00711     _PR_IOQ_MAX_OSFD(me->cpu) = -1;
00712     _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT;
00713     while (q != &_PR_IOQ(me->cpu)) {
00714         PRPollQueue *pq = _PR_POLLQUEUE_PTR(q);
00715         PRBool notify = PR_FALSE;
00716         _PRWin16PollDesc *pds = pq->pds;
00717         _PRWin16PollDesc *epds = pds + pq->npds;
00718         PRInt32 pq_max_osfd = -1;
00719 
00720         q = q->next;
00721         for (; pds < epds; pds++) {
00722             PRInt32 osfd = pds->osfd;
00723             pds->out_flags = 0;
00724             PR_ASSERT(osfd >= 0 || pds->in_flags == 0);
00725             if (pds->in_flags == 0) {
00726                 continue;  /* skip this fd */
00727             }
00728             if ( getsockopt(osfd, 
00729                     (int)SOL_SOCKET, 
00730                     SO_TYPE, 
00731                     (char*)&sockOpt, 
00732                     &sockOptLen) == SOCKET_ERROR ) 
00733             {
00734                 if ( WSAGetLastError() == WSAENOTSOCK )
00735                 {
00736                     PR_LOG(_pr_io_lm, PR_LOG_MAX,
00737                         ("file descriptor %d is bad", osfd));
00738                     pds->out_flags = PR_POLL_NVAL;
00739                     notify = PR_TRUE;
00740                 }
00741             }
00742             if (osfd > pq_max_osfd) {
00743                 pq_max_osfd = osfd;
00744             }
00745         }
00746 
00747         if (notify) {
00748             PRIntn pri;
00749             PR_REMOVE_LINK(&pq->links);
00750             pq->on_ioq = PR_FALSE;
00751 
00752             /*
00753          * Decrement the count of descriptors for each desciptor/event
00754          * because this I/O request is being removed from the
00755          * ioq
00756          */
00757             pds = pq->pds;
00758             for (; pds < epds; pds++) {
00759                 PRInt32 osfd = pds->osfd;
00760                 PRInt16 in_flags = pds->in_flags;
00761                 PR_ASSERT(osfd >= 0 || in_flags == 0);
00762                 if (in_flags & PR_POLL_READ) {
00763                     if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0)
00764                         FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu));
00765                 }
00766                 if (in_flags & PR_POLL_WRITE) {
00767                     if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0)
00768                         FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu));
00769                 }
00770                 if (in_flags & PR_POLL_EXCEPT) {
00771                     if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0)
00772                         FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
00773                 }
00774             }
00775 
00776             _PR_THREAD_LOCK(pq->thr);
00777             if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {
00778                 _PRCPU *cpu = pq->thr->cpu;
00779                 
00780                 _PR_SLEEPQ_LOCK(pq->thr->cpu);
00781                 _PR_DEL_SLEEPQ(pq->thr, PR_TRUE);
00782                 _PR_SLEEPQ_UNLOCK(pq->thr->cpu);
00783 
00784                 pri = pq->thr->priority;
00785                 pq->thr->state = _PR_RUNNABLE;
00786 
00787                 _PR_RUNQ_LOCK(cpu);
00788                 _PR_ADD_RUNQ(pq->thr, cpu, pri);
00789                 _PR_RUNQ_UNLOCK(cpu);
00790             }
00791             _PR_THREAD_UNLOCK(pq->thr);
00792         } else {
00793             if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu))
00794                 _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout;
00795             if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd)
00796                 _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd;
00797         }
00798     }
00799 } /* end FindBadFDs() */
00800 
00801 /*
00802 ** Called by the scheduler when there is nothing to do. This means that
00803 ** all threads are blocked on some monitor somewhere.
00804 **
00805 ** Pause the current CPU. longjmp to the cpu's pause stack
00806 */
00807 PRInt32 _PR_MD_PAUSE_CPU( PRIntervalTime ticks)
00808 {
00809     PRThread *me = _MD_CURRENT_THREAD();
00810     struct timeval timeout, *tvp;
00811     fd_set r, w, e;
00812     fd_set *rp, *wp, *ep;
00813     PRInt32 max_osfd, nfd;
00814     PRInt32 rv;
00815     PRCList *q;
00816     PRUint32 min_timeout;
00817 
00818     PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
00819 
00820     /*
00821      * assigment of fd_sets
00822      */
00823     r = _PR_FD_READ_SET(me->cpu);
00824     w = _PR_FD_WRITE_SET(me->cpu);
00825     e = _PR_FD_EXCEPTION_SET(me->cpu);
00826 
00827     rp = &r;
00828     wp = &w;
00829     ep = &e;
00830 
00831     max_osfd = _PR_IOQ_MAX_OSFD(me->cpu) + 1;
00832     min_timeout = _PR_IOQ_TIMEOUT(me->cpu);
00833     /*
00834     ** Compute the minimum timeout value: make it the smaller of the
00835     ** timeouts specified by the i/o pollers or the timeout of the first
00836     ** sleeping thread.
00837     */
00838     q = _PR_SLEEPQ(me->cpu).next;
00839 
00840     if (q != &_PR_SLEEPQ(me->cpu)) {
00841         PRThread *t = _PR_THREAD_PTR(q);
00842 
00843         if (t->sleep < min_timeout) {
00844             min_timeout = t->sleep;
00845         }
00846     }
00847     if (min_timeout > ticks) {
00848         min_timeout = ticks;
00849     }
00850 
00851     if (min_timeout == PR_INTERVAL_NO_TIMEOUT) {
00852         tvp = NULL;
00853     } else {
00854         timeout.tv_sec = PR_IntervalToSeconds(min_timeout);
00855         timeout.tv_usec = PR_IntervalToMicroseconds(min_timeout)
00856             % PR_USEC_PER_SEC;
00857         tvp = &timeout;
00858     }
00859 
00860     _PR_MD_IOQ_UNLOCK();
00861     _MD_CHECK_FOR_EXIT();
00862     /*
00863      * check for i/o operations
00864      */
00865 
00866     nfd = _MD_SELECT(max_osfd, rp, wp, ep, tvp);
00867 
00868     _MD_CHECK_FOR_EXIT();
00869     _PR_MD_IOQ_LOCK();
00870     /*
00871     ** Notify monitors that are associated with the selected descriptors.
00872     */
00873     if (nfd > 0) {
00874         q = _PR_IOQ(me->cpu).next;
00875         _PR_IOQ_MAX_OSFD(me->cpu) = -1;
00876         _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT;
00877         while (q != &_PR_IOQ(me->cpu)) {
00878             PRPollQueue *pq = _PR_POLLQUEUE_PTR(q);
00879             PRBool notify = PR_FALSE;
00880             _PRWin16PollDesc *pds = pq->pds;
00881             _PRWin16PollDesc *epds = pds + pq->npds;
00882             PRInt32 pq_max_osfd = -1;
00883 
00884             q = q->next;
00885             for (; pds < epds; pds++) {
00886                 PRInt32 osfd = pds->osfd;
00887                 PRInt16 in_flags = pds->in_flags;
00888                 PRInt16 out_flags = 0;
00889                 PR_ASSERT(osfd >= 0 || in_flags == 0);
00890                 if ((in_flags & PR_POLL_READ) && FD_ISSET(osfd, rp)) {
00891                     out_flags |= PR_POLL_READ;
00892                 }
00893                 if ((in_flags & PR_POLL_WRITE) && FD_ISSET(osfd, wp)) {
00894                     out_flags |= PR_POLL_WRITE;
00895                 }
00896                 if ((in_flags & PR_POLL_EXCEPT) && FD_ISSET(osfd, ep)) {
00897                     out_flags |= PR_POLL_EXCEPT;
00898                 }
00899                 pds->out_flags = out_flags;
00900                 if (out_flags) {
00901                     notify = PR_TRUE;
00902                 }
00903                 if (osfd > pq_max_osfd) {
00904                     pq_max_osfd = osfd;
00905                 }
00906             }
00907             if (notify == PR_TRUE) {
00908                 PRIntn pri;
00909                 PRThread *thred;
00910 
00911                 PR_REMOVE_LINK(&pq->links);
00912                 pq->on_ioq = PR_FALSE;
00913 
00914                 /*
00915                  * Decrement the count of descriptors for each desciptor/event
00916                  * because this I/O request is being removed from the
00917                  * ioq
00918                  */
00919                 pds = pq->pds;
00920                 for (; pds < epds; pds++) {
00921                     PRInt32 osfd = pds->osfd;
00922                     PRInt16 in_flags = pds->in_flags;
00923                     PR_ASSERT(osfd >= 0 || in_flags == 0);
00924                     if (in_flags & PR_POLL_READ) {
00925                         if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0)
00926                             FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu));
00927                     }
00928                     if (in_flags & PR_POLL_WRITE) {
00929                         if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0)
00930                             FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu));
00931                     }
00932                     if (in_flags & PR_POLL_EXCEPT) {
00933                         if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0)
00934                             FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
00935                     }
00936                 }
00937                  thred = pq->thr;
00938                 _PR_THREAD_LOCK(thred);
00939                 if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {
00940                     _PRCPU *cpu = thred->cpu;
00941                     _PR_SLEEPQ_LOCK(pq->thr->cpu);
00942                     _PR_DEL_SLEEPQ(pq->thr, PR_TRUE);
00943                     _PR_SLEEPQ_UNLOCK(pq->thr->cpu);
00944 
00945                     pri = pq->thr->priority;
00946                     pq->thr->state = _PR_RUNNABLE;
00947 
00948                     pq->thr->cpu = cpu;
00949                     _PR_RUNQ_LOCK(cpu);
00950                     _PR_ADD_RUNQ(pq->thr, cpu, pri);
00951                     _PR_RUNQ_UNLOCK(cpu);
00952                     if (_pr_md_idle_cpus > 1)
00953                         _PR_MD_WAKEUP_WAITER(thred);
00954                 }
00955                 _PR_THREAD_UNLOCK(thred);
00956             } else {
00957                 if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu))
00958                     _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout;
00959                 if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd)
00960                     _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd;
00961             }
00962         }
00963     } else if (nfd < 0) {
00964         if ( WSAGetLastError() == WSAENOTSOCK )
00965         {
00966             FindBadFDs();
00967         } else {
00968             PR_LOG(_pr_io_lm, PR_LOG_MAX, ("select() failed with errno %d",
00969                 errno));
00970         }
00971     }
00972     _PR_MD_IOQ_UNLOCK();
00973     return(0);
00974     
00975 } /* end _PR_MD_PAUSE_CPU() */
00976 
00977 
00978 /*
00979 ** _MD_pr_poll() -- Implement MD polling
00980 **
00981 ** The function was snatched (re-used) from the unix implementation.
00982 ** 
00983 ** The native thread stuff was deleted.
00984 ** The pollqueue is instantiated on the mdthread structure
00985 ** to keep the stack frame from being corrupted when this
00986 ** thread is waiting on the poll.
00987 **
00988 */
00989 extern PRInt32 
00990 _MD_PR_POLL(PRPollDesc *pds, PRIntn npds,
00991                         PRIntervalTime timeout)
00992 {
00993     PRPollDesc *pd, *epd;
00994     PRInt32 n, err, pdcnt;
00995     PRIntn is;
00996     _PRWin16PollDesc *spds, *spd;
00997     PRThread *me = _PR_MD_CURRENT_THREAD();
00998     PRPollQueue *pq;
00999 
01000     pq = &me->md.thr_pq;
01001     
01002     /*
01003      * XXX
01004      *   PRPollDesc has a PRFileDesc field, fd, while the IOQ
01005      *   is a list of PRPollQueue structures, each of which contains
01006      *   a _PRWin16PollDesc. A _PRWin16PollDesc struct contains
01007      *   the OS file descriptor, osfd, and not a PRFileDesc.
01008      *   So, we have allocate memory for _PRWin16PollDesc structures,
01009      *   copy the flags information from the pds list and have pq
01010      *   point to this list of _PRWin16PollDesc structures.
01011      *
01012      *   It would be better if the memory allocation can be avoided.
01013      */
01014 
01015     spds = (_PRWin16PollDesc*) PR_MALLOC(npds * sizeof(_PRWin16PollDesc));
01016     if (!spds) {
01017         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
01018            return -1;
01019     }
01020     spd = spds;
01021 
01022     _PR_INTSOFF(is);
01023     _PR_MD_IOQ_LOCK();
01024        _PR_THREAD_LOCK(me);
01025 
01026     if (_PR_PENDING_INTERRUPT(me)) {
01027         me->flags &= ~_PR_INTERRUPT;
01028         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
01029         _PR_THREAD_UNLOCK(me);
01030         _PR_MD_IOQ_UNLOCK();
01031         PR_DELETE(spds);
01032            return -1;
01033     }
01034 
01035     pdcnt = 0;
01036     for (pd = pds, epd = pd + npds; pd < epd; pd++) {
01037         PRInt32 osfd;
01038         PRInt16 in_flags = pd->in_flags;
01039         PRFileDesc *bottom = pd->fd;
01040 
01041         if ((NULL == bottom) || (in_flags == 0)) {
01042             continue;
01043         }
01044         while (bottom->lower != NULL) {
01045             bottom = bottom->lower;
01046         }
01047         osfd = bottom->secret->md.osfd;
01048 
01049         PR_ASSERT(osfd >= 0 || in_flags == 0);
01050 
01051         spd->osfd = osfd;
01052         spd->in_flags = pd->in_flags;
01053         spd++;
01054         pdcnt++;
01055 
01056         if (in_flags & PR_POLL_READ)  {
01057             FD_SET(osfd, &_PR_FD_READ_SET(me->cpu));
01058             _PR_FD_READ_CNT(me->cpu)[osfd]++;
01059         }
01060         if (in_flags & PR_POLL_WRITE) {
01061             FD_SET(osfd, &_PR_FD_WRITE_SET(me->cpu));
01062             (_PR_FD_WRITE_CNT(me->cpu))[osfd]++;
01063         }
01064         if (in_flags & PR_POLL_EXCEPT) {
01065             FD_SET(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
01066             (_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]++;
01067         }
01068         if (osfd > _PR_IOQ_MAX_OSFD(me->cpu))
01069             _PR_IOQ_MAX_OSFD(me->cpu) = osfd;
01070     }
01071     if (timeout < _PR_IOQ_TIMEOUT(me->cpu))
01072         _PR_IOQ_TIMEOUT(me->cpu) = timeout;
01073 
01074 
01075     pq->pds = spds;
01076     pq->npds = pdcnt;
01077 
01078     pq->thr = me;
01079     pq->on_ioq = PR_TRUE;
01080     pq->timeout = timeout;
01081     _PR_ADD_TO_IOQ((*pq), me->cpu);
01082     _PR_SLEEPQ_LOCK(me->cpu);
01083     _PR_ADD_SLEEPQ(me, timeout);
01084     me->state = _PR_IO_WAIT;
01085     me->io_pending = PR_TRUE;
01086     me->io_suspended = PR_FALSE;
01087     _PR_SLEEPQ_UNLOCK(me->cpu);
01088     _PR_THREAD_UNLOCK(me);
01089     _PR_MD_IOQ_UNLOCK();
01090 
01091     _PR_MD_WAIT(me, timeout);
01092 
01093     me->io_pending = PR_FALSE;
01094     me->io_suspended = PR_FALSE;
01095 
01096     /*
01097      * Copy the out_flags from the _PRWin16PollDesc structures to the
01098      * user's PRPollDesc structures and free the allocated memory
01099      */
01100     spd = spds;
01101     for (pd = pds, epd = pd + npds; pd < epd; pd++) {
01102         if ((NULL == pd->fd) || (pd->in_flags == 0)) {
01103             pd->out_flags = 0;
01104             continue;
01105         }
01106         pd->out_flags = spd->out_flags;
01107         spd++;
01108     }
01109     PR_DELETE(spds);
01110 
01111     /*
01112     ** If we timed out the pollq might still be on the ioq. Remove it
01113     ** before continuing.
01114     */
01115     if (pq->on_ioq) {
01116         _PR_INTSOFF(is);
01117         _PR_MD_IOQ_LOCK();
01118         /*
01119          * Need to check pq.on_ioq again
01120          */
01121         if (pq->on_ioq == PR_TRUE) {
01122             PR_REMOVE_LINK(&pq->links);
01123             for (pd = pds, epd = pd + npds; pd < epd; pd++) {
01124                 PRInt32 osfd;
01125                 PRInt16 in_flags = pd->in_flags;
01126                 PRFileDesc *bottom = pd->fd;
01127 
01128                 if ((NULL == bottom) || (in_flags == 0)) {
01129                     continue;
01130                 }
01131                 while (bottom->lower != NULL) {
01132                     bottom = bottom->lower;
01133                 }
01134                 osfd = bottom->secret->md.osfd;
01135                 PR_ASSERT(osfd >= 0 || in_flags == 0);
01136                 if (in_flags & PR_POLL_READ)  {
01137                     if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0)
01138                         FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu));
01139                 }
01140                 if (in_flags & PR_POLL_WRITE) {
01141                     if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0)
01142                             FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu));
01143                 }
01144                 if (in_flags & PR_POLL_EXCEPT) {
01145                     if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0)
01146                             FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
01147                 }
01148             }
01149         }
01150         _PR_MD_IOQ_UNLOCK();
01151         _PR_INTSON(is);
01152     }
01153     if (_PR_PENDING_INTERRUPT(me)) {
01154         me->flags &= ~_PR_INTERRUPT;
01155         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
01156            return -1;
01157     } else {
01158         n = 0;
01159         if (pq->on_ioq == PR_FALSE) {
01160             /* Count the number of ready descriptors */
01161             while (--npds >= 0) {
01162             if (pds->out_flags) {
01163                 n++;
01164             }
01165                 pds++;
01166             }
01167         }
01168         return n;
01169     }
01170 } /* end _MD_pr_poll() */