[gnome-builder/wip/chergert/clang] clang: implement cancelRequest support in daemon
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/clang] clang: implement cancelRequest support in daemon
- Date: Fri, 27 Apr 2018 02:58:12 +0000 (UTC)
commit 8c1067a9638d2319c434c3c286f7898ace6d878a
Author: Christian Hergert <chergert redhat com>
Date: Thu Apr 26 19:58:44 2018 -0700
clang: implement cancelRequest support in daemon
This allows us to cancel an in-flight operation across the process
boundary.
src/plugins/clang/gnome-builder-clang.c | 50 +++++++++++++++++++++++
src/plugins/clang/ide-clang-client.c | 70 ++++++++++++++++++++++++++++-----
2 files changed, 111 insertions(+), 9 deletions(-)
---
diff --git a/src/plugins/clang/gnome-builder-clang.c b/src/plugins/clang/gnome-builder-clang.c
index 12f50d187..17a5b88b5 100644
--- a/src/plugins/clang/gnome-builder-clang.c
+++ b/src/plugins/clang/gnome-builder-clang.c
@@ -37,6 +37,7 @@
static guint in_flight;
static gboolean closing;
static GMainLoop *main_loop;
+static GQueue ops;
/* Client Operations {{{1 */
@@ -46,6 +47,7 @@ typedef struct
JsonrpcClient *client;
GVariant *id;
GCancellable *cancellable;
+ GList link;
} ClientOp;
static void
@@ -96,6 +98,7 @@ client_op_unref (ClientOp *op)
g_clear_object (&op->cancellable);
g_clear_object (&op->client);
g_clear_pointer (&op->id, g_variant_unref);
+ g_queue_unlink (&ops, &op->link);
g_slice_free (ClientOp, op);
in_flight--;
@@ -118,6 +121,9 @@ client_op_new (JsonrpcClient *client,
op->client = g_object_ref (client);
op->cancellable = g_cancellable_new ();
op->ref_count = 1;
+ op->link.data = op;
+
+ g_queue_push_tail_link (&ops, &op->link);
++in_flight;
@@ -812,6 +818,49 @@ handle_initialize (JsonrpcServer *server,
client_op_reply (op, NULL);
}
+/* Cancel Request {{{1 */
+
+static void
+handle_cancel_request (JsonrpcServer *server,
+ JsonrpcClient *client,
+ const gchar *method,
+ GVariant *id,
+ GVariant *params,
+ IdeClang *clang)
+{
+ g_autoptr(ClientOp) op = NULL;
+ g_autoptr(GVariant) cid = NULL;
+
+ g_assert (JSONRPC_IS_SERVER (server));
+ g_assert (JSONRPC_IS_CLIENT (client));
+ g_assert (g_str_equal (method, "$/cancelRequest"));
+ g_assert (id != NULL);
+ g_assert (IDE_IS_CLANG (clang));
+
+ op = client_op_new (client, id);
+
+ if (params == NULL || !(cid = g_variant_lookup_value (params, "id", NULL)))
+ {
+ client_op_bad_params (op);
+ return;
+ }
+
+ /* Lookup in-flight command to cancel it */
+
+ for (const GList *iter = ops.head; iter != NULL; iter = iter->next)
+ {
+ ClientOp *ele = iter->data;
+
+ if (g_variant_equal (ele->id, cid))
+ {
+ g_cancellable_cancel (ele->cancellable);
+ break;
+ }
+ }
+
+ client_op_reply (op, NULL);
+}
+
/* Main and Server Setup {{{1 */
static void
@@ -881,6 +930,7 @@ main (gint argc,
ADD_HANDLER ("clang/locateSymbol", handle_locate_symbol);
ADD_HANDLER ("clang/getHighlightIndex", handle_get_highlight_index);
ADD_HANDLER ("clang/setBuffer", handle_set_buffer);
+ ADD_HANDLER ("$/cancelRequest", handle_cancel_request);
#undef ADD_HANDLER
diff --git a/src/plugins/clang/ide-clang-client.c b/src/plugins/clang/ide-clang-client.c
index d82e7c8a5..c02e988a1 100644
--- a/src/plugins/clang/ide-clang-client.c
+++ b/src/plugins/clang/ide-clang-client.c
@@ -48,8 +48,12 @@ enum {
typedef struct
{
- gchar *method;
- GVariant *params;
+ IdeClangClient *self;
+ GCancellable *cancellable;
+ gchar *method;
+ GVariant *params;
+ GVariant *id;
+ gulong cancel_id;
} Call;
G_DEFINE_TYPE_EXTENDED (IdeClangClient, ide_clang_client, IDE_TYPE_OBJECT, 0,
@@ -60,8 +64,16 @@ call_free (gpointer data)
{
Call *c = data;
+ if (c->cancel_id != 0)
+ g_cancellable_disconnect (c->cancellable, c->cancel_id);
+
+ c->cancel_id = 0;
+
g_clear_pointer (&c->method, g_free);
g_clear_pointer (&c->params, g_variant_unref);
+ g_clear_pointer (&c->id, g_variant_unref);
+ g_clear_object (&c->cancellable);
+ g_clear_object (&c->self);
g_slice_free (Call, c);
}
@@ -144,6 +156,7 @@ ide_clang_client_subprocess_exited (IdeClangClient *self,
if (self->state == STATE_RUNNING)
self->state = STATE_SPAWNING;
+ g_clear_object (&self->rpc_client);
g_clear_pointer (&self->seq_by_file, g_hash_table_unref);
IDE_EXIT;
@@ -168,6 +181,7 @@ ide_clang_client_subprocess_spawned (IdeClangClient *self,
g_assert (IDE_IS_CLANG_CLIENT (self));
g_assert (IDE_IS_SUBPROCESS (subprocess));
g_assert (IDE_IS_SUBPROCESS_SUPERVISOR (supervisor));
+ g_assert (self->rpc_client == NULL);
if (self->state == STATE_SPAWNING)
self->state = STATE_RUNNING;
@@ -185,7 +199,6 @@ ide_clang_client_subprocess_spawned (IdeClangClient *self,
fd = g_unix_output_stream_get_fd (G_UNIX_OUTPUT_STREAM (output));
g_unix_set_fd_nonblocking (fd, TRUE, NULL);
- g_clear_object (&self->rpc_client);
self->rpc_client = jsonrpc_client_new (stream);
jsonrpc_client_set_use_gvariant (self->rpc_client, TRUE);
@@ -472,17 +485,46 @@ ide_clang_client_call_get_client_cb (GObject *object,
return;
}
+ if (ide_task_return_error_if_cancelled (task))
+ return;
+
call = ide_task_get_task_data (task);
g_assert (call != NULL);
g_assert (call->method != NULL);
- jsonrpc_client_call_async (client,
- call->method,
- call->params,
- ide_task_get_cancellable (task),
- ide_clang_client_call_cb,
- g_object_ref (task));
+ jsonrpc_client_call_with_id_async (client,
+ call->method,
+ call->params,
+ &call->id,
+ ide_task_get_cancellable (task),
+ ide_clang_client_call_cb,
+ g_object_ref (task));
+}
+
+static void
+ide_clang_client_call_cancelled (GCancellable *cancellable,
+ Call *call)
+{
+ g_autoptr(GVariant) params = NULL;
+ GVariantDict dict;
+
+ g_assert (G_IS_CANCELLABLE (cancellable));
+ g_assert (call != NULL);
+ g_assert (call->cancellable == cancellable);
+ g_assert (call->cancel_id != 0);
+ g_assert (IDE_IS_CLANG_CLIENT (call->self));
+
+ if (call->self->rpc_client == NULL)
+ return;
+
+ g_variant_dict_init (&dict, NULL);
+ g_variant_dict_insert_value (&dict, "id", call->id);
+
+ ide_clang_client_call_async (call->self,
+ "$/cancelRequest",
+ g_variant_dict_end (&dict),
+ NULL, NULL, NULL);
}
void
@@ -501,6 +543,7 @@ ide_clang_client_call_async (IdeClangClient *self,
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
call = g_slice_new0 (Call);
+ call->self = g_object_ref (self);
call->method = g_strdup (method);
call->params = g_variant_ref_sink (params);
@@ -508,6 +551,15 @@ ide_clang_client_call_async (IdeClangClient *self,
ide_task_set_source_tag (task, ide_clang_client_call_async);
ide_task_set_task_data (task, call, call_free);
+ if (cancellable != NULL)
+ {
+ call->cancellable = g_object_ref (cancellable);
+ call->cancel_id = g_cancellable_connect (cancellable,
+ G_CALLBACK (ide_clang_client_call_cancelled),
+ call,
+ NULL);
+ }
+
ide_clang_client_get_client_async (self,
cancellable,
ide_clang_client_call_get_client_cb,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]