pluginloader-win32: Fix for pipe connection error

Don't error out on WAIT_IO_COMPLETION. It means queued APC job
was executed but the job may not be our callback.
For example, user or system might be able to schedule APC on
gst_init() thread or so.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4405>
This commit is contained in:
Seungha Yang 2023-04-12 22:39:58 +09:00 committed by GStreamer Marge Bot
parent bbb0a30f32
commit acdf70e576

View file

@ -156,6 +156,7 @@ typedef struct
* binary chunk format: 64 bytes * binary chunk format: 64 bytes
* architecture: 64 bytes */ * architecture: 64 bytes */
guint8 version_info[GST_PLUGIN_LOADER_VERSION_INFO_SIZE]; guint8 version_info[GST_PLUGIN_LOADER_VERSION_INFO_SIZE];
gboolean apc_called;
} Win32PluginLoader; } Win32PluginLoader;
struct _GstPluginLoader struct _GstPluginLoader
@ -168,6 +169,7 @@ struct _GstPluginLoader
wchar_t *env_string; wchar_t *env_string;
PROCESS_INFORMATION child_info; PROCESS_INFORMATION child_info;
LARGE_INTEGER frequency;
gboolean got_plugin_detail; gboolean got_plugin_detail;
gboolean client_running; gboolean client_running;
@ -286,6 +288,8 @@ gst_plugin_loader_try_helper (GstPluginLoader * self, gchar * location)
DWORD wait_ret; DWORD wait_ret;
gchar *pipe_name = NULL; gchar *pipe_name = NULL;
HANDLE waitables[2]; HANDLE waitables[2];
LARGE_INTEGER now;
LONGLONG timeout;
memset (&si, 0, sizeof (STARTUPINFOW)); memset (&si, 0, sizeof (STARTUPINFOW));
si.cb = sizeof (STARTUPINFOW); si.cb = sizeof (STARTUPINFOW);
@ -317,6 +321,7 @@ gst_plugin_loader_try_helper (GstPluginLoader * self, gchar * location)
loader->overlap.InternalHigh = 0; loader->overlap.InternalHigh = 0;
loader->overlap.Offset = 0; loader->overlap.Offset = 0;
loader->overlap.OffsetHigh = 0; loader->overlap.OffsetHigh = 0;
loader->apc_called = FALSE;
/* Async pipe should return zero */ /* Async pipe should return zero */
if (ConnectNamedPipe (loader->pipe, &loader->overlap)) { if (ConnectNamedPipe (loader->pipe, &loader->overlap)) {
@ -352,26 +357,60 @@ gst_plugin_loader_try_helper (GstPluginLoader * self, gchar * location)
goto error; goto error;
} }
ret = QueryPerformanceCounter (&now);
g_assert (ret);
/* 10 seconds timeout */
timeout = now.QuadPart + 10 * self->frequency.QuadPart;
/* Wait for client connection */ /* Wait for client connection */
waitables[0] = loader->overlap.hEvent; waitables[0] = loader->overlap.hEvent;
waitables[1] = self->child_info.hProcess; waitables[1] = self->child_info.hProcess;
wait_ret = WaitForMultipleObjectsEx (2, waitables, FALSE, 5000, TRUE); do {
if (wait_ret == WAIT_OBJECT_0) { wait_ret = WaitForMultipleObjectsEx (2, waitables, FALSE, 5000, TRUE);
ret = GetOverlappedResult (loader->pipe, &loader->overlap, &n_bytes, FALSE); switch (wait_ret) {
if (!ret) { case WAIT_OBJECT_0:
last_err = GetLastError (); ret = GetOverlappedResult (loader->pipe,
err = g_win32_error_message (last_err); &loader->overlap, &n_bytes, FALSE);
GST_ERROR ("GetOverlappedResult failed with 0x%x (%s)", if (!ret) {
last_err, GST_STR_NULL (err)); last_err = GetLastError ();
goto kill_child; err = g_win32_error_message (last_err);
GST_ERROR ("GetOverlappedResult failed with 0x%x (%s)",
last_err, GST_STR_NULL (err));
goto kill_child;
}
break;
case WAIT_OBJECT_0 + 1:
GST_ERROR ("Child process got terminated");
goto kill_child;
case WAIT_IO_COMPLETION:
ret = QueryPerformanceCounter (&now);
g_assert (ret);
if (now.QuadPart > timeout) {
GST_ERROR ("Connection takes too long, give up");
goto kill_child;
}
if (loader->apc_called) {
GST_WARNING
("Unexpected our APC called while waiting for client connection");
} else {
GST_DEBUG ("WAIT_IO_COMPLETION, waiting again");
}
break;
case WAIT_TIMEOUT:
GST_ERROR ("WaitForMultipleObjectsEx timeout");
goto kill_child;
default:
last_err = GetLastError ();
err = g_win32_error_message (last_err);
GST_ERROR
("Unexpected WaitForMultipleObjectsEx return 0x%x, with 0x%x (%s)",
(guint) wait_ret, last_err, GST_STR_NULL (err));
goto kill_child;
} }
} else { } while (wait_ret == WAIT_IO_COMPLETION);
last_err = GetLastError ();
err = g_win32_error_message (last_err);
GST_ERROR ("Unexpected WaitForSingleObjectEx return 0x%x, with 0x%x (%s)",
(guint) wait_ret, last_err, GST_STR_NULL (err));
goto kill_child;
}
/* Do version check */ /* Do version check */
loader->expected_pkt = PACKET_VERSION; loader->expected_pkt = PACKET_VERSION;
@ -563,6 +602,8 @@ win32_plugin_loader_write_payload_finish (DWORD error_code, DWORD n_bytes,
Win32PluginLoader *self = (Win32PluginLoader *) overlapped; Win32PluginLoader *self = (Win32PluginLoader *) overlapped;
PacketHeader *header = &self->tx_header; PacketHeader *header = &self->tx_header;
self->apc_called = TRUE;
if (error_code != ERROR_SUCCESS) if (error_code != ERROR_SUCCESS)
SET_ERROR_AND_RETURN (self, error_code); SET_ERROR_AND_RETURN (self, error_code);
@ -582,6 +623,8 @@ win32_plugin_loader_write_header_finish (DWORD error_code, DWORD n_bytes,
Win32PluginLoader *self = (Win32PluginLoader *) overlapped; Win32PluginLoader *self = (Win32PluginLoader *) overlapped;
PacketHeader *header = &self->tx_header; PacketHeader *header = &self->tx_header;
self->apc_called = TRUE;
if (error_code != ERROR_SUCCESS) if (error_code != ERROR_SUCCESS)
SET_ERROR_AND_RETURN (self, error_code); SET_ERROR_AND_RETURN (self, error_code);
@ -855,6 +898,8 @@ win32_plugin_loader_read_payload_finish (DWORD error_code, DWORD n_bytes,
Win32PluginLoader *self = (Win32PluginLoader *) overlapped; Win32PluginLoader *self = (Win32PluginLoader *) overlapped;
PacketHeader *header = &self->rx_header; PacketHeader *header = &self->rx_header;
self->apc_called = TRUE;
if (error_code != ERROR_SUCCESS) if (error_code != ERROR_SUCCESS)
SET_ERROR_AND_RETURN (self, error_code); SET_ERROR_AND_RETURN (self, error_code);
@ -874,6 +919,8 @@ win32_plugin_loader_read_header_finish (DWORD error_code, DWORD n_bytes,
Win32PluginLoader *self = (Win32PluginLoader *) overlapped; Win32PluginLoader *self = (Win32PluginLoader *) overlapped;
PacketHeader *header = &self->rx_header; PacketHeader *header = &self->rx_header;
self->apc_called = TRUE;
if (error_code != ERROR_SUCCESS) if (error_code != ERROR_SUCCESS)
SET_ERROR_AND_RETURN (self, error_code); SET_ERROR_AND_RETURN (self, error_code);
@ -1016,6 +1063,7 @@ gst_plugin_loader_new (GstRegistry * registry)
guint i; guint i;
wchar_t lib_dir[MAX_PATH]; wchar_t lib_dir[MAX_PATH];
wchar_t *origin_path = NULL; wchar_t *origin_path = NULL;
BOOL ret;
if (!registry) if (!registry)
return NULL; return NULL;
@ -1088,6 +1136,10 @@ gst_plugin_loader_new (GstRegistry * registry)
free (origin_path); free (origin_path);
FreeEnvironmentStringsW (env_str); FreeEnvironmentStringsW (env_str);
ret = QueryPerformanceFrequency (&self->frequency);
/* Must not return zero */
g_assert (ret);
return self; return self;
} }