libweston: Introduce timeline subscription and timeline subscription object
authorMarius Vlad <marius.vlad@collabora.com>
Thu, 5 Sep 2019 11:20:43 +0000 (14:20 +0300)
committerMarius Vlad <marius.vlad@collabora.com>
Thu, 17 Oct 2019 18:41:09 +0000 (21:41 +0300)
An object based on 'weston_timeline_subscription' will be created for
each subscription created. It contains the next object ID and list of
'weston_timeline_subscription_object'.

It will automatically be cleaned by the logging framework when the
subscription gets destroyed, or use the object destroy signal to trigger
the destruction of the timeline subscription (@pq), when the object
itself is being destroyed.

This class will hanged-off the subscription, such that we can
retrieve it when going over all the subscriptions.

An object based on 'weston_timeline_subscription_object' will help
maintain the state of the objects seen and will be created when a new
object will be emitted for a particular 'weston_timeline_subscription'.

Adds wrappers for ensuring the timeline subscription object is created
or has to be searched in order to be found, as to avoid duplicated code.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Suggested-by: Daniel Stone <daniel.stone@collabora.com>
libweston/timeline.c
libweston/timeline.h

index 144a593d974346a0d1c5808b3762bc2b946483d3..35ccc523a982aa249f9fa3393ba2d3c2e3b8d7f7 100644 (file)
 #include <time.h>
 #include <assert.h>
 
-#include "timeline.h"
 #include <libweston/libweston.h>
+#include <libweston/weston-log.h>
+#include "timeline.h"
+#include "weston-log-internal.h"
 
 WL_EXPORT int weston_timeline_enabled_;
 
 struct timeline_emit_context {
        FILE *cur;
-       FILE *out;
-       unsigned series;
+       struct weston_log_subscription *subscription;
 };
 
-static unsigned
-timeline_new_id(void)
+/** Create a timeline subscription and hang it off the subscription
+ *
+ * Called when the subscription is created.
+ *
+ * @ingroup internal-log
+ */
+void
+weston_timeline_create_subscription(struct weston_log_subscription *sub,
+               void *user_data)
 {
-       static unsigned idc;
+       struct weston_timeline_subscription *tl_sub = zalloc(sizeof(*tl_sub));
+       if (!tl_sub)
+               return;
 
-       if (++idc == 0)
-               ++idc;
+       wl_list_init(&tl_sub->objects);
 
-       return idc;
+       /* attach this timeline_subscription to it */
+       weston_log_subscription_set_data(sub, tl_sub);
 }
 
