[wing/wip/pipe-refactor: 2/2] wip: rework named pipe
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [wing/wip/pipe-refactor: 2/2] wip: rework named pipe
- Date: Thu, 14 Jul 2016 10:31:16 +0000 (UTC)
commit 0807e8cf007f557b40d29a65602a0d4927e7980f
Author: Ignacio Casal Quinteiro <icq gnome org>
Date: Thu Jul 14 12:29:40 2016 +0200
wip: rework named pipe
wing/wingnamedpipelistener.c | 370 ++++++++++++++++++++++++++----------------
1 files changed, 233 insertions(+), 137 deletions(-)
---
diff --git a/wing/wingnamedpipelistener.c b/wing/wingnamedpipelistener.c
index de2409a..a59971f 100644
--- a/wing/wingnamedpipelistener.c
+++ b/wing/wingnamedpipelistener.c
@@ -28,11 +28,17 @@
typedef struct
{
gchar *pipe_name;
+ GObject *source_object;
+} PipeData;
+
+typedef struct
+{
+ PipeData *pdata;
HANDLE handle;
OVERLAPPED overlapped;
- GObject *source_object;
gboolean already_connected;
-} PipeData;
+ GError *error;
+} PipeHandleData;
typedef struct
{
@@ -53,11 +59,6 @@ pipe_data_new (const gchar *pipe_name,
data = g_slice_new0 (PipeData);
data->pipe_name = g_strdup (pipe_name);
- data->handle = handle;
- data->overlapped.hEvent = CreateEvent (NULL, /* default security attribute */
- TRUE, /* manual-reset event */
- TRUE, /* initial state = signaled */
- NULL); /* unnamed event object */
if (source_object)
data->source_object = g_object_ref (source_object);
@@ -68,12 +69,37 @@ static void
pipe_data_free (PipeData *data)
{
g_free (data->pipe_name);
- CloseHandle (data->handle);
- CloseHandle (data->overlapped.hEvent);
g_clear_object (&data->source_object);
g_slice_free (PipeData, data);
}
+static PipeHandleData *
+pipe_handle_data_new (PipeData *data)
+{
+ PipeHandleData *handle_data;
+
+ handle_data = g_slice_new0 (PipeHandleData);
+ handle_data->pdata = data;
+ handle_data->handle = INVALID_HANDLE_VALUE;
+ handle_data->overlapped.hEvent = CreateEvent (NULL, /* default security attribute */
+ TRUE, /* manual-reset event */
+ TRUE, /* initial state = signaled */
+ NULL); /* unnamed event object */
+
+ return handle_data;
+}
+
+static void
+pipe_handle_data_free (PipeHandleData *data)
+{
+ if (data->handle != INVALID_HANDLE_VALUE)
+ CloseHandle (data->handle);
+
+ CloseHandle (data->overlapped.handle);
+ g_clear_error (data->error);
+ g_slice_free (PipeHandleData, data);
+}
+
static void
wing_named_pipe_listener_finalize (GObject *object)
{
@@ -151,75 +177,30 @@ wing_named_pipe_listener_add_named_pipe (WingNamedPipeListener *listener,
GError **error)
{
WingNamedPipeListenerPrivate *priv;
- gunichar2 *pipe_namew;
- PipeData *pipe_data;
- HANDLE handle;
g_return_val_if_fail (WING_IS_NAMED_PIPE_LISTENER (listener), FALSE);
g_return_val_if_fail (pipe_name != NULL, FALSE);
priv = wing_named_pipe_listener_get_instance_private (listener);
- pipe_namew = g_utf8_to_utf16 (pipe_name, -1, NULL, NULL, NULL);
-
- handle = CreateNamedPipeW (pipe_namew,
- PIPE_ACCESS_DUPLEX |
- FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE |
- PIPE_READMODE_BYTE |
- PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- DEFAULT_PIPE_BUF_SIZE,
- DEFAULT_PIPE_BUF_SIZE,
- 0, NULL);
- g_free (pipe_namew);
-
- if (handle == INVALID_HANDLE_VALUE)
- {
- int errsv = GetLastError ();
- gchar *emsg = g_win32_error_message (errsv);
-
- g_set_error (error,
- G_IO_ERROR,
- g_io_error_from_win32_error (errsv),
- "Error creating named pipe '%s': %s",
- pipe_name, emsg);
-
- g_free (emsg);
- return FALSE;
- }
-
- pipe_data = pipe_data_new (pipe_name, handle, source_object);
+ g_ptr_array_add (priv->named_pipes,
+ pipe_data_new (pipe_name, source_object));
- if (!ConnectNamedPipe (handle, &pipe_data->overlapped))
- {
- switch (GetLastError ())
- {
- case ERROR_IO_PENDING:
- break;
- case ERROR_PIPE_CONNECTED:
- pipe_data->already_connected = TRUE;
- break;
- default:
- {
- int errsv = GetLastError ();
- gchar *emsg = g_win32_error_message (errsv);
-
- g_set_error (error,
- G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
- "Failed to connect named pipe '%s': %s",
- pipe_name, emsg);
- g_free (emsg);
- pipe_data_free (pipe_data);
-
- return FALSE;
- }
- }
- }
+ return TRUE;
+}
- g_ptr_array_add (priv->named_pipes, pipe_data);
+typedef struct
+{
+ GPtrArray *handle_data_array;
+ GList *sources;
+} ConnectReadyData;
- return TRUE;
+static void
+free_connect_ready_data (ConnectReadyData *data)
+{
+ g_ptr_array_free (data->handle_data_array);
+ free_sources (data->sources);
+ g_slice_free (ConnectReadyData, data);
}
static gboolean
@@ -227,29 +208,26 @@ connect_ready (HANDLE handle,
gpointer user_data)
{
GTask *task = user_data;
- WingNamedPipeListener *listener = g_task_get_source_object (task);
- WingNamedPipeListenerPrivate *priv;
- PipeData *pipe_data = NULL;
+ ConnectReadyData *data = g_task_get_task_data (task);
+ PipeHandleData *handle_data = NULL;
gulong cbret;
guint i;
- priv = wing_named_pipe_listener_get_instance_private (listener);
-
- for (i = 0; i < priv->named_pipes->len; i++)
+ for (i = 0; i < data->handle_data_array->len; i++)
{
- PipeData *pdata;
+ PipeHandleData *hdata;
- pdata = priv->named_pipes->pdata[i];
- if (pdata->overlapped.hEvent == handle)
+ hdata = data->handle_data_array->pdata[i];
+ if (hdata->overlapped.hEvent == handle)
{
- pipe_data = pdata;
+ handle_data = hdata;
break;
}
}
- g_return_val_if_fail (pipe_data != NULL, FALSE);
+ g_return_val_if_fail (handle_data != NULL, FALSE);
- if (!GetOverlappedResult (pipe_data->handle, &pipe_data->overlapped, &cbret, FALSE))
+ if (!GetOverlappedResult (handle_data->handle, &handle_data->overlapped, &cbret, FALSE))
{
int errsv = GetLastError ();
gchar *emsg = g_win32_error_message (errsv);
@@ -265,16 +243,18 @@ connect_ready (HANDLE handle,
{
WingNamedPipeConnection *connection;
- if (pipe_data->source_object != NULL)
+ if (handle_data->pdata->source_object != NULL)
g_object_set_qdata_full (G_OBJECT (task),
source_quark,
- g_object_ref (pipe_data->source_object),
+ g_object_ref (handle_data->pdata->source_object),
g_object_unref);
connection = g_object_new (WING_TYPE_NAMED_PIPE_CONNECTION,
- "handle", pipe_data->handle,
- "close-handle", FALSE,
+ "handle", handle_data->handle,
+ "close-handle", TRUE,
NULL);
+ handle_data->handle = INVALID_HANDLE_VALUE;
+
g_task_return_pointer (task, connection, g_object_unref);
}
@@ -284,24 +264,21 @@ connect_ready (HANDLE handle,
}
static GList *
-add_sources (WingNamedPipeListener *listener,
+add_sources (GPtrArray *handle_data_array,
WingHandleSourceFunc callback,
gpointer callback_data,
GCancellable *cancellable,
GMainContext *context)
{
- WingNamedPipeListenerPrivate *priv;
- PipeData *data;
+ PipeHandleData *data;
GSource *source;
GList *sources;
guint i;
- priv = wing_named_pipe_listener_get_instance_private (listener);
-
sources = NULL;
- for (i = 0; i < priv->named_pipes->len; i++)
+ for (i = 0; i < handle_data_array->len; i++)
{
- data = priv->named_pipes->pdata[i];
+ data = handle_data_array->pdata[i];
source = _wing_handle_create_source (data->overlapped.hEvent,
cancellable);
@@ -330,9 +307,9 @@ free_sources (GList *sources)
}
struct AcceptData {
- WingNamedPipeListener *listener;
GMainLoop *loop;
- PipeData *pipe_data;
+ GPtrArray *handle_data_array;
+ PipeHandleData *handle_data;
};
static gboolean
@@ -340,25 +317,22 @@ accept_callback (HANDLE handle,
gpointer user_data)
{
struct AcceptData *data = user_data;
- WingNamedPipeListenerPrivate *priv;
- PipeData *pipe_data = NULL;
+ PipeHandleData *handle_data = NULL;
guint i;
- priv = wing_named_pipe_listener_get_instance_private (data->listener);
-
- for (i = 0; i < priv->named_pipes->len; i++)
+ for (i = 0; i < data->handle_data_array->len; i++)
{
- PipeData *pdata;
+ PipeHandleData *hdata;
- pdata = priv->named_pipes->pdata[i];
- if (pdata->overlapped.hEvent == handle)
+ hdata = data->handle_data_array->pdata[i];
+ if (hdata->overlapped.hEvent == handle)
{
- pipe_data = pdata;
+ handle_data = hdata;
break;
}
}
- data->pipe_data = pipe_data;
+ data->handle_data = handle_data;
g_main_loop_quit (data->loop);
return TRUE;
@@ -367,23 +341,114 @@ accept_callback (HANDLE handle,
/* Check if any of the named pipes is already connected
* and pick the the first one.
*/
-static PipeData *
-find_first_connected (WingNamedPipeListener *listener)
+static PipeHandleData *
+find_first_connected (GPtrArray *handle_data_array)
+{
+ guint i;
+
+ for (i = 0; i < handle_data_array->len; i++)
+ {
+ PipeHandleData *handle_data = handle_data_array->pdata[i];
+
+ if (handle_data->already_connected)
+ return handle_data;
+ }
+
+ return NULL;
+}
+
+static gboolean
+get_all_pipes_with_error (GPtrArray *handle_data_array)
+{
+ guint i;
+
+ for (i = 0; i < handle_data_array->len; i++)
+ {
+ PipeHandleData *handle_data = handle_data_array->pdata[i];
+
+ if (handle_data->error == NULL)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GPtrArray *
+connect_pipes (WingNamedPipeListener *listener)
{
WingNamedPipeListenerPrivate *priv;
+ GPtrArray *handle_data_array;
guint i;
priv = wing_named_pipe_listener_get_instance_private (listener);
+ handle_data_array = g_ptr_array_new_with_free_func ((GDestroyNotify) pipe_handle_data_free);
+
for (i = 0; i < priv->named_pipes->len; i++)
{
PipeData *pdata = priv->named_pipes->pdata[i];
+ gunichar2 *pipe_namew;
+ HANDLE handle;
+ PipeHandleData *handle_data;
+
+ handle_data = pipe_handle_data_new (pdata);
+ g_ptr_array_add (handle_data_array, handle_data);
+
+ pipe_namew = g_utf8_to_utf16 (pdata->pipe_name, -1, NULL, NULL, NULL);
+
+ handle = CreateNamedPipeW (pipe_namew,
+ PIPE_ACCESS_DUPLEX |
+ FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE |
+ PIPE_READMODE_BYTE |
+ PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ DEFAULT_PIPE_BUF_SIZE,
+ DEFAULT_PIPE_BUF_SIZE,
+ 0, NULL);
+ g_free (pipe_namew);
+
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ int errsv = GetLastError ();
+ gchar *emsg = g_win32_error_message (errsv);
- if (pdata->already_connected)
- return pdata;
+ handle_data->error = g_error_new (G_IO_ERROR,
+ g_io_error_from_win32_error (errsv),
+ "Error creating named pipe '%s': %s",
+ pdata->pipe_name, emsg);
+ g_free (emsg);
+
+ continue;
+ }
+
+ handle_data->handle = handle;
+
+ if (!ConnectNamedPipe (handle, &handle_data->overlapped))
+ {
+ switch (GetLastError ())
+ {
+ case ERROR_IO_PENDING:
+ break;
+ case ERROR_PIPE_CONNECTED:
+ handle_data->already_connected = TRUE;
+ break;
+ default:
+ {
+ int errsv = GetLastError ();
+ gchar *emsg = g_win32_error_message (errsv);
+
+ handle_data->error = g_error_new (G_IO_ERROR,
+ g_io_error_from_win32_error (errsv),
+ "Failed to connect named pipe '%s': %s",
+ pdata->pipe_name, emsg);
+ g_free (emsg);
+ }
+ }
+ }
}
- return NULL;
+ return handle_data_array;
}
/**
@@ -415,31 +480,42 @@ wing_named_pipe_listener_accept (WingNamedPipeListener *listener,
GError **error)
{
WingNamedPipeListenerPrivate *priv;
- PipeData *pipe_data = NULL;
+ PipeHandleData *handle_data = NULL;
WingNamedPipeConnection *connection = NULL;
+ GPtrArray *handle_data_array;
g_return_val_if_fail (WING_IS_NAMED_PIPE_LISTENER (listener), NULL);
priv = wing_named_pipe_listener_get_instance_private (listener);
- if (priv->named_pipes->len == 1)
+ handle_data_array = connect_pipes (listener);
+ if (get_all_pipes_with_error (handle_data_array))
+ {
+ /* Return the first error */
+ handle_data = handle_data_array->pdata[0];
+ *error = g_error_copy (handle_data->error);
+ g_ptr_array_free (handle_data_array);
+ return NULL;
+ }
+
+ if (handle_data_array->len == 1)
{
gboolean success;
- pipe_data = priv->named_pipes->pdata[0];
- success = pipe_data->already_connected;
+ handle_data = handle_data_array->pdata[0];
+ success = handle_data->already_connected;
if (!success)
- success = WaitForSingleObject (pipe_data->overlapped.hEvent, INFINITE) == WAIT_OBJECT_0;
+ success = WaitForSingleObject (handle_data->overlapped.hEvent, INFINITE) == WAIT_OBJECT_0;
if (!success)
pipe_data = NULL;
}
else
{
- pipe_data = find_first_connected (listener);
+ handle_data = find_first_connected (listener);
- if (pipe_data == NULL)
+ if (handle_data == NULL)
{
GList *sources;
struct AcceptData data;
@@ -450,29 +526,33 @@ wing_named_pipe_listener_accept (WingNamedPipeListener *listener,
loop = g_main_loop_new (priv->main_context, FALSE);
data.loop = loop;
- data.listener = listener;
+ data.handle_data_array = handle_data_array;
- sources = add_sources (listener,
+ sources = add_sources (handle_data_array,
accept_callback,
&data,
cancellable,
priv->main_context);
g_main_loop_run (loop);
- pipe_data = data.pipe_data;
+ handle_data = data.handle_data;
free_sources (sources);
g_main_loop_unref (loop);
}
}
- if (pipe_data != NULL)
+ if (handle_data != NULL)
{
connection = g_object_new (WING_TYPE_NAMED_PIPE_CONNECTION,
- "handle", pipe_data->handle,
- "close-handle", FALSE,
+ "handle", handle_data->handle,
+ "close-handle", TRUE,
NULL);
+ handle_data->handle = INVALID_HANDLE_VALUE;
+
if (source_object)
- *source_object = pipe_data->source_object;
+ *source_object = handle_data->pdata->source_object;
+
+ g_ptr_array_free (handle_data_array);
}
return connection;
@@ -500,44 +580,60 @@ wing_named_pipe_listener_accept_async (WingNamedPipeListener *listener,
gpointer user_data)
{
WingNamedPipeListenerPrivate *priv;
- PipeData *pipe_data;
+ PipeHandleData *handle_data;
GTask *task;
- GList *sources;
+ ConnectReadyData *data;
guint i;
task = g_task_new (listener, cancellable, callback, user_data);
priv = wing_named_pipe_listener_get_instance_private (listener);
- pipe_data = find_first_connected (listener);
+ handle_data_array = connect_pipes (listener);
+ if (get_all_pipes_with_error (handle_data_array))
+ {
+ /* Return the first error */
+ handle_data = handle_data_array->pdata[0];
+ g_task_return_error (task, g_error_copy (handle_data->error));
+ g_object_unref (task);
+ g_ptr_array_free (handle_data_array);
+ return NULL;
+ }
+
+ handle_data = find_first_connected (handle_data_array);
- if (pipe_data != NULL)
+ if (handle_data != NULL)
{
WingNamedPipeConnection *connection;
- if (pipe_data->source_object)
+ if (handle_data->pdata->source_object)
g_object_set_qdata_full (G_OBJECT (task),
source_quark,
- g_object_ref (pipe_data->source_object),
+ g_object_ref (handle_data->pdata->source_object),
g_object_unref);
connection = g_object_new (WING_TYPE_NAMED_PIPE_CONNECTION,
- "handle", pipe_data->handle,
- "close-handle", FALSE,
+ "handle", handle_data->handle,
+ "close-handle", TRUE,
NULL);
+ handle_data->handle = INVALID_HANDLE_VALUE;
+
g_task_return_pointer (task, connection, g_object_unref);
g_object_unref (task);
+ g_ptr_array_free (handle_data_array);
return;
}
- sources = add_sources (listener,
- connect_ready,
- task,
- cancellable,
- g_main_context_get_thread_default ());
- g_task_set_task_data (task, sources, (GDestroyNotify) free_sources);
+ data = g_slice_new0 (ConnectReadyData);
+ data->handle_data_array = handle_data_array;
+ data->sources = add_sources (handle_data_array,
+ connect_ready,
+ task,
+ cancellable,
+ g_main_context_get_thread_default ());
+ g_task_set_task_data (task, data, (GDestroyNotify) free_connect_ready_data);
}
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]