From fb10ed768b64c6b43147df0cdf0fe7a69a82f57a Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Thu, 5 Sep 2019 14:20:43 +0300 Subject: [PATCH] libweston: Introduce timeline subscription and timeline subscription object 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 Suggested-by: Daniel Stone --- libweston/timeline.c | 238 ++++++++++++++++++++++++++++++++++--------- libweston/timeline.h | 23 +++++ 2 files changed, 215 insertions(+), 46 deletions(-) diff --git a/libweston/timeline.c b/libweston/timeline.c index 144a593d..35ccc523 100644 --- a/libweston/timeline.c +++ b/libweston/timeline.c @@ -32,91 +32,229 @@ #include #include -#include "timeline.h" #include +#include +#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); diff --git a/libweston/timeline.h b/libweston/timeline.h index 6feafa35..bc98add7 100644 --- a/libweston/timeline.h +++ b/libweston/timeline.h @@ -27,6 +27,12 @@ #ifndef WESTON_TIMELINE_H #define WESTON_TIMELINE_H +#include +#include + +#include +#include + 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___); \