From 34b2f4ffcab7b054fb9dbac93717c3695221a184 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 14 Sep 2024 19:18:08 -0700 Subject: [PATCH] Use non-blocking pipes for process I/O on Windows Fixes https://github.com/libsdl-org/SDL/issues/10846 --- src/file/SDL_iostream.c | 29 ++++++++++++++++++++---- src/process/windows/SDL_windowsprocess.c | 13 +++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/file/SDL_iostream.c b/src/file/SDL_iostream.c index 0d9f39fbb..41ac90fd8 100644 --- a/src/file/SDL_iostream.c +++ b/src/file/SDL_iostream.c @@ -202,8 +202,17 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size, if (total_need < READAHEAD_BUFFER_SIZE) { if (!ReadFile(iodata->h, iodata->data, READAHEAD_BUFFER_SIZE, &bytes, NULL)) { - if (GetLastError() != ERROR_HANDLE_EOF && GetLastError() != ERROR_BROKEN_PIPE) { + DWORD error = GetLastError(); + switch (error) { + case ERROR_BROKEN_PIPE: + case ERROR_HANDLE_EOF: + break; + case ERROR_NO_DATA: + *status = SDL_IO_STATUS_NOT_READY; + break; + default: WIN_SetError("Error reading from datastream"); + break; } return 0; } @@ -214,8 +223,17 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size, total_read += read_ahead; } else { if (!ReadFile(iodata->h, ptr, (DWORD)total_need, &bytes, NULL)) { - if (GetLastError() != ERROR_HANDLE_EOF && GetLastError() != ERROR_BROKEN_PIPE) { + DWORD error = GetLastError(); + switch (error) { + case ERROR_BROKEN_PIPE: + case ERROR_HANDLE_EOF: + break; + case ERROR_NO_DATA: + *status = SDL_IO_STATUS_NOT_READY; + break; + default: WIN_SetError("Error reading from datastream"); + break; } return 0; } @@ -227,7 +245,6 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size, static size_t SDLCALL windows_file_write(void *userdata, const void *ptr, size_t size, SDL_IOStatus *status) { IOStreamWindowsData *iodata = (IOStreamWindowsData *) userdata; - const size_t total_bytes = size; DWORD bytes; if (iodata->left) { @@ -248,11 +265,13 @@ static size_t SDLCALL windows_file_write(void *userdata, const void *ptr, size_t } } - if (!WriteFile(iodata->h, ptr, (DWORD)total_bytes, &bytes, NULL)) { + if (!WriteFile(iodata->h, ptr, (DWORD)size, &bytes, NULL)) { WIN_SetError("Error writing to datastream"); return 0; } - + if (bytes == 0 && size > 0) { + *status = SDL_IO_STATUS_NOT_READY; + } return bytes; } diff --git a/src/process/windows/SDL_windowsprocess.c b/src/process/windows/SDL_windowsprocess.c index 6ad61403e..945edf716 100644 --- a/src/process/windows/SDL_windowsprocess.c +++ b/src/process/windows/SDL_windowsprocess.c @@ -200,6 +200,7 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID HANDLE stdin_pipe[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; HANDLE stdout_pipe[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; HANDLE stderr_pipe[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; + DWORD pipe_mode = PIPE_NOWAIT; bool result = false; // Keep the malloc() before exec() so that an OOM won't run a process at all @@ -263,6 +264,10 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID stdin_pipe[WRITE_END] = INVALID_HANDLE_VALUE; goto done; } + if (!SetNamedPipeHandleState(stdin_pipe[WRITE_END], &pipe_mode, NULL, NULL)) { + WIN_SetError("SetNamedPipeHandleState()"); + goto done; + } if (!SetHandleInformation(stdin_pipe[WRITE_END], HANDLE_FLAG_INHERIT, 0) ) { WIN_SetError("SetHandleInformation()"); goto done; @@ -296,6 +301,10 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID stdout_pipe[WRITE_END] = INVALID_HANDLE_VALUE; goto done; } + if (!SetNamedPipeHandleState(stdout_pipe[READ_END], &pipe_mode, NULL, NULL)) { + WIN_SetError("SetNamedPipeHandleState()"); + goto done; + } if (!SetHandleInformation(stdout_pipe[READ_END], HANDLE_FLAG_INHERIT, 0) ) { WIN_SetError("SetHandleInformation()"); goto done; @@ -338,6 +347,10 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID stderr_pipe[WRITE_END] = INVALID_HANDLE_VALUE; goto done; } + if (!SetNamedPipeHandleState(stderr_pipe[READ_END], &pipe_mode, NULL, NULL)) { + WIN_SetError("SetNamedPipeHandleState()"); + goto done; + } if (!SetHandleInformation(stderr_pipe[READ_END], HANDLE_FLAG_INHERIT, 0) ) { WIN_SetError("SetHandleInformation()"); goto done;