From a5630eafec4f139adf1da4a5ba54894715d7b50f Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 12 Oct 2017 13:13:42 +0200 Subject: [PATCH] libweston: add weston_debug API and implementation 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 append the debug scope name along with the timestamp in weston_debug_scope_timestamp API Signed-off-by: Maniraj Devadoss Reviewed-by: Pekka Paalanen Add explicit advertisement of debug scope names. Signed-off-by: Daniel Stone Reviewed-by: Emre Ucan --- Makefile.am | 2 + libweston/compositor.c | 5 + libweston/compositor.h | 9 + libweston/weston-debug.c | 732 +++++++++++++++++++++++++++++++++++++++ libweston/weston-debug.h | 107 ++++++ 5 files changed, 855 insertions(+) create mode 100644 libweston/weston-debug.c create mode 100644 libweston/weston-debug.h diff --git a/Makefile.am b/Makefile.am index e38ac009..d5ed3e58 100644 --- a/Makefile.am +++ b/Makefile.am @@ -96,6 +96,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 9deb7817..01616550 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; @@ -6702,6 +6705,8 @@ weston_compositor_destroy(struct weston_compositor *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 8b7a1020..33f02b18 100644 --- a/libweston/compositor.h +++ b/libweston/compositor.h @@ -1048,6 +1048,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; @@ -1160,6 +1161,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 { @@ -2318,6 +2321,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 00000000..04895ad5 --- /dev/null +++ b/libweston/weston-debug.c @@ -0,0 +1,732 @@ +/* + * Copyright © 2017 Pekka Paalanen + * Copyright © 2018 Zodiac Inflight Innovations + * + * 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 +#include +#include +#include +#include +#include + +/** 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 */ +}; + +/** 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, + scope->desc); + } +} + +/** 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 = compositor->weston_debug; + + assert(wdc); + 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; must not be NULL. + * \param desc The debug scope description for humans; must not be NULL. + * \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; may be NULL. + * + * 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; may be NULL. + * \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. + * + * If the given scope is NULL, this function will always return false, + * making it safe to use in teardown or destroy code, provided the + * scope is initialized to NULL before creation and set to NULL after + * destruction. + * + * \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; must not be NULL. + * \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; may be NULL, in which case + * nothing will be written. + * \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; may be NULL, in which case + * nothing will be written. + * \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; may be NULL, in which case + * nothing will be written. + * \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); +} + +/** Write debug scope name and current time into string + * + * \param scope[in] debug scope; may be NULL + * \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, if a scope is available. + * 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) ? scope->name : "no scope"); + } else { + snprintf(buf, len, "[?][%s]", + (scope) ? scope->name : "no scope"); + } + + return buf; +} diff --git a/libweston/weston-debug.h b/libweston/weston-debug.h new file mode 100644 index 00000000..c76cec85 --- /dev/null +++ b/libweston/weston-debug.h @@ -0,0 +1,107 @@ +/* + * Copyright © 2017 Pekka Paalanen + * + * 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 +#include +#include + +#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 */