Main Page | File List | Globals

src/select.c

Go to the documentation of this file.
00001 /*
00002      This file is part of PlibC.
00003      (C) 2005 Nils Durner (and other contributing authors)
00004 
00005            This library is free software; you can redistribute it and/or
00006            modify it under the terms of the GNU Lesser General Public
00007            License as published by the Free Software Foundation; either
00008            version 2.1 of the License, or (at your option) any later version.
00009         
00010            This library is distributed in the hope that it will be useful,
00011            but WITHOUT ANY WARRANTY; without even the implied warranty of
00012            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013            Lesser General Public License for more details.
00014         
00015            You should have received a copy of the GNU Lesser General Public
00016            License along with this library; if not, write to the Free Software
00017            Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 */
00019 
00033 #include "plibc_private.h"
00034 
00047 int _win_select(int max_fd, fd_set * rfds, fd_set * wfds, fd_set * efds,
00048                 const struct timeval *tv)
00049 {
00050   DWORD ms_total, limit;
00051   HANDLE handles[MAXIMUM_WAIT_OBJECTS], hPipes[MAXIMUM_WAIT_OBJECTS];
00052   int handle_slot_to_fd[MAXIMUM_WAIT_OBJECTS];
00053   int n_handles, i, iPipes;
00054   fd_set sock_read, sock_write, sock_except;
00055   fd_set aread, awrite, aexcept;
00056   int sock_max_fd;
00057   struct timeval tvslice;
00058   int retcode;
00059 
00060 #define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))
00061 
00062   n_handles = 0;
00063   sock_max_fd = -1;
00064   iPipes = 0;
00065 
00066   /* calculate how long we need to wait in milliseconds */
00067   if(tv == NULL)
00068     ms_total = INFINITE;
00069   else
00070   {
00071     ms_total = tv->tv_sec * 1000;
00072     ms_total += tv->tv_usec / 1000;
00073   }
00074 
00075   /* select() may be used as a portable way to sleep */
00076   if (!(rfds || wfds || efds))
00077   {
00078     Sleep(ms_total);
00079 
00080     return 0;
00081   }
00082 
00083   FD_ZERO(&sock_read);
00084   FD_ZERO(&sock_write);
00085   FD_ZERO(&sock_except);
00086 
00087   /* build an array of handles for non-sockets */
00088   for(i = 0; i < max_fd; i++)
00089   {
00090     if(SAFE_FD_ISSET(i, rfds) || SAFE_FD_ISSET(i, wfds) ||
00091        SAFE_FD_ISSET(i, efds))
00092     {
00093       unsigned long ulVal;
00094 
00095       if (ioctlsocket(i, FIONREAD, &ulVal) != SOCKET_ERROR && _get_osfhandle(i) == -1) 
00096       {
00097         /* socket */
00098         if(SAFE_FD_ISSET(i, rfds))
00099           FD_SET(i, &sock_read);
00100 
00101         if(SAFE_FD_ISSET(i, wfds))
00102           FD_SET(i, &sock_write);
00103 
00104         if(SAFE_FD_ISSET(i, efds))
00105           FD_SET(i, &sock_except);
00106 
00107         if(i > sock_max_fd)
00108           sock_max_fd = i;
00109       }
00110       else
00111       {
00112         if (GetFileType((HANDLE) i) == FILE_TYPE_PIPE)
00113           hPipes[iPipes++] = (HANDLE) i;  /* Pipe */
00114         else
00115         {
00116           handles[n_handles] = (HANDLE) _get_osfhandle(i);
00117           if ((DWORD) handles[n_handles] == 0xffffffff)
00118             handles[n_handles] = (HANDLE) i;
00119           handle_slot_to_fd[n_handles] = i;
00120           n_handles++;
00121         }
00122       }
00123     }
00124   }
00125 
00126   if((n_handles == 0) && (iPipes == 0))
00127   {
00128     /* plain sockets only - let winsock handle the whole thing */
00129     return select(max_fd, rfds, wfds, efds, tv);
00130   }
00131 
00132   /* mixture of handles and sockets; lets multiplex between
00133    * winsock and waiting on the handles */
00134 
00135   FD_ZERO(&aread);
00136   FD_ZERO(&awrite);
00137   FD_ZERO(&aexcept);
00138 
00139   limit = GetTickCount() + ms_total;
00140   do
00141   {
00142     retcode = 0;
00143 
00144     if(sock_max_fd >= 0)
00145     {
00146       /* overwrite the zero'd sets here; the select call
00147        * will clear those that are not active */
00148       aread = sock_read;
00149       awrite = sock_write;
00150       aexcept = sock_except;
00151 
00152       tvslice.tv_sec = 0;
00153       tvslice.tv_usec = 100000;
00154 
00155       if ((retcode = select(sock_max_fd + 1, &aread, &awrite, &aexcept,
00156                             &tvslice)) == SOCKET_ERROR)
00157       {
00158         SetErrnoFromWinsockError(WSAGetLastError());
00159 
00160         return -1;
00161       }
00162     }
00163 
00164     if(n_handles > 0)
00165     {
00166       /* check handles */
00167       DWORD wret;
00168 
00169       wret =
00170         MsgWaitForMultipleObjects(n_handles, handles, FALSE,
00171                                   retcode > 0 ? 0 : 100, QS_ALLEVENTS);
00172 
00173       if(wret == WAIT_TIMEOUT)
00174       {
00175         /* set retcode to 0; this is the default.
00176          * select() may have set it to something else,
00177          * in which case we leave it alone, so this branch
00178          * does nothing */
00179         ;
00180       }
00181       else if(wret == WAIT_FAILED)
00182       {
00183         SetErrnoFromWinError(GetLastError());
00184 
00185         return -1;
00186       }
00187       else
00188       {
00189         for(i = 0; i < n_handles; i++)
00190         {
00191           if(WAIT_OBJECT_0 == WaitForSingleObject(handles[i], 0))
00192           {
00193             if(SAFE_FD_ISSET(handle_slot_to_fd[i], rfds))
00194             {
00195               FD_SET(handle_slot_to_fd[i], &aread);
00196             }
00197 
00198             if(SAFE_FD_ISSET(handle_slot_to_fd[i], wfds))
00199               FD_SET(handle_slot_to_fd[i], &awrite);
00200 
00201             if(SAFE_FD_ISSET(handle_slot_to_fd[i], efds))
00202               FD_SET(handle_slot_to_fd[i], &aexcept);
00203 
00204             retcode++;
00205           }
00206         }
00207       }
00208     }
00209 
00210     /* Poll Pipes */
00211     for(i = 0; i < iPipes; i++)
00212     {
00213       DWORD dwBytes;
00214       if(SAFE_FD_ISSET(hPipes[i], rfds))
00215       {
00216             if (! PeekNamedPipe(hPipes[i], NULL, 0, NULL, &dwBytes, NULL))
00217             {
00218               retcode = -1;
00219               SetErrnoFromWinError(GetLastError());
00220             }
00221             else if (dwBytes)
00222             {
00223               FD_SET((int) hPipes[i], &aread);
00224               retcode++;
00225             }
00226       }
00227       else if (SAFE_FD_ISSET(hPipes[i], wfds) || SAFE_FD_ISSET(hPipes[i], efds))
00228       {
00229         errno = ENOSYS;
00230         return -1;  /* Not implemented */
00231       }
00232     }
00233   }
00234   while(retcode == 0 && (ms_total == INFINITE || GetTickCount() < limit));
00235 
00236   if(rfds)
00237     *rfds = aread;
00238 
00239   if(wfds)
00240     *wfds = awrite;
00241 
00242   if(efds)
00243     *efds = aexcept;
00244 
00245   return retcode;
00246 }

Generated on Sun Sep 4 11:16:47 2005 for PlibC by  doxygen 1.4.2