win32: use overlapped events for streams

Any file handle created with FLAG_OVERLAPPED must have
ReadFile()/WriteFile() called with an OVERLAPPED structure.
Failing to do so will give unspecified results, invalid read/write or
corruption.

Without FLAG_OVERLAPPED, it is not possible to read and write
concurrently, even with two seperate threads, created by 2 input and
output gio streams. Also, only with FLAG_OVERLAPPED may an IO
operation be asynchronous and thus be cancellable.

We may want to call ReOpenFile() to make sure the FLAG is set, but
this API is only available since Vista+.

According to MSDN doc, adding the OVERLAPPED argument for IO operation
on handles without FLAG_OVERLAPPED is allowed, and indeed the existing
test still passes.

v2:
- update GetLastError() after _g_win32_overlap_wait_result ()
- split the unrelated ERROR_MORE_DATA handling

https://bugzilla.gnome.org/show_bug.cgi?id=679288
This commit is contained in:
Marc-André Lureau
2012-07-02 21:45:41 +02:00
parent 96a0c589ee
commit 23d80a04da
4 changed files with 121 additions and 25 deletions

View File

@@ -293,6 +293,8 @@ g_win32_output_stream_write (GOutputStream *stream,
GWin32OutputStream *win32_stream;
BOOL res;
DWORD nbytes, nwritten;
OVERLAPPED overlap = { 0, };
gssize retval = -1;
win32_stream = G_WIN32_OUTPUT_STREAM (stream);
@@ -304,24 +306,49 @@ g_win32_output_stream_write (GOutputStream *stream,
else
nbytes = count;
res = WriteFile (win32_stream->priv->handle, buffer, nbytes, &nwritten, NULL);
if (!res)
overlap.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
g_return_val_if_fail (overlap.hEvent != NULL, -1);
res = WriteFile (win32_stream->priv->handle, buffer, nbytes, &nwritten, &overlap);
if (res)
retval = nwritten;
else
{
int errsv = GetLastError ();
gchar *emsg = g_win32_error_message (errsv);
if (errsv == ERROR_HANDLE_EOF)
return 0;
if (errsv == ERROR_IO_PENDING &&
_g_win32_overlap_wait_result (win32_stream->priv->handle,
&overlap, &nwritten, cancellable))
{
retval = nwritten;
goto end;
}
g_set_error (error, G_IO_ERROR,
g_io_error_from_win32_error (errsv),
_("Error writing to handle: %s"),
emsg);
g_free (emsg);
return -1;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
goto end;
errsv = GetLastError ();
if (errsv == ERROR_HANDLE_EOF ||
errsv == ERROR_BROKEN_PIPE)
{
retval = 0;
}
else
{
gchar *emsg;
emsg = g_win32_error_message (errsv);
g_set_error (error, G_IO_ERROR,
g_io_error_from_win32_error (errsv),
_("Error writing to handle: %s"),
emsg);
g_free (emsg);
}
}
return nwritten;
end:
CloseHandle (overlap.hEvent);
return retval;
}
static gboolean