Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to change HANDLE that has been opened for synchronous I/O to be opened for asynchronous I/O during its lifetime?

Most of my daily programming work in Windows is nowadays around I/O operations of all kind (pipes, consoles, files, sockets, ...). I am well aware of different methods of reading and writing from/to different kinds of handles (Synchronous, asynchronous waiting for completion on events, waiting on file HANDLEs, I/O completion ports, and alertable I/O). We use many of those.

For some of our applications it would be very useful to have only one way to treat all handles. I mean, the program may not know, what kind of handle it has received and we would like to use, let's say, I/O completion ports for all.

So first I would ask:

Let's assume I have a handle:

HANDLE h;

which has been received by my process for I/O from somewhere. Is there any easy and reliable way to find out what flags it has been created with? The main flag in question is FILE_FLAG_OVERLAPPED.

The only way known to me so far, is to try to register such handle into I/O completion port (using CreateIoCompletionPort()). If that succeeds the handle has been created with FILE_FLAG_OVERLAPPED. But then only I/O completion port must be used, as the handle can not be unregistered from it without closing the HANDLE h itself.

Providing there is an easy a way to determine presence of FILE_FLAG_OVERLAPPED, there would come my second question:

Is there any way how to add such flag to already existing handle? That would make a handle that has been originally open for synchronous operations to be open for asynchronous. Would there be a way how to create opposite (remove the FILE_FLAG_OVERLAPPED to create synchronous handle from asynchronous)?

I have not found any direct way after reading through MSDN and googling a lot. Would there be at least some trick that could do the same? Like re-creating the handle in same way using CreateFile() function or something similar? Something even partly documented or not documented at all?

The main place where I would need this, is to determine the the way (or change the way) process should read/write from handles sent to it by third party applications. We can not control how third party products create their handles.

Dear Windows gurus: help please!

With regards

Martin

like image 206
Martin Dobšík Avatar asked Mar 19 '10 07:03

Martin Dobšík


1 Answers

3 years passed and Windows 8 has been released. Thanks to the regression introduced in implementation of console in Windows 8 I got to do something about the issue which triggered this question. So I have finally tried to use ReOpenFile() function call.

In one sentence: for my purposes it is useless.

The ReOpenFile() API is used for “taking an existing file handle and getting another handle that has a different set of access rights”. At least that is stated in the original article.

I tried to use The ReOpenFile() on Console input handle:

  stdin_in = GetStdHandle(STD_INPUT_HANDLE);
  stdin_in_operlapped = ReOpenFile(stdin_in, GENERIC_READ | GENERIC_WRITE,
                                   FILE_SHARE_READ, FILE_FLAG_OVERLAPPED);
  if (stdin_in_operlapped ==  INVALID_HANDLE_VALUE)
    {
      my_debug("failed to ReOpen stdin handle with OVERLAPPED flag: %d", GetLastError());
      exit(1);
    }

And what I get is: error 1168: “Element Not Found”. “Thank you Microsoft”. I will not even try to use it for anonymous pipes, since the documentation states:

“Asynchronous (overlapped) read and write operations are not supported by anonymous pipes. This means that you cannot use the ReadFileEx and WriteFileEx functions with anonymous pipes. In addition, the lpOverlapped parameter of ReadFile and WriteFile is ignored when these functions are used with anonymous pipes.”

Thank you, people, all for your suggestions. When reading from handle asynchronously, one has to be ready also for the fact that the operation may complete synchronously. That I know. The main reason I was asking this question is:

when a synchronous read has been issued on some objects (at least anonymous pipes, and console input in Windows 8) then calling CloseHandle() from another thread on the same handle will either fail, or hang, until the ReadFile() completes; that means it will hang indefinitely in many cases. That is the reason why I wanted to replace the synchronous handle with asynchronous.

Now it is clear to me that it is simply not possible in Windows operating systems to cancel some read operations in straightforward way. When reading from synchronous handles, one just has to exit from application even if ReadFile() is still reading from a handle in some thread, because it is simply impossible to reliably wake up such a read operation. In know... In newer OS it is possible to cancel that operation. However, there is no way to know weather the thread is in the ReadFile() call already, or not yet. If ReadFile() is not called yet then there is no operation to cancel and subsequent read will hang. The only way would be to close the handle, but that operation hangs, or fails on some objects and on some operating systems. The only proper solution to this is asynchronous I/O. But, as I mentioned in the beginning, our APP is started by third party apps and we can't force them all to always create named pipes with overlapped flag set for the stdio.

I am giving up and going to implement nasty ugly hacks... we will have to keep reading without OVERLAPPED structure from HANDLEs that have been created with OVERLAPPED flag, and leaking handles and threads....

like image 158
Martin Dobšík Avatar answered Sep 25 '22 20:09

Martin Dobšík