/* Monitor a pipe for input */ void read_pipe_poll (HANDLE hStop, void *_data) { DWORD event; DWORD n; LPSELECTQUERY iterQuery; LPSELECTDATA lpSelectData; DWORD i; /* Poll pipe */ event = 0; n = 0; lpSelectData = (LPSELECTDATA)_data; #ifdef DBUG dbug_print("Checking data pipe"); #endif while (lpSelectData->EState == SELECT_STATE_NONE) { for (i = 0; i < lpSelectData->nQueriesCount; i++) { iterQuery = &(lpSelectData->aQueries[i]); if (check_error( lpSelectData, PeekNamedPipe( iterQuery->hFileDescr, NULL, 0, NULL, &n, NULL) == 0)) { break; }; if (n > 0) { lpSelectData->EState = SELECT_STATE_SIGNALED; select_data_result_add(lpSelectData, iterQuery->EMode, iterQuery->lpOrig); }; }; /* Alas, nothing except polling seems to work for pipes. Check the state & stop_worker_event every 10 ms */ if (lpSelectData->EState == SELECT_STATE_NONE) { event = WaitForSingleObject(hStop, 10); if (event == WAIT_OBJECT_0 || check_error(lpSelectData, event == WAIT_FAILED)) { break; } } } #ifdef DBUG dbug_print("Finish checking data on pipe"); #endif }
void read_console_poll(HANDLE hStop, void *_data) { HANDLE events[2]; INPUT_RECORD record; DWORD waitRes; DWORD n; LPSELECTDATA lpSelectData; LPSELECTQUERY lpQuery; #ifdef DBUG dbug_print("Waiting for data on console"); #endif record; waitRes = 0; n = 0; lpSelectData = (LPSELECTDATA)_data; lpQuery = &(lpSelectData->aQueries[0]); events[0] = hStop; events[1] = lpQuery->hFileDescr; while (lpSelectData->EState == SELECT_STATE_NONE) { waitRes = WaitForMultipleObjects(2, events, FALSE, INFINITE); if (waitRes == WAIT_OBJECT_0 || check_error(lpSelectData, waitRes == WAIT_FAILED)) { /* stop worker event or error */ break; } /* console event */ if (check_error(lpSelectData, PeekConsoleInput(lpQuery->hFileDescr, &record, 1, &n) == 0)) { break; } /* check for ASCII keypress only */ if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown && record.Event.KeyEvent.uChar.AsciiChar != 0) { select_data_result_add(lpSelectData, lpQuery->EMode, lpQuery->lpOrig); lpSelectData->EState = SELECT_STATE_SIGNALED; break; } else { /* discard everything else and try again */ if (check_error(lpSelectData, ReadConsoleInput(lpQuery->hFileDescr, &record, 1, &n) == 0)) { break; } } }; }
/* Add a static result */ LPSELECTDATA static_poll_add (LPSELECTDATA lpSelectData, SELECTMODE EMode, HANDLE hFileDescr, LPVOID lpOrig) { LPSELECTDATA res; LPSELECTDATA hd; /* Look for an already initialized static element */ hd = lpSelectData; res = select_data_job_search(&hd, SELECT_TYPE_STATIC); /* Add a new query/result */ select_data_query_add(res, EMode, hFileDescr, lpOrig); select_data_result_add(res, EMode, lpOrig); return hd; }
/* Monitor socket */ 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; 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; mode = iterQuery->EMode; if ((mode & SELECT_MODE_READ) != 0) { 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, WSAEventSelect( (SOCKET)(iterQuery->hFileDescr), aEvents[nEvents], maskEvents) == SOCKET_ERROR); } /* Add stop event */ aEvents[nEvents] = hStop; nEvents++; if (lpSelectData->nError == 0) { check_error(lpSelectData, WaitForMultipleObjects( nEvents, aEvents, FALSE, INFINITE) == WAIT_FAILED); }; if (lpSelectData->nError == 0) { for (i = 0; i < lpSelectData->nQueriesCount; i++) { iterQuery = &(lpSelectData->aQueries[i]); if (WaitForSingleObject(aEvents[i], 0) == WAIT_OBJECT_0) { DEBUG_PRINT("Socket %d has pending events", (i - 1)); if (iterQuery != NULL) { /* 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. Restore the blocking one. */ if (iterQuery->uFlagsFd & FLAGS_FD_IS_BLOCKING) { DEBUG_PRINT("Restore a blocking socket"); iMode = 0; check_error(lpSelectData, WSAEventSelect((SOCKET)(iterQuery->hFileDescr), aEvents[i], 0) != 0 || ioctlsocket((SOCKET)(iterQuery->hFileDescr), FIONBIO, &iMode) != 0); } else { check_error(lpSelectData, WSAEventSelect((SOCKET)(iterQuery->hFileDescr), aEvents[i], 0) != 0); }; CloseHandle(aEvents[i]); aEvents[i] = INVALID_HANDLE_VALUE; } } }
/* Monitor a pipe for input */ void read_pipe_poll (HANDLE hStop, void *_data) { DWORD res; DWORD event; DWORD n; LPSELECTQUERY iterQuery; LPSELECTDATA lpSelectData; DWORD i; DWORD wait; /* Poll pipe */ event = 0; n = 0; lpSelectData = (LPSELECTDATA)_data; wait = 1; DEBUG_PRINT("Checking data pipe"); while (lpSelectData->EState == SELECT_STATE_NONE) { for (i = 0; i < lpSelectData->nQueriesCount; i++) { iterQuery = &(lpSelectData->aQueries[i]); res = PeekNamedPipe( iterQuery->hFileDescr, NULL, 0, NULL, &n, NULL); if (check_error(lpSelectData, (res == 0) && (GetLastError() != ERROR_BROKEN_PIPE))) { break; }; if ((n > 0) || (res == 0)) { lpSelectData->EState = SELECT_STATE_SIGNALED; select_data_result_add(lpSelectData, iterQuery->EMode, iterQuery->lpOrigIdx); }; }; /* Alas, nothing except polling seems to work for pipes. Check the state & stop_worker_event every 10 ms */ if (lpSelectData->EState == SELECT_STATE_NONE) { event = WaitForSingleObject(hStop, wait); /* Fast start: begin to wait 1, 2, 4, 8 and then 10 ms. * If we are working with the output of a program there is * a chance that one of the 4 first calls succeed. */ wait = 2 * wait; if (wait > 10) { wait = 10; }; if (event == WAIT_OBJECT_0 || check_error(lpSelectData, event == WAIT_FAILED)) { break; } } } DEBUG_PRINT("Finish checking data on pipe"); }
/* Monitor socket */ 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; lpSelectData = (LPSELECTDATA)_data; for (nEvents = 0; nEvents < lpSelectData->nQueriesCount; nEvents++) { iterQuery = &(lpSelectData->aQueries[nEvents]); aEvents[nEvents] = CreateEvent(NULL, TRUE, FALSE, NULL); maskEvents = 0; switch (iterQuery->EMode) { 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; } check_error(lpSelectData, WSAEventSelect( (SOCKET)(iterQuery->hFileDescr), aEvents[nEvents], maskEvents) == SOCKET_ERROR); } /* Add stop event */ aEvents[nEvents] = hStop; nEvents++; if (lpSelectData->nError == 0) { check_error(lpSelectData, WaitForMultipleObjects( nEvents, aEvents, FALSE, INFINITE) == WAIT_FAILED); }; if (lpSelectData->nError == 0) { for (i = 0; i < lpSelectData->nQueriesCount; i++) { iterQuery = &(lpSelectData->aQueries[i]); if (WaitForSingleObject(aEvents[i], 0) == WAIT_OBJECT_0) { DEBUG_PRINT("Socket %d has pending events", (i - 1)); if (iterQuery != NULL) { select_data_result_add(lpSelectData, iterQuery->EMode, iterQuery->lpOrigIdx); } } /* WSAEventSelect() automatically sets socket to nonblocking mode. Restore the blocking one. */ if (iterQuery->uFlagsFd & FLAGS_FD_IS_BLOCKING) { DEBUG_PRINT("Restore a blocking socket"); iMode = 1; check_error(lpSelectData, WSAEventSelect((SOCKET)(iterQuery->hFileDescr), aEvents[i], 0) != 0 || ioctlsocket((SOCKET)(iterQuery->hFileDescr), FIONBIO, &iMode) != 0); } else { check_error(lpSelectData, WSAEventSelect((SOCKET)(iterQuery->hFileDescr), aEvents[i], 0) != 0); }; CloseHandle(aEvents[i]); aEvents[i] = INVALID_HANDLE_VALUE; } } }