summaryrefslogtreecommitdiffstats
path: root/otherlibs/win32unix
diff options
context:
space:
mode:
Diffstat (limited to 'otherlibs/win32unix')
-rw-r--r--otherlibs/win32unix/select.c693
-rw-r--r--otherlibs/win32unix/windbug.h6
2 files changed, 434 insertions, 265 deletions
diff --git a/otherlibs/win32unix/select.c b/otherlibs/win32unix/select.c
index af9766ff8..7069d140f 100644
--- a/otherlibs/win32unix/select.c
+++ b/otherlibs/win32unix/select.c
@@ -114,9 +114,9 @@ typedef enum _SELECTHANDLETYPE {
typedef enum _SELECTMODE {
SELECT_MODE_NONE = 0,
- SELECT_MODE_READ,
- SELECT_MODE_WRITE,
- SELECT_MODE_EXCEPT,
+ SELECT_MODE_READ = 1,
+ SELECT_MODE_WRITE = 2,
+ SELECT_MODE_EXCEPT = 4,
} SELECTMODE;
typedef enum _SELECTSTATE {
@@ -157,7 +157,9 @@ typedef SELECTQUERY *LPSELECTQUERY;
typedef struct _SELECTDATA {
LIST lst;
SELECTTYPE EType;
- SELECTRESULT aResults[MAXIMUM_SELECT_OBJECTS];
+ /* Sockets may generate a result for all three lists from one single query object
+ */
+ SELECTRESULT aResults[MAXIMUM_SELECT_OBJECTS * 3];
DWORD nResultsCount;
/* Data following are dedicated to APC like call, they
will be initialized if required.
@@ -240,7 +242,7 @@ DWORD select_data_result_add (LPSELECTDATA lpSelectData, SELECTMODE EMode, int l
DWORD i;
res = 0;
- if (lpSelectData->nResultsCount < MAXIMUM_SELECT_OBJECTS)
+ if (lpSelectData->nResultsCount < MAXIMUM_SELECT_OBJECTS * 3)
{
i = lpSelectData->nResultsCount;
lpSelectData->aResults[i].EMode = EMode;
@@ -490,31 +492,38 @@ LPSELECTDATA read_pipe_poll_add (LPSELECTDATA lpSelectData,
void socket_poll (HANDLE hStop, void *_data)
{
LPSELECTDATA lpSelectData;
- LPSELECTQUERY iterQuery;
- HANDLE aEvents[MAXIMUM_SELECT_OBJECTS];
- DWORD nEvents;
- long maskEvents;
- DWORD i;
- u_long iMode;
+ LPSELECTQUERY iterQuery;
+ HANDLE aEvents[MAXIMUM_SELECT_OBJECTS];
+ DWORD nEvents;
+ long maskEvents;
+ DWORD i;
+ u_long iMode;
+ SELECTMODE mode;
+ WSANETWORKEVENTS events;
lpSelectData = (LPSELECTDATA)_data;
+ DEBUG_PRINT("Worker has %d queries to service", lpSelectData->nQueriesCount);
for (nEvents = 0; nEvents < lpSelectData->nQueriesCount; nEvents++)
{
iterQuery = &(lpSelectData->aQueries[nEvents]);
aEvents[nEvents] = CreateEvent(NULL, TRUE, FALSE, NULL);
maskEvents = 0;
- switch (iterQuery->EMode)
+ mode = iterQuery->EMode;
+ if ((mode & SELECT_MODE_READ) != 0)
{
- case SELECT_MODE_READ:
- maskEvents = FD_READ | FD_ACCEPT | FD_CLOSE;
- break;
- case SELECT_MODE_WRITE:
- maskEvents = FD_WRITE | FD_CONNECT | FD_CLOSE;
- break;
- case SELECT_MODE_EXCEPT:
- maskEvents = FD_OOB;
- break;
+ DEBUG_PRINT("Polling read for %d", iterQuery->hFileDescr);
+ maskEvents |= FD_READ | FD_ACCEPT | FD_CLOSE;
+ }
+ if ((mode & SELECT_MODE_WRITE) != 0)
+ {
+ DEBUG_PRINT("Polling write for %d", iterQuery->hFileDescr);
+ maskEvents |= FD_WRITE | FD_CONNECT | FD_CLOSE;
+ }
+ if ((mode & SELECT_MODE_EXCEPT) != 0)
+ {
+ DEBUG_PRINT("Polling exceptions for %d", iterQuery->hFileDescr);
+ maskEvents |= FD_OOB;
}
check_error(lpSelectData,
@@ -548,7 +557,23 @@ void socket_poll (HANDLE hStop, void *_data)
DEBUG_PRINT("Socket %d has pending events", (i - 1));
if (iterQuery != NULL)
{
- select_data_result_add(lpSelectData, iterQuery->EMode, iterQuery->lpOrigIdx);
+ /* Find out what kind of events were raised
+ */
+ if (WSAEnumNetworkEvents((SOCKET)(iterQuery->hFileDescr), aEvents[i], &events) == 0)
+ {
+ if ((iterQuery->EMode & SELECT_MODE_READ) != 0 && (events.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) != 0)
+ {
+ select_data_result_add(lpSelectData, SELECT_MODE_READ, iterQuery->lpOrigIdx);
+ }
+ if ((iterQuery->EMode & SELECT_MODE_WRITE) != 0 && (events.lNetworkEvents & (FD_WRITE | FD_CONNECT | FD_CLOSE)) != 0)
+ {
+ select_data_result_add(lpSelectData, SELECT_MODE_WRITE, iterQuery->lpOrigIdx);
+ }
+ if ((iterQuery->EMode & SELECT_MODE_EXCEPT) != 0 && (events.lNetworkEvents & FD_OOB) != 0)
+ {
+ select_data_result_add(lpSelectData, SELECT_MODE_EXCEPT, iterQuery->lpOrigIdx);
+ }
+ }
}
}
/* WSAEventSelect() automatically sets socket to nonblocking mode.
@@ -581,23 +606,88 @@ LPSELECTDATA socket_poll_add (LPSELECTDATA lpSelectData,
unsigned int uFlagsFd)
{
LPSELECTDATA res;
- LPSELECTDATA hd;
+ LPSELECTDATA candidate;
+ DWORD i;
+ LPSELECTQUERY aQueries;
- hd = lpSelectData;
+ res = lpSelectData;
+ candidate = NULL;
+ aQueries = NULL;
+
/* Polling socket can be done mulitple handle at the same time. You just
need one worker to use it. Try to find if there is already a worker
handling this kind of request.
+ Only one event can be associated with a given socket which means that if a socket
+ is in more than one of the fd_sets then we have to find that particular query and update
+ EMode with the additional flag.
*/
DEBUG_PRINT("Scanning list of worker to find one that already handle socket");
- res = select_data_job_search(&hd, SELECT_TYPE_SOCKET);
-
- /* Add a new socket to poll */
- res->funcWorker = socket_poll;
- DEBUG_PRINT("Add socket %x to worker", hFileDescr);
- select_data_query_add(res, EMode, hFileDescr, lpOrigIdx, uFlagsFd);
- DEBUG_PRINT("Socket %x added", hFileDescr);
+ /* Search for job */
+ DEBUG_PRINT("Searching for an available job for type %d for descriptor %d", SELECT_TYPE_SOCKET, hFileDescr);
+ while (res != NULL)
+ {
+ if (res->EType == SELECT_TYPE_SOCKET)
+ {
+ i = res->nQueriesCount - 1;
+ aQueries = res->aQueries;
+ while (i >= 0 && aQueries[i].hFileDescr != hFileDescr)
+ {
+ i--;
+ }
+ /* If we didn't find the socket but this worker has available slots, store it
+ */
+ if (i < 0)
+ {
+ if ( res->nQueriesCount < MAXIMUM_SELECT_OBJECTS)
+ {
+ candidate = res;
+ }
+ res = LIST_NEXT(LPSELECTDATA, res);
+ }
+ else
+ {
+ /* Previous socket query located -- we're finished
+ */
+ aQueries = &aQueries[i];
+ break;
+ }
+ }
+ else
+ {
+ res = LIST_NEXT(LPSELECTDATA, res);
+ }
+ }
- return hd;
+ if (res == NULL)
+ {
+ res = candidate;
+
+ /* No matching job found, create one */
+ if (res == NULL)
+ {
+ DEBUG_PRINT("No job for type %d found, create one", SELECT_TYPE_SOCKET);
+ res = select_data_new(lpSelectData, SELECT_TYPE_SOCKET);
+ res->funcWorker = socket_poll;
+ res->nQueriesCount = 1;
+ aQueries = &res->aQueries[0];
+ }
+ else
+ {
+ aQueries = &(res->aQueries[res->nQueriesCount++]);
+ }
+ aQueries->EMode = EMode;
+ aQueries->hFileDescr = hFileDescr;
+ aQueries->lpOrigIdx = lpOrigIdx;
+ aQueries->uFlagsFd = uFlagsFd;
+ DEBUG_PRINT("Socket %x added", hFileDescr);
+ }
+ else
+ {
+ aQueries->EMode |= EMode;
+ DEBUG_PRINT("Socket %x updated to %d", hFileDescr, aQueries->EMode);
+ }
+
+ return res;
}
/***********************/
@@ -817,6 +907,42 @@ static value find_handle(LPSELECTRESULT iterResult, value readfds, value writefd
#define MAX(a, b) ((a) > (b) ? (a) : (b))
+/* Convert fdlist to an fd_set if all the handles in fdlist are sockets and return 0.
+ * Returns 1 if a non-socket value is encountered.
+ */
+static int fdlist_to_fdset(value fdlist, fd_set *fdset)
+{
+ value l, c;
+ FD_ZERO(fdset);
+ for (l = fdlist; l != Val_int(0); l = Field(l, 1)) {
+ c = Field(l, 0);
+ if (Descr_kind_val(c) == KIND_SOCKET) {
+ FD_SET(Socket_val(c), fdset);
+ } else {
+ DEBUG_PRINT("Non socket value encountered");
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static value fdset_to_fdlist(value fdlist, fd_set *fdset)
+{
+ value res = Val_int(0);
+ Begin_roots2(fdlist, res)
+ for (/*nothing*/; fdlist != Val_int(0); fdlist = Field(fdlist, 1)) {
+ value s = Field(fdlist, 0);
+ if (FD_ISSET(Socket_val(s), fdset)) {
+ value newres = alloc_small(2, 0);
+ Field(newres, 0) = s;
+ Field(newres, 1) = res;
+ res = newres;
+ }
+ }
+ End_roots();
+ return res;
+}
+
CAMLprim value unix_select(value readfds, value writefds, value exceptfds, value timeout)
{
/* Event associated to handle */
@@ -860,246 +986,287 @@ CAMLprim value unix_select(value readfds, value writefds, value exceptfds, value
CAMLlocal5 (read_list, write_list, except_list, res, l);
CAMLlocal1 (fd);
+ fd_set read, write, except;
+ double tm;
+ struct timeval tv;
+ struct timeval * tvp;
+
DEBUG_PRINT("in select");
- nEventsCount = 0;
- nEventsMax = 0;
- lpEventsDone = NULL;
- lpSelectData = NULL;
- iterSelectData = NULL;
- iterResult = NULL;
- err = 0;
- hasStaticData = 0;
- waitRet = 0;
- readfds_len = caml_list_length(readfds);
- writefds_len = caml_list_length(writefds);
- exceptfds_len = caml_list_length(exceptfds);
- hdsMax = MAX(readfds_len, MAX(writefds_len, exceptfds_len));
-
- hdsData = (HANDLE *)caml_stat_alloc(sizeof(HANDLE) * hdsMax);
-
- if (Double_val(timeout) >= 0.0)
- {
- milliseconds = 1000 * Double_val(timeout);
- DEBUG_PRINT("Will wait %d ms", milliseconds);
- }
- else
- {
- milliseconds = INFINITE;
- }
-
-
- /* Create list of select data, based on the different list of fd to watch */
- DEBUG_PRINT("Dispatch read fd");
- handle_set_init(&hds, hdsData, hdsMax);
- i=0;
- for (l = readfds; l != Val_int(0); l = Field(l, 1))
- {
- fd = Field(l, 0);
- if (!handle_set_mem(&hds, Handle_val(fd)))
- {
- handle_set_add(&hds, Handle_val(fd));
- lpSelectData = select_data_dispatch(lpSelectData, SELECT_MODE_READ, fd, i++);
- }
- else
- {
- DEBUG_PRINT("Discarding handle %x which is already monitor for read", Handle_val(fd));
- }
- }
- handle_set_reset(&hds);
-
- DEBUG_PRINT("Dispatch write fd");
- handle_set_init(&hds, hdsData, hdsMax);
- i=0;
- for (l = writefds; l != Val_int(0); l = Field(l, 1))
- {
- fd = Field(l, 0);
- if (!handle_set_mem(&hds, Handle_val(fd)))
- {
- handle_set_add(&hds, Handle_val(fd));
- lpSelectData = select_data_dispatch(lpSelectData, SELECT_MODE_WRITE, fd, i++);
- }
- else
- {
- DEBUG_PRINT("Discarding handle %x which is already monitor for write", Handle_val(fd));
+ err = 0;
+ tm = Double_val(timeout);
+ if (readfds == Val_int(0) && writefds == Val_int(0) && exceptfds == Val_int(0)) {
+ DEBUG_PRINT("nothing to do");
+ if ( tm > 0.0 ) {
+ enter_blocking_section();
+ Sleep( (int)(tm * 1000));
+ leave_blocking_section();
}
- }
- handle_set_reset(&hds);
-
- DEBUG_PRINT("Dispatch exceptional fd");
- handle_set_init(&hds, hdsData, hdsMax);
- i=0;
- for (l = exceptfds; l != Val_int(0); l = Field(l, 1))
- {
- fd = Field(l, 0);
- if (!handle_set_mem(&hds, Handle_val(fd)))
- {
- handle_set_add(&hds, Handle_val(fd));
- lpSelectData = select_data_dispatch(lpSelectData, SELECT_MODE_EXCEPT, fd, i++);
- }
- else
- {
- DEBUG_PRINT("Discarding handle %x which is already monitor for exceptional", Handle_val(fd));
- }
- }
- handle_set_reset(&hds);
-
- /* Building the list of handle to wait for */
- DEBUG_PRINT("Building events done array");
- nEventsMax = list_length((LPLIST)lpSelectData);
- nEventsCount = 0;
- lpEventsDone = (HANDLE *)caml_stat_alloc(sizeof(HANDLE) * nEventsMax);
-
- iterSelectData = lpSelectData;
- while (iterSelectData != NULL)
- {
- /* Check if it is static data. If this is the case, launch everything
- * but don't wait for events. It helps to test if there are events on
- * any other fd (which are not static), knowing that there is at least
- * one result (the static data).
- */
- if (iterSelectData->EType == SELECT_TYPE_STATIC)
- {
- hasStaticData = TRUE;
- };
-
- /* Execute APC */
- if (iterSelectData->funcWorker != NULL)
- {
- iterSelectData->lpWorker =
- worker_job_submit(
- iterSelectData->funcWorker,
- (void *)iterSelectData);
- DEBUG_PRINT("Job submitted to worker %x", iterSelectData->lpWorker);
- lpEventsDone[nEventsCount] = worker_job_event_done(iterSelectData->lpWorker);
- nEventsCount++;
- };
- iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData);
- };
-
- DEBUG_PRINT("Need to watch %d workers", nEventsCount);
-
- /* Processing select itself */
- enter_blocking_section();
- /* There are worker started, waiting to be monitored */
- if (nEventsCount > 0)
- {
- /* Waiting for event */
- if (err == 0 && !hasStaticData)
- {
- DEBUG_PRINT("Waiting for one select worker to be done");
- switch (WaitForMultipleObjects(nEventsCount, lpEventsDone, FALSE, milliseconds))
- {
- case WAIT_FAILED:
- err = GetLastError();
- break;
-
- case WAIT_TIMEOUT:
- DEBUG_PRINT("Select timeout");
- break;
-
- default:
- DEBUG_PRINT("One worker is done");
- break;
- };
- }
-
- /* Ordering stop to every worker */
- DEBUG_PRINT("Sending stop signal to every select workers");
- iterSelectData = lpSelectData;
- while (iterSelectData != NULL)
- {
- if (iterSelectData->lpWorker != NULL)
- {
- worker_job_stop(iterSelectData->lpWorker);
- };
- iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData);
- };
+ read_list = write_list = except_list = Val_int(0);
+ } else {
+ if (fdlist_to_fdset(readfds, &read) && fdlist_to_fdset(writefds, &write) && fdlist_to_fdset(exceptfds, &except)) {
+ DEBUG_PRINT("only sockets to select on, using classic select");
+ if (tm < 0.0) {
+ tvp = (struct timeval *) NULL;
+ } else {
+ tv.tv_sec = (int) tm;
+ tv.tv_usec = (int) (1e6 * (tm - (int) tm));
+ tvp = &tv;
+ }
+ enter_blocking_section();
+ if (select(FD_SETSIZE, &read, &write, &except, tvp) == -1) {
+ err = WSAGetLastError();
+ DEBUG_PRINT("Error %ld occurred", err);
+ }
+ leave_blocking_section();
+ if (err) {
+ DEBUG_PRINT("Error %ld occurred", err);
+ win32_maperr(err);
+ uerror("select", Nothing);
+ }
+ read_list = fdset_to_fdlist(readfds, &read);
+ write_list = fdset_to_fdlist(writefds, &write);
+ except_list = fdset_to_fdlist(exceptfds, &except);
+ } else {
+ nEventsCount = 0;
+ nEventsMax = 0;
+ lpEventsDone = NULL;
+ lpSelectData = NULL;
+ iterSelectData = NULL;
+ iterResult = NULL;
+ hasStaticData = 0;
+ waitRet = 0;
+ readfds_len = caml_list_length(readfds);
+ writefds_len = caml_list_length(writefds);
+ exceptfds_len = caml_list_length(exceptfds);
+ hdsMax = MAX(readfds_len, MAX(writefds_len, exceptfds_len));
- DEBUG_PRINT("Waiting for every select worker to be done");
- switch (WaitForMultipleObjects(nEventsCount, lpEventsDone, TRUE, INFINITE))
- {
- case WAIT_FAILED:
- err = GetLastError();
- break;
-
- default:
- DEBUG_PRINT("Every worker is done");
- break;
- }
- }
- /* Nothing to monitor but some time to wait. */
- else if (!hasStaticData)
- {
- Sleep(milliseconds);
- }
- leave_blocking_section();
-
- DEBUG_PRINT("Error status: %d (0 is ok)", err);
- /* Build results */
- if (err == 0)
- {
- DEBUG_PRINT("Building result");
- read_list = Val_unit;
- write_list = Val_unit;
- except_list = Val_unit;
-
- iterSelectData = lpSelectData;
- while (iterSelectData != NULL)
- {
- for (i = 0; i < iterSelectData->nResultsCount; i++)
- {
- iterResult = &(iterSelectData->aResults[i]);
- l = alloc_small(2, 0);
- Store_field(l, 0, find_handle(iterResult, readfds, writefds, exceptfds));
- switch (iterResult->EMode)
+ hdsData = (HANDLE *)caml_stat_alloc(sizeof(HANDLE) * hdsMax);
+
+ if (tm >= 0.0)
{
- case SELECT_MODE_READ:
- Store_field(l, 1, read_list);
- read_list = l;
- break;
- case SELECT_MODE_WRITE:
- Store_field(l, 1, write_list);
- write_list = l;
- break;
- case SELECT_MODE_EXCEPT:
- Store_field(l, 1, except_list);
- except_list = l;
- break;
+ milliseconds = 1000 * tm;
+ DEBUG_PRINT("Will wait %d ms", milliseconds);
+ }
+ else
+ {
+ milliseconds = INFINITE;
+ }
+
+
+ /* Create list of select data, based on the different list of fd to watch */
+ DEBUG_PRINT("Dispatch read fd");
+ handle_set_init(&hds, hdsData, hdsMax);
+ i=0;
+ for (l = readfds; l != Val_int(0); l = Field(l, 1))
+ {
+ fd = Field(l, 0);
+ if (!handle_set_mem(&hds, Handle_val(fd)))
+ {
+ handle_set_add(&hds, Handle_val(fd));
+ lpSelectData = select_data_dispatch(lpSelectData, SELECT_MODE_READ, fd, i++);
+ }
+ else
+ {
+ DEBUG_PRINT("Discarding handle %x which is already monitor for read", Handle_val(fd));
+ }
+ }
+ handle_set_reset(&hds);
+
+ DEBUG_PRINT("Dispatch write fd");
+ handle_set_init(&hds, hdsData, hdsMax);
+ i=0;
+ for (l = writefds; l != Val_int(0); l = Field(l, 1))
+ {
+ fd = Field(l, 0);
+ if (!handle_set_mem(&hds, Handle_val(fd)))
+ {
+ handle_set_add(&hds, Handle_val(fd));
+ lpSelectData = select_data_dispatch(lpSelectData, SELECT_MODE_WRITE, fd, i++);
+ }
+ else
+ {
+ DEBUG_PRINT("Discarding handle %x which is already monitor for write", Handle_val(fd));
+ }
+ }
+ handle_set_reset(&hds);
+
+ DEBUG_PRINT("Dispatch exceptional fd");
+ handle_set_init(&hds, hdsData, hdsMax);
+ i=0;
+ for (l = exceptfds; l != Val_int(0); l = Field(l, 1))
+ {
+ fd = Field(l, 0);
+ if (!handle_set_mem(&hds, Handle_val(fd)))
+ {
+ handle_set_add(&hds, Handle_val(fd));
+ lpSelectData = select_data_dispatch(lpSelectData, SELECT_MODE_EXCEPT, fd, i++);
+ }
+ else
+ {
+ DEBUG_PRINT("Discarding handle %x which is already monitor for exceptional", Handle_val(fd));
+ }
+ }
+ handle_set_reset(&hds);
+
+ /* Building the list of handle to wait for */
+ DEBUG_PRINT("Building events done array");
+ nEventsMax = list_length((LPLIST)lpSelectData);
+ nEventsCount = 0;
+ lpEventsDone = (HANDLE *)caml_stat_alloc(sizeof(HANDLE) * nEventsMax);
+
+ iterSelectData = lpSelectData;
+ while (iterSelectData != NULL)
+ {
+ /* Check if it is static data. If this is the case, launch everything
+ * but don't wait for events. It helps to test if there are events on
+ * any other fd (which are not static), knowing that there is at least
+ * one result (the static data).
+ */
+ if (iterSelectData->EType == SELECT_TYPE_STATIC)
+ {
+ hasStaticData = TRUE;
+ };
+
+ /* Execute APC */
+ if (iterSelectData->funcWorker != NULL)
+ {
+ iterSelectData->lpWorker =
+ worker_job_submit(
+ iterSelectData->funcWorker,
+ (void *)iterSelectData);
+ DEBUG_PRINT("Job submitted to worker %x", iterSelectData->lpWorker);
+ lpEventsDone[nEventsCount] = worker_job_event_done(iterSelectData->lpWorker);
+ nEventsCount++;
+ };
+ iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData);
+ };
+
+ DEBUG_PRINT("Need to watch %d workers", nEventsCount);
+
+ /* Processing select itself */
+ enter_blocking_section();
+ /* There are worker started, waiting to be monitored */
+ if (nEventsCount > 0)
+ {
+ /* Waiting for event */
+ if (err == 0 && !hasStaticData)
+ {
+ DEBUG_PRINT("Waiting for one select worker to be done");
+ switch (WaitForMultipleObjects(nEventsCount, lpEventsDone, FALSE, milliseconds))
+ {
+ case WAIT_FAILED:
+ err = GetLastError();
+ break;
+
+ case WAIT_TIMEOUT:
+ DEBUG_PRINT("Select timeout");
+ break;
+
+ default:
+ DEBUG_PRINT("One worker is done");
+ break;
+ };
+ }
+
+ /* Ordering stop to every worker */
+ DEBUG_PRINT("Sending stop signal to every select workers");
+ iterSelectData = lpSelectData;
+ while (iterSelectData != NULL)
+ {
+ if (iterSelectData->lpWorker != NULL)
+ {
+ worker_job_stop(iterSelectData->lpWorker);
+ };
+ iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData);
+ };
+
+ DEBUG_PRINT("Waiting for every select worker to be done");
+ switch (WaitForMultipleObjects(nEventsCount, lpEventsDone, TRUE, INFINITE))
+ {
+ case WAIT_FAILED:
+ err = GetLastError();
+ break;
+
+ default:
+ DEBUG_PRINT("Every worker is done");
+ break;
+ }
+ }
+ /* Nothing to monitor but some time to wait. */
+ else if (!hasStaticData)
+ {
+ Sleep(milliseconds);
+ }
+ leave_blocking_section();
+
+ DEBUG_PRINT("Error status: %d (0 is ok)", err);
+ /* Build results */
+ if (err == 0)
+ {
+ DEBUG_PRINT("Building result");
+ read_list = Val_unit;
+ write_list = Val_unit;
+ except_list = Val_unit;
+
+ iterSelectData = lpSelectData;
+ while (iterSelectData != NULL)
+ {
+ for (i = 0; i < iterSelectData->nResultsCount; i++)
+ {
+ iterResult = &(iterSelectData->aResults[i]);
+ l = alloc_small(2, 0);
+ Store_field(l, 0, find_handle(iterResult, readfds, writefds, exceptfds));
+ switch (iterResult->EMode)
+ {
+ case SELECT_MODE_READ:
+ Store_field(l, 1, read_list);
+ read_list = l;
+ break;
+ case SELECT_MODE_WRITE:
+ Store_field(l, 1, write_list);
+ write_list = l;
+ break;
+ case SELECT_MODE_EXCEPT:
+ Store_field(l, 1, except_list);
+ except_list = l;
+ break;
+ }
+ }
+ /* We try to only process the first error, bypass other errors */
+ if (err == 0 && iterSelectData->EState == SELECT_STATE_ERROR)
+ {
+ err = iterSelectData->nError;
+ }
+ iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData);
+ }
+ }
+
+ /* Free resources */
+ DEBUG_PRINT("Free selectdata resources");
+ iterSelectData = lpSelectData;
+ while (iterSelectData != NULL)
+ {
+ lpSelectData = iterSelectData;
+ iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData);
+ select_data_free(lpSelectData);
+ }
+ lpSelectData = NULL;
+
+ /* Free allocated events/handle set array */
+ DEBUG_PRINT("Free local allocated resources");
+ caml_stat_free(lpEventsDone);
+ caml_stat_free(hdsData);
+
+ DEBUG_PRINT("Raise error if required");
+ if (err != 0)
+ {
+ win32_maperr(err);
+ uerror("select", Nothing);
}
- }
- /* We try to only process the first error, bypass other errors */
- if (err == 0 && iterSelectData->EState == SELECT_STATE_ERROR)
- {
- err = iterSelectData->nError;
- }
- iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData);
}
}
- /* Free resources */
- DEBUG_PRINT("Free selectdata resources");
- iterSelectData = lpSelectData;
- while (iterSelectData != NULL)
- {
- lpSelectData = iterSelectData;
- iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData);
- select_data_free(lpSelectData);
- }
- lpSelectData = NULL;
-
- /* Free allocated events/handle set array */
- DEBUG_PRINT("Free local allocated resources");
- caml_stat_free(lpEventsDone);
- caml_stat_free(hdsData);
-
- DEBUG_PRINT("Raise error if required");
- if (err != 0)
- {
- win32_maperr(err);
- uerror("select", Nothing);
- }
-
DEBUG_PRINT("Build final result");
res = alloc_small(3, 0);
Store_field(res, 0, read_list);
diff --git a/otherlibs/win32unix/windbug.h b/otherlibs/win32unix/windbug.h
index 3e2341361..efaeffc01 100644
--- a/otherlibs/win32unix/windbug.h
+++ b/otherlibs/win32unix/windbug.h
@@ -18,13 +18,15 @@
#include <stdio.h>
#include <windows.h>
+/* According to MSDN, MSVC supports the gcc ## operator (to deal with empty argument lists)
+ */
#define DEBUG_PRINT(fmt, ...) \
do \
{ \
if (debug_test()) \
{ \
- fprintf(stderr, "DBUG (pid:%d, tid: %d): ", GetCurrentProcessId(), GetCurrentThreadId()); \
- fprintf(stderr, fmt, __VA_ARGS__); \
+ fprintf(stderr, "DBUG (pid:%ld, tid: %ld): ", GetCurrentProcessId(), GetCurrentThreadId()); \
+ fprintf(stderr, fmt, ##__VA_ARGS__); \
fprintf(stderr, "\n"); \
fflush(stderr); \
}; \