-static int
-check_series(struct timeline_emit_context *ctx,
-            struct weston_timeline_object *to)
+static void
+weston_timeline_destroy_subscription_object(struct weston_timeline_subscription_object *sub_obj)
+{
+       /* remove the notify listener */
+       wl_list_remove(&sub_obj->destroy_listener.link);
+       sub_obj->destroy_listener.notify = NULL;
+
+       wl_list_remove(&sub_obj->subscription_link);
+       free(sub_obj);
+}
+
+/** Destroy the timeline subscription and all timeline subscription objects
+ * associated with it.
+ *
+ * Called when (before) the subscription is destroyed.
+ *
+ * @ingroup internal-log
+ */
+void
+weston_timeline_destroy_subscription(struct weston_log_subscription *sub,
+                                    void *user_data)
 {
-       if (to->series == 0 || to->series != ctx->series) {
-               to->series = ctx->series;
-               to->id = timeline_new_id();
-               return 1;
+       struct weston_timeline_subscription *tl_sub =
+               weston_log_subscription_get_data(sub);
+       struct weston_timeline_subscription_object *sub_obj, *tmp_sub_obj;
+
+       if (!tl_sub)
+               return;
+
+       wl_list_for_each_safe(sub_obj, tmp_sub_obj,
+                             &tl_sub->objects, subscription_link)
+               weston_timeline_destroy_subscription_object(sub_obj);
+
+       free(tl_sub);
+}
+
+static bool
+weston_timeline_check_object_refresh(struct weston_timeline_subscription_object *obj)
+{
+       if (obj->force_refresh == true) {
+               obj->force_refresh = false;
+               return true;
        }
+       return false;
+}
+
+static struct weston_timeline_subscription_object *
+weston_timeline_subscription_search(struct weston_timeline_subscription *tl_sub,
+                                   void *object)
+{
+       struct weston_timeline_subscription_object *sub_obj;
+
+       wl_list_for_each(sub_obj, &tl_sub->objects, subscription_link)
+               if (sub_obj->object == object)
+                       return sub_obj;
+
+       return NULL;
+}
+
+static struct weston_timeline_subscription_object *
+weston_timeline_subscription_object_create(void *object,
+                                          struct weston_timeline_subscription *tm_sub)
+{
+       struct weston_timeline_subscription_object *sub_obj;
 
-       if (to->force_refresh) {
-               to->force_refresh = 0;
-               return 1;
+       sub_obj = zalloc(sizeof(*sub_obj));
+       sub_obj->id = ++tm_sub->next_id;
+       sub_obj->object = object;
+
+       /* when the object is created so that it has the chance to display the
+        * object ID, we set the refresh status; it will only be re-freshed by
+        * the backend (or part parts) when the underlying objects has suffered
+        * modifications */
+       sub_obj->force_refresh = true;
+
+       wl_list_insert(&tm_sub->objects, &sub_obj->subscription_link);
+
+       return sub_obj;
+}
+
+static void
+weston_timeline_destroy_subscription_object_notify(struct wl_listener *listener, void *data)
+{
+       struct weston_timeline_subscription_object *sub_obj;
+
+       sub_obj = wl_container_of(listener, sub_obj, destroy_listener);
+       weston_timeline_destroy_subscription_object(sub_obj);
+}
+
+static struct weston_timeline_subscription_object *
+weston_timeline_subscription_output_ensure(struct weston_timeline_subscription *tl_sub,
+               struct weston_output *output)
+{
+       struct weston_timeline_subscription_object *sub_obj;
+
+       sub_obj = weston_timeline_subscription_search(tl_sub, output);
+       if (!sub_obj) {
+               sub_obj = weston_timeline_subscription_object_create(output, tl_sub);
+
+               sub_obj->destroy_listener.notify =
+                       weston_timeline_destroy_subscription_object_notify;
+               wl_signal_add(&output->destroy_signal,
+                             &sub_obj->destroy_listener);
        }
+       return sub_obj;
+}
 
-       return 0;
+static struct weston_timeline_subscription_object *
+weston_timeline_subscription_surface_ensure(struct weston_timeline_subscription *tl_sub,
+               struct weston_surface *surface)
+{
+       struct weston_timeline_subscription_object *sub_obj;
+
+       sub_obj = weston_timeline_subscription_search(tl_sub, surface);
+       if (!sub_obj) {
+               sub_obj = weston_timeline_subscription_object_create(surface, tl_sub);
+
+               sub_obj->destroy_listener.notify =
+                       weston_timeline_destroy_subscription_object_notify;
+               wl_signal_add(&surface->destroy_signal,
+                             &sub_obj->destroy_listener);
+       }
+
+       return sub_obj;
 }
 
 static void
-fprint_quoted_string(FILE *fp, const char *str)
+fprint_quoted_string(struct weston_log_subscription *sub, const char *str)
 {
        if (!str) {
-               fprintf(fp, "null");
+               weston_log_subscription_printf(sub, "null");
                return;
        }
 
-       fprintf(fp, "\"%s\"", str);
+       weston_log_subscription_printf(sub, "\"%s\"", str);
+}
+
+static void
+emit_weston_output_print_id(struct weston_log_subscription *sub,
+                           struct weston_timeline_subscription_object *sub_obj,
+                           const char *name)
+{
+       if (!weston_timeline_check_object_refresh(sub_obj))
+               return;
+
+       weston_log_subscription_printf(sub, "{ \"id\":%u, "
+                       "\"type\":\"weston_output\", \"name\":", sub_obj->id);
+       fprint_quoted_string(sub, name);
+       weston_log_subscription_printf(sub, " }\n");
 }
 
 static int
 emit_weston_output(struct timeline_emit_context *ctx, void *obj)
 {
-       struct weston_output *o = obj;
+       struct weston_log_subscription *sub = ctx->subscription;
+       struct weston_output *output = obj;
+       struct weston_timeline_subscription_object *sub_obj;
+       struct weston_timeline_subscription *tl_sub;
 
-       if (check_series(ctx, &o->timeline)) {
-               fprintf(ctx->out, "{ \"id\":%u, "
-                       "\"type\":\"weston_output\", \"name\":",
-                       o->timeline.id);
-               fprint_quoted_string(ctx->out, o->name);
-               fprintf(ctx->out, " }\n");
-       }
+       tl_sub = weston_log_subscription_get_data(sub);
+       sub_obj = weston_timeline_subscription_output_ensure(tl_sub, output);
+       emit_weston_output_print_id(sub, sub_obj, output->name);
 
-       fprintf(ctx->cur, "\"wo\":%u", o->timeline.id);
+       assert(sub_obj->id != 0);
+       fprintf(ctx->cur, "\"wo\":%u", sub_obj->id);
 
        return 1;
 }
 
+
 static void
-check_weston_surface_description(struct timeline_emit_context *ctx,
-                                struct weston_surface *s)
+check_weston_surface_description(struct weston_log_subscription *sub,
+                                struct weston_surface *s,
+                                struct weston_timeline_subscription *tm_sub,
+                                struct weston_timeline_subscription_object *sub_obj)
 {
        struct weston_surface *mains;
        char d[512];
        char mainstr[32];
 
-       if (!check_series(ctx, &s->timeline))
+       if (!weston_timeline_check_object_refresh(sub_obj))
                return;
 
        mains = weston_surface_get_main_surface(s);
        if (mains != s) {
-               check_weston_surface_description(ctx, mains);
-               if (snprintf(mainstr, sizeof(mainstr),
-                            ", \"main_surface\":%u", mains->timeline.id) < 0)
+               struct weston_timeline_subscription_object *new_sub_obj;
+
+               new_sub_obj = weston_timeline_subscription_surface_ensure(tm_sub, mains);
+               check_weston_surface_description(sub, mains, tm_sub, new_sub_obj);
+               if (snprintf(mainstr, sizeof(mainstr), ", \"main_surface\":%u",
+                            new_sub_obj->id) < 0)
                        mainstr[0] = '\0';
        } else {
                mainstr[0] = '\0';
@@ -125,19 +263,27 @@ check_weston_surface_description(struct timeline_emit_context *ctx,
        if (!s->get_label || s->get_label(s, d, sizeof(d)) < 0)
                d[0] = '\0';
 
-       fprintf(ctx->out, "{ \"id\":%u, "
-               "\"type\":\"weston_surface\", \"desc\":", s->timeline.id);
-       fprint_quoted_string(ctx->out, d[0] ? d : NULL);
-       fprintf(ctx->out, "%s }\n", mainstr);
+       weston_log_subscription_printf(sub, "{ \"id\":%u, "
+                                      "\"type\":\"weston_surface\", \"desc\":",
+                                      sub_obj->id);
+       fprint_quoted_string(sub, d[0] ? d : NULL);
+       weston_log_subscription_printf(sub, "%s }\n", mainstr);
 }
 
 static int
 emit_weston_surface(struct timeline_emit_context *ctx, void *obj)
 {
-       struct weston_surface *s = obj;
+       struct weston_log_subscription *sub = ctx->subscription;
+       struct weston_surface *surface = obj;
+       struct weston_timeline_subscription_object *sub_obj;
+       struct weston_timeline_subscription *tl_sub;
+
+       tl_sub = weston_log_subscription_get_data(sub);
+       sub_obj = weston_timeline_subscription_surface_ensure(tl_sub, surface);
+       check_weston_surface_description(sub, surface, tl_sub, sub_obj);
 
-       check_weston_surface_description(ctx, s);
-       fprintf(ctx->cur, "\"ws\":%u", s->timeline.id);
+       assert(sub_obj->id != 0);
+       fprintf(ctx->cur, "\"ws\":%u", sub_obj->id);
 
        return 1;
 }
@@ -214,7 +360,7 @@ weston_timeline_point(const char *name, ...)
        if (ferror(ctx.cur)) {
                weston_log("Timeline error in constructing entry, closing.\n");
        } else {
-               fprintf(ctx.out, "%s", buf);
+               weston_log_subscription_printf(ctx.subscription, "%s", buf);
        }
 
        fclose(ctx.cur);
index 6feafa3534325b4b2ef50461310e92ba689c8b20..bc98add79f78fd88a3e5bbef09a855c8f80f61d0 100644 (file)
 #ifndef WESTON_TIMELINE_H
 #define WESTON_TIMELINE_H
 
+#include <wayland-util.h>
+#include <stdbool.h>
+
+#include <libweston/weston-log.h>
+#include <wayland-server-core.h>
+
 extern int weston_timeline_enabled_;
 
 enum timeline_type {
@@ -37,6 +43,23 @@ enum timeline_type {
        TLT_GPU,
 };
 
+struct weston_timeline_subscription {
+       unsigned int next_id;
+       struct wl_list objects; /**< weston_timeline_subscription_object::subscription_link */
+};
+
+/**
+ * Created when object is first seen for a particular timeline subscription
+ * Destroyed when the subscription got destroyed or object was destroyed
+ */
+struct weston_timeline_subscription_object {
+       void *object;                           /**< points to the object */
+       unsigned int id;
+       bool force_refresh;
+       struct wl_list subscription_link;       /**< weston_timeline_subscription::objects */
+       struct wl_listener destroy_listener;
+};
+
 #define TYPEVERIFY(type, arg) ({               \
        typeof(arg) tmp___ = (arg);             \
        (void)((type)0 == tmp___);              \