u/[session|system]: Add default and optional implementation for system and session

This commit is contained in:
Jakob Bornecrantz 2023-11-30 02:23:53 +00:00
parent 76c630d2bd
commit f0dbb46cd9
5 changed files with 580 additions and 0 deletions

View file

@ -75,11 +75,15 @@ add_library(
u_pretty_print.h
u_prober.c
u_prober.h
u_session.c
u_session.h
u_space_overseer.c
u_space_overseer.h
u_string_list.cpp
u_string_list.h
u_string_list.hpp
u_system.c
u_system.h
u_system_helpers.c
u_system_helpers.h
u_template_historybuf.hpp

View file

@ -0,0 +1,133 @@
// Copyright 2023, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Helper to implement @ref xrt_session.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup aux_util
*/
#include "util/u_system.h"
#include "util/u_session.h"
/*
*
* Helpers.
*
*/
static inline struct u_session *
u_session(struct xrt_session *xs)
{
return (struct u_session *)xs;
}
/*
*
* Member functions.
*
*/
static xrt_result_t
push_event(struct xrt_session_event_sink *xses, const union xrt_session_event *xse)
{
struct u_session *us = container_of(xses, struct u_session, sink);
u_session_event_push(us, xse);
return XRT_SUCCESS;
}
static xrt_result_t
poll_events(struct xrt_session *xs, union xrt_session_event *out_xse)
{
struct u_session *us = u_session(xs);
u_session_event_pop(us, out_xse);
return XRT_SUCCESS;
}
static void
destroy(struct xrt_session *xs)
{
struct u_session *us = u_session(xs);
if (us->usys != NULL) {
u_system_remove_session(us->usys, &us->base, &us->sink);
}
free(xs);
}
/*
*
* 'Exported' functions.
*
*/
struct u_session *
u_session_create(struct u_system *usys)
{
struct u_session *us = U_TYPED_CALLOC(struct u_session);
// xrt_session fields.
us->base.poll_events = poll_events;
us->base.destroy = destroy;
// xrt_session_event_sink fields.
us->sink.push_event = push_event;
// u_session fields.
XRT_MAYBE_UNUSED int ret = os_mutex_init(&us->events.mutex);
assert(ret == 0);
us->usys = usys;
// If we got a u_system.
if (usys != NULL) {
u_system_add_session(usys, &us->base, &us->sink);
}
return us;
}
void
u_session_event_push(struct u_session *us, const union xrt_session_event *xse)
{
struct u_session_event *use = U_TYPED_CALLOC(struct u_session_event);
use->xse = *xse;
os_mutex_lock(&us->events.mutex);
// Find the last slot.
struct u_session_event **slot = &us->events.ptr;
while (*slot != NULL) {
slot = &(*slot)->next;
}
*slot = use;
os_mutex_unlock(&us->events.mutex);
}
void
u_session_event_pop(struct u_session *us, union xrt_session_event *out_xse)
{
U_ZERO(out_xse);
out_xse->type = XRT_SESSION_EVENT_NONE;
os_mutex_lock(&us->events.mutex);
if (us->events.ptr != NULL) {
struct u_session_event *use = us->events.ptr;
*out_xse = use->xse;
us->events.ptr = use->next;
free(use);
}
os_mutex_unlock(&us->events.mutex);
}

View file

@ -0,0 +1,91 @@
// Copyright 2023, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Helper to implement @ref xrt_session.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup aux_util
*/
#include "xrt/xrt_session.h"
#include "os/os_threading.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!
* Struct used by @ref u_session to queue up events.
*
* @ingroup aux_util
*/
struct u_session_event
{
union xrt_session_event xse;
struct u_session_event *next;
};
/*!
* This is a helper struct that fully implements @ref xrt_session object.
*
* The use of @ref u_system is optional, but if not used you will need to track
* the session and signal it's destruction yourself.
*
* @ingroup aux_util
* @implements xrt_session
*/
struct u_session
{
struct xrt_session base;
//! Pushes events to this session, used to share to other components.
struct xrt_session_event_sink sink;
//! Owning system, optional.
struct u_system *usys;
struct
{
struct os_mutex mutex;
struct u_session_event *ptr;
} events;
};
/*!
* Create a session, optionally pass in a @ref u_system. If @p usys is not NULL
* the call register this session on that system. This function is exposed so
* that code can re-use @ref u_session as a base class.
*
* @public @memberof u_session
* @ingroup aux_util
*/
struct u_session *
u_session_create(struct u_system *usys);
/*!
* Push an event to this session. This function is exposed so that code can
* re-use @ref u_session as a base class.
*
*
* @public @memberof u_session
* @ingroup aux_util
*/
void
u_session_event_push(struct u_session *us, const union xrt_session_event *xse);
/*!
* Pop a single event from this session, if no event is available
* then the type of the event will be @ref XRT_SESSION_EVENT_NONE.
*
* @public @memberof u_session
* @ingroup aux_util
*/
void
u_session_event_pop(struct u_session *us, union xrt_session_event *out_xse);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,214 @@
// Copyright 2023, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Helper to implement @ref xrt_system.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup aux_util
*/
#include "xrt/xrt_compositor.h"
#include "os/os_threading.h"
#include "util/u_system.h"
#include "util/u_session.h"
#include "util/u_misc.h"
#include "util/u_logging.h"
/*
*
* Helpers.
*
*/
static inline struct u_system *
u_system(struct xrt_system *xsys)
{
return (struct u_system *)xsys;
}
/*
*
* Member functions.
*
*/
static xrt_result_t
push_event(struct xrt_session_event_sink *xses, const union xrt_session_event *xse)
{
struct u_system *usys = container_of(xses, struct u_system, broadcast);
u_system_broadcast_event(usys, xse);
return XRT_SUCCESS;
}
static xrt_result_t
create_session(struct xrt_system *xsys,
const struct xrt_session_info *xsi,
struct xrt_session **out_xs,
struct xrt_compositor_native **out_xcn)
{
struct u_system *usys = u_system(xsys);
xrt_result_t xret = XRT_SUCCESS;
if (out_xcn != NULL && usys->xsysc == NULL) {
U_LOG_E("No system compositor in system, can't create native compositor.");
return XRT_ERROR_COMPOSITOR_NOT_SUPPORTED;
}
struct u_session *us = u_session_create(usys);
// Skip making a native compositor if not asked for.
if (out_xcn == NULL) {
goto out_session;
}
xret = xrt_syscomp_create_native_compositor( //
usys->xsysc, //
xsi, //
out_xcn); //
if (xret != XRT_SUCCESS) {
goto err;
}
out_session:
*out_xs = &us->base;
return XRT_SUCCESS;
err:
return xret;
}
static void
destroy(struct xrt_system *xsys)
{
struct u_system *usys = u_system(xsys);
if (usys->sessions.count > 0) {
U_LOG_E("Number of sessions not zero, things will crash!");
free(usys->sessions.pairs);
usys->sessions.pairs = NULL;
usys->sessions.count = 0;
}
free(usys);
}
/*
*
* 'Exported' functions.
*
*/
struct u_system *
u_system_create(void)
{
struct u_system *usys = U_TYPED_CALLOC(struct u_system);
// xrt_system fields.
usys->base.create_session = create_session;
usys->base.destroy = destroy;
// xrt_session_event_sink fields.
usys->broadcast.push_event = push_event;
// u_system fields.
XRT_MAYBE_UNUSED int ret = os_mutex_init(&usys->sessions.mutex);
assert(ret == 0);
return usys;
}
void
u_system_add_session(struct u_system *usys, struct xrt_session *xs, struct xrt_session_event_sink *xses)
{
assert(xs != NULL);
assert(xses != NULL);
os_mutex_lock(&usys->sessions.mutex);
uint32_t count = usys->sessions.count;
U_ARRAY_REALLOC_OR_FREE(usys->sessions.pairs, struct u_system_session_pair, count + 1);
usys->sessions.pairs[count] = (struct u_system_session_pair){xs, xses};
usys->sessions.count++;
os_mutex_unlock(&usys->sessions.mutex);
}
void
u_system_remove_session(struct u_system *usys, struct xrt_session *xs, struct xrt_session_event_sink *xses)
{
os_mutex_lock(&usys->sessions.mutex);
uint32_t count = usys->sessions.count;
uint32_t dst = 0;
// Find where the session we are removing is.
while (dst < count) {
if (usys->sessions.pairs[dst].xs == xs) {
break;
} else {
dst++;
}
}
// Guards against empty array as well as not finding the session.
if (dst >= count) {
U_LOG_E("Could not find session to remove!");
goto unlock;
}
// Should not be true with above check.
assert(count > 0);
/*
* Do copies if we are not removing the last session,
* this also guards against uint32_t::max.
*/
if (dst < count - 1) {
// Copy from every follow down one.
for (uint32_t src = dst + 1; src < count; src++, dst++) {
usys->sessions.pairs[dst] = usys->sessions.pairs[src];
}
}
count--;
U_ARRAY_REALLOC_OR_FREE(usys->sessions.pairs, struct u_system_session_pair, count);
usys->sessions.count = count;
unlock:
os_mutex_unlock(&usys->sessions.mutex);
}
void
u_system_broadcast_event(struct u_system *usys, const union xrt_session_event *xse)
{
xrt_result_t xret;
os_mutex_lock(&usys->sessions.mutex);
for (uint32_t i = 0; i < usys->sessions.count; i++) {
xret = xrt_session_event_sink_push(usys->sessions.pairs[i].xses, xse);
if (xret != XRT_SUCCESS) {
U_LOG_W("Failed to push event to session, dropping.");
}
}
os_mutex_unlock(&usys->sessions.mutex);
}
void
u_system_set_system_compositor(struct u_system *usys, struct xrt_system_compositor *xsysc)
{
assert(usys->xsysc == NULL);
usys->xsysc = xsysc;
}

View file

@ -0,0 +1,138 @@
// Copyright 2023, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Helper to implement @ref xrt_system.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup aux_util
*/
#include "xrt/xrt_system.h"
#include "xrt/xrt_session.h"
#include "os/os_threading.h"
#ifdef __cplusplus
extern "C" {
#endif
struct xrt_session;
struct xrt_session_event_sink;
union xrt_session_event;
/*!
* A pair of @ref xrt_session and @ref xrt_session_event_sink that has been
* registered to this system, used to multiplex events to all sessions.
*
* @ingroup aux_util
*/
struct u_system_session_pair
{
struct xrt_session *xs;
struct xrt_session_event_sink *xses;
};
/*!
* A helper to implement a @ref xrt_system, takes care of multiplexing events
* to sessions.
*
* @ingroup aux_util
* @implements xrt_system
*/
struct u_system
{
struct xrt_system base;
//! Pushes events to all sessions created from this system.
struct xrt_session_event_sink broadcast;
struct
{
struct os_mutex mutex;
//! Number of session and event sink pairs.
uint32_t count;
//! Array of session and event sink pairs.
struct u_system_session_pair *pairs;
} sessions;
/*!
* Used to implement @ref xrt_system::create_session, can be NULL. This
* field should be set with @ref u_system_set_system_compositor.
*/
struct xrt_system_compositor *xsysc;
};
/*!
* Create a @ref u_system.
*
* @public @memberof u_system
* @ingroup aux_util
*/
struct u_system *
u_system_create(void);
/*!
* Add a @ref xrt_session to be tracked and to receive multiplexed events.
*
* @public @memberof u_system
* @ingroup aux_util
*/
void
u_system_add_session(struct u_system *usys, struct xrt_session *xs, struct xrt_session_event_sink *xses);
/*!
* Remove a @ref xrt_session from tracking, it will no longer receive events,
* the given @p xses needs to match when it was added.
*
* @public @memberof u_system
* @ingroup aux_util
*/
void
u_system_remove_session(struct u_system *usys, struct xrt_session *xs, struct xrt_session_event_sink *xses);
/*!
* Broadcast event to all sessions under this system.
*
* @public @memberof u_system
* @ingroup aux_util
*/
void
u_system_broadcast_event(struct u_system *usys, const union xrt_session_event *xse);
/*!
* Set the system compositor, used in the @ref xrt_system_create_session call.
*
* @public @memberof u_system
* @ingroup aux_util
*/
void
u_system_set_system_compositor(struct u_system *usys, struct xrt_system_compositor *xsysc);
/*!
* Destroy an @ref u_system_create allocated @ref u_system - helper function.
*
* @param[in,out] usys_ptr A pointer to the @ref u_system_create allocated
* struct pointer.
*
* Will destroy the system devices if @p *usys_ptr is not NULL. Will then set
* @p *usys_ptr to NULL.
*
* @public @memberof u_system
*/
static inline void
u_system_destroy(struct u_system **usys_ptr)
{
struct u_system *usys = *usys_ptr;
if (usys == NULL) {
return;
}
*usys_ptr = NULL;
usys->base.destroy(&usys->base);
}
#ifdef __cplusplus
}
#endif