On Windows 10, I'm waiting for input from the console using
WaitForSingleObject( GetStdHandle(STD_INPUT_HANDLE), ... )
and to cancel this waiting using CancelSynchronousIo().
But the cancellation does nothing (returns 0 and GetLastError() is ERROR_NOT_FOUND).
Any idea what I could be doing wrong?
Should I be able to cancel this waiting for new input on stdin?
(I actually want to do this with any HANDLE whose GetFileType() is FILE_TYPE_CHAR, not only stdin, but stdin is certainly the most important use case and the simplest to test with).
Related discussions I've found:
Synchronous ReadFile() on stdin cannot be unblocked by CancelSynchronousIo()
win32: how stop ReadFile (stdin|pipe)
But unfortunately they only discuss ReadFile(), not WaitForSingleObject(). I've also tried WaitForMultipleObjects() (with just a single object in the array), same problem.
(Background: I'm trying to improve input handling in the GHC Haskell compiler runtime.)
CancelSynchronousIo cancel I/O operations that are issued by the specified thread. more concrete it cancel IRP packets which associated with specified thread via call IoCancelIrp. if use undocumented NtCancelSynchronousIoFile (CancelSynchronousIo internally call it with IoRequestToCancel = 0) we can be more selective - cancel only i/o request which used specified IoRequestToCancel (system check that Irp->UserIosb == IoRequestToCancel and cancel only this requests)
but WaitForSingleObject this is not I/O request. this call not create any IRP which can be canceled. so - no way do this.
however if you use WaitForSingleObjectEx with bAlertable set to TRUE - you can break wait by queue apc to thread by using QueueUserAPC . also if use NtWaitForSingleObject instead WaitForSingleObjectEx we can also alert thread by using undocumented call NtAlertThread. in this case NtWaitForSingleObject will break with STATUS_ALERTED (note that WaitForSingleObjectEx which internally call NtWaitForSingleObject do special check for STATUS_ALERTED and in case this status - again run NtWaitForSingleObject - as result we can not break WaitForSingleObjectEx by call NtAlertThread, but NtWaitForSingleObject will be breaked.
so if you need break waiting for std input - create additional thread, which must call not CancelSynchronousIo (this senseless) but QueueUserAPC or NtAlertThread (only if you use NtWaitForSingleObject for wait). and input thread must wait in alertable state. so demo code can look like:
extern "C" NTSYSCALLAPI NTSTATUS NTAPI NtAlertThread(HANDLE ThreadHandle);
VOID NTAPI OnApc(ULONG_PTR Parameter)
{
DbgPrint("OnApc(%p)\n", Parameter);
}
DWORD CALLBACK BreakWaitThread(HANDLE hThread)
{
switch (LONG status = MessageBoxW(0, L"Use Apc(yes) or Alert(No) ?", L"BreakWaitThread",
MB_ICONQUESTION|MB_YESNOCANCEL|MB_DEFBUTTON3))
{
case IDYES:
if (!QueueUserAPC(OnApc, hThread, 0))
{
DbgPrint("QueueUserAPC=%u\n", GetLastError());
}
break;
case IDNO:
if (0 > (status = NtAlertThread(hThread)))
{
DbgPrint("AlertThread=%x\n", status);
}
break;
case IDCANCEL:
DbgPrint("canceled\n");
break;
default:
DbgPrint("MessageBox=%x\n", status);
}
CloseHandle(hThread);
return 0;
}
void ConsoleLoop(HANDLE hStdIn)
{
ULONG NumberOfEvents, NumberOfEventsRead, n;
INPUT_RECORD buf[8], *p;
for (;;)
{
switch (ZwWaitForSingleObject(hStdIn, TRUE, 0))
//switch (WaitForSingleObjectEx(hStdIn, INFINITE, TRUE))
{
case WAIT_OBJECT_0:
while (GetNumberOfConsoleInputEvents(hStdIn, &NumberOfEvents) && NumberOfEvents)
{
do
{
NumberOfEventsRead = min(RTL_NUMBER_OF(buf), NumberOfEvents);
if (ReadConsoleInput(hStdIn, buf, NumberOfEventsRead, &NumberOfEventsRead) && NumberOfEventsRead)
{
n = NumberOfEventsRead;
p = buf;
do
{
if (p->EventType == KEY_EVENT)
{
DbgPrint("%u(%u) %C %x %x %x\n",
p->Event.KeyEvent.bKeyDown,
p->Event.KeyEvent.wRepeatCount,
p->Event.KeyEvent.uChar.UnicodeChar,
p->Event.KeyEvent.wVirtualKeyCode,
p->Event.KeyEvent.wVirtualScanCode,
p->Event.KeyEvent.dwControlKeyState);
if (VK_OEM_PERIOD == p->Event.KeyEvent.wVirtualKeyCode)
{
return ;//if user type '.' return for demo
}
}
} while (p++, --n);
}
else
{
FlushConsoleInputBuffer(hStdIn);
break;
}
} while (NumberOfEvents -= NumberOfEventsRead);
}
continue;
case STATUS_USER_APC:
DbgPrint("\nUSER_APC\n");
return;
case STATUS_ALERTED:
DbgPrint("\nALERTED\n");
return;
case WAIT_FAILED :
DbgPrint("\nWAIT_FAILED=%u\n", GetLastError());
return;
default:
__debugbreak();
return;
}
}
}
void SimpleDemo()
{
if (HANDLE hCurrentThread = OpenThread(THREAD_ALERT|THREAD_SET_CONTEXT , FALSE, GetCurrentThreadId()))
{
ULONG dwThreadId;
HANDLE hThread = CreateThread(0, 0, BreakWaitThread, hCurrentThread, 0, &dwThreadId);
if (hThread)
{
ConsoleLoop(GetStdHandle(STD_INPUT_HANDLE));
PostThreadMessage(dwThreadId, WM_QUIT, 0, 0);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
else
{
CloseHandle(hCurrentThread);
}
}
}
Console I/O is difficult to use asynchronously, it is simply not designed for it. See IO Completion Ports (IOCP) and Asynchronous I/O through STDIN, STDOUT and STDERR for some possible workarounds.
If that is not an option for you, then you will have to either:
use WaitForSingleObject() in a loop with a short timeout. Create a flag variable that your loop can look at on each iteration to break the loop if the flag is set.
use WaitForMutipleObjects(), giving it 2 HANDLEs to wait on - one for the console (or whatever), and one for an event object from CreateEvent(). Then you can signal the event with SetEvent() when you want to break the wait. The return value of WaitForMutipleObjects() will tell you which HANDLE was signaled.
Related
I'm writing a Class for COM ports in C++ using win-api. Righ now I test the functionality on RS232 with connected Rx and Tx pins.
I've encountered somewhat weird problem. I use separate thread for reading from the COM port. Within the thread I use SetCommMask, WaitCommEvent and WaitForSingleObject to wait for char arrival into buffer. However the WaitForSingleObject tends to exit without actually receiving any chars.
I assumed this was caused by wrong use of mentioned functions, but then I discovered, that premature exit does not occur every time (first time always works as intended).
In second go the thread enters the waiting state and exits a while later proceeding to ReadFile, where it waits indefinitely, because the buffer is empty, no data is to be sent and Total timeout is not used.
I've already been advised to simply use ReadFile and process only the data I acquire, however I use another thread to check if the communication channel has been disconnected and right now I need to distinguish between waiting for data and reading data.
Calling ClearCommError to check input buffer with ReadFile is not an option, because in such a case InQue is always 0. Therefore I cannot tell whether ReadFile is actually reading or waiting.
//following code runs in separate thread
DWORD dwEventMask1, dwEventMask2, LastError, Status;
OVERLAPPED Overlapped; HANDLE Serial_Port_Handle;
std::string stringBuffer("");
const size_t ReadBufferLength = 256;
char tempBuffer[ReadBufferLength];
GetCommMask(Serial_Port_Handle, &dwEventMask1);
if (dwEventMask1) // Before starting the thread I check the state of Input Buffer with GetCommError().
{ // If Buffer is not empty, CommMask is set to 0 signaling there is no need for waiting.
Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
//wait for comm event
if (!WaitCommEvent(Serial_Port_Handle, &dwEventMask1, &Overlapped))
{
if ((LastError = GetLastError()) == ERROR_IO_PENDING)
{
Waiting = true; //signal bool for synchronization purposes
if ((Status = WaitForSingleObject(Overlapped.hEvent, INFINITE)) == WAIT_OBJECT_0)
{
GetCommMask(Serial_Port_Handle, &dwEventMask2);
Waiting = false;
CloseHandle(Overlapped.hEvent);
// I close handle and set all members of Overlapped struct to 0
}
if (dwEventMask2 !== dwEventMask1) // check if wait have not exited because of SetCommMast()
return;
}
}
}
do // this loop reads from input buffer until empty
{
Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);//set up read overlapped operation
if (ReadFile(Serial_Port_Handle, tempBuffer, ReadBufferLength - 1, &NoBytesRead, &Overlapped)) //start read opperation
{ //Read operation done on 1 go
GetOverlappedResult(Serial_Port_Handle, &Overlapped, &NoBytesRead, FALSE); //get NoBytesRead
CloseHandle(Overlapped.hEvent)
stringBuffer.append(tempBuffer, (size_t) NoBytesRead); // save read data
}
else if ((LastError = GetLastError()) == ERROR_IO_PENDING) //operation not yet complete
{
GetOverlappedResult(Serial_Port_Handle, &Overlapped, &NoBytesRead, TRUE); // wait for completion
stringBuffer.append(tempBuffer, (size_t)NoBytesRead);
}
else
{
CloseHandle(Overlapped.hEvent)
return;
}
} while ((NoBytesRead == (ReadBufferLength - 1)) && NoBytesRead);
// Loop runs while tempBuffer's full capacity is used.
// I realize that since I don't use Total Timeout there is a possibility
// of the loop getting stuck. If you can suggest other solution than using
// Total Timeout or use GetCommError() to get input buffer state, please do so.
return;
This code is somewhat simplified (checking for return values, ets.).
1) Have any of you experienced such a behaviour?
2) I use OVERLAPPED operations in the code. After the operation exits I always use CloseHandle and reinitialize the OVERLAPPED structure before using it for another operation. Is this correct or is resetting the structure sufficient?
It is bad logic as a whole. For example, there are the following issues.
CreateEvent/CloseHandle should not executed at every ReadFile/WaitCommEvent.
The usage of GetCommMask/WaitCommEvent is also wrong.
The read data size specified in ReadFile is fixed regardless of the situation.
It also includes the comment on #RbMm.
You may want to redesign your program with reference to the following articles and source code:
Synchronization and Overlapped Input and Output
Serial Communications
bmo/mttty
In Addition:
I did not notice that a file handle (not an event handle) was specified for WaitForSingleObject, as pointed out by #Rita Han.
The biggest problem is that.
However, the situation that it is better to redesign has not changed.
There is no description of WaitCommEvent and Overlapped for it in the source of #Rita Han's answer. Also, the read data size is fixed in ReadFile.
On the other hand:
Although it does not occur in the source code of the question, it is possible for WaitCommEvent/WaitForSingleObject to generate an event that is not specified in SetCommMask.
While the WaitCommEvent is waiting for completion, change the event mask with SetCommMask.
Remarks - WaitCommEvent function
If a process attempts to change the device handle's event mask by using the SetCommMask function while an overlapped WaitCommEvent operation is in progress, WaitCommEvent returns immediately. The variable pointed to by the lpEvtMask parameter is set to zero.
While WaitCommEvent is waiting for completion, call WaitCommEvent multiple times using the same Overlapped structure.
Synchronization and Overlapped Input and Output
When performing multiple simultaneous overlapped operations on a single thread, the calling thread must specify an OVERLAPPED structure for each operation. Each OVERLAPPED structure must specify a handle to a different manual-reset event object.
A thread should not reuse an event with the assumption that the event will be signaled only by that thread's overlapped operation. An event is signaled on the same thread as the overlapped operation that is completing. Using the same event on multiple threads can lead to a race condition in which the event is signaled correctly for the thread whose operation completes first and prematurely for other threads using that event.
The document is described as above, but depending on the device driver/vendor, the WaitCommEvent that is called later ends with an error, and the WaitCommEvent waiting for completion is lpEvtMask return with zero (as in SetCommMask).
For multiple Overlapped structure variables:
A common programming know-how is that using a single variable for multiple purposes is prone to bugs.
If you are designing in asynchronous and/or multi-threading, it is better to prepare at least three Overlapped structure variables for ReadFile, WriteFile, WaitCommEvent.
About starting ReadFile regardless of the state of the input buffer:
This is about calling ReadFile with a fixed length of 256 bytes without acquiring the size of the received data in the input buffer of the device driver.
In fact, even if all the data arrives, if it is less than 256 bytes, it will always be delayed until a 256 byte receive timeout occurs.
For example, the loop reads one byte at a time until a timeout error occurs, which means the end of the received data (1-byte read timeout would have no impact).
Or, as answered in the previous article, use ClearCommError to obtain the size of the data stored in the device driver's input buffer, and call ReadFile specifying that size.
There will be no problem with the application-side buffer handling you are explaining.
About the behavior of WaiCommEvent when calling SetCommMask:
It may depend on the device driver you are using.
However the WaitForSingleObject tends to exit without actually
receiving any chars.
Wait for the event handle instead of serial device handle.
I got it working. The following is my code example you can have a try:
DWORD errCode = 0;
BOOL result = false;
HANDLE serialDeviceHdl = CreateFile(L"COM8", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (!serialDeviceHdl)
{
errCode = GetLastError();
cout << "Open device failed. Error code: " << errCode << endl;
return 0;
}
OVERLAPPED overlappedForWrite = {};
overlappedForWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD writenSize = 0;
result = WriteFile(serialDeviceHdl, "hello", 5, &writenSize, &overlappedForWrite);
if (FALSE == result)
{
errCode = GetLastError();
if (ERROR_IO_PENDING == errCode)
{
cout << "Overlapped I/O operation is in progress." << endl;
}
else
{
cout << "Write to device failed. Error code: " << errCode << endl;
}
}
DWORD returnValue = WaitForSingleObject(overlappedForWrite.hEvent, INFINITE);
if (WAIT_OBJECT_0 == returnValue)
{
cout << "The state of the specified object is signaled." << endl;
}
else
{
cout << "Wait for single object failed. Error code: " << returnValue << endl;
}
CHAR readBuf[5];
DWORD readSize = 0;
OVERLAPPED overlappedForRead = {};
overlappedForRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
result = ReadFile(serialDeviceHdl, readBuf, 5, &readSize, &overlappedForRead);
if (FALSE == result)
{
errCode = GetLastError();
if (ERROR_IO_PENDING == errCode)
{
cout << "Overlapped I/O operation is in progress." << endl;
}
else
{
cout << "Write to device failed. Error code: " << errCode << endl;
}
}
returnValue = WaitForSingleObject(overlappedForRead.hEvent, INFINITE);
if (WAIT_OBJECT_0 == returnValue)
{
cout << "The state of the specified object is signaled." << endl;
}
else
{
cout << "Wait for single object failed. Error code: " << returnValue << endl;
}
UWP (or "Metro") apps in Windows 8/10 can be suspended when they are not in the foreground. Apps in this state continue to exist but no longer consume CPU time. It looks like this change was introduced to improve performance on low-power/storage devices like tablets and phones.
What is the most elegant and simple method to detect a process in this state?
I can see 2 possible solutions at the moment:
Call NtQuerySystemInformation() and the enumerate each process and each thread. A process is "suspended" if all threads are in the suspended state. This approach will require a lot of code and critically NtQuerySystemInformation() is only semi-documented and could be removed in a future OS. NtQueryInformationProcess() may also offer a similar solution with the same problem.
Call GetProcessTimes() and record the counters for each process. Wait some longish time (minutes) and check again. If the process counters haven't changed then assume the process is suspended. I admit this is a hack but maybe could work if the time period is long enough.
Is there a more elegant way?
for this exist PROCESS_EXTENDED_BASIC_INFORMATION - meaning of flags in it described in this answer. you are need IsFrozen flag. so you need open process with PROCESS_QUERY_LIMITED_INFORMATION access (for do this for all processes, you will be need have SE_DEBUG_PRIVILEGE enabled in token). and call NtQuerySystemInformation with ProcessBasicInformation and PROCESS_EXTENDED_BASIC_INFORMATION as input. for enumerate all processes we can use NtQuerySystemInformation with SystemProcessInformation. of course possible and use CreateToolhelp32Snapshot + Process32First + Process32Next but this api very not efficient, compare direct call to NtQuerySystemInformation
also possible enumerate all threads in process and check it state and if state wait - wait reason. this is very easy, because all this information already returned by single call to NtQuerySystemInformation with SystemProcessInformation. with this we not need open processes. usually both this ways give the same result (for suspended/frozen) processes, but however use IsFrozen is most correct solution.
void PrintSuspended()
{
BOOLEAN b;
RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &b);
ULONG cb = 0x1000;
NTSTATUS status;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (PBYTE buf = new BYTE[cb])
{
if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
union {
PBYTE pb;
SYSTEM_PROCESS_INFORMATION* spi;
};
pb = buf;
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
if (!spi->UniqueProcessId)
{
continue;
}
if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
(ULONG)(ULONG_PTR)spi->UniqueProcessId))
{
PROCESS_EXTENDED_BASIC_INFORMATION pebi;
if (0 <= NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pebi, sizeof(pebi), 0) &&
pebi.Size >= sizeof(pebi))
{
if (pebi.IsFrozen)
{
DbgPrint("f:%x %wZ\n", spi->UniqueProcessId, spi->ImageName);
}
}
CloseHandle(hProcess);
}
if (ULONG NumberOfThreads = spi->NumberOfThreads)
{
SYSTEM_THREAD_INFORMATION* TH = spi->TH;
do
{
if (TH->ThreadState != StateWait || TH->WaitReason != Suspended)
{
break;
}
} while (TH++, --NumberOfThreads);
if (!NumberOfThreads)
{
DbgPrint("s:%x %wZ\n", spi->UniqueProcessId, spi->ImageName);
}
}
} while (NextEntryOffset = spi->NextEntryOffset);
}
delete [] buf;
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
}
I am writing a simple Named Pipes server for Windows, calling the Windows API (in Java with JNA but this is not relevant).
I am trying to figure out how to avoid that the server stays stuck forever waiting for a client to connect or for data to come from the client.
The server code does the following:
1) It creates the pipe by calling CreateNamedPipe, with PIPE_WAIT in the dwPipeMode argument.
2) It calls ConnectNamedPipe which doesn't return until a client has connected.
3) It enters a loop where it repeatedly reads a message from the client by calling ReadFile which doesn't return until data is read, and for each received message it sends a message back to the client in response by calling WriteFile.
4) After many such conversations the client and the server will disconnect from the pipe.
I just would like to be able to set timeouts in the wait for ConnectNamedPipe at step 2 and ReadFile at step 3, and I can't see where to set the timeouts. There is the nDefaultTimeOut argument in CreateNamedPipe function, but it doesn't really sound to be intended for that; the API doc says:
The default time-out value, in milliseconds, if the WaitNamedPipe function specifies NMPWAIT_USE_DEFAULT_WAIT.
So the nDefaultTimeOut arg in CreateNamedPipe sounds like the default timeout that the clients which would connect to the pipe would use for their operations and only if they call the WaitNamedPipe function. In fact in my tests values of 0 or 1000 don't make a difference, the call to ConnectNamedPipe never returns (unless a client connects). What I'm looking for is timeouts in the server instead, on the calls to ConnectNamedPipe and ReadFile.
As the doc of CreateNamedPipe, for the dwPipeMode argument with PIPE_WAIT says, Blocking mode is enabled. When the pipe handle is specified in the ReadFile, WriteFile, or ConnectNamedPipe function, the operations are not completed until there is data to read, all data is written, or a client is connected. Use of this mode can mean waiting indefinitely in some situations for a client process to perform an action.
So maybe the way to implement such timeouts is to create the pipe in non-blocking mode (with PIPE_NOWAIT instead of PIPE_WAIT) so that calls to ReadFile, WriteFile and ConnectNamedPipe return immediately, and then somehow monitor myself the event (client connected or data received) in a loop, and check myself within the loop whether a timeout elapsed or another interrupting event occurred (like the user clicking a Cancel button) ?
ADDED: It looks like for the ReadFile call I might be able to use PeekNamedPipe which returns immediately, to check if there is data to read, and only then call ReadFile. I will try that. But I still have the same problem for the call to ConnectNamedPipe.
ADDED: As I suspected and the answers confirmed, being a novice to pipes I was looking at them from a somehow skew angle, from which the need for timeouts appeared greater than it actually is.
F.ex. the reasoning behind wanting to timeout calls to ReadFile was that if I (the server) am inside it reading data from the client and the client suddenly shuts down, sometimes I might end up stuck inside the ReadFile. But now I know that if the ReadFile is reading from a pipe and the client shuts down, the ReadFile will always error out, so the execution won't be stuck inside it.
I suggest you set FILE_FLAG_OVERLAPPED and use an event to check/wait for completion.
Although this is originally intended for asynchronous IO, you can instead time the event to your predefined time to live.
If you then wanted to cancel the I/O operation, you can use the CancelIo() function. If you just wanted to do some work and then resume waiting, you can do that too - timing out the wait doesn't automatically cancel the I/O, so you would not need to call ConnectNamedPipe again.
You could also, as you yourself suggested set PIPE_NOWAIT and poll the connection until successfull, either way should bring the same result in this use case. Note however that this is legacy functionality and Microsoft discourage use of this option.
Some real-world code to demonstrate the asynchronous use of the server end of a pipe, in a GUI application:
void wait_for_object(HANDLE object)
{
DWORD dw;
MSG msg;
for (;;)
{
dw = MsgWaitForMultipleObjectsEx(1, &object, INFINITE, QS_ALLINPUT, 0);
if (dw == WAIT_OBJECT_0) break;
if (dw == WAIT_OBJECT_0 + 1)
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
continue;
}
srvfail(L"sleep() messageloop", GetLastError());
}
}
HANDLE server_pipe;
HANDLE io_event;
void pipe_connection(void)
{
OVERLAPPED overlapped;
DWORD dw, err;
SecureZeroMemory(&overlapped, sizeof(overlapped));
overlapped.hEvent = io_event;
if (!ReadFile(server_pipe, input_buffer, sizeof(input_buffer) - 1, NULL, &overlapped))
{
err = GetLastError();
if (err == ERROR_IO_PENDING)
{
wait_for_object(io_event);
if (!GetOverlappedResult(server_pipe, &overlapped, &dw, FALSE))
{
srvfail(L"Read from pipe failed asynchronously.", GetLastError());
}
}
else
{
srvfail(L"Read from pipe failed synchronously.", GetLastError());
}
}
else
{
if (!GetOverlappedResult(server_pipe, &overlapped, &dw, FALSE))
{
srvfail(L"GetOverlappedResult failed reading from pipe.", GetLastError());
}
}
input_buffer[dw] = '\0';
process_command();
if (!WriteFile(server_pipe, &output_struct,
((char *)&output_struct.output_string - (char *)&output_struct) + output_struct.string_length,
NULL, &overlapped))
{
err = GetLastError();
if (err == ERROR_IO_PENDING)
{
wait_for_object(io_event);
if (!GetOverlappedResult(server_pipe, &overlapped, &dw, FALSE))
{
srvfail(L"Write to pipe failed asynchronously.", GetLastError());
}
}
else
{
srvfail(L"Write to pipe failed synchronously.", GetLastError());
}
}
else
{
if (!GetOverlappedResult(server_pipe, &overlapped, &dw, FALSE))
{
srvfail(L"GetOverlappedResult failed writing to pipe.", GetLastError());
}
}
if (!FlushFileBuffers(server_pipe)) srvfail(L"FlushFileBuffers failed.", GetLastError());
if (!DisconnectNamedPipe(server_pipe)) srvfail(L"DisconnectNamedPipe failed.", GetLastError());
}
void server(void)
{
OVERLAPPED overlapped;
DWORD err, dw;
// Create the named pipe
server_pipe = CreateNamedPipe(pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, buffer_size, buffer_size, 0, NULL);
if (server_pipe == INVALID_HANDLE_VALUE) srvfail(L"CreateNamedPipe failed.", GetLastError());
// Wait for connections
io_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (io_event == NULL) srvfail(L"CreateEvent(io_event) failed.", GetLastError());
for (;;)
{
SecureZeroMemory(&overlapped, sizeof(overlapped));
overlapped.hEvent = io_event;
if (!ConnectNamedPipe(server_pipe, &overlapped))
{
err = GetLastError();
if (err == ERROR_PIPE_CONNECTED)
{
pipe_connection();
}
else if (err == ERROR_IO_PENDING)
{
wait_for_object(io_event);
if (!GetOverlappedResult(server_pipe, &overlapped, &dw, FALSE))
{
srvfail(L"Pipe connection failed asynchronously.", GetLastError());
}
pipe_connection();
}
else
{
srvfail(L"Pipe connection failed synchronously.", GetLastError());
}
}
else
{
if (!GetOverlappedResult(server_pipe, &overlapped, &dw, FALSE))
{
srvfail(L"GetOverlappedResult failed connecting pipe.", GetLastError());
}
pipe_connection();
}
}
}
(This code has been edited down from the original to remove extraneous logic. I haven't tried compiling the edited version, so there may be some minor problems. Also note the use of global variables, which is OK in my case because the application is very small, but should usually be avoided.)
The use of MsgWaitForMultipleObjectsEx() allows window messages to be processed while you are waiting for I/O to complete. If you were also waiting for something else to happen, you could pass it an array of handles rather than just a single handle - for example, if you wanted to monitor a child process and do something when it exited, you could pass an array containing both io_event and the process handle. And if you just had to do some other job periodically, you could set a timeout for the wait, or use a window timer.
I 'm using the CreatePipe to redirect stdin/out from a process to my process.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365152(v=vs.85).aspx
This works ok so far. The problem is when I want to terminate the thread that waits for the client process to write something.
I can use CancelIoEx() but this only works in Vista+, and I also want an XP solution. Without CancelIoEx(), ReadFile() in the other thread never returns.
I cannot also use OVERLAPPED ReadFile, for pipes created with CreatePipe do not support it.
Any options?
Save a handle to the write end of the stdout pipe when creating the child process. You can then write a character to this to unblock the thread that has called ReadFile (that is reading from the read end of the stdout pipe). In order not to interpret this as data, create an Event (CreateEvent) that is set (SetEvent) in the thread that writes the dummy character, and is checked after ReadFile returns. A bit messy, but seems to work.
/* Init */
stdout_closed_event = CreateEvent(NULL, TRUE, FALSE, NULL);
/* Read thread */
read_result = ReadFile(stdout_read, data, buf_len, &bytes_read, NULL);
if (!read_result)
ret = -1;
else
ret = bytes_read;
if ((bytes_read > 0) && (WAIT_OBJECT_0 == WaitForSingleObject(stdout_closed_event, 0))) {
if (data[bytes_read-1] == eot) {
if (bytes_read > 1) {
/* Discard eot character, but return the rest of the read data that should be valid. */
ret--;
} else {
/* No data. */
ret = -1;
}
}
}
/* Cancel thread */
HMODULE mod = LoadLibrary (L"Kernel32.dll");
BOOL WINAPI (*cancel_io_ex) (HANDLE, LPOVERLAPPED) = NULL;
if (mod != NULL) {
cancel_io_ex = (BOOL WINAPI (*) (HANDLE, LPOVERLAPPED)) GetProcAddress (mod, "CancelIoEx");
}
if (cancel_io_ex != NULL) {
cancel_io_ex(stdout_write_pipe, NULL);
} else {
SetEvent(stdout_closed_event);
WriteFile(stdout_write_pipe, &eot, 1, &written, NULL);
}
When do you need to use this type of modified message loop in multithreaded application?
DWORD nWaitCount;
HANDLE hWaitArray[4];
BOOL quit;
int exitCode;
while (!quit)
{
MSG msg;
int rc;
rc = MsgWaitForMultipleObjects(nWaitCount, hWaitArray, FALSE, INFINITE,QS_ALLINPUT);
if (rc == WAIT_OBJECT_O + nWaitCount)
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
quit = TRUE;
exitCode = msg.wParam;
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else if (rc >= WAIT_OBJECT_0 && rc < WAIT_OBJECT_0 + nwaitCount)
{
int nlndex = rc - WAIT_OBJECT_0;
}
else if (rc >= WAIT_ABANDONED_0 && rc < WAIT_ABANDONED_0+ nWaitCount)
{
int nlndex = rc - WAIT_ABANDONED_O;
}
}
Hopefully never. But it is the kind of code you have to write when you want the UI thread to block on synchronization objects. A UI thread is not permitted to block, Windows prevents you from calling WaitForMultipleObjects(). The reason is that it is very likely to cause deadlock.
The reason for that is COM. COM is everywhere in Windows, the most common examples are the clipboard, drag+drop and the shell dialogs. COM marshals interface method calls made from a worker thread for COM objects that live on the STA (Single Threaded Apartment) by using the message loop. If the STA thread isn't pumping messages then the call won't complete. And calls that can't complete are ingredient number one for deadlock. Add a UI thread that waits for the worker thread to complete and deadlock is assured.
You avoid this kind of code by having a worker thread use PostMessage() to signal the UI thread that something important happened.