2021-02-08 18:50:21 +00:00
|
|
|
// Copyright 2020-2021, Collabora, Ltd.
|
2020-04-11 00:28:35 +00:00
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
|
|
|
* @brief Common server side code.
|
|
|
|
* @author Pete Black <pblack@collabora.com>
|
|
|
|
* @author Jakob Bornecrantz <jakob@collabora.com>
|
2021-02-08 18:50:21 +00:00
|
|
|
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
2020-04-11 00:28:35 +00:00
|
|
|
* @ingroup ipc_server
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "xrt/xrt_compiler.h"
|
|
|
|
|
2020-11-12 14:01:34 +00:00
|
|
|
#include "util/u_logging.h"
|
2020-06-23 20:30:18 +00:00
|
|
|
|
2020-04-11 00:28:35 +00:00
|
|
|
#include "os/os_threading.h"
|
|
|
|
|
2020-10-29 13:40:43 +00:00
|
|
|
#include "shared/ipc_protocol.h"
|
|
|
|
#include "shared/ipc_utils.h"
|
2020-05-08 19:24:21 +00:00
|
|
|
|
2020-04-11 00:28:35 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Logging
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2020-11-12 14:01:34 +00:00
|
|
|
#define IPC_TRACE(d, ...) U_LOG_IFL_T(d->ll, __VA_ARGS__)
|
|
|
|
#define IPC_DEBUG(d, ...) U_LOG_IFL_D(d->ll, __VA_ARGS__)
|
|
|
|
#define IPC_INFO(d, ...) U_LOG_IFL_I(d->ll, __VA_ARGS__)
|
|
|
|
#define IPC_WARN(d, ...) U_LOG_IFL_W(d->ll, __VA_ARGS__)
|
|
|
|
#define IPC_ERROR(d, ...) U_LOG_IFL_E(d->ll, __VA_ARGS__)
|
2020-04-11 00:28:35 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Structs
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define IPC_SERVER_NUM_XDEVS 8
|
2020-05-30 15:34:40 +00:00
|
|
|
#define IPC_MAX_CLIENT_SWAPCHAINS 32
|
2020-06-17 06:36:38 +00:00
|
|
|
//#define IPC_MAX_CLIENTS 8
|
2020-04-11 00:28:35 +00:00
|
|
|
|
|
|
|
struct xrt_instance;
|
|
|
|
struct xrt_compositor;
|
2020-07-14 22:13:07 +00:00
|
|
|
struct xrt_compositor_native;
|
2020-05-12 12:58:17 +00:00
|
|
|
|
2020-04-11 00:28:35 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Information about a single swapchain.
|
|
|
|
*
|
|
|
|
* @ingroup ipc_server
|
|
|
|
*/
|
|
|
|
struct ipc_swapchain_data
|
|
|
|
{
|
|
|
|
uint32_t width;
|
|
|
|
uint32_t height;
|
|
|
|
uint64_t format;
|
|
|
|
uint32_t num_images;
|
2020-05-30 15:34:40 +00:00
|
|
|
|
|
|
|
bool active;
|
2020-04-11 00:28:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Holds the state for a single client.
|
|
|
|
*
|
|
|
|
* @ingroup ipc_server
|
|
|
|
*/
|
|
|
|
struct ipc_client_state
|
|
|
|
{
|
|
|
|
//! Link back to the main server.
|
|
|
|
struct ipc_server *server;
|
|
|
|
|
|
|
|
//! Compositor for this client.
|
|
|
|
struct xrt_compositor *xc;
|
|
|
|
|
2020-08-18 16:05:43 +00:00
|
|
|
//! Is the inputs and outputs active.
|
|
|
|
bool io_active;
|
|
|
|
|
2020-04-11 00:28:35 +00:00
|
|
|
//! Number of swapchains in use by client
|
|
|
|
uint32_t num_swapchains;
|
|
|
|
|
|
|
|
//! Ptrs to the swapchains
|
|
|
|
struct xrt_swapchain *xscs[IPC_MAX_CLIENT_SWAPCHAINS];
|
|
|
|
|
|
|
|
//! Data for the swapchains.
|
|
|
|
struct ipc_swapchain_data swapchain_data[IPC_MAX_CLIENT_SWAPCHAINS];
|
|
|
|
|
|
|
|
//! Socket fd used for client comms
|
2020-07-07 21:06:41 +00:00
|
|
|
struct ipc_message_channel imc;
|
2020-04-11 00:28:35 +00:00
|
|
|
|
2020-06-17 06:36:38 +00:00
|
|
|
struct ipc_app_state client_state;
|
|
|
|
|
|
|
|
int server_thread_index;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum ipc_thread_state
|
|
|
|
{
|
|
|
|
IPC_THREAD_READY,
|
|
|
|
IPC_THREAD_STARTING,
|
|
|
|
IPC_THREAD_RUNNING,
|
|
|
|
IPC_THREAD_STOPPING,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ipc_thread
|
|
|
|
{
|
|
|
|
struct os_thread thread;
|
|
|
|
volatile enum ipc_thread_state state;
|
|
|
|
volatile struct ipc_client_state ics;
|
2020-04-11 00:28:35 +00:00
|
|
|
};
|
|
|
|
|
2020-08-18 16:05:43 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
struct ipc_device
|
|
|
|
{
|
|
|
|
//! The actual device.
|
|
|
|
struct xrt_device *xdev;
|
|
|
|
|
|
|
|
//! Is the IO suppressed for this device.
|
|
|
|
bool io_active;
|
|
|
|
};
|
|
|
|
|
2021-02-08 18:50:21 +00:00
|
|
|
/*!
|
|
|
|
* Platform-specific mainloop object for the IPC server.
|
|
|
|
*
|
|
|
|
* Contents are essentially implementation details, but are listed in full here so they may be included by value in the
|
|
|
|
* main ipc_server struct.
|
|
|
|
*
|
2021-02-24 21:22:08 +00:00
|
|
|
* @see ipc_design
|
|
|
|
*
|
2021-02-08 18:50:21 +00:00
|
|
|
* @ingroup ipc_server
|
|
|
|
*/
|
|
|
|
struct ipc_server_mainloop
|
|
|
|
{
|
2021-03-25 17:05:15 +00:00
|
|
|
|
|
|
|
#if defined(XRT_OS_ANDROID) || defined(XRT_OS_LINUX) || defined(XRT_DOXYGEN)
|
|
|
|
//! For waiting on various events in the main thread.
|
|
|
|
int epoll_fd;
|
|
|
|
#endif
|
|
|
|
|
2021-02-24 21:22:08 +00:00
|
|
|
#if defined(XRT_OS_ANDROID) || defined(XRT_DOXYGEN)
|
|
|
|
/*!
|
|
|
|
* @name Android Mainloop Members
|
|
|
|
* @{
|
|
|
|
*/
|
2021-02-12 15:23:59 +00:00
|
|
|
|
|
|
|
//! File descriptor for the read end of our pipe for submitting new clients
|
|
|
|
int pipe_read;
|
|
|
|
|
2021-02-24 21:22:08 +00:00
|
|
|
/*!
|
|
|
|
* File descriptor for the write end of our pipe for submitting new clients
|
|
|
|
*
|
|
|
|
* Must hold client_push_mutex while writing.
|
|
|
|
*/
|
2021-02-12 15:23:59 +00:00
|
|
|
int pipe_write;
|
|
|
|
|
2021-02-24 21:22:08 +00:00
|
|
|
/*!
|
|
|
|
* Mutex for being able to register oneself as a new client.
|
|
|
|
*
|
|
|
|
* Locked only by threads in `ipc_server_mainloop_add_fd()`.
|
|
|
|
*
|
|
|
|
* This must be locked first, and kept locked the entire time a client is attempting to register and wait for
|
|
|
|
* confirmation. It ensures no acknowledgements of acceptance are lost and moves the overhead of ensuring this
|
|
|
|
* to the client thread.
|
|
|
|
*/
|
|
|
|
pthread_mutex_t client_push_mutex;
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* The last client fd we accepted, to acknowledge client acceptance.
|
|
|
|
*
|
|
|
|
* Also used as a sentinel during shutdown.
|
|
|
|
*
|
|
|
|
* Must hold accept_mutex while writing.
|
|
|
|
*/
|
2021-02-12 15:23:59 +00:00
|
|
|
int last_accepted_fd;
|
|
|
|
|
2021-02-24 21:22:08 +00:00
|
|
|
/*!
|
|
|
|
* Condition variable for accepting clients.
|
|
|
|
*
|
|
|
|
* Signalled when @ref last_accepted_fd is updated.
|
|
|
|
*
|
|
|
|
* Associated with @ref accept_mutex
|
|
|
|
*/
|
|
|
|
pthread_cond_t accept_cond;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Mutex for accepting clients.
|
|
|
|
*
|
|
|
|
* Locked by both clients and server: that is, by threads in `ipc_server_mainloop_add_fd()` and in the
|
|
|
|
* server/compositor thread in an implementation function called from `ipc_server_mainloop_poll()`.
|
|
|
|
*
|
|
|
|
* Exists to operate in conjunction with @ref accept_cond - it exists to make sure that the client can be woken
|
|
|
|
* when the server accepts it.
|
|
|
|
*/
|
2021-02-12 15:23:59 +00:00
|
|
|
pthread_mutex_t accept_mutex;
|
|
|
|
|
|
|
|
|
2021-02-24 21:22:08 +00:00
|
|
|
/*! @} */
|
|
|
|
#define XRT_IPC_GOT_IMPL
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if (defined(XRT_OS_LINUX) && !defined(XRT_OS_ANDROID)) || defined(XRT_DOXYGEN)
|
|
|
|
/*!
|
|
|
|
* @name Desktop Linux Mainloop Members
|
|
|
|
* @{
|
|
|
|
*/
|
2021-02-08 18:50:21 +00:00
|
|
|
|
|
|
|
//! Socket that we accept connections on.
|
|
|
|
int listen_socket;
|
|
|
|
|
|
|
|
//! Were we launched by socket activation, instead of explicitly?
|
|
|
|
bool launched_by_socket;
|
|
|
|
|
|
|
|
//! The socket filename we bound to, if any.
|
|
|
|
char *socket_filename;
|
2021-02-24 21:22:08 +00:00
|
|
|
|
|
|
|
/*! @} */
|
|
|
|
|
|
|
|
#define XRT_IPC_GOT_IMPL
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef XRT_IPC_GOT_IMPL
|
2021-02-08 18:50:21 +00:00
|
|
|
#error "Need port"
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* De-initialize the mainloop object.
|
|
|
|
* @public @memberof ipc_server_mainloop
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ipc_server_mainloop_deinit(struct ipc_server_mainloop *ml);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Initialize the mainloop object.
|
|
|
|
*
|
|
|
|
* @return <0 on error.
|
|
|
|
* @public @memberof ipc_server_mainloop
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ipc_server_mainloop_init(struct ipc_server_mainloop *ml);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* @brief Poll the mainloop.
|
|
|
|
*
|
|
|
|
* Any errors are signalled by calling ipc_server_handle_failure()
|
|
|
|
* @public @memberof ipc_server_mainloop
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ipc_server_mainloop_poll(struct ipc_server *vs, struct ipc_server_mainloop *ml);
|
|
|
|
|
2020-04-11 00:28:35 +00:00
|
|
|
/*!
|
|
|
|
* Main IPC object for the server.
|
|
|
|
*
|
|
|
|
* @ingroup ipc_server
|
|
|
|
*/
|
|
|
|
struct ipc_server
|
|
|
|
{
|
|
|
|
struct xrt_instance *xinst;
|
|
|
|
|
2020-10-21 20:18:57 +00:00
|
|
|
//! Handle for the current process, e.g. pidfile on linux
|
|
|
|
struct u_process *process;
|
|
|
|
|
2020-12-14 18:07:26 +00:00
|
|
|
/* ---- HACK ---- */
|
|
|
|
void *hack;
|
|
|
|
/* ---- HACK ---- */
|
|
|
|
|
2021-01-12 19:25:16 +00:00
|
|
|
|
|
|
|
//! System compositor.
|
|
|
|
struct xrt_system_compositor *xsysc;
|
2020-04-11 00:28:35 +00:00
|
|
|
|
2020-08-18 16:05:43 +00:00
|
|
|
struct ipc_device idevs[IPC_SERVER_NUM_XDEVS];
|
2020-05-07 15:24:14 +00:00
|
|
|
struct xrt_tracking_origin *xtracks[IPC_SERVER_NUM_XDEVS];
|
2020-04-11 00:28:35 +00:00
|
|
|
|
|
|
|
struct ipc_shared_memory *ism;
|
2020-07-16 16:22:40 +00:00
|
|
|
xrt_shmem_handle_t ism_handle;
|
2020-04-11 00:28:35 +00:00
|
|
|
|
2021-02-08 18:50:21 +00:00
|
|
|
struct ipc_server_mainloop ml;
|
2020-04-11 00:28:35 +00:00
|
|
|
|
|
|
|
// Is the mainloop supposed to run.
|
|
|
|
volatile bool running;
|
|
|
|
|
|
|
|
// Should we exit when a client disconnects.
|
|
|
|
bool exit_on_disconnect;
|
|
|
|
|
2020-11-12 14:01:34 +00:00
|
|
|
enum u_logging_level ll;
|
2020-04-11 00:28:35 +00:00
|
|
|
|
2020-06-17 06:36:38 +00:00
|
|
|
struct ipc_thread threads[IPC_MAX_CLIENTS];
|
2020-06-23 20:30:18 +00:00
|
|
|
|
2020-06-17 06:36:38 +00:00
|
|
|
volatile uint32_t current_slot_index;
|
2020-06-23 20:30:18 +00:00
|
|
|
|
2021-03-18 23:17:42 +00:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
int active_client_index;
|
|
|
|
int last_active_client_index;
|
|
|
|
|
|
|
|
struct os_mutex lock;
|
|
|
|
} global_state;
|
2020-04-11 00:28:35 +00:00
|
|
|
};
|
|
|
|
|
2021-02-08 18:50:21 +00:00
|
|
|
|
|
|
|
#ifndef XRT_OS_ANDROID
|
2020-04-11 00:28:35 +00:00
|
|
|
/*!
|
|
|
|
* Main entrypoint to the compositor process.
|
|
|
|
*
|
|
|
|
* @ingroup ipc_server
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ipc_server_main(int argc, char **argv);
|
2021-02-08 18:50:21 +00:00
|
|
|
#endif
|
2020-04-11 00:28:35 +00:00
|
|
|
|
2021-02-12 15:23:59 +00:00
|
|
|
#ifdef XRT_OS_ANDROID
|
2020-11-25 13:10:39 +00:00
|
|
|
/*!
|
2021-02-12 15:23:59 +00:00
|
|
|
* Main entrypoint to the server process.
|
|
|
|
*
|
|
|
|
* @param ps Pointer to populate with the server struct.
|
|
|
|
* @param startup_complete_callback Function to call upon completing startup and populating *ps, but before entering the
|
|
|
|
* mainloop.
|
|
|
|
* @param data user data to pass to your callback.
|
2020-11-25 13:10:39 +00:00
|
|
|
*
|
|
|
|
* @ingroup ipc_server
|
|
|
|
*/
|
|
|
|
int
|
2021-02-12 15:23:59 +00:00
|
|
|
ipc_server_main_android(struct ipc_server **ps, void (*startup_complete_callback)(void *data), void *data);
|
2020-11-25 13:10:39 +00:00
|
|
|
#endif
|
|
|
|
|
2020-06-17 06:36:38 +00:00
|
|
|
/*!
|
2021-03-18 23:17:42 +00:00
|
|
|
* Set the new active client.
|
|
|
|
*
|
|
|
|
* @ingroup ipc_server
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ipc_server_set_active_client(struct ipc_server *s, int active_client_index);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Called by client threads to set a session to active.
|
|
|
|
*
|
|
|
|
* @ingroup ipc_server
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ipc_server_activate_session(volatile struct ipc_client_state *ics);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Called by client threads to set a session to deactivate.
|
|
|
|
*
|
|
|
|
* @ingroup ipc_server
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ipc_server_deactivate_session(volatile struct ipc_client_state *ics);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Called by client threads to recalculate active client.
|
2020-06-17 06:36:38 +00:00
|
|
|
*
|
|
|
|
* @ingroup ipc_server
|
|
|
|
*/
|
|
|
|
void
|
2021-03-18 23:17:42 +00:00
|
|
|
ipc_server_update_state(struct ipc_server *s);
|
2020-06-17 06:36:38 +00:00
|
|
|
|
2020-04-11 00:28:35 +00:00
|
|
|
/*!
|
|
|
|
* Thread function for the client side dispatching.
|
|
|
|
*
|
|
|
|
* @ingroup ipc_server
|
|
|
|
*/
|
|
|
|
void *
|
|
|
|
ipc_server_client_thread(void *_cs);
|
|
|
|
|
2021-04-27 19:16:09 +00:00
|
|
|
/*!
|
|
|
|
* This destroyes the native compositor for this client and any extra objects
|
|
|
|
* created from it, like all of the swapchains.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ipc_server_client_destroy_compositor(volatile struct ipc_client_state *ics);
|
|
|
|
|
2021-02-08 18:50:21 +00:00
|
|
|
/*!
|
|
|
|
* @defgroup ipc_server_internals Server Internals
|
|
|
|
* @brief These are only called by the platform-specific mainloop polling code.
|
|
|
|
* @ingroup ipc_server
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
/*!
|
|
|
|
* Start a thread for a client connected at the other end of the file descriptor @p fd.
|
|
|
|
* @memberof ipc_server
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ipc_server_start_client_listener_thread(struct ipc_server *vs, int fd);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Perform whatever needs to be done when the mainloop polling encounters a failure.
|
|
|
|
* @memberof ipc_server
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ipc_server_handle_failure(struct ipc_server *vs);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Perform whatever needs to be done when the mainloop polling identifies that the server should be shut down.
|
|
|
|
*
|
|
|
|
* Does something like setting a flag or otherwise signalling for shutdown: does not itself explicitly exit.
|
|
|
|
* @memberof ipc_server
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ipc_server_handle_shutdown_signal(struct ipc_server *vs);
|
|
|
|
//! @}
|
2020-04-11 00:28:35 +00:00
|
|
|
|
2020-08-18 16:05:43 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Helpers
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Get a xdev with the given device_id.
|
|
|
|
*/
|
|
|
|
static inline struct xrt_device *
|
|
|
|
get_xdev(volatile struct ipc_client_state *ics, uint32_t device_id)
|
|
|
|
{
|
|
|
|
return ics->server->idevs[device_id].xdev;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Get a idev with the given device_id.
|
|
|
|
*/
|
|
|
|
static inline struct ipc_device *
|
|
|
|
get_idev(volatile struct ipc_client_state *ics, uint32_t device_id)
|
|
|
|
{
|
|
|
|
return &ics->server->idevs[device_id];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-11 00:28:35 +00:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|