weston-debug: Introduce weston_log_subscription and weston_log_subscriber objects

Adds a minimalistic API for managing the subscription object. The
subscribe functionality will be brought in once we re-organize a bit
weston-debug-stream and split it properly. It extends the logging
context with a linked list of potential subscription and adds a linked
list of subscriptions in the log scope.

This patch represents the start of a logging framework for weston. It's
being built around weston-debug, with the intent to superseded it, and
make weston-debug a client of the framework. Further more the logging
framework should replace current logging handler and allow other types
of streams to be used.

Currently present in libweston under weston-debug we have log scopes, debug
streams and a logging context.

With this patch, two (internal) objects are being added: the concept of
a subscriber and the concept of subscription.  The subscription object
is a ephemeral object, implicitly managed which is created each time one
would want to a subscribe to a scope. The scope will maintain a list of
subscriptions and will continue to be explicitly managed.

The streams will use the subscriber object as a base class to extend
upon. By doing so it allows to customize the stream with specific
functions that manipulate the underlaying storage. The subscriber object
will require a subscribe function and specific stream functions and like
the scope, will be explicitly managed.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Suggested-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
Marius Vlad 2019-06-25 12:48:56 +03:00
parent e48bfc7c0c
commit e0a858a5f2
2 changed files with 238 additions and 2 deletions

View File

@ -30,6 +30,8 @@
#include "helpers.h" #include "helpers.h"
#include <libweston/libweston.h> #include <libweston/libweston.h>
#include "weston-log-internal.h"
#include "weston-debug-server-protocol.h" #include "weston-debug-server-protocol.h"
#include <assert.h> #include <assert.h>
@ -41,14 +43,27 @@
/** Main weston-log context /** Main weston-log context
* *
* One per weston_compositor. * One per weston_compositor. Stores list of scopes created and a list pending
* subscriptions.
* *
* \internal * A pending subscription is a subscription to a scope which hasn't been
* created. When the scope is finally created the pending subscription will be
* removed from the pending subscription list, but not before was added in the
* scope's subscription list and that of the subscriber list.
*
* Pending subscriptions only make sense for other types of streams, other than
* those created by weston-debug protocol. In the case of the weston-debug
* protocol, the subscription processes is done automatically whenever a client
* connects and subscribes to a scope which was previously advertised by the
* compositor.
*
* @internal
*/ */
struct weston_log_context { struct weston_log_context {
struct wl_listener compositor_destroy_listener; struct wl_listener compositor_destroy_listener;
struct wl_global *global; struct wl_global *global;
struct wl_list scope_list; /**< weston_log_scope::compositor_link */ struct wl_list scope_list; /**< weston_log_scope::compositor_link */
struct wl_list pending_subscription_list; /**< weston_log_subscription::source_link */
}; };
/** weston-log message scope /** weston-log message scope
@ -64,8 +79,37 @@ struct weston_log_scope {
void *user_data; void *user_data;
struct wl_list stream_list; /**< weston_debug_stream::scope_link */ struct wl_list stream_list; /**< weston_debug_stream::scope_link */
struct wl_list compositor_link; struct wl_list compositor_link;
struct wl_list subscription_list; /**< weston_log_subscription::source_link */
}; };
/** Ties a subscriber to a scope
*
* A subscription is created each time we'd want to subscribe to a scope. From
* the stream type we can retrieve the subscriber and from the subscriber we
* reach each of the streams callbacks. See also weston_log_subscriber object.
*
* When a subscription has been created we store it in the scope's subscription
* list and in the subscriber's subscription list. The subscription might be a
* pending subscription until the scope for which there's was a subscribe has
* been created. The scope creation will take of looking through the pending
* subscription list.
*
* A subscription can reached from a subscriber subscription list by using the
* streams base class.
*
* @internal
*/
struct weston_log_subscription {
struct weston_log_subscriber *owner;
struct wl_list owner_link; /**< weston_log_subscriber::subscription_list */
char *scope_name;
struct weston_log_scope *source;
struct wl_list source_link; /**< weston_log_scope::subscription_list or
weston_log_context::pending_subscription_list */
};
/** A debug stream created by a client /** A debug stream created by a client
* *
* A client provides a file descriptor for the server to write debug * A client provides a file descriptor for the server to write debug
@ -80,6 +124,118 @@ struct weston_debug_stream {
struct wl_list scope_link; struct wl_list scope_link;
}; };
/** Creates a new subscription using the subscriber by \c owner.
*
* The subscription created is added to the \c owner subscription list.
* Destroying the subscription using weston_log_subscription_destroy() will
* remove the link from the subscription list and free storage alloc'ed.
*
* @param owner the subscriber owner, must be created before creating a
* subscription
* @param scope_name the scope for which to create this subscription
* @returns a weston_log_subscription object in case of success, or NULL
* otherwise
*
* @internal
* @sa weston_log_subscription_destroy, weston_log_subscription_remove,
* weston_log_subscription_add
*/
struct weston_log_subscription *
weston_log_subscription_create(struct weston_log_subscriber *owner,
const char *scope_name)
{
struct weston_log_subscription *sub;
assert(owner);
assert(scope_name);
sub = zalloc(sizeof(*sub));
if (!sub)
return NULL;
sub->owner = owner;
sub->scope_name = strdup(scope_name);
wl_list_insert(&sub->owner->subscription_list, &sub->owner_link);
return sub;
}
/** Destroys the subscription
*
* @param sub
* @internal
*/
void
weston_log_subscription_destroy(struct weston_log_subscription *sub)
{
if (sub->owner)
wl_list_remove(&sub->owner_link);
free(sub->scope_name);
free(sub);
}
/** Retrieve a subscription by using the subscriber
*
* This is useful when trying to find a subscription from the subscriber by
* having only access to the stream.
*
* @param subscriber the subscriber in question
* @returns a weston_log_subscription object
*
* @internal
*/
struct weston_log_subscription *
weston_log_subscriber_get_only_subscription(struct weston_log_subscriber *subscriber)
{
struct weston_log_subscription *sub;
/* unlikely, but can happen */
if (wl_list_length(&subscriber->subscription_list) == 0)
return NULL;
assert(wl_list_length(&subscriber->subscription_list) == 1);
return wl_container_of(subscriber->subscription_list.prev,
sub, owner_link);
}
/** Adds the subscription \c sub to the subscription list of the
* scope.
*
* This should used when the scope has been created, and the subscription \c
* sub has be created before calling this function.
*
* @param scope the scope
* @param sub the subscription, it must be created before, see
* weston_log_subscription_create()
*
* @internal
*/
void
weston_log_subscription_add(struct weston_log_scope *scope,
struct weston_log_subscription *sub)
{
assert(scope);
assert(sub);
/* don't allow subscriptions to have a source already! */
assert(!sub->source);
sub->source = scope;
wl_list_insert(&scope->subscription_list, &sub->source_link);
}
/** Removes the subscription from the scope's subscription list
*
* @internal
*/
void
weston_log_subscription_remove(struct weston_log_subscription *sub)
{
assert(sub);
if (sub->source)
wl_list_remove(&sub->source_link);
sub->source = NULL;
}
static struct weston_log_scope * static struct weston_log_scope *
get_scope(struct weston_log_context *log_ctx, const char *name) get_scope(struct weston_log_context *log_ctx, const char *name)
{ {

View File

@ -0,0 +1,80 @@
/*
* Copyright © 2019 Collabora Ltd
*
* 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_LOG_INTERNAL_H
#define WESTON_LOG_INTERNAL_H
#include "wayland-util.h"
/** Subscriber allows each type of stream to customize or to provide its own
* methods to manipulate the underlying storage. It follows also an
* object-oriented approach, contains the ops callbacks and a list of
* subcriptions of type weston_log_subscription. Each subscription created will
* be both added to this subscription list and that of the weston_log_scope.
*
* A kind of stream can inherit the subscriber class and provide its own callbacks:
* @code
* struct weston_log_data_stream {
* struct weston_log_subscriber base;
* struct weston_data_stream opaque;
* };
* @endcode
*
* Passing the base class will require container retrieval type of methods
* to be allowed to reach the opaque type (i.e., container_of()).
*
* @internal
*
*/
struct weston_log_subscriber {
/** write the data pointed by @param data */
void (*write)(struct weston_log_subscriber *sub, const char *data, size_t len);
/** For the type of streams that required additional destroy operation
* for destroying the stream */
void (*destroy)(struct weston_log_subscriber *sub);
/** For the type of streams that can inform the 'consumer' part that
* write operation has been terminated/finished and should close the
* stream.
*/
void (*complete)(struct weston_log_subscriber *sub);
struct wl_list subscription_list; /**< weston_log_subscription::owner_link */
};
struct weston_log_subscription *
weston_log_subscription_create(struct weston_log_subscriber *owner,
const char *scope_name);
void
weston_log_subscription_destroy(struct weston_log_subscription *sub);
struct weston_log_subscription *
weston_log_subscriber_get_only_subscription(struct weston_log_subscriber *subscriber);
void
weston_log_subscription_add(struct weston_log_scope *scope,
struct weston_log_subscription *sub);
void
weston_log_subscription_remove(struct weston_log_subscription *sub);
#endif /* WESTON_LOG_INTERNAL_H */