1 /***********************************************************************/
5 /* Contributed by Sylvain Le Gall for Lexifi */
7 /* Copyright 2008 Institut National de Recherche en Informatique et */
8 /* en Automatique. All rights reserved. This file is distributed */
9 /* under the terms of the GNU Library General Public License, with */
10 /* the special exception on linking described in file ../../LICENSE. */
12 /***********************************************************************/
14 /* $Id: select.c 9143 2008-11-26 13:27:21Z xleroy $ */
22 #include "unixsupport.h"
24 #include "winworker.h"
27 /* This constant define the maximum number of objects that
28 * can be handle by a SELECTDATA.
29 * It takes the following parameters into account:
30 * - limitation on number of objects is mostly due to limitation
31 * a WaitForMultipleObjects
32 * - there is always an event "hStop" to watch
34 * This lead to pick the following value as the biggest possible
37 #define MAXIMUM_SELECT_OBJECTS (MAXIMUM_WAIT_OBJECTS - 1)
39 /* Manage set of handle */
40 typedef struct _SELECTHANDLESET {
46 typedef SELECTHANDLESET *LPSELECTHANDLESET;
48 void handle_set_init (LPSELECTHANDLESET hds, LPHANDLE lpHdl, DWORD max)
56 /* Set to invalid value every entry of the handle */
57 for (i = 0; i < hds->nMax; i++)
59 hds->lpHdl[i] = INVALID_HANDLE_VALUE;
63 void handle_set_add (LPSELECTHANDLESET hds, HANDLE hdl)
65 LPSELECTHANDLESET res;
67 if (hds->nLast < hds->nMax)
69 hds->lpHdl[hds->nLast] = hdl;
74 dbug_print("Adding handle %x to set %x", hdl, hds);
78 BOOL handle_set_mem (LPSELECTHANDLESET hds, HANDLE hdl)
84 for (i = 0; !res && i < hds->nLast; i++)
86 res = (hds->lpHdl[i] == hdl);
92 void handle_set_reset (LPSELECTHANDLESET hds)
96 for (i = 0; i < hds->nMax; i++)
98 hds->lpHdl[i] = INVALID_HANDLE_VALUE;
105 /* Data structure for handling select */
107 typedef enum _SELECTHANDLETYPE {
108 SELECT_HANDLE_NONE = 0,
110 SELECT_HANDLE_CONSOLE,
112 SELECT_HANDLE_SOCKET,
115 typedef enum _SELECTMODE {
116 SELECT_MODE_NONE = 0,
122 typedef enum _SELECTSTATE {
123 SELECT_STATE_NONE = 0,
124 SELECT_STATE_INITFAILED,
126 SELECT_STATE_SIGNALED
129 typedef enum _SELECTTYPE {
130 SELECT_TYPE_NONE = 0,
131 SELECT_TYPE_STATIC, /* Result is known without running anything */
132 SELECT_TYPE_CONSOLE_READ, /* Reading data on console */
133 SELECT_TYPE_PIPE_READ, /* Reading data on pipe */
134 SELECT_TYPE_SOCKET /* Classic select */
137 /* Data structure for results */
138 typedef struct _SELECTRESULT {
144 typedef SELECTRESULT *LPSELECTRESULT;
146 /* Data structure for query */
147 typedef struct _SELECTQUERY {
154 typedef SELECTQUERY *LPSELECTQUERY;
156 typedef struct _SELECTDATA {
159 SELECTRESULT aResults[MAXIMUM_SELECT_OBJECTS];
161 /* Data following are dedicated to APC like call, they
162 will be initialized if required.
164 WORKERFUNC funcWorker;
165 SELECTQUERY aQueries[MAXIMUM_SELECT_OBJECTS];
172 typedef SELECTDATA *LPSELECTDATA;
174 /* Get error status if associated condition is false */
175 static BOOL check_error(LPSELECTDATA lpSelectData, BOOL bFailed)
177 if (bFailed && lpSelectData->nError == 0)
179 lpSelectData->EState = SELECT_STATE_ERROR;
180 lpSelectData->nError = GetLastError();
185 /* Create data associated with a select operation */
186 LPSELECTDATA select_data_new (LPSELECTDATA lpSelectData, SELECTTYPE EType)
188 /* Allocate the data structure */
192 if (!HeapLock(GetProcessHeap()))
194 win32_maperr(GetLastError());
195 uerror("select", Nothing);
197 res = (LPSELECTDATA)HeapAlloc(GetProcessHeap(), 0, sizeof(SELECTDATA));
198 HeapUnlock(GetProcessHeap());
200 /* Init common data */
201 list_init((LPLIST)res);
202 list_next_set((LPLIST)res, (LPLIST)lpSelectData);
204 res->nResultsCount = 0;
207 /* Data following are dedicated to APC like call, they
208 will be initialized if required. For now they are set to
211 res->funcWorker = NULL;
212 res->nQueriesCount = 0;
213 res->EState = SELECT_STATE_NONE;
215 res->lpWorker = NULL;
220 /* Free select data */
221 void select_data_free (LPSELECTDATA lpSelectData)
226 dbug_print("Freeing data of %x", lpSelectData);
229 /* Free APC related data, if they exists */
230 if (lpSelectData->lpWorker != NULL)
232 worker_job_finish(lpSelectData->lpWorker);
233 lpSelectData->lpWorker = NULL;
236 /* Make sure results/queries cannot be accessed */
237 lpSelectData->nResultsCount = 0;
238 lpSelectData->nQueriesCount = 0;
240 if (!HeapLock(GetProcessHeap()))
242 win32_maperr(GetLastError());
243 uerror("select_data_free", Nothing);
245 HeapFree(GetProcessHeap(), 0, lpSelectData);
246 HeapUnlock(GetProcessHeap());
249 /* Add a result to select data, return zero if something goes wrong. */
250 DWORD select_data_result_add (LPSELECTDATA lpSelectData, SELECTMODE EMode, LPVOID lpOrig)
256 if (lpSelectData->nResultsCount < MAXIMUM_SELECT_OBJECTS)
258 i = lpSelectData->nResultsCount;
259 lpSelectData->aResults[i].EMode = EMode;
260 lpSelectData->aResults[i].lpOrig = lpOrig;
261 lpSelectData->nResultsCount++;
268 /* Add a query to select data, return zero if something goes wrong */
269 DWORD select_data_query_add (LPSELECTDATA lpSelectData, SELECTMODE EMode, HANDLE hFileDescr, LPVOID lpOrig)
275 if (lpSelectData->nQueriesCount < MAXIMUM_SELECT_OBJECTS)
277 i = lpSelectData->nQueriesCount;
278 lpSelectData->aQueries[i].EMode = EMode;
279 lpSelectData->aQueries[i].hFileDescr = hFileDescr;
280 lpSelectData->aQueries[i].lpOrig = lpOrig;
281 lpSelectData->nQueriesCount++;
288 /* Search for a job that has available query slots and that match provided type.
289 * If none is found, create a new one. Return the corresponding SELECTDATA, and
290 * update provided SELECTDATA head, if required.
292 LPSELECTDATA select_data_job_search (LPSELECTDATA *lppSelectData, SELECTTYPE EType)
300 dbug_print("Searching an available job for type %d", EType);
302 res = *lppSelectData;
307 && res->nQueriesCount < MAXIMUM_SELECT_OBJECTS
311 res = LIST_NEXT(LPSELECTDATA, res);
314 /* No matching job found, create one */
318 dbug_print("No job for type %d found, create one", EType);
320 res = select_data_new(*lppSelectData, EType);
321 *lppSelectData = res;
327 /***********************/
329 /***********************/
331 void read_console_poll(HANDLE hStop, void *_data)
337 LPSELECTDATA lpSelectData;
338 LPSELECTQUERY lpQuery;
341 dbug_print("Waiting for data on console");
347 lpSelectData = (LPSELECTDATA)_data;
348 lpQuery = &(lpSelectData->aQueries[0]);
351 events[1] = lpQuery->hFileDescr;
352 while (lpSelectData->EState == SELECT_STATE_NONE)
354 waitRes = WaitForMultipleObjects(2, events, FALSE, INFINITE);
355 if (waitRes == WAIT_OBJECT_0 || check_error(lpSelectData, waitRes == WAIT_FAILED))
357 /* stop worker event or error */
361 if (check_error(lpSelectData, PeekConsoleInput(lpQuery->hFileDescr, &record, 1, &n) == 0))
365 /* check for ASCII keypress only */
366 if (record.EventType == KEY_EVENT &&
367 record.Event.KeyEvent.bKeyDown &&
368 record.Event.KeyEvent.uChar.AsciiChar != 0)
370 select_data_result_add(lpSelectData, lpQuery->EMode, lpQuery->lpOrig);
371 lpSelectData->EState = SELECT_STATE_SIGNALED;
376 /* discard everything else and try again */
377 if (check_error(lpSelectData, ReadConsoleInput(lpQuery->hFileDescr, &record, 1, &n) == 0))
385 /* Add a function to monitor console input */
386 LPSELECTDATA read_console_poll_add (LPSELECTDATA lpSelectData, SELECTMODE EMode, HANDLE hFileDescr, LPVOID lpOrig)
390 res = select_data_new(lpSelectData, SELECT_TYPE_CONSOLE_READ);
391 res->funcWorker = read_console_poll;
392 select_data_query_add(res, SELECT_MODE_READ, hFileDescr, lpOrig);
397 /***********************/
399 /***********************/
401 /* Monitor a pipe for input */
402 void read_pipe_poll (HANDLE hStop, void *_data)
406 LPSELECTQUERY iterQuery;
407 LPSELECTDATA lpSelectData;
413 lpSelectData = (LPSELECTDATA)_data;
416 dbug_print("Checking data pipe");
418 while (lpSelectData->EState == SELECT_STATE_NONE)
420 for (i = 0; i < lpSelectData->nQueriesCount; i++)
422 iterQuery = &(lpSelectData->aQueries[i]);
426 iterQuery->hFileDescr,
438 lpSelectData->EState = SELECT_STATE_SIGNALED;
439 select_data_result_add(lpSelectData, iterQuery->EMode, iterQuery->lpOrig);
443 /* Alas, nothing except polling seems to work for pipes.
444 Check the state & stop_worker_event every 10 ms
446 if (lpSelectData->EState == SELECT_STATE_NONE)
448 event = WaitForSingleObject(hStop, 10);
449 if (event == WAIT_OBJECT_0 || check_error(lpSelectData, event == WAIT_FAILED))
456 dbug_print("Finish checking data on pipe");
460 /* Add a function to monitor pipe input */
461 LPSELECTDATA read_pipe_poll_add (LPSELECTDATA lpSelectData, SELECTMODE EMode, HANDLE hFileDescr, LPVOID lpOrig)
467 /* Polling pipe is a non blocking operation by default. This means that each
468 worker can handle many pipe. We begin to try to find a worker that is
469 polling pipe, but for which there is under the limit of pipe per worker.
472 dbug_print("Searching an available worker handling pipe");
474 res = select_data_job_search(&hd, SELECT_TYPE_PIPE_READ);
476 /* Add a new pipe to poll */
477 res->funcWorker = read_pipe_poll;
478 select_data_query_add(res, EMode, hFileDescr, lpOrig);
483 /***********************/
485 /***********************/
488 void socket_poll (HANDLE hStop, void *_data)
490 LPSELECTDATA lpSelectData;
491 LPSELECTQUERY iterQuery;
492 HANDLE aEvents[MAXIMUM_SELECT_OBJECTS];
498 lpSelectData = (LPSELECTDATA)_data;
500 for (nEvents = 0; nEvents < lpSelectData->nQueriesCount; nEvents++)
502 iterQuery = &(lpSelectData->aQueries[nEvents]);
503 aEvents[nEvents] = CreateEvent(NULL, TRUE, FALSE, NULL);
505 switch (iterQuery->EMode)
507 case SELECT_MODE_READ:
508 maskEvents = FD_READ | FD_ACCEPT | FD_CLOSE;
510 case SELECT_MODE_WRITE:
511 maskEvents = FD_WRITE | FD_CONNECT | FD_CLOSE;
513 case SELECT_MODE_EXCEPT:
517 check_error(lpSelectData,
519 (SOCKET)(iterQuery->hFileDescr),
521 maskEvents) == SOCKET_ERROR);
525 aEvents[nEvents] = hStop;
528 if (lpSelectData->nError == 0)
530 check_error(lpSelectData,
531 WaitForMultipleObjects(
535 INFINITE) == WAIT_FAILED);
538 if (lpSelectData->nError == 0)
540 for (i = 0; i < lpSelectData->nQueriesCount; i++)
542 iterQuery = &(lpSelectData->aQueries[i]);
543 if (WaitForSingleObject(aEvents[i], 0) == WAIT_OBJECT_0)
546 dbug_print("Socket %d has pending events", (i - 1));
548 if (iterQuery != NULL)
550 select_data_result_add(lpSelectData, iterQuery->EMode, iterQuery->lpOrig);
553 /* WSAEventSelect() automatically sets socket to nonblocking mode.
554 Restore the blocking one. */
556 check_error(lpSelectData,
557 WSAEventSelect((SOCKET)(iterQuery->hFileDescr), aEvents[i], 0) != 0 ||
558 ioctlsocket((SOCKET)(iterQuery->hFileDescr), FIONBIO, &iMode) != 0);
560 CloseHandle(aEvents[i]);
561 aEvents[i] = INVALID_HANDLE_VALUE;
566 /* Add a function to monitor socket */
567 LPSELECTDATA socket_poll_add (LPSELECTDATA lpSelectData, SELECTMODE EMode, HANDLE hFileDescr, LPVOID lpOrig)
573 /* Polling socket can be done mulitple handle at the same time. You just
574 need one worker to use it. Try to find if there is already a worker
575 handling this kind of request.
578 dbug_print("Scanning list of worker to find one that already handle socket");
580 res = select_data_job_search(&hd, SELECT_TYPE_SOCKET);
582 /* Add a new socket to poll */
583 res->funcWorker = socket_poll;
585 dbug_print("Add socket %x to worker", hFileDescr);
587 select_data_query_add(res, EMode, hFileDescr, lpOrig);
589 dbug_print("Socket %x added", hFileDescr);
595 /***********************/
597 /***********************/
599 /* Add a static result */
600 LPSELECTDATA static_poll_add (LPSELECTDATA lpSelectData, SELECTMODE EMode, HANDLE hFileDescr, LPVOID lpOrig)
605 /* Look for an already initialized static element */
607 res = select_data_job_search(&hd, SELECT_TYPE_STATIC);
609 /* Add a new query/result */
610 select_data_query_add(res, EMode, hFileDescr, lpOrig);
611 select_data_result_add(res, EMode, lpOrig);
616 /********************************/
617 /* Generic select data handling */
618 /********************************/
620 /* Guess handle type */
621 static SELECTHANDLETYPE get_handle_type(value fd)
624 SELECTHANDLETYPE res;
629 res = SELECT_HANDLE_NONE;
631 if (Descr_kind_val(fd) == KIND_SOCKET)
633 res = SELECT_HANDLE_SOCKET;
637 switch(GetFileType(Handle_val(fd)))
640 res = SELECT_HANDLE_DISK;
643 case FILE_TYPE_CHAR: /* character file or a console */
644 if (GetConsoleMode(Handle_val(fd), &mode) != 0)
646 res = SELECT_HANDLE_CONSOLE;
650 res = SELECT_HANDLE_NONE;
654 case FILE_TYPE_PIPE: /* a named or an anonymous pipe (socket already handled) */
655 res = SELECT_HANDLE_PIPE;
660 CAMLreturnT(SELECTHANDLETYPE, res);
663 /* Choose what to do with given data */
664 LPSELECTDATA select_data_dispatch (LPSELECTDATA lpSelectData, SELECTMODE EMode, value fd)
676 hFileDescr = Handle_val(fd);
679 alreadyAdded = FALSE;
682 dbug_print("Begin dispatching handle %x", hFileDescr);
686 dbug_print("Waiting for %d on handle %x", EMode, hFileDescr);
689 /* There is only 2 way to have except mode: transmission of OOB data through
690 a socket TCP/IP and through a strange interaction with a TTY.
691 With windows, we only consider the TCP/IP except condition
693 switch(get_handle_type(fd))
695 case SELECT_HANDLE_DISK:
697 dbug_print("Handle %x is a disk handle", hFileDescr);
699 /* Disk is always ready in read/write operation */
700 if (EMode == SELECT_MODE_READ || EMode == SELECT_MODE_WRITE)
702 res = static_poll_add(res, EMode, hFileDescr, lpOrig);
706 case SELECT_HANDLE_CONSOLE:
708 dbug_print("Handle %x is a console handle", hFileDescr);
710 /* Console is always ready in write operation, need to check for read. */
711 if (EMode == SELECT_MODE_READ)
713 res = read_console_poll_add(res, EMode, hFileDescr, lpOrig);
715 else if (EMode == SELECT_MODE_WRITE)
717 res = static_poll_add(res, EMode, hFileDescr, lpOrig);
721 case SELECT_HANDLE_PIPE:
723 dbug_print("Handle %x is a pipe handle", hFileDescr);
725 /* Console is always ready in write operation, need to check for read. */
726 if (EMode == SELECT_MODE_READ)
729 dbug_print("Need to check availability of data on pipe");
731 res = read_pipe_poll_add(res, EMode, hFileDescr, lpOrig);
733 else if (EMode == SELECT_MODE_WRITE)
736 dbug_print("No need to check availability of data on pipe, write operation always possible");
738 res = static_poll_add(res, EMode, hFileDescr, lpOrig);
742 case SELECT_HANDLE_SOCKET:
744 dbug_print("Handle %x is a socket handle", hFileDescr);
746 if (getsockname((SOCKET)hFileDescr, &sa, &sa_len) == SOCKET_ERROR)
748 if (WSAGetLastError() == WSAEINVAL)
750 /* Socket is not bound */
752 dbug_print("Socket is not connected");
754 if (EMode == SELECT_MODE_WRITE || EMode == SELECT_MODE_READ)
756 res = static_poll_add(res, EMode, hFileDescr, lpOrig);
763 res = socket_poll_add(res, EMode, hFileDescr, lpOrig);
769 dbug_print("Handle %x is unknown", hFileDescr);
771 caml_failwith("Unknown handle");
776 dbug_print("Finish dispatching handle %x", hFileDescr);
779 CAMLreturnT(LPSELECTDATA, res);
782 static DWORD caml_list_length (value lst)
789 for (res = 0, l = lst; l != Val_int(0); l = Field(l, 1), res++)
792 CAMLreturnT(DWORD, res);
795 #define MAX(a, b) ((a) > (b) ? (a) : (b))
797 CAMLprim value unix_select(value readfds, value writefds, value exceptfds, value timeout)
799 /* Event associated to handle */
802 HANDLE *lpEventsDone;
804 /* Data for all handles */
805 LPSELECTDATA lpSelectData;
806 LPSELECTDATA iterSelectData;
808 /* Iterator for results */
809 LPSELECTRESULT iterResult;
820 /* Is there static select data */
821 BOOL hasStaticData = FALSE;
831 /* Length of each list */
836 CAMLparam4 (readfds, writefds, exceptfds, timeout);
837 CAMLlocal5 (read_list, write_list, except_list, res, l);
841 dbug_print("in select");
848 iterSelectData = NULL;
853 readfds_len = caml_list_length(readfds);
854 writefds_len = caml_list_length(writefds);
855 exceptfds_len = caml_list_length(exceptfds);
856 hdsMax = MAX(readfds_len, MAX(writefds_len, exceptfds_len));
858 if (!HeapLock(GetProcessHeap()))
860 win32_maperr(GetLastError());
861 uerror("select", Nothing);
863 hdsData = (HANDLE *)HeapAlloc(
866 sizeof(HANDLE) * hdsMax);
867 HeapUnlock(GetProcessHeap());
869 if (Double_val(timeout) >= 0.0)
871 milliseconds = 1000 * Double_val(timeout);
873 dbug_print("Will wait %d ms", milliseconds);
878 milliseconds = INFINITE;
882 /* Create list of select data, based on the different list of fd to watch */
884 dbug_print("Dispatch read fd");
886 handle_set_init(&hds, hdsData, hdsMax);
887 for (l = readfds; l != Val_int(0); l = Field(l, 1))
890 if (!handle_set_mem(&hds, Handle_val(fd)))
892 handle_set_add(&hds, Handle_val(fd));
893 lpSelectData = select_data_dispatch(lpSelectData, SELECT_MODE_READ, fd);
898 dbug_print("Discarding handle %x which is already monitor for read", Handle_val(fd));
902 handle_set_reset(&hds);
905 dbug_print("Dispatch write fd");
907 handle_set_init(&hds, hdsData, hdsMax);
908 for (l = writefds; l != Val_int(0); l = Field(l, 1))
911 if (!handle_set_mem(&hds, Handle_val(fd)))
913 handle_set_add(&hds, Handle_val(fd));
914 lpSelectData = select_data_dispatch(lpSelectData, SELECT_MODE_WRITE, fd);
919 dbug_print("Discarding handle %x which is already monitor for write", Handle_val(fd));
923 handle_set_reset(&hds);
926 dbug_print("Dispatch exceptional fd");
928 handle_set_init(&hds, hdsData, hdsMax);
929 for (l = exceptfds; l != Val_int(0); l = Field(l, 1))
932 if (!handle_set_mem(&hds, Handle_val(fd)))
934 handle_set_add(&hds, Handle_val(fd));
935 lpSelectData = select_data_dispatch(lpSelectData, SELECT_MODE_EXCEPT, fd);
940 dbug_print("Discarding handle %x which is already monitor for exceptional", Handle_val(fd));
944 handle_set_reset(&hds);
946 /* Building the list of handle to wait for */
948 dbug_print("Building events done array");
950 nEventsMax = list_length((LPLIST)lpSelectData);
952 if (!HeapLock(GetProcessHeap()))
954 win32_maperr(GetLastError());
955 uerror("select", Nothing);
957 lpEventsDone = (HANDLE *)HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * nEventsMax);
958 HeapUnlock(GetProcessHeap());
960 iterSelectData = lpSelectData;
961 while (iterSelectData != NULL)
963 /* Check if it is static data. If this is the case, launch everything
964 * but don't wait for events. It helps to test if there are events on
965 * any other fd (which are not static), knowing that there is at least
966 * one result (the static data).
968 if (iterSelectData->EType == SELECT_TYPE_STATIC)
970 hasStaticData = TRUE;
974 if (iterSelectData->funcWorker != NULL)
976 iterSelectData->lpWorker =
978 iterSelectData->funcWorker,
979 (void *)iterSelectData);
981 dbug_print("Job submitted to worker %x", iterSelectData->lpWorker);
983 lpEventsDone[nEventsCount] = worker_job_event_done(iterSelectData->lpWorker);
986 iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData);
990 dbug_print("Need to watch %d workers", nEventsCount);
993 /* Processing select itself */
994 enter_blocking_section();
995 /* There are worker started, waiting to be monitored */
996 if (nEventsCount > 0)
998 /* Waiting for event */
999 if (err == 0 && !hasStaticData)
1002 dbug_print("Waiting for one select worker to be done");
1004 switch (WaitForMultipleObjects(nEventsCount, lpEventsDone, FALSE, milliseconds))
1007 err = GetLastError();
1012 dbug_print("Select timeout");
1018 dbug_print("One worker is done");
1024 /* Ordering stop to every worker */
1026 dbug_print("Sending stop signal to every select workers");
1028 iterSelectData = lpSelectData;
1029 while (iterSelectData != NULL)
1031 if (iterSelectData->lpWorker != NULL)
1033 worker_job_stop(iterSelectData->lpWorker);
1035 iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData);
1039 dbug_print("Waiting for every select worker to be done");
1041 switch (WaitForMultipleObjects(nEventsCount, lpEventsDone, TRUE, INFINITE))
1044 err = GetLastError();
1049 dbug_print("Every worker is done");
1054 /* Nothing to monitor but some time to wait. */
1055 else if (!hasStaticData)
1057 Sleep(milliseconds);
1059 leave_blocking_section();
1062 dbug_print("Error status: %d (0 is ok)", err);
1068 dbug_print("Building result");
1070 read_list = Val_unit;
1071 write_list = Val_unit;
1072 except_list = Val_unit;
1074 iterSelectData = lpSelectData;
1075 while (iterSelectData != NULL)
1077 for (i = 0; i < iterSelectData->nResultsCount; i++)
1079 iterResult = &(iterSelectData->aResults[i]);
1080 l = alloc_small(2, 0);
1081 Store_field(l, 0, (value)iterResult->lpOrig);
1082 switch (iterResult->EMode)
1084 case SELECT_MODE_READ:
1085 Store_field(l, 1, read_list);
1088 case SELECT_MODE_WRITE:
1089 Store_field(l, 1, write_list);
1092 case SELECT_MODE_EXCEPT:
1093 Store_field(l, 1, except_list);
1098 /* We try to only process the first error, bypass other errors */
1099 if (err == 0 && iterSelectData->EState == SELECT_STATE_ERROR)
1101 err = iterSelectData->nError;
1103 iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData);
1107 /* Free resources */
1109 dbug_print("Free selectdata resources");
1111 iterSelectData = lpSelectData;
1112 while (iterSelectData != NULL)
1114 lpSelectData = iterSelectData;
1115 iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData);
1116 select_data_free(lpSelectData);
1118 lpSelectData = NULL;
1120 /* Free allocated events/handle set array */
1122 dbug_print("Free local allocated resources");
1124 if (!HeapLock(GetProcessHeap()))
1126 win32_maperr(GetLastError());
1127 uerror("select", Nothing);
1129 HeapFree(GetProcessHeap(), 0, lpEventsDone);
1130 HeapFree(GetProcessHeap(), 0, hdsData);
1131 HeapUnlock(GetProcessHeap());
1134 dbug_print("Raise error if required");
1139 uerror("select", Nothing);
1143 dbug_print("Build final result");
1145 res = alloc_small(3, 0);
1146 Store_field(res, 0, read_list);
1147 Store_field(res, 1, write_list);
1148 Store_field(res, 2, except_list);
1151 dbug_print("out select");