blob: 837e3588de56bcdd5812601d16ea764f6fa3a67e [file] [log] [blame]
Pekka Paalanena5630ea2017-10-12 13:13:42 +02001/*
2 * Copyright © 2017 Pekka Paalanen <pq@iki.fi>
3 * Copyright © 2018 Zodiac Inflight Innovations
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27#include "config.h"
28
Marius Vladc901e892019-06-21 22:49:18 +030029#include <libweston/weston-log.h>
Pekka Paalanena5630ea2017-10-12 13:13:42 +020030#include "helpers.h"
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020031#include <libweston/libweston.h>
Pekka Paalanena5630ea2017-10-12 13:13:42 +020032
Marius Vlade0a858a2019-06-25 12:48:56 +030033#include "weston-log-internal.h"
Pekka Paalanena5630ea2017-10-12 13:13:42 +020034#include "weston-debug-server-protocol.h"
35
36#include <assert.h>
37#include <unistd.h>
38#include <stdarg.h>
39#include <string.h>
40#include <errno.h>
41#include <sys/time.h>
42
Marius Vlad3d7d9782019-04-17 12:35:38 +030043/** Main weston-log context
Pekka Paalanena5630ea2017-10-12 13:13:42 +020044 *
Marius Vlade0a858a2019-06-25 12:48:56 +030045 * One per weston_compositor. Stores list of scopes created and a list pending
46 * subscriptions.
Pekka Paalanena5630ea2017-10-12 13:13:42 +020047 *
Marius Vlade0a858a2019-06-25 12:48:56 +030048 * A pending subscription is a subscription to a scope which hasn't been
49 * created. When the scope is finally created the pending subscription will be
50 * removed from the pending subscription list, but not before was added in the
51 * scope's subscription list and that of the subscriber list.
52 *
53 * Pending subscriptions only make sense for other types of streams, other than
54 * those created by weston-debug protocol. In the case of the weston-debug
55 * protocol, the subscription processes is done automatically whenever a client
56 * connects and subscribes to a scope which was previously advertised by the
57 * compositor.
58 *
59 * @internal
Pekka Paalanena5630ea2017-10-12 13:13:42 +020060 */
Marius Vlad3d7d9782019-04-17 12:35:38 +030061struct weston_log_context {
Pekka Paalanena5630ea2017-10-12 13:13:42 +020062 struct wl_listener compositor_destroy_listener;
63 struct wl_global *global;
Marius Vlad5d5e3352019-04-17 13:05:38 +030064 struct wl_list scope_list; /**< weston_log_scope::compositor_link */
Marius Vlade0a858a2019-06-25 12:48:56 +030065 struct wl_list pending_subscription_list; /**< weston_log_subscription::source_link */
Pekka Paalanena5630ea2017-10-12 13:13:42 +020066};
67
Marius Vlad5d5e3352019-04-17 13:05:38 +030068/** weston-log message scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +020069 *
Marius Vlad7e4db952019-04-17 13:47:06 +030070 * This is used for scoping logging/debugging messages. Clients can subscribe
71 * to only the scopes they are interested in. A scope is identified by its name
Pekka Paalanena5630ea2017-10-12 13:13:42 +020072 * (also referred to as debug stream name).
73 */
Marius Vlad5d5e3352019-04-17 13:05:38 +030074struct weston_log_scope {
Pekka Paalanena5630ea2017-10-12 13:13:42 +020075 char *name;
76 char *desc;
Marius Vladdad882a2019-07-17 15:43:53 +030077 weston_log_scope_cb new_subscriber;
Pekka Paalanena5630ea2017-10-12 13:13:42 +020078 void *user_data;
Pekka Paalanena5630ea2017-10-12 13:13:42 +020079 struct wl_list compositor_link;
Marius Vlade0a858a2019-06-25 12:48:56 +030080 struct wl_list subscription_list; /**< weston_log_subscription::source_link */
Pekka Paalanena5630ea2017-10-12 13:13:42 +020081};
82
Marius Vlade0a858a2019-06-25 12:48:56 +030083/** Ties a subscriber to a scope
84 *
85 * A subscription is created each time we'd want to subscribe to a scope. From
86 * the stream type we can retrieve the subscriber and from the subscriber we
87 * reach each of the streams callbacks. See also weston_log_subscriber object.
88 *
89 * When a subscription has been created we store it in the scope's subscription
90 * list and in the subscriber's subscription list. The subscription might be a
91 * pending subscription until the scope for which there's was a subscribe has
92 * been created. The scope creation will take of looking through the pending
93 * subscription list.
94 *
95 * A subscription can reached from a subscriber subscription list by using the
96 * streams base class.
97 *
98 * @internal
99 */
100struct weston_log_subscription {
101 struct weston_log_subscriber *owner;
102 struct wl_list owner_link; /**< weston_log_subscriber::subscription_list */
103
104 char *scope_name;
105 struct weston_log_scope *source;
106 struct wl_list source_link; /**< weston_log_scope::subscription_list or
107 weston_log_context::pending_subscription_list */
108};
109
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300110static struct weston_log_subscription *
111find_pending_subscription(struct weston_log_context *log_ctx,
112 const char *scope_name)
113{
114 struct weston_log_subscription *sub;
115
116 wl_list_for_each(sub, &log_ctx->pending_subscription_list, source_link)
117 if (!strncmp(sub->scope_name, scope_name, strlen(scope_name)))
118 return sub;
119
120 return NULL;
121}
122
123/** Create a pending subscription and add it the list of pending subscriptions
124 *
125 * @param owner a subscriber represented by weston_log_subscriber object
126 * @param scope_name the name of the scope (which we don't have in the list of scopes)
127 * @param log_ctx the logging context used to add the pending subscription
128 *
129 * @memberof weston_log_subscription
130 */
131static void
132weston_log_subscription_create_pending(struct weston_log_subscriber *owner,
133 const char *scope_name,
134 struct weston_log_context *log_ctx)
135{
136 assert(owner);
137 assert(scope_name);
138 struct weston_log_subscription *sub = zalloc(sizeof(*sub));
139
140 if (!sub)
141 return;
142
143 sub->scope_name = strdup(scope_name);
144 sub->owner = owner;
145
146 wl_list_insert(&log_ctx->pending_subscription_list, &sub->source_link);
147}
148
149/** Destroys the pending subscription created previously with
150 * weston_log_subscription_create_pending()
151 *
152 * @param sub the weston_log_subscription object to remove from the list
153 * of subscriptions and to destroy the subscription
154 *
155 * @memberof weston_log_subscription
156 */
157static void
158weston_log_subscription_destroy_pending(struct weston_log_subscription *sub)
159{
160 assert(sub);
161 /* pending subsriptions do not have a source */
162 wl_list_remove(&sub->source_link);
163 free(sub->scope_name);
164 free(sub);
165}
166
Marius Vladdad882a2019-07-17 15:43:53 +0300167static void
168weston_log_subscription_write(struct weston_log_subscription *sub,
169 const char *data, size_t len)
170{
171 if (sub->owner && sub->owner->write)
172 sub->owner->write(sub->owner, data, len);
173}
174
175static void
176weston_log_subscription_vprintf(struct weston_log_subscription *sub,
177 const char *fmt, va_list ap)
178{
179 static const char oom[] = "Out of memory";
180 char *str;
181 int len;
182
183 if (!weston_log_scope_is_enabled(sub->source))
184 return;
185
186 len = vasprintf(&str, fmt, ap);
187 if (len >= 0) {
188 weston_log_subscription_write(sub, str, len);
189 free(str);
190 } else {
191 weston_log_subscription_write(sub, oom, sizeof oom - 1);
192 }
193}
194
Marius Vlade0a858a2019-06-25 12:48:56 +0300195/** Creates a new subscription using the subscriber by \c owner.
196 *
197 * The subscription created is added to the \c owner subscription list.
198 * Destroying the subscription using weston_log_subscription_destroy() will
199 * remove the link from the subscription list and free storage alloc'ed.
200 *
Marius Vlad5ae0e622019-07-11 17:44:50 +0300201 * Note that this adds the subscription to the scope's subscription list
202 * hence the \c scope required argument.
203 *
Marius Vlade0a858a2019-06-25 12:48:56 +0300204 * @param owner the subscriber owner, must be created before creating a
205 * subscription
Marius Vlad5ae0e622019-07-11 17:44:50 +0300206 * @param scope the scope in order to add the subscription to the scope's
207 * subscription list
Marius Vlade0a858a2019-06-25 12:48:56 +0300208 * @returns a weston_log_subscription object in case of success, or NULL
209 * otherwise
210 *
211 * @internal
212 * @sa weston_log_subscription_destroy, weston_log_subscription_remove,
213 * weston_log_subscription_add
214 */
Marius Vlad5ae0e622019-07-11 17:44:50 +0300215void
Marius Vlade0a858a2019-06-25 12:48:56 +0300216weston_log_subscription_create(struct weston_log_subscriber *owner,
Marius Vlad5ae0e622019-07-11 17:44:50 +0300217 struct weston_log_scope *scope)
Marius Vlade0a858a2019-06-25 12:48:56 +0300218{
219 struct weston_log_subscription *sub;
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300220 assert(owner);
Marius Vlad5ae0e622019-07-11 17:44:50 +0300221 assert(scope);
222 assert(scope->name);
Marius Vlade0a858a2019-06-25 12:48:56 +0300223
224 sub = zalloc(sizeof(*sub));
225 if (!sub)
Marius Vlad5ae0e622019-07-11 17:44:50 +0300226 return;
Marius Vlade0a858a2019-06-25 12:48:56 +0300227
228 sub->owner = owner;
Marius Vlad5ae0e622019-07-11 17:44:50 +0300229 sub->scope_name = strdup(scope->name);
Marius Vlade0a858a2019-06-25 12:48:56 +0300230
231 wl_list_insert(&sub->owner->subscription_list, &sub->owner_link);
Marius Vlad5ae0e622019-07-11 17:44:50 +0300232
233 weston_log_subscription_add(scope, sub);
Marius Vladdad882a2019-07-17 15:43:53 +0300234 weston_log_run_cb_new_subscriber(sub);
Marius Vlade0a858a2019-06-25 12:48:56 +0300235}
236
237/** Destroys the subscription
238 *
Marius Vlad5ae0e622019-07-11 17:44:50 +0300239 * Removes the subscription from the scopes subscription list and from
240 * subscriber's subscription list. It destroys the subscription afterwads.
241 *
242 * @memberof weston_log_subscription
Marius Vlade0a858a2019-06-25 12:48:56 +0300243 */
244void
245weston_log_subscription_destroy(struct weston_log_subscription *sub)
246{
Marius Vlad5ae0e622019-07-11 17:44:50 +0300247 assert(sub);
Marius Vlade0a858a2019-06-25 12:48:56 +0300248 if (sub->owner)
249 wl_list_remove(&sub->owner_link);
Marius Vlad5ae0e622019-07-11 17:44:50 +0300250
251 weston_log_subscription_remove(sub);
Marius Vlade0a858a2019-06-25 12:48:56 +0300252 free(sub->scope_name);
253 free(sub);
254}
255
256/** Retrieve a subscription by using the subscriber
257 *
258 * This is useful when trying to find a subscription from the subscriber by
259 * having only access to the stream.
260 *
261 * @param subscriber the subscriber in question
262 * @returns a weston_log_subscription object
263 *
264 * @internal
265 */
266struct weston_log_subscription *
267weston_log_subscriber_get_only_subscription(struct weston_log_subscriber *subscriber)
268{
269 struct weston_log_subscription *sub;
270 /* unlikely, but can happen */
271 if (wl_list_length(&subscriber->subscription_list) == 0)
272 return NULL;
273
274 assert(wl_list_length(&subscriber->subscription_list) == 1);
275
276 return wl_container_of(subscriber->subscription_list.prev,
277 sub, owner_link);
278}
279
280/** Adds the subscription \c sub to the subscription list of the
281 * scope.
282 *
283 * This should used when the scope has been created, and the subscription \c
284 * sub has be created before calling this function.
285 *
286 * @param scope the scope
287 * @param sub the subscription, it must be created before, see
288 * weston_log_subscription_create()
289 *
290 * @internal
291 */
292void
293weston_log_subscription_add(struct weston_log_scope *scope,
294 struct weston_log_subscription *sub)
295{
296 assert(scope);
297 assert(sub);
298 /* don't allow subscriptions to have a source already! */
299 assert(!sub->source);
300
301 sub->source = scope;
302 wl_list_insert(&scope->subscription_list, &sub->source_link);
303}
304
305/** Removes the subscription from the scope's subscription list
306 *
307 * @internal
308 */
309void
310weston_log_subscription_remove(struct weston_log_subscription *sub)
311{
312 assert(sub);
313 if (sub->source)
314 wl_list_remove(&sub->source_link);
315 sub->source = NULL;
316}
317
Marius Vlad8f329e22019-06-21 14:57:02 +0300318/** Look-up the scope from the scope list stored in the log context, by
319 * matching against the \c name.
320 *
321 * @param log_ctx
322 * @param name the scope name, see weston_compositor_add_log_scope()
323 * @returns NULL if none found, or a pointer to a weston_log_scope
324 *
325 * @internal
326 */
327struct weston_log_scope *
328weston_log_get_scope(struct weston_log_context *log_ctx, const char *name)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200329{
Marius Vlad5d5e3352019-04-17 13:05:38 +0300330 struct weston_log_scope *scope;
Marius Vlad3d7d9782019-04-17 12:35:38 +0300331 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200332 if (strcmp(name, scope->name) == 0)
333 return scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200334 return NULL;
335}
336
Marius Vladdad882a2019-07-17 15:43:53 +0300337/** Wrapper to invoke the weston_log_scope_cb. Allows to call the cb new_subscriber of
Marius Vlad8f329e22019-06-21 14:57:02 +0300338 * a log scope.
339 *
340 * @internal
341 */
342void
Marius Vladdad882a2019-07-17 15:43:53 +0300343weston_log_run_cb_new_subscriber(struct weston_log_subscription *sub)
Marius Vlad8f329e22019-06-21 14:57:02 +0300344{
Marius Vladdad882a2019-07-17 15:43:53 +0300345 if (sub->source->new_subscriber)
346 sub->source->new_subscriber(sub, sub->source->user_data);
Marius Vlad8f329e22019-06-21 14:57:02 +0300347}
348
349/** Advertise the log scope name and the log scope description
350 *
351 * This is only used by the weston-debug protocol!
352 *
353 * @internal
354 */
355void
356weston_debug_protocol_advertise_scopes(struct weston_log_context *log_ctx,
357 struct wl_resource *res)
358{
359 struct weston_log_scope *scope;
360 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
361 weston_debug_v1_send_available(res, scope->name, scope->desc);
362}
363
Marius Vlad880b4852019-04-07 17:07:58 +0300364/**
Marius Vlad3d7d9782019-04-17 12:35:38 +0300365 * Connect weston_compositor structure to weston_log_context structure.
Marius Vlad880b4852019-04-07 17:07:58 +0300366 *
367 * \param compositor
Marius Vlad3d7d9782019-04-17 12:35:38 +0300368 * \param log_ctx
Marius Vlad880b4852019-04-07 17:07:58 +0300369 * \return 0 on success, -1 on failure
370 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300371 * Sets weston_compositor::weston_log_ctx.
Marius Vlad880b4852019-04-07 17:07:58 +0300372 */
373int
Marius Vlad3d7d9782019-04-17 12:35:38 +0300374weston_log_ctx_compositor_setup(struct weston_compositor *compositor,
375 struct weston_log_context *log_ctx)
Marius Vlad880b4852019-04-07 17:07:58 +0300376{
Marius Vlad6f098662019-04-17 13:50:28 +0300377 assert(!compositor->weston_log_ctx);
378 assert(log_ctx);
Marius Vlad880b4852019-04-07 17:07:58 +0300379
Marius Vlad3d7d9782019-04-17 12:35:38 +0300380 compositor->weston_log_ctx = log_ctx;
Marius Vlad880b4852019-04-07 17:07:58 +0300381 return 0;
382}
383
Marius Vlada2dace22019-06-12 16:05:44 +0300384/** Creates weston_log_context structure
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200385 *
Marius Vlada2dace22019-06-12 16:05:44 +0300386 * \return NULL in case of failure, or a weston_log_context object in case of
387 * success
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200388 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300389 * weston_log_context is a singleton for each weston_compositor.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200390 *
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200391 */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300392WL_EXPORT struct weston_log_context *
393weston_log_ctx_compositor_create(void)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200394{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300395 struct weston_log_context *log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200396
Marius Vlad3d7d9782019-04-17 12:35:38 +0300397 log_ctx = zalloc(sizeof *log_ctx);
398 if (!log_ctx)
Marius Vlad880b4852019-04-07 17:07:58 +0300399 return NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200400
Marius Vlad3d7d9782019-04-17 12:35:38 +0300401 wl_list_init(&log_ctx->scope_list);
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300402 wl_list_init(&log_ctx->pending_subscription_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200403
Marius Vlad3d7d9782019-04-17 12:35:38 +0300404 return log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200405}
406
Marius Vlad3d7d9782019-04-17 12:35:38 +0300407/** Destroy weston_log_context structure
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200408 *
409 * \param compositor The libweston compositor whose weston-debug to tear down.
410 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300411 * Clears weston_compositor::weston_log_ctx.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200412 *
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200413 */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300414WL_EXPORT void
415weston_log_ctx_compositor_destroy(struct weston_compositor *compositor)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200416{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300417 struct weston_log_context *log_ctx = compositor->weston_log_ctx;
Marius Vlad5d5e3352019-04-17 13:05:38 +0300418 struct weston_log_scope *scope;
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300419 struct weston_log_subscription *pending_sub, *pending_sub_tmp;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200420
Marius Vlad3d7d9782019-04-17 12:35:38 +0300421 if (log_ctx->global)
422 wl_global_destroy(log_ctx->global);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200423
Marius Vlad3d7d9782019-04-17 12:35:38 +0300424 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
Marius Vladef4c2682019-06-23 15:48:54 +0300425 fprintf(stderr, "Internal warning: debug scope '%s' has not been destroyed.\n",
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200426 scope->name);
427
428 /* Remove head to not crash if scope removed later. */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300429 wl_list_remove(&log_ctx->scope_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200430
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300431 /* Remove any pending subscription(s) which nobody subscribed to */
432 wl_list_for_each_safe(pending_sub, pending_sub_tmp,
433 &log_ctx->pending_subscription_list, source_link) {
434 weston_log_subscription_destroy_pending(pending_sub);
435 }
436
437 /* pending_subscription_list should be empty at this point */
438
Marius Vlad3d7d9782019-04-17 12:35:38 +0300439 free(log_ctx);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200440
Marius Vlad3d7d9782019-04-17 12:35:38 +0300441 compositor->weston_log_ctx = NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200442}
443
444/** Enable weston-debug protocol extension
445 *
446 * \param compositor The libweston compositor where to enable.
447 *
448 * This enables the weston_debug_v1 Wayland protocol extension which any client
Emmanuel Gil Peyrot426c2462019-02-20 16:33:32 +0100449 * can use to get debug messages from the compositor.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200450 *
451 * WARNING: This feature should not be used in production. If a client
452 * provides a file descriptor that blocks writes, it will block the whole
453 * compositor indefinitely.
454 *
455 * There is no control on which client is allowed to subscribe to debug
456 * messages. Any and all clients are allowed.
457 *
458 * The debug extension is disabled by default, and once enabled, cannot be
459 * disabled again.
460 */
461WL_EXPORT void
462weston_compositor_enable_debug_protocol(struct weston_compositor *compositor)
463{
Marius Vlad1e2fda22019-04-07 19:07:16 +0300464 struct weston_log_context *log_ctx = compositor->weston_log_ctx;
465 assert(log_ctx);
466 if (log_ctx->global)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200467 return;
468
Marius Vlad1e2fda22019-04-07 19:07:16 +0300469 log_ctx->global = wl_global_create(compositor->wl_display,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200470 &weston_debug_v1_interface, 1,
Marius Vlad69e75712019-06-25 13:29:57 +0300471 log_ctx, weston_log_bind_weston_debug);
Marius Vlad1e2fda22019-04-07 19:07:16 +0300472 if (!log_ctx->global)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200473 return;
474
Marius Vladef4c2682019-06-23 15:48:54 +0300475 fprintf(stderr, "WARNING: debug protocol has been enabled. "
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200476 "This is a potential denial-of-service attack vector and "
477 "information leak.\n");
478}
479
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200480/** Determine if the debug protocol has been enabled
481 *
482 * \param wc The libweston compositor to verify if debug protocol has been enabled
483 */
484WL_EXPORT bool
485weston_compositor_is_debug_protocol_enabled(struct weston_compositor *wc)
486{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300487 return wc->weston_log_ctx->global != NULL;
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200488}
489
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300490/** Register a new stream name, creating a log scope.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200491 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300492 * @param log_ctx The weston_log_context where to add.
493 * @param name The debug stream/scope name; must not be NULL.
494 * @param description The log scope description for humans; must not be NULL.
Marius Vladdad882a2019-07-17 15:43:53 +0300495 * @param new_subscriber Optional callback when a client subscribes to this
496 * scope.
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300497 * @param user_data Optional user data pointer for the callback.
498 * @returns A valid pointer on success, NULL on failure.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200499 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300500 * This function is used to create a log scope. All debug message printing
501 * happens for a scope, which allows clients to subscribe to the kind of debug
502 * messages they want by \c name. For the weston-debug protocol,
503 * subscription for the scope will happen automatically but for other types of
504 * streams, weston_log_subscribe() should be called as to create a subscription
505 * and tie it to the scope created by this function.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200506 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300507 * \p name must be unique in the weston_compositor instance. \p name
508 * and \p description must both be provided. In case of the weston-debug
509 * protocol, the description is printed when a client asks for a list of
510 * supported log scopes.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200511 *
Marius Vladdad882a2019-07-17 15:43:53 +0300512 * \p new_subscriber, if not NULL, is called when a client subscribes to the log
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300513 * scope creating a debug stream. This is for log scopes that need to print
514 * messages as a response to a client appearing, e.g. printing a list of
515 * windows on demand or a static preamble. The argument \p user_data is
516 * passed in to the callback and is otherwise unused.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200517 *
Marius Vladdad882a2019-07-17 15:43:53 +0300518 * For one-shot debug streams, \c new_subscriber should finally call
519 * weston_log_subscription_complete() to close the stream and tell the client
520 * the printing is complete. Otherwise the client expects more data to be
521 * written. The complete callback in weston_log_subscriber should be installed
522 * to trigger it and it is set-up automatically for the weston-debug protocol.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200523 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300524 * As subscription can take place before creating the scope, any pending
525 * subscriptions to scope added by weston_log_subscribe(), will be checked
526 * against the scope being created and if found will be added to the scope's
527 * subscription list.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200528 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300529 * The log scope must be destroyed using weston_compositor_log_scope_destroy()
530 * before destroying the weston_compositor.
531 *
532 * @memberof weston_log_scope
533 * @sa weston_log_scope_cb, weston_log_subscribe
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200534 */
Marius Vlad5d5e3352019-04-17 13:05:38 +0300535WL_EXPORT struct weston_log_scope *
Marius Vlad7e4db952019-04-17 13:47:06 +0300536weston_compositor_add_log_scope(struct weston_log_context *log_ctx,
537 const char *name,
538 const char *description,
Marius Vladdad882a2019-07-17 15:43:53 +0300539 weston_log_scope_cb new_subscriber,
Marius Vlad7e4db952019-04-17 13:47:06 +0300540 void *user_data)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200541{
Marius Vlad5d5e3352019-04-17 13:05:38 +0300542 struct weston_log_scope *scope;
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300543 struct weston_log_subscription *pending_sub = NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200544
Marius Vlad1e2fda22019-04-07 19:07:16 +0300545 if (!name || !description) {
Marius Vladef4c2682019-06-23 15:48:54 +0300546 fprintf(stderr, "Error: cannot add a debug scope without name or description.\n");
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200547 return NULL;
548 }
549
Marius Vlad3d7d9782019-04-17 12:35:38 +0300550 if (!log_ctx) {
Marius Vladef4c2682019-06-23 15:48:54 +0300551 fprintf(stderr, "Error: cannot add debug scope '%s', infra not initialized.\n",
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200552 name);
553 return NULL;
554 }
555
Marius Vlad8f329e22019-06-21 14:57:02 +0300556 if (weston_log_get_scope(log_ctx, name)){
Marius Vladef4c2682019-06-23 15:48:54 +0300557 fprintf(stderr, "Error: debug scope named '%s' is already registered.\n",
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200558 name);
559 return NULL;
560 }
561
562 scope = zalloc(sizeof *scope);
563 if (!scope) {
Marius Vladef4c2682019-06-23 15:48:54 +0300564 fprintf(stderr, "Error adding debug scope '%s': out of memory.\n",
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200565 name);
566 return NULL;
567 }
568
569 scope->name = strdup(name);
570 scope->desc = strdup(description);
Marius Vladdad882a2019-07-17 15:43:53 +0300571 scope->new_subscriber = new_subscriber;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200572 scope->user_data = user_data;
Marius Vlad7814f302019-06-21 14:20:15 +0300573 wl_list_init(&scope->subscription_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200574
575 if (!scope->name || !scope->desc) {
Marius Vladef4c2682019-06-23 15:48:54 +0300576 fprintf(stderr, "Error adding debug scope '%s': out of memory.\n",
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200577 name);
578 free(scope->name);
579 free(scope->desc);
580 free(scope);
581 return NULL;
582 }
583
Marius Vlad3d7d9782019-04-17 12:35:38 +0300584 wl_list_insert(log_ctx->scope_list.prev, &scope->compositor_link);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200585
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300586 /* check if there are any pending subscriptions to this scope */
587 while ((pending_sub = find_pending_subscription(log_ctx, scope->name)) != NULL) {
Marius Vlad5ae0e622019-07-11 17:44:50 +0300588 weston_log_subscription_create(pending_sub->owner, scope);
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300589
590 /* remove it from pending */
591 weston_log_subscription_destroy_pending(pending_sub);
592 }
593
594
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200595 return scope;
596}
597
Marius Vlad3d7d9782019-04-17 12:35:38 +0300598/** Destroy a log scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200599 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300600 * @param scope The log scope to destroy; may be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200601 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300602 * Destroys the log scope, calling each stream's destroy callback if one was
603 * installed/created.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200604 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300605 * @memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200606 */
607WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300608weston_compositor_log_scope_destroy(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200609{
Marius Vlad7814f302019-06-21 14:20:15 +0300610 struct weston_log_subscription *sub, *sub_tmp;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200611
612 if (!scope)
613 return;
614
Marius Vlad7814f302019-06-21 14:20:15 +0300615 wl_list_for_each_safe(sub, sub_tmp, &scope->subscription_list, source_link) {
616 /* destroy each subscription */
617 if (sub->owner->destroy)
618 sub->owner->destroy(sub->owner);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200619
Marius Vlad7814f302019-06-21 14:20:15 +0300620 weston_log_subscription_destroy(sub);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200621 }
622
623 wl_list_remove(&scope->compositor_link);
624 free(scope->name);
625 free(scope->desc);
626 free(scope);
627}
628
629/** Are there any active subscriptions to the scope?
630 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300631 * \param scope The log scope to check; may be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200632 * \return True if any streams are open for this scope, false otherwise.
633 *
634 * As printing some debugging messages may be relatively expensive, one
635 * can use this function to determine if there is a need to gather the
636 * debugging information at all. If this function returns false, all
637 * printing for this scope is dropped, so gathering the information is
638 * pointless.
639 *
640 * The return value of this function should not be stored, as new clients
641 * may subscribe to the debug scope later.
642 *
643 * If the given scope is NULL, this function will always return false,
644 * making it safe to use in teardown or destroy code, provided the
645 * scope is initialized to NULL before creation and set to NULL after
646 * destruction.
647 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300648 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200649 */
650WL_EXPORT bool
Marius Vlad7e4db952019-04-17 13:47:06 +0300651weston_log_scope_is_enabled(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200652{
653 if (!scope)
654 return false;
655
Marius Vlad7814f302019-06-21 14:20:15 +0300656 return !wl_list_empty(&scope->subscription_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200657}
658
Marius Vladdad882a2019-07-17 15:43:53 +0300659/** Close the stream's complete callback if one was installed/created.
660 *
661 */
662WL_EXPORT void
663weston_log_subscription_complete(struct weston_log_subscription *sub)
664{
665 if (sub->owner && sub->owner->complete)
666 sub->owner->complete(sub->owner);
667}
668
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300669/** Close the log scope.
670 *
671 * @param scope The log scope to complete; may be NULL.
672 *
673 * Complete the log scope, calling each stream's complete callback if one was
674 * installed/created. This can be useful to signal the reading end that the
675 * data has been transmited and should no longer expect that written over the
676 * stream. Particularly useful for the weston-debug protocol.
677 *
678 * @memberof weston_log_scope
679 * @sa weston_compositor_add_log_scope, weston_compositor_log_scope_destroy
680 */
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200681WL_EXPORT void
Marius Vlad7814f302019-06-21 14:20:15 +0300682weston_log_scope_complete(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200683{
Marius Vlad7814f302019-06-21 14:20:15 +0300684 struct weston_log_subscription *sub;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200685
Marius Vlad7814f302019-06-21 14:20:15 +0300686 if (!scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200687 return;
688
Marius Vlad7814f302019-06-21 14:20:15 +0300689 wl_list_for_each(sub, &scope->subscription_list, source_link)
Marius Vladdad882a2019-07-17 15:43:53 +0300690 weston_log_subscription_complete(sub);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200691}
692
Marius Vlad7e4db952019-04-17 13:47:06 +0300693/** Write log data for a scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200694 *
695 * \param scope The debug scope to write for; may be NULL, in which case
696 * nothing will be written.
Marius Vlada2dace22019-06-12 16:05:44 +0300697 * \param[in] data Pointer to the data to write.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200698 * \param len Number of bytes to write.
699 *
700 * Writes the given data to all subscribed clients' streams.
701 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300702 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200703 */
704WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300705weston_log_scope_write(struct weston_log_scope *scope,
706 const char *data, size_t len)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200707{
Marius Vlad7814f302019-06-21 14:20:15 +0300708 struct weston_log_subscription *sub;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200709
710 if (!scope)
711 return;
712
Marius Vlad7814f302019-06-21 14:20:15 +0300713 wl_list_for_each(sub, &scope->subscription_list, source_link)
Marius Vladdad882a2019-07-17 15:43:53 +0300714 weston_log_subscription_write(sub, data, len);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200715}
716
717/** Write a formatted string for a scope (varargs)
718 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300719 * \param scope The log scope to write for; may be NULL, in which case
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200720 * nothing will be written.
721 * \param fmt Printf-style format string.
722 * \param ap Formatting arguments.
723 *
724 * Writes to formatted string to all subscribed clients' streams.
725 *
726 * The behavioral details for each stream are the same as for
727 * weston_debug_stream_write().
728 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300729 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200730 */
731WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300732weston_log_scope_vprintf(struct weston_log_scope *scope,
733 const char *fmt, va_list ap)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200734{
735 static const char oom[] = "Out of memory";
736 char *str;
737 int len;
738
Marius Vlad7e4db952019-04-17 13:47:06 +0300739 if (!weston_log_scope_is_enabled(scope))
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200740 return;
741
742 len = vasprintf(&str, fmt, ap);
743 if (len >= 0) {
Marius Vlad7e4db952019-04-17 13:47:06 +0300744 weston_log_scope_write(scope, str, len);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200745 free(str);
746 } else {
Marius Vlad7e4db952019-04-17 13:47:06 +0300747 weston_log_scope_write(scope, oom, sizeof oom - 1);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200748 }
749}
750
751/** Write a formatted string for a scope
752 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300753 * \param scope The log scope to write for; may be NULL, in which case
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200754 * nothing will be written.
755 * \param fmt Printf-style format string and arguments.
756 *
757 * Writes to formatted string to all subscribed clients' streams.
758 *
759 * The behavioral details for each stream are the same as for
760 * weston_debug_stream_write().
761 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300762 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200763 */
764WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300765weston_log_scope_printf(struct weston_log_scope *scope,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200766 const char *fmt, ...)
767{
768 va_list ap;
769
770 va_start(ap, fmt);
Marius Vlad7e4db952019-04-17 13:47:06 +0300771 weston_log_scope_vprintf(scope, fmt, ap);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200772 va_end(ap);
773}
774
Marius Vladdad882a2019-07-17 15:43:53 +0300775/** Write a formatted string for a subscription
776 *
777 * \param sub The subscription to write for; may be NULL, in which case
778 * nothing will be written.
779 * \param fmt Printf-style format string and arguments.
780 *
781 * Writes to formatted string to the stream that created the subscription.
782 *
783 */
784WL_EXPORT void
785weston_log_subscription_printf(struct weston_log_subscription *sub,
786 const char *fmt, ...)
787{
788 va_list ap;
789
790 va_start(ap, fmt);
791 weston_log_subscription_vprintf(sub, fmt, ap);
792 va_end(ap);
793}
794
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200795/** Write debug scope name and current time into string
796 *
Marius Vlada2dace22019-06-12 16:05:44 +0300797 * \param[in] scope debug scope; may be NULL
798 * \param[out] buf Buffer to store the string.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200799 * \param len Available size in the buffer in bytes.
800 * \return \c buf
801 *
802 * Reads the current local wall-clock time and formats it into a string.
803 * and append the debug scope name to it, if a scope is available.
804 * The string is NUL-terminated, even if truncated.
805 */
806WL_EXPORT char *
Marius Vlad7e4db952019-04-17 13:47:06 +0300807weston_log_scope_timestamp(struct weston_log_scope *scope,
808 char *buf, size_t len)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200809{
810 struct timeval tv;
811 struct tm *bdt;
812 char string[128];
813 size_t ret = 0;
814
815 gettimeofday(&tv, NULL);
816
817 bdt = localtime(&tv.tv_sec);
818 if (bdt)
819 ret = strftime(string, sizeof string,
820 "%Y-%m-%d %H:%M:%S", bdt);
821
822 if (ret > 0) {
823 snprintf(buf, len, "[%s.%03ld][%s]", string,
824 tv.tv_usec / 1000,
825 (scope) ? scope->name : "no scope");
826 } else {
827 snprintf(buf, len, "[?][%s]",
828 (scope) ? scope->name : "no scope");
829 }
830
831 return buf;
832}
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300833
834/** Subscribe to a scope
835 *
836 * Creates a subscription which is used to subscribe the \p subscriber
837 * to the scope \c scope_name.
838 *
839 * If \c scope_name has already been created (using
840 * weston_compositor_add_log_scope) the subscription will take place
841 * immediately, otherwise we store the subscription into a pending list. See
842 * also weston_compositor_add_log_scope().
843 *
844 * @param log_ctx the log context, used for accessing pending list
845 * @param subscriber the subscriber, which has to be created before
846 * @param scope_name the scope name. In case the scope is not created
847 * we temporarily store the subscription in the pending list.
848 */
849WL_EXPORT void
850weston_log_subscribe(struct weston_log_context *log_ctx,
851 struct weston_log_subscriber *subscriber,
852 const char *scope_name)
853{
854 assert(log_ctx);
855 assert(subscriber);
856 assert(scope_name);
857
858 struct weston_log_scope *scope;
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300859
860 scope = weston_log_get_scope(log_ctx, scope_name);
Marius Vlad5ae0e622019-07-11 17:44:50 +0300861 if (scope)
862 weston_log_subscription_create(subscriber, scope);
863 else
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300864 /*
865 * if we don't have already as scope for it, add it to pending
866 * subscription list
867 */
868 weston_log_subscription_create_pending(subscriber, scope_name, log_ctx);
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300869}