[gnome-builder: 3/4] lsp: avoid some allocations and cleanup lifecycle handling
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder: 3/4] lsp: avoid some allocations and cleanup lifecycle handling
- Date: Fri, 19 Feb 2021 19:58:29 +0000 (UTC)
commit b3b5df8edbdf39eda9ea05046f0858a453a3fd4e
Author: Christian Hergert <chergert redhat com>
Date: Fri Feb 19 11:57:59 2021 -0800
lsp: avoid some allocations and cleanup lifecycle handling
This moves to using an embedded GQueue and GLink to avoid extra allocations
as well as cleaning up how we manage the lifecycle of these objects.
src/libide/lsp/ide-lsp-client.c | 190 +++++++++++++++++++++++++---------------
1 file changed, 118 insertions(+), 72 deletions(-)
---
diff --git a/src/libide/lsp/ide-lsp-client.c b/src/libide/lsp/ide-lsp-client.c
index c028deace..1645498f7 100644
--- a/src/libide/lsp/ide-lsp-client.c
+++ b/src/libide/lsp/ide-lsp-client.c
@@ -43,11 +43,12 @@ typedef struct
typedef struct
{
+ GList link;
IdeTask *task;
- const gchar *method;
+ gchar *method;
GVariant *params;
GCancellable *cancellable;
-} LspMessage;
+} PendingMessage;
typedef struct
{
@@ -61,7 +62,7 @@ typedef struct
IdeLspTrace trace;
gchar *root_uri;
gboolean initialized;
- GQueue *pending_messages;
+ GQueue pending_messages;
} IdeLspClientPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (IdeLspClient, ide_lsp_client, IDE_TYPE_OBJECT)
@@ -103,6 +104,10 @@ enum {
N_SIGNALS
};
+static void ide_lsp_client_call_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data);
+
static GParamSpec *properties [N_PROPS];
static guint signals [N_SIGNALS];
@@ -132,37 +137,55 @@ async_call_unref (gpointer data)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (AsyncCall, async_call_unref);
-static LspMessage *
-lsp_message_new (IdeTask *task,
- const gchar *method,
- GVariant *params,
- GCancellable *cancellable)
-{
- LspMessage *lm = g_atomic_rc_box_new0 (LspMessage);
- lm->task = g_object_ref (task);
- lm->method = method;
- lm->params = g_variant_ref (params);
- lm->cancellable = g_object_ref (cancellable);
- return lm;
-}
-
static void
-lsp_message_finalize (gpointer data)
+pending_message_fail (PendingMessage *message)
{
- LspMessage *lm = data;
- g_clear_object (&lm->task);
- g_clear_pointer (&lm->params, g_variant_unref);
- g_clear_pointer (&lm->cancellable, g_object_unref);
+ g_assert (message != NULL);
+ g_assert (message->link.prev == NULL);
+ g_assert (message->link.next == NULL);
+ g_assert (message->link.data == message);
+ g_assert (IDE_IS_TASK (message->task));
+ g_assert (!message->cancellable || G_IS_CANCELLABLE (message->cancellable));
+ g_assert (message->method != NULL);
+
+ ide_task_return_new_error (message->task,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ "The operation has been cancelled");
+
+ g_clear_object (&message->task);
+ g_clear_object (&message->cancellable);
+ g_clear_pointer (&message->method, g_free);
+ g_clear_pointer (&message->params, g_variant_unref);
+ g_slice_free (PendingMessage, message);
}
static void
-lsp_message_unref (gpointer data)
+pending_message_submit (PendingMessage *message,
+ JsonrpcClient *rpc_client)
{
- g_atomic_rc_box_release_full (data, lsp_message_finalize);
+ g_assert (JSONRPC_IS_CLIENT (rpc_client));
+ g_assert (message != NULL);
+ g_assert (message->link.prev == NULL);
+ g_assert (message->link.next == NULL);
+ g_assert (message->link.data == message);
+ g_assert (IDE_IS_TASK (message->task));
+ g_assert (!message->cancellable || G_IS_CANCELLABLE (message->cancellable));
+ g_assert (message->method != NULL);
+
+ jsonrpc_client_call_async (rpc_client,
+ message->method,
+ message->params,
+ message->cancellable,
+ ide_lsp_client_call_cb,
+ g_steal_pointer (&message->task));
+
+ g_clear_object (&message->cancellable);
+ g_clear_pointer (&message->method, g_free);
+ g_clear_pointer (&message->params, g_variant_unref);
+ g_slice_free (PendingMessage, message);
}
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (LspMessage, lsp_message_unref);
-
static gboolean
ide_lsp_client_supports_buffer (IdeLspClient *self,
IdeBuffer *buffer)
@@ -1066,6 +1089,25 @@ ide_lsp_client_handle_call (IdeLspClient *self,
IDE_RETURN (FALSE);
}
+static void
+ide_lsp_client_dispose (GObject *object)
+{
+ IdeLspClient *self = (IdeLspClient *)object;
+ IdeLspClientPrivate *priv = ide_lsp_client_get_instance_private (self);
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+
+ while (priv->pending_messages.length > 0)
+ {
+ PendingMessage *message = priv->pending_messages.head->data;
+
+ g_queue_unlink (&priv->pending_messages, &message->link);
+ pending_message_fail (message);
+ }
+
+ G_OBJECT_CLASS (ide_lsp_client_parent_class)->dispose (object);
+}
+
static void
ide_lsp_client_finalize (GObject *object)
{
@@ -1081,7 +1123,6 @@ ide_lsp_client_finalize (GObject *object)
g_clear_object (&priv->rpc_client);
g_clear_object (&priv->buffer_manager_signals);
g_clear_object (&priv->project_signals);
- g_clear_object (&priv->pending_messages);
G_OBJECT_CLASS (ide_lsp_client_parent_class)->finalize (object);
}
@@ -1171,6 +1212,7 @@ ide_lsp_client_class_init (IdeLspClientClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = ide_lsp_client_dispose;
object_class->finalize = ide_lsp_client_finalize;
object_class->get_property = ide_lsp_client_get_property;
object_class->set_property = ide_lsp_client_set_property;
@@ -1336,16 +1378,10 @@ ide_lsp_client_init (IdeLspClient *self)
G_CONNECT_SWAPPED);
}
-static void
-ide_lsp_client_call_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data);
-
static void
ide_lsp_client_flush_queue (IdeLspClient *self)
{
IdeLspClientPrivate *priv = ide_lsp_client_get_instance_private (self);
- guint queue_length;
IDE_ENTRY;
@@ -1353,32 +1389,17 @@ ide_lsp_client_flush_queue (IdeLspClient *self)
g_assert (IDE_IS_LSP_CLIENT (self));
g_return_if_fail (!priv->rpc_client || JSONRPC_IS_CLIENT (priv->rpc_client));
- queue_length = g_queue_get_length (priv->pending_messages);
+ if (priv->pending_messages.length == 0 || priv->rpc_client == NULL)
+ IDE_EXIT;
- if (queue_length > 0)
- {
- g_autoptr (LspMessage) message;
+ IDE_TRACE_MSG ("Flushing pending queue of length %u", priv->pending_messages.length);
- while (NULL != (message = g_queue_pop_head (priv->pending_messages)))
- {
- g_return_if_fail (message->method != NULL);
- g_return_if_fail (!message->cancellable || G_IS_CANCELLABLE (message->cancellable));
-
- if (priv->rpc_client == NULL)
- ide_task_return_new_error (message->task,
- G_IO_ERROR,
- G_IO_ERROR_NOT_CONNECTED,
- "No connection to language server");
-
- jsonrpc_client_call_async (priv->rpc_client,
- message->method,
- message->params,
- message->cancellable,
- ide_lsp_client_call_cb,
- g_steal_pointer (&message->task));
- }
+ while (priv->pending_messages.length > 0)
+ {
+ PendingMessage *message = priv->pending_messages.head->data;
+ g_queue_unlink (&priv->pending_messages, &message->link);
+ pending_message_submit (message, priv->rpc_client);
}
- IDE_TRACE_MSG ("LSP processed build up queue of length: %d", queue_length);
IDE_EXIT;
}
@@ -1395,7 +1416,6 @@ ide_lsp_client_initialized_cb (GObject *object,
IdeBufferManager *buffer_manager;
IdeProject *project;
IdeContext *context;
- guint queue_length;
IDE_ENTRY;
@@ -1419,12 +1439,7 @@ ide_lsp_client_initialized_cb (GObject *object,
g_signal_emit (self, signals[INITIALIZED], 0);
- queue_length = g_queue_get_length (priv->pending_messages);
-
- if (queue_length > 0)
- {
- ide_lsp_client_flush_queue (self);
- }
+ ide_lsp_client_flush_queue (self);
IDE_EXIT;
}
@@ -1511,7 +1526,6 @@ ide_lsp_client_start (IdeLspClient *self)
}
priv->rpc_client = jsonrpc_client_new (priv->io_stream);
- priv->pending_messages = g_queue_new();
workdir = ide_context_ref_workdir (context);
root_path = g_file_get_path (workdir);
@@ -1750,6 +1764,38 @@ ide_lsp_client_call_cb (GObject *object,
IDE_EXIT;
}
+static void
+ide_lsp_client_queue_message (IdeLspClient *self,
+ const char *method,
+ GVariant *params,
+ GCancellable *cancellable,
+ IdeTask *task)
+
+{
+ IdeLspClientPrivate *priv = ide_lsp_client_get_instance_private (self);
+ PendingMessage *pending;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_LSP_CLIENT (self));
+ g_assert (method != NULL);
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+ g_assert (IDE_IS_TASK (task));
+
+ IDE_TRACE_MSG ("Queuing LSP call to method %s", method);
+
+ pending = g_slice_new0 (PendingMessage);
+ pending->link.data = pending;
+ pending->task = g_steal_pointer (&task);
+ pending->method = g_strdup (method);
+ pending->params = params ? g_variant_ref (params) : NULL;
+ g_set_object (&pending->cancellable, cancellable);
+
+ g_queue_push_tail_link (&priv->pending_messages, &pending->link);
+
+ IDE_EXIT;
+}
+
/**
* ide_lsp_client_call_async:
* @self: An #IdeLspClient
@@ -1775,7 +1821,6 @@ ide_lsp_client_call_async (IdeLspClient *self,
{
IdeLspClientPrivate *priv = ide_lsp_client_get_instance_private (self);
g_autoptr(IdeTask) task = NULL;
- g_autoptr(LspMessage) message = NULL;
IDE_ENTRY;
@@ -1793,13 +1838,14 @@ ide_lsp_client_call_async (IdeLspClient *self,
G_IO_ERROR,
G_IO_ERROR_NOT_CONNECTED,
"No connection to language server");
- else if (!priv->initialized && !(g_str_equal(method, "initialize") || g_str_equal (method, "initialized")))
- {
- IDE_TRACE_MSG("queueing up method: %s", method);
- message = lsp_message_new(g_steal_pointer(&task), method, params, g_steal_pointer (&cancellable));
-
- g_queue_push_head(priv->pending_messages, g_steal_pointer (&message));
- }
+ else if (!priv->initialized &&
+ !(g_str_equal (method, "initialize") ||
+ g_str_equal (method, "initialized")))
+ ide_lsp_client_queue_message (self,
+ method,
+ params,
+ cancellable,
+ g_steal_pointer (&task));
else
jsonrpc_client_call_async (priv->rpc_client,
method,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]