Reviewed-by: Emre Ucan <eu...@de.adit-jv.com> Best regards
Emre Ucan Engineering Software Base (ADITG/ESB) Tel. +49 5121 49 6937 > -----Original Message----- > From: wayland-devel [mailto:wayland-devel- > boun...@lists.freedesktop.org] On Behalf Of Daniel Stone > Sent: Freitag, 20. Juli 2018 21:06 > To: wayland-devel@lists.freedesktop.org > Cc: pekka.paala...@collabora.co.uk; emre.u...@de.adit-jv.com; > maniraj.devad...@in.bosch.com > Subject: [PATCH weston v5 03/14] libweston: add weston_debug API and > implementation > > From: Pekka Paalanen <p...@iki.fi> > > weston_debug is both a libweston API for relaying debugging messages, > and the compositor-debug wayland protocol implementation for accessing > those > debug messages from a Wayland client. > > weston_debug_compositor_{create,destroy}() are private API, hence not > exported. > > Signed-off-by: Pekka Paalanen <p...@iki.fi> > > append the debug scope name along with the timestamp in > weston_debug_scope_timestamp API > > Signed-off-by: Maniraj Devadoss <maniraj.devad...@in.bosch.com> > Reviewed-by: Pekka Paalanen <pekka.paala...@collabora.co.uk> > > Add explicit advertisement of debug scope names. > > Signed-off-by: Daniel Stone <dani...@collabora.com> > --- > Makefile.am | 2 + > libweston/compositor.c | 6 + > libweston/compositor.h | 9 + > libweston/weston-debug.c | 723 > +++++++++++++++++++++++++++++++++++++++ > libweston/weston-debug.h | 107 ++++++ > 5 files changed, 847 insertions(+) > create mode 100644 libweston/weston-debug.c > create mode 100644 libweston/weston-debug.h > > diff --git a/Makefile.am b/Makefile.am > index 66eb365c5..c2d9048b3 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -98,6 +98,8 @@ libweston_@LIBWESTON_MAJOR@_la_SOURCES = > \ > libweston/linux-dmabuf.h \ > libweston/pixel-formats.c \ > libweston/pixel-formats.h \ > + libweston/weston-debug.c \ > + libweston/weston-debug.h \ > shared/helpers.h \ > shared/matrix.c \ > shared/matrix.h \ > diff --git a/libweston/compositor.c b/libweston/compositor.c > index 9deb7817f..8768f67a0 100644 > --- a/libweston/compositor.c > +++ b/libweston/compositor.c > @@ -6361,6 +6361,9 @@ weston_compositor_create(struct wl_display > *display, void *user_data) > ec, bind_presentation)) > goto fail; > > + if (weston_debug_compositor_create(ec) < 0) > + goto fail; > + > if (weston_input_init(ec) != 0) > goto fail; > > @@ -6699,9 +6702,12 @@ weston_compositor_destroy(struct > weston_compositor *compositor) > > weston_plugin_api_destroy_list(compositor); > > + > if (compositor->heads_changed_source) > wl_event_source_remove(compositor- > >heads_changed_source); > > + weston_debug_compositor_destroy(compositor); > + > free(compositor); > } > > diff --git a/libweston/compositor.h b/libweston/compositor.h > index fd0ff7b5b..83448b70f 100644 > --- a/libweston/compositor.h > +++ b/libweston/compositor.h > @@ -1049,6 +1049,7 @@ struct weston_touch_calibrator; > > struct weston_desktop_xwayland; > struct weston_desktop_xwayland_interface; > +struct weston_debug_compositor; > > struct weston_compositor { > struct wl_signal destroy_signal; > @@ -1161,6 +1162,8 @@ struct weston_compositor { > weston_touch_calibration_save_func touch_calibration_save; > struct weston_layer calibrator_layer; > struct weston_touch_calibrator *touch_calibrator; > + > + struct weston_debug_compositor *weston_debug; > }; > > struct weston_buffer { > @@ -2315,6 +2318,12 @@ int > weston_compositor_enable_touch_calibrator(struct weston_compositor > *compositor, > weston_touch_calibration_save_func save); > > +int > +weston_debug_compositor_create(struct weston_compositor > *compositor); > + > +void > +weston_debug_compositor_destroy(struct weston_compositor > *compositor); > + > #ifdef __cplusplus > } > #endif > diff --git a/libweston/weston-debug.c b/libweston/weston-debug.c > new file mode 100644 > index 000000000..039247f14 > --- /dev/null > +++ b/libweston/weston-debug.c > @@ -0,0 +1,723 @@ > +/* > + * Copyright © 2017 Pekka Paalanen <p...@iki.fi> > + * > + * Permission is hereby granted, free of charge, to any person obtaining > + * a copy of this software and associated documentation files (the > + * "Software"), to deal in the Software without restriction, including > + * without limitation the rights to use, copy, modify, merge, publish, > + * distribute, sublicense, and/or sell copies of the Software, and to > + * permit persons to whom the Software is furnished to do so, subject to > + * the following conditions: > + * > + * The above copyright notice and this permission notice (including the > + * next paragraph) shall be included in all copies or substantial > + * portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES > OF > + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND > + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT > HOLDERS > + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN > AN > + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR > IN > + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > THE > + * SOFTWARE. > + */ > + > +#include "config.h" > + > +#include "weston-debug.h" > +#include "helpers.h" > +#include "compositor.h" > + > +#include "weston-debug-server-protocol.h" > + > +#include <unistd.h> > +#include <stdarg.h> > +#include <string.h> > +#include <errno.h> > +#include <sys/time.h> > + > +/** Main weston-debug context > + * > + * One per weston_compositor. > + * > + * \internal > + */ > +struct weston_debug_compositor { > + struct weston_compositor *compositor; > + struct wl_listener compositor_destroy_listener; > + struct wl_global *global; > + struct wl_list scope_list; /**< > weston_debug_scope::compositor_link */ > + > + struct weston_debug_scope *list; > +}; > + > +/** weston-debug message scope > + * > + * This is used for scoping debugging messages. Clients can subscribe to > + * only the scopes they are interested in. A scope is identified by its name > + * (also referred to as debug stream name). > + */ > +struct weston_debug_scope { > + char *name; > + char *desc; > + weston_debug_scope_cb begin_cb; > + void *user_data; > + struct wl_list stream_list; /**< weston_debug_stream::scope_link */ > + struct wl_list compositor_link; > +}; > + > +/** A debug stream created by a client > + * > + * A client provides a file descriptor for the server to write debug > + * messages into. A weston_debug_stream is associated to one > + * weston_debug_scope via the scope name, and the scope provides the > messages. > + * There can be several streams for the same scope, all streams getting the > + * same messages. > + */ > +struct weston_debug_stream { > + int fd; /**< client provided fd */ > + struct wl_resource *resource; /**< weston_debug_stream_v1 > object */ > + struct wl_list scope_link; > +}; > + > +static struct weston_debug_scope * > +get_scope(struct weston_debug_compositor *wdc, const char *name) > +{ > + struct weston_debug_scope *scope; > + > + wl_list_for_each(scope, &wdc->scope_list, compositor_link) > + if (strcmp(name, scope->name) == 0) > + return scope; > + > + return NULL; > +} > + > +static void > +stream_close_unlink(struct weston_debug_stream *stream) > +{ > + if (stream->fd != -1) > + close(stream->fd); > + stream->fd = -1; > + > + wl_list_remove(&stream->scope_link); > + wl_list_init(&stream->scope_link); > +} > + > +static void WL_PRINTF(2, 3) > +stream_close_on_failure(struct weston_debug_stream *stream, > + const char *fmt, ...) > +{ > + char *msg; > + va_list ap; > + int ret; > + > + stream_close_unlink(stream); > + > + va_start(ap, fmt); > + ret = vasprintf(&msg, fmt, ap); > + va_end(ap); > + > + if (ret > 0) { > + weston_debug_stream_v1_send_failure(stream->resource, > msg); > + free(msg); > + } else { > + weston_debug_stream_v1_send_failure(stream->resource, > + "MEMFAIL"); > + } > +} > + > +static struct weston_debug_stream * > +stream_create(struct weston_debug_compositor *wdc, const char *name, > + int32_t streamfd, struct wl_resource *stream_resource) > +{ > + struct weston_debug_stream *stream; > + struct weston_debug_scope *scope; > + > + stream = zalloc(sizeof *stream); > + if (!stream) > + return NULL; > + > + stream->fd = streamfd; > + stream->resource = stream_resource; > + > + scope = get_scope(wdc, name); > + if (scope) { > + wl_list_insert(&scope->stream_list, &stream->scope_link); > + > + if (scope->begin_cb) > + scope->begin_cb(stream, scope->user_data); > + } else { > + wl_list_init(&stream->scope_link); > + stream_close_on_failure(stream, > + "Debug stream name '%s' is > unknown.", > + name); > + } > + > + return stream; > +} > + > +static void > +stream_destroy(struct wl_resource *stream_resource) > +{ > + struct weston_debug_stream *stream; > + > + stream = wl_resource_get_user_data(stream_resource); > + > + if (stream->fd != -1) > + close(stream->fd); > + wl_list_remove(&stream->scope_link); > + free(stream); > +} > + > +static void > +weston_debug_stream_destroy(struct wl_client *client, > + struct wl_resource *stream_resource) > +{ > + wl_resource_destroy(stream_resource); > +} > + > +static const struct weston_debug_stream_v1_interface > + weston_debug_stream_impl > = { > + weston_debug_stream_destroy > +}; > + > +static void > +weston_debug_destroy(struct wl_client *client, > + struct wl_resource *global_resource) > +{ > + wl_resource_destroy(global_resource); > +} > + > +static void > +weston_debug_subscribe(struct wl_client *client, > + struct wl_resource *global_resource, > + const char *name, > + int32_t streamfd, > + uint32_t new_stream_id) > +{ > + struct weston_debug_compositor *wdc; > + struct wl_resource *stream_resource; > + uint32_t version; > + struct weston_debug_stream *stream; > + > + wdc = wl_resource_get_user_data(global_resource); > + version = wl_resource_get_version(global_resource); > + > + stream_resource = wl_resource_create(client, > + > &weston_debug_stream_v1_interface, > + version, new_stream_id); > + if (!stream_resource) > + goto fail; > + > + stream = stream_create(wdc, name, streamfd, stream_resource); > + if (!stream) > + goto fail; > + > + wl_resource_set_implementation(stream_resource, > + &weston_debug_stream_impl, > + stream, stream_destroy); > + return; > + > +fail: > + close(streamfd); > + wl_client_post_no_memory(client); > +} > + > +static const struct weston_debug_v1_interface weston_debug_impl = { > + weston_debug_destroy, > + weston_debug_subscribe > +}; > + > +static void > +bind_weston_debug(struct wl_client *client, > + void *data, uint32_t version, uint32_t id) > +{ > + struct weston_debug_compositor *wdc = data; > + struct weston_debug_scope *scope; > + struct wl_resource *resource; > + > + resource = wl_resource_create(client, > + &weston_debug_v1_interface, > + version, id); > + if (!resource) { > + wl_client_post_no_memory(client); > + return; > + } > + wl_resource_set_implementation(resource, &weston_debug_impl, > + wdc, NULL); > + > + wl_list_for_each(scope, &wdc->scope_list, compositor_link) > + weston_debug_v1_send_available(resource, scope->name); > +} > + > +/** Initialize weston-debug structure > + * > + * \param compositor The libweston compositor. > + * \return 0 on success, -1 on failure. > + * > + * weston_debug_compositor is a singleton for each weston_compositor. > + * > + * Sets weston_compositor::weston_debug. > + * > + * \internal > + */ > +int > +weston_debug_compositor_create(struct weston_compositor > *compositor) > +{ > + struct weston_debug_compositor *wdc; > + > + if (compositor->weston_debug) > + return -1; > + > + wdc = zalloc(sizeof *wdc); > + if (!wdc) > + return -1; > + > + wdc->compositor = compositor; > + wl_list_init(&wdc->scope_list); > + > + compositor->weston_debug = wdc; > + > + return 0; > +} > + > +/** Destroy weston_debug_compositor structure > + * > + * \param compositor The libweston compositor whose weston-debug to > tear down. > + * > + * Clears weston_compositor::weston_debug. > + * > + * \internal > + */ > +void > +weston_debug_compositor_destroy(struct weston_compositor > *compositor) > +{ > + struct weston_debug_compositor *wdc = compositor- > >weston_debug; > + struct weston_debug_scope *scope; > + > + if (wdc->global) > + wl_global_destroy(wdc->global); > + > + wl_list_for_each(scope, &wdc->scope_list, compositor_link) > + weston_log("Internal warning: debug scope '%s' has not > been destroyed.\n", > + scope->name); > + > + /* Remove head to not crash if scope removed later. */ > + wl_list_remove(&wdc->scope_list); > + > + free(wdc); > + > + compositor->weston_debug = NULL; > +} > + > +/** Enable weston-debug protocol extension > + * > + * \param compositor The libweston compositor where to enable. > + * > + * This enables the weston_debug_v1 Wayland protocol extension which > any > + * client can use to get debug messsages from the compositor. > + * > + * WARNING: This feature should not be used in production. If a client > + * provides a file descriptor that blocks writes, it will block the whole > + * compositor indefinitely. > + * > + * There is no control on which client is allowed to subscribe to debug > + * messages. Any and all clients are allowed. > + * > + * The debug extension is disabled by default, and once enabled, cannot be > + * disabled again. > + */ > +WL_EXPORT void > +weston_compositor_enable_debug_protocol(struct weston_compositor > *compositor) > +{ > + struct weston_debug_compositor *wdc; > + > + wdc = compositor->weston_debug; > + if (!wdc) > + return; > + > + if (wdc->global) > + return; > + > + wdc->global = wl_global_create(compositor->wl_display, > + &weston_debug_v1_interface, 1, > + wdc, bind_weston_debug); > + if (!wdc->global) > + return; > + > + weston_log("WARNING: debug protocol has been enabled. " > + "This is a potential denial-of-service attack vector and " > + "information leak.\n"); > +} > + > +/** Register a new debug stream name, creating a debug scope > + * > + * \param compositor The libweston compositor where to add. > + * \param name The debug stream/scope name. > + * \param desc The debug scope description for humans. > + * \param begin_cb Optional callback when a client subscribes to this scope. > + * \param user_data Optional user data pointer for the callback. > + * \return A valid pointer on success, NULL on failure. > + * > + * This function is used to create a debug scope. All debug message printing > + * happens for a scope, which allows clients to subscribe to the kind of > + * debug messages they want by \c name. > + * > + * \c name must be unique in the \c weston_compositor instance. \c name > and > + * \c description must both be provided. The description is printed when a > + * client asks for a list of supported debug scopes. > + * > + * \c begin_cb, if not NULL, is called when a client subscribes to the > + * debug scope creating a debug stream. This is for debug scopes that need > + * to print messages as a response to a client appearing, e.g. printing a > + * list of windows on demand or a static preamble. The argument \c > user_data > + * is passed in to the callback and is otherwise unused. > + * > + * For one-shot debug streams, \c begin_cb should finally call > + * weston_debug_stream_complete() to close the stream and tell the client > + * the printing is complete. Otherwise the client expects more to be written > + * to its file descriptor. > + * > + * The debug scope must be destroyed before destroying the > + * \c weston_compositor. > + * > + * \memberof weston_debug_scope > + * \sa weston_debug_stream, weston_debug_scope_cb > + */ > +WL_EXPORT struct weston_debug_scope * > +weston_compositor_add_debug_scope(struct weston_compositor > *compositor, > + const char *name, > + const char *description, > + weston_debug_scope_cb begin_cb, > + void *user_data) > +{ > + struct weston_debug_compositor *wdc; > + struct weston_debug_scope *scope; > + > + if (!compositor || !name || !description) { > + weston_log("Error: cannot add a debug scope without name > or description.\n"); > + return NULL; > + } > + > + wdc = compositor->weston_debug; > + if (!wdc) { > + weston_log("Error: cannot add debug scope '%s', infra not > initialized.\n", > + name); > + return NULL; > + } > + > + if (get_scope(wdc, name)){ > + weston_log("Error: debug scope named '%s' is already > registered.\n", > + name); > + return NULL; > + } > + > + scope = zalloc(sizeof *scope); > + if (!scope) { > + weston_log("Error adding debug scope '%s': out of > memory.\n", > + name); > + return NULL; > + } > + > + scope->name = strdup(name); > + scope->desc = strdup(description); > + scope->begin_cb = begin_cb; > + scope->user_data = user_data; > + wl_list_init(&scope->stream_list); > + > + if (!scope->name || !scope->desc) { > + weston_log("Error adding debug scope '%s': out of > memory.\n", > + name); > + free(scope->name); > + free(scope->desc); > + free(scope); > + return NULL; > + } > + > + wl_list_insert(wdc->scope_list.prev, &scope->compositor_link); > + > + return scope; > +} > + > +/** Destroy a debug scope > + * > + * \param scope The debug scope to destroy. > + * > + * Destroys the debug scope, closing all open streams subscribed to it and > + * sending them each a \c weston_debug_stream_v1.failure event. > + * > + * \memberof weston_debug_scope > + */ > +WL_EXPORT void > +weston_debug_scope_destroy(struct weston_debug_scope *scope) > +{ > + struct weston_debug_stream *stream; > + > + if (!scope) > + return; > + > + while (!wl_list_empty(&scope->stream_list)) { > + stream = wl_container_of(scope->stream_list.prev, > + stream, scope_link); > + > + stream_close_on_failure(stream, "debug name removed"); > + } > + > + wl_list_remove(&scope->compositor_link); > + free(scope->name); > + free(scope->desc); > + free(scope); > +} > + > +/** Are there any active subscriptions to the scope? > + * > + * \param scope The debug scope to check. > + * \return True if any streams are open for this scope, false otherwise. > + * > + * As printing some debugging messages may be relatively expensive, one > + * can use this function to determine if there is a need to gather the > + * debugging information at all. If this function returns false, all > + * printing for this scope is dropped, so gathering the information is > + * pointless. > + * > + * The return value of this function should not be stored, as new clients > + * may subscribe to the debug scope later. > + * > + * \memberof weston_debug_scope > + */ > +WL_EXPORT bool > +weston_debug_scope_is_enabled(struct weston_debug_scope *scope) > +{ > + if (!scope) > + return false; > + > + return !wl_list_empty(&scope->stream_list); > +} > + > +/** Write data into a specific debug stream > + * > + * \param stream The debug stream to write into. > + * \param data[in] Pointer to the data to write. > + * \param len Number of bytes to write. > + * > + * Writes the given data (binary verbatim) into the debug stream. > + * If \c len is zero or negative, the write is silently dropped. > + * > + * Writing is continued until all data has been written or > + * a write fails. If the write fails due to a signal, it is re-tried. > + * Otherwise on failure, the stream is closed and > + * \c weston_debug_stream_v1.failure event is sent to the client. > + * > + * \memberof weston_debug_stream > + */ > +WL_EXPORT void > +weston_debug_stream_write(struct weston_debug_stream *stream, > + const char *data, size_t len) > +{ > + ssize_t len_ = len; > + ssize_t ret; > + int e; > + > + if (stream->fd == -1) > + return; > + > + while (len_ > 0) { > + ret = write(stream->fd, data, len_); > + e = errno; > + if (ret < 0) { > + if (e == EINTR) > + continue; > + > + stream_close_on_failure(stream, > + "Error writing %zd bytes: %s (%d)", > + len_, strerror(e), e); > + break; > + } > + > + len_ -= ret; > + data += ret; > + } > +} > + > +/** Write a formatted string into a specific debug stream (varargs) > + * > + * \param stream The debug stream to write into. > + * \param fmt Printf-style format string. > + * \param ap Formatting arguments. > + * > + * The behavioral details are the same as for > weston_debug_stream_write(). > + * > + * \memberof weston_debug_stream > + */ > +WL_EXPORT void > +weston_debug_stream_vprintf(struct weston_debug_stream *stream, > + const char *fmt, va_list ap) > +{ > + char *str; > + int len; > + > + len = vasprintf(&str, fmt, ap); > + if (len >= 0) { > + weston_debug_stream_write(stream, str, len); > + free(str); > + } else { > + stream_close_on_failure(stream, "Out of memory"); > + } > +} > + > +/** Write a formatted string into a specific debug stream > + * > + * \param stream The debug stream to write into. > + * \param fmt Printf-style format string and arguments. > + * > + * The behavioral details are the same as for > weston_debug_stream_write(). > + * > + * \memberof weston_debug_stream > + */ > +WL_EXPORT void > +weston_debug_stream_printf(struct weston_debug_stream *stream, > + const char *fmt, ...) > +{ > + va_list ap; > + > + va_start(ap, fmt); > + weston_debug_stream_vprintf(stream, fmt, ap); > + va_end(ap); > +} > + > +/** Close the debug stream and send success event > + * > + * \param stream The debug stream to close. > + * > + * Closes the debug stream and sends \c > weston_debug_stream_v1.complete > + * event to the client. This tells the client the debug information dump > + * is complete. > + * > + * \memberof weston_debug_stream > + */ > +WL_EXPORT void > +weston_debug_stream_complete(struct weston_debug_stream *stream) > +{ > + stream_close_unlink(stream); > + weston_debug_stream_v1_send_complete(stream->resource); > +} > + > +/** Write debug data for a scope > + * > + * \param scope The debug scope to write for. > + * \param data[in] Pointer to the data to write. > + * \param len Number of bytes to write. > + * > + * Writes the given data to all subscribed clients' streams. > + * > + * The behavioral details for each stream are the same as for > + * weston_debug_stream_write(). > + * > + * \memberof weston_debug_scope > + */ > +WL_EXPORT void > +weston_debug_scope_write(struct weston_debug_scope *scope, > + const char *data, size_t len) > +{ > + struct weston_debug_stream *stream; > + > + if (!scope) > + return; > + > + wl_list_for_each(stream, &scope->stream_list, scope_link) > + weston_debug_stream_write(stream, data, len); > +} > + > +/** Write a formatted string for a scope (varargs) > + * > + * \param scope The debug scope to write for. > + * \param fmt Printf-style format string. > + * \param ap Formatting arguments. > + * > + * Writes to formatted string to all subscribed clients' streams. > + * > + * The behavioral details for each stream are the same as for > + * weston_debug_stream_write(). > + * > + * \memberof weston_debug_scope > + */ > +WL_EXPORT void > +weston_debug_scope_vprintf(struct weston_debug_scope *scope, > + const char *fmt, va_list ap) > +{ > + static const char oom[] = "Out of memory"; > + char *str; > + int len; > + > + if (!weston_debug_scope_is_enabled(scope)) > + return; > + > + len = vasprintf(&str, fmt, ap); > + if (len >= 0) { > + weston_debug_scope_write(scope, str, len); > + free(str); > + } else { > + weston_debug_scope_write(scope, oom, sizeof oom - 1); > + } > +} > + > +/** Write a formatted string for a scope > + * > + * \param scope The debug scope to write for. > + * \param fmt Printf-style format string and arguments. > + * > + * Writes to formatted string to all subscribed clients' streams. > + * > + * The behavioral details for each stream are the same as for > + * weston_debug_stream_write(). > + * > + * \memberof weston_debug_scope > + */ > +WL_EXPORT void > +weston_debug_scope_printf(struct weston_debug_scope *scope, > + const char *fmt, ...) > +{ > + va_list ap; > + > + va_start(ap, fmt); > + weston_debug_scope_vprintf(scope, fmt, ap); > + va_end(ap); > +} > + > +/** Format current time as a string > + * and append the debug scope name to it > + * > + * \param scope[in] debug scope. > + * \param buf[out] Buffer to store the string. > + * \param len Available size in the buffer in bytes. > + * \return \c buf > + * > + * Reads the current local wall-clock time and formats it into a string. > + * and append the debug scope name to it. > + * The string is nul-terminated, even if truncated. > + */ > +WL_EXPORT char * > +weston_debug_scope_timestamp(struct weston_debug_scope *scope, > + char *buf, size_t len) > +{ > + struct timeval tv; > + struct tm *bdt; > + char string[128]; > + size_t ret = 0; > + > + gettimeofday(&tv, NULL); > + > + bdt = localtime(&tv.tv_sec); > + if (bdt) > + ret = strftime(string, sizeof string, > + "%Y-%m-%d %H:%M:%S", bdt); > + > + if (ret > 0) > + snprintf(buf, len, "[%s.%03ld][%s]", string, > + tv.tv_usec / 1000, scope->name); > + else > + snprintf(buf, len, "[?][%s]", scope->name); > + > + return buf; > +} > diff --git a/libweston/weston-debug.h b/libweston/weston-debug.h > new file mode 100644 > index 000000000..c76cec852 > --- /dev/null > +++ b/libweston/weston-debug.h > @@ -0,0 +1,107 @@ > +/* > + * Copyright © 2017 Pekka Paalanen <p...@iki.fi> > + * > + * Permission is hereby granted, free of charge, to any person obtaining > + * a copy of this software and associated documentation files (the > + * "Software"), to deal in the Software without restriction, including > + * without limitation the rights to use, copy, modify, merge, publish, > + * distribute, sublicense, and/or sell copies of the Software, and to > + * permit persons to whom the Software is furnished to do so, subject to > + * the following conditions: > + * > + * The above copyright notice and this permission notice (including the > + * next paragraph) shall be included in all copies or substantial > + * portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES > OF > + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND > + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT > HOLDERS > + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN > AN > + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR > IN > + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > THE > + * SOFTWARE. > + */ > + > +#ifndef WESTON_DEBUG_H > +#define WESTON_DEBUG_H > + > +#include <stdbool.h> > +#include <stdlib.h> > +#include <stdarg.h> > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +struct weston_compositor; > + > +void > +weston_compositor_enable_debug_protocol(struct weston_compositor > *); > + > +struct weston_debug_scope; > +struct weston_debug_stream; > + > +/** weston_debug_scope callback > + * > + * \param stream The debug stream. > + * \param user_data The \c user_data argument given to > + * weston_compositor_add_debug_scope() > + * > + * \memberof weston_debug_scope > + * \sa weston_debug_stream > + */ > +typedef void (*weston_debug_scope_cb)(struct weston_debug_stream > *stream, > + void *user_data); > + > +struct weston_debug_scope * > +weston_compositor_add_debug_scope(struct weston_compositor > *compositor, > + const char *name, > + const char *description, > + weston_debug_scope_cb begin_cb, > + void *user_data); > + > +void > +weston_debug_scope_destroy(struct weston_debug_scope *scope); > + > +bool > +weston_debug_scope_is_enabled(struct weston_debug_scope *scope); > + > +void > +weston_debug_scope_write(struct weston_debug_scope *scope, > + const char *data, size_t len); > + > +void > +weston_debug_scope_vprintf(struct weston_debug_scope *scope, > + const char *fmt, va_list ap); > + > +void > +weston_debug_scope_printf(struct weston_debug_scope *scope, > + const char *fmt, ...) > + __attribute__ ((format (printf, 2, 3))); > + > +void > +weston_debug_stream_write(struct weston_debug_stream *stream, > + const char *data, size_t len); > + > +void > +weston_debug_stream_vprintf(struct weston_debug_stream *stream, > + const char *fmt, va_list ap); > + > +void > +weston_debug_stream_printf(struct weston_debug_stream *stream, > + const char *fmt, ...) > + __attribute__ ((format (printf, 2, 3))); > + > +void > +weston_debug_stream_complete(struct weston_debug_stream *stream); > + > +char * > +weston_debug_scope_timestamp(struct weston_debug_scope *scope, > + char *buf, size_t len); > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif /* WESTON_DEBUG_H */ > -- > 2.17.1 > > _______________________________________________ > wayland-devel mailing list > wayland-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/wayland-devel _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel