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 <pq@iki.fi> append the debug scope name along with the timestamp in weston_debug_scope_timestamp API Signed-off-by: Maniraj Devadoss <Maniraj.Devadoss@in.bosch.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Add explicit advertisement of debug scope names. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Emre Ucan <eucan@de.adit-jv.com>
This commit is contained in:
parent
4fc1ee8d5b
commit
a5630eafec
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,732 @@
|
|||
/*
|
||||
* Copyright © 2017 Pekka Paalanen <pq@iki.fi>
|
||||
* 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 <assert.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 */
|
||||
};
|
||||
|
||||
/** 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;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright © 2017 Pekka Paalanen <pq@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 */
|
Loading…
Reference in New Issue