Monado OpenXR Runtime
ipc_server.h
Go to the documentation of this file.
1// Copyright 2020-2023, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Common server side code.
6 * @author Pete Black <pblack@collabora.com>
7 * @author Jakob Bornecrantz <jakob@collabora.com>
8 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
9 * @ingroup ipc_server
10 */
11
12#pragma once
13
14#include "xrt/xrt_compiler.h"
15#include "xrt/xrt_limits.h"
16#include "xrt/xrt_space.h"
17#include "xrt/xrt_system.h"
18
19#include "os/os_threading.h"
20
21#include "util/u_logging.h"
22
23#include "shared/ipc_protocol.h"
25
26#include <stdio.h>
27
28
29#ifdef __cplusplus
30extern "C" {
31#endif
32
33/*
34 *
35 * Logging
36 *
37 */
38
39#define IPC_TRACE(d, ...) U_LOG_IFL_T(d->log_level, __VA_ARGS__)
40#define IPC_DEBUG(d, ...) U_LOG_IFL_D(d->log_level, __VA_ARGS__)
41#define IPC_INFO(d, ...) U_LOG_IFL_I(d->log_level, __VA_ARGS__)
42#define IPC_WARN(d, ...) U_LOG_IFL_W(d->log_level, __VA_ARGS__)
43#define IPC_ERROR(d, ...) U_LOG_IFL_E(d->log_level, __VA_ARGS__)
44
45#define IPC_CHK_AND_RET(S, ...) U_LOG_CHK_AND_RET((S)->log_level, __VA_ARGS__)
46#define IPC_CHK_WITH_GOTO(S, ...) U_LOG_CHK_WITH_GOTO((S)->log_level, __VA_ARGS__)
47#define IPC_CHK_WITH_RET(S, ...) U_LOG_CHK_WITH_RET((S)->log_level, __VA_ARGS__)
48#define IPC_CHK_ONLY_PRINT(S, ...) U_LOG_CHK_ONLY_PRINT((S)->log_level, __VA_ARGS__)
49#define IPC_CHK_ALWAYS_RET(S, ...) U_LOG_CHK_ALWAYS_RET((S)->log_level, __VA_ARGS__)
50
51
52/*
53 *
54 * Structs
55 *
56 */
57
58#define IPC_MAX_CLIENT_SEMAPHORES 8
59#define IPC_MAX_CLIENT_SWAPCHAINS (XRT_MAX_LAYERS * 2)
60#define IPC_MAX_CLIENT_SPACES 128
61
62struct xrt_instance;
63struct xrt_compositor;
65
66
67/*!
68 * Information about a single swapchain.
69 *
70 * @ingroup ipc_server
71 */
73{
74 uint32_t width;
75 uint32_t height;
76 uint64_t format;
77 uint32_t image_count;
78
79 bool active;
80};
81
82/*!
83 * Holds the state for a single client.
84 *
85 * @ingroup ipc_server
86 */
88{
89 //! Link back to the main server.
91
92 //! Session for this client.
93 struct xrt_session *xs;
94
95 //! Compositor for this client.
97
98 //! Is the inputs and outputs active.
100
101 //! Number of swapchains in use by client
103
104 //! Ptrs to the swapchains
105 struct xrt_swapchain *xscs[IPC_MAX_CLIENT_SWAPCHAINS];
106
107 //! Data for the swapchains.
108 struct ipc_swapchain_data swapchain_data[IPC_MAX_CLIENT_SWAPCHAINS];
109
110 //! Number of compositor semaphores in use by client
112
113 //! Ptrs to the semaphores.
114 struct xrt_compositor_semaphore *xcsems[IPC_MAX_CLIENT_SEMAPHORES];
115
116 struct
117 {
118 uint32_t root;
119 uint32_t local;
120 uint32_t stage;
121 uint32_t unbounded;
122 } semantic_spaces;
123
124 //! Number of spaces.
125 uint32_t space_count;
126 //! Index of localspace in ipc client.
128 //! Index of localspace in space overseer.
130 //! Index of localfloorspace in ipc client.
132 //! Index of localfloorspace in space overseer.
134
135 //! Ptrs to the spaces.
136 struct xrt_space *xspcs[IPC_MAX_CLIENT_SPACES];
137
138 //! Which of the references spaces is the client using.
140
141 //! Which of the device features is the client using.
142 bool device_feature_used[XRT_DEVICE_FEATURE_MAX_ENUM];
143
144 //! Socket fd used for client comms
146
147 struct ipc_app_state client_state;
148
149
150 uint64_t plane_detection_size;
151 uint64_t plane_detection_count;
152
153 //! Array of plane detection ids with plane_detection_size entries.
155
156 //! Array of xrt_devices with plane_detection_size entries.
158
159 int server_thread_index;
160
161 xrt_shmem_handle_t ism_handle;
162};
163
164enum ipc_thread_state
165{
166 IPC_THREAD_READY,
167 IPC_THREAD_STARTING,
168 IPC_THREAD_RUNNING,
169 IPC_THREAD_STOPPING,
170};
171
173{
174 struct os_thread thread;
175 volatile enum ipc_thread_state state;
176 volatile struct ipc_client_state ics;
177};
178
179
180/*!
181 *
182 */
184{
185 //! The actual device.
187
188 //! Is the IO suppressed for this device.
190};
191
192/*!
193 * Platform-specific mainloop object for the IPC server.
194 *
195 * Contents are essentially implementation details, but are listed in full here so they may be included by value in the
196 * main ipc_server struct.
197 *
198 * @see ipc_design
199 *
200 * @ingroup ipc_server
201 */
203{
204
205#if defined(XRT_OS_ANDROID) || defined(XRT_OS_LINUX) || defined(XRT_DOXYGEN)
206 //! For waiting on various events in the main thread.
208#endif
209
210#if defined(XRT_OS_ANDROID) || defined(XRT_DOXYGEN)
211 /*!
212 * @name Android Mainloop Members
213 * @{
214 */
215
216 //! File descriptor for the read end of our pipe for submitting new clients
218
219 /*!
220 * File descriptor for the write end of our pipe for submitting new clients
221 *
222 * Must hold client_push_mutex while writing.
223 */
225
226 /*!
227 * Mutex for being able to register oneself as a new client.
228 *
229 * Locked only by threads in `ipc_server_mainloop_add_fd()`.
230 *
231 * This must be locked first, and kept locked the entire time a client is attempting to register and wait for
232 * confirmation. It ensures no acknowledgements of acceptance are lost and moves the overhead of ensuring this
233 * to the client thread.
234 */
235 pthread_mutex_t client_push_mutex;
236
237
238 /*!
239 * The last client fd we accepted, to acknowledge client acceptance.
240 *
241 * Also used as a sentinel during shutdown.
242 *
243 * Must hold accept_mutex while writing.
244 */
246
247 /*!
248 * Condition variable for accepting clients.
249 *
250 * Signalled when @ref last_accepted_fd is updated.
251 *
252 * Associated with @ref accept_mutex
253 */
254 pthread_cond_t accept_cond;
255
256 /*!
257 * Mutex for accepting clients.
258 *
259 * Locked by both clients and server: that is, by threads in `ipc_server_mainloop_add_fd()` and in the
260 * server/compositor thread in an implementation function called from `ipc_server_mainloop_poll()`.
261 *
262 * Exists to operate in conjunction with @ref accept_cond - it exists to make sure that the client can be woken
263 * when the server accepts it.
264 */
265 pthread_mutex_t accept_mutex;
266
267
268 /*! @} */
269#define XRT_IPC_GOT_IMPL
270#endif
271
272#if (defined(XRT_OS_LINUX) && !defined(XRT_OS_ANDROID)) || defined(XRT_DOXYGEN)
273 /*!
274 * @name Desktop Linux Mainloop Members
275 * @{
276 */
277
278 //! Socket that we accept connections on.
280
281 //! Were we launched by socket activation, instead of explicitly?
283
284 //! The socket filename we bound to, if any.
286
287 /*! @} */
288
289#define XRT_IPC_GOT_IMPL
290#endif
291
292#if defined(XRT_OS_WINDOWS) || defined(XRT_DOXYGEN)
293 /*!
294 * @name Desktop Windows Mainloop Members
295 * @{
296 */
297
298 //! Named Pipe that we accept connections on.
300
301 //! Name of the Pipe that we accept connections on.
303
304 /*! @} */
305
306#define XRT_IPC_GOT_IMPL
307#endif
308
309#ifndef XRT_IPC_GOT_IMPL
310#error "Need port"
311#endif
312};
313
314/*!
315 * De-initialize the mainloop object.
316 * @public @memberof ipc_server_mainloop
317 */
318void
320
321/*!
322 * Initialize the mainloop object.
323 *
324 * @return <0 on error.
325 * @public @memberof ipc_server_mainloop
326 */
327int
329
330/*!
331 * @brief Poll the mainloop.
332 *
333 * Any errors are signalled by calling ipc_server_handle_failure()
334 * @public @memberof ipc_server_mainloop
335 */
336void
338
339/*!
340 * Main IPC object for the server.
341 *
342 * @ingroup ipc_server
343 */
345{
346 struct xrt_instance *xinst;
347
348 //! Handle for the current process, e.g. pidfile on linux
350
351 struct u_debug_gui *debug_gui;
352
353 //! The @ref xrt_iface level system.
355
356 //! System devices.
358
359 //! Space overseer.
361
362 //! System compositor.
364
367
368 struct ipc_shared_memory *isms[IPC_MAX_CLIENTS];
369
370 struct ipc_server_mainloop ml;
371
372 // Is the mainloop supposed to run.
373 volatile bool running;
374
375 // Should we exit when a client disconnects.
376 bool exit_on_disconnect;
377
378 // Should we exit when no clients are connected.
379 bool exit_when_idle;
380
381 // Timestamp when last client disconnected (for exit_when_idle delay)
382 uint64_t last_client_disconnect_ns;
383
384 // How long to wait after all clients disconnect before exiting (in nanoseconds)
385 uint64_t exit_when_idle_delay_ns;
386
387 enum u_logging_level log_level;
388
389 struct ipc_thread threads[IPC_MAX_CLIENTS];
390
391 volatile uint32_t current_slot_index;
392
393 //! Generator for IDs.
394 uint32_t id_generator;
395
396 struct
397 {
398 int active_client_index;
399 int last_active_client_index;
400
401 // Counter for total number of connected clients
402 uint32_t connected_client_count;
403
404 struct os_mutex lock;
405 } global_state;
406};
407
408
409/*!
410 * Get the current state of a client.
411 *
412 * @ingroup ipc_server
413 */
415ipc_server_get_client_app_state(struct ipc_server *s, uint32_t client_id, struct ipc_app_state *out_ias);
416
417/*!
418 * Set the new active client.
419 *
420 * @ingroup ipc_server
421 */
423ipc_server_set_active_client(struct ipc_server *s, uint32_t client_id);
424
425/*!
426 * Toggle the io for this client.
427 *
428 * @ingroup ipc_server
429 */
431ipc_server_toggle_io_client(struct ipc_server *s, uint32_t client_id);
432
433/*!
434 * Called by client threads to set a session to active.
435 *
436 * @ingroup ipc_server
437 */
438void
440
441/*!
442 * Called by client threads to set a session to deactivate.
443 *
444 * @ingroup ipc_server
445 */
446void
448
449/*!
450 * Called by client threads to recalculate active client.
451 *
452 * @ingroup ipc_server
453 */
454void
456
457/*!
458 * Thread function for the client side dispatching.
459 *
460 * @ingroup ipc_server
461 */
462void *
463ipc_server_client_thread(void *_ics);
464
465/*!
466 * This destroys the native compositor for this client and any extra objects
467 * created from it, like all of the swapchains.
468 */
469void
471
472/*!
473 * @defgroup ipc_server_internals Server Internals
474 * @brief These are only called by the platform-specific mainloop polling code.
475 * @ingroup ipc_server
476 * @{
477 */
478/*!
479 * Called when a client has connected, it takes the client's ipc handle.
480 * Handles all things needed to be done for a client connecting, like starting
481 * it's thread.
482 *
483 * @param vs The IPC server.
484 * @param ipc_handle Handle to communicate over.
485 * @memberof ipc_server
486 */
487void
489
490/*!
491 * Perform whatever needs to be done when the mainloop polling encounters a failure.
492 * @memberof ipc_server
493 */
494void
496
497/*!
498 * Perform whatever needs to be done when the mainloop polling identifies that the server should be shut down.
499 *
500 * Does something like setting a flag or otherwise signalling for shutdown: does not itself explicitly exit.
501 * @memberof ipc_server
502 */
503void
505
507ipc_server_get_system_properties(struct ipc_server *vs, struct xrt_system_properties *out_properties);
508//! @}
509
510/*
511 *
512 * Helpers
513 *
514 */
515
516/*!
517 * Get a xdev with the given device_id.
518 */
519static inline struct xrt_device *
520get_xdev(volatile struct ipc_client_state *ics, uint32_t device_id)
521{
522 return ics->server->idevs[device_id].xdev;
523}
524
525/*!
526 * Get a idev with the given device_id.
527 */
528static inline struct ipc_device *
529get_idev(volatile struct ipc_client_state *ics, uint32_t device_id)
530{
531 return &ics->server->idevs[device_id];
532}
533
534/*!
535 * Get the data in the shared memory of the given client.
536 */
537static inline struct ipc_shared_memory *
538get_ism(volatile struct ipc_client_state *ics)
539{
540 return ics->server->isms[ics->server_thread_index];
541}
542
543/*!
544 * Get the handle for the shared memory of the given client.
545 */
546static inline xrt_shmem_handle_t
547get_ism_handle(volatile struct ipc_client_state *ics)
548{
549 return ics->ism_handle;
550}
551
552#ifdef __cplusplus
553}
554#endif
Generic typedef for platform-specific shared memory handle.
u_logging_level
Logging level enum.
Definition: u_logging.h:44
void ipc_server_handle_client_connected(struct ipc_server *vs, xrt_ipc_handle_t ipc_handle)
Called when a client has connected, it takes the client's ipc handle.
Definition: ipc_server_process.c:885
void ipc_server_handle_shutdown_signal(struct ipc_server *vs)
Perform whatever needs to be done when the mainloop polling identifies that the server should be shut...
Definition: ipc_server_process.c:879
void ipc_server_handle_failure(struct ipc_server *vs)
Perform whatever needs to be done when the mainloop polling encounters a failure.
Definition: ipc_server_process.c:872
xrt_result_t ipc_server_get_client_app_state(struct ipc_server *s, uint32_t client_id, struct ipc_app_state *out_ias)
Get the current state of a client.
Definition: ipc_server_process.c:782
void ipc_server_deactivate_session(volatile struct ipc_client_state *ics)
Called by client threads to set a session to deactivate.
Definition: ipc_server_process.c:846
void ipc_server_activate_session(volatile struct ipc_client_state *ics)
Called by client threads to set a session to active.
Definition: ipc_server_process.c:812
void * ipc_server_client_thread(void *_ics)
Thread function for the client side dispatching.
Definition: ipc_server_per_client_thread.c:402
void ipc_server_update_state(struct ipc_server *s)
Called by client threads to recalculate active client.
Definition: ipc_server_process.c:861
xrt_result_t ipc_server_set_active_client(struct ipc_server *s, uint32_t client_id)
Set the new active client.
Definition: ipc_server_process.c:792
xrt_result_t ipc_server_toggle_io_client(struct ipc_server *s, uint32_t client_id)
Toggle the io for this client.
Definition: ipc_server_process.c:802
#define XRT_SYSTEM_MAX_DEVICES
Maximum number of devices simultaneously usable by an implementation of xrt_system_devices.
Definition: xrt_system.h:141
#define XRT_SPACE_REFERENCE_TYPE_COUNT
The number of enumerations in xrt_reference_space_type.
Definition: xrt_defines.h:610
enum xrt_result xrt_result_t
Result type used across Monado.
IPC message channel functions.
Common protocol definition.
void ipc_server_client_destroy_session_and_compositor(volatile struct ipc_client_state *ics)
This destroys the native compositor for this client and any extra objects created from it,...
Definition: ipc_server_per_client_thread.c:371
static struct ipc_shared_memory * get_ism(volatile struct ipc_client_state *ics)
Get the data in the shared memory of the given client.
Definition: ipc_server.h:538
static struct xrt_device * get_xdev(volatile struct ipc_client_state *ics, uint32_t device_id)
Get a xdev with the given device_id.
Definition: ipc_server.h:520
static struct ipc_device * get_idev(volatile struct ipc_client_state *ics, uint32_t device_id)
Get a idev with the given device_id.
Definition: ipc_server.h:529
static xrt_shmem_handle_t get_ism_handle(volatile struct ipc_client_state *ics)
Get the handle for the shared memory of the given client.
Definition: ipc_server.h:547
Wrapper around OS threading native functions.
State for a connected application.
Definition: ipc_protocol.h:309
Holds the state for a single client.
Definition: ipc_server.h:88
uint32_t swapchain_count
Number of swapchains in use by client.
Definition: ipc_server.h:102
struct xrt_swapchain * xscs[(XRT_MAX_LAYERS *2)]
Ptrs to the swapchains.
Definition: ipc_server.h:105
struct xrt_session * xs
Session for this client.
Definition: ipc_server.h:93
struct ipc_message_channel imc
Socket fd used for client comms.
Definition: ipc_server.h:145
struct xrt_device ** plane_detection_xdev
Array of xrt_devices with plane_detection_size entries.
Definition: ipc_server.h:157
struct ipc_server * server
Link back to the main server.
Definition: ipc_server.h:90
uint32_t local_floor_space_index
Index of localfloorspace in ipc client.
Definition: ipc_server.h:131
struct ipc_swapchain_data swapchain_data[(XRT_MAX_LAYERS *2)]
Data for the swapchains.
Definition: ipc_server.h:108
uint32_t compositor_semaphore_count
Number of compositor semaphores in use by client.
Definition: ipc_server.h:111
uint32_t local_space_overseer_index
Index of localspace in space overseer.
Definition: ipc_server.h:129
struct xrt_space * xspcs[128]
Ptrs to the spaces.
Definition: ipc_server.h:136
uint32_t local_space_index
Index of localspace in ipc client.
Definition: ipc_server.h:127
bool ref_space_used[XRT_SPACE_REFERENCE_TYPE_COUNT]
Which of the references spaces is the client using.
Definition: ipc_server.h:139
struct xrt_compositor_semaphore * xcsems[8]
Ptrs to the semaphores.
Definition: ipc_server.h:114
uint32_t space_count
Number of spaces.
Definition: ipc_server.h:125
bool device_feature_used[XRT_DEVICE_FEATURE_MAX_ENUM]
Which of the device features is the client using.
Definition: ipc_server.h:142
bool io_active
Is the inputs and outputs active.
Definition: ipc_server.h:99
uint64_t * plane_detection_ids
Array of plane detection ids with plane_detection_size entries.
Definition: ipc_server.h:154
uint32_t local_floor_space_overseer_index
Index of localfloorspace in space overseer.
Definition: ipc_server.h:133
struct xrt_compositor * xc
Compositor for this client.
Definition: ipc_server.h:96
Definition: ipc_server.h:184
bool io_active
Is the IO suppressed for this device.
Definition: ipc_server.h:189
struct xrt_device * xdev
The actual device.
Definition: ipc_server.h:186
Wrapper for a socket and flags.
Definition: ipc_message_channel.h:30
Platform-specific mainloop object for the IPC server.
Definition: ipc_server.h:203
bool launched_by_socket
Were we launched by socket activation, instead of explicitly?
Definition: ipc_server.h:282
pthread_cond_t accept_cond
Condition variable for accepting clients.
Definition: ipc_server.h:254
char * pipe_name
Name of the Pipe that we accept connections on.
Definition: ipc_server.h:302
int last_accepted_fd
The last client fd we accepted, to acknowledge client acceptance.
Definition: ipc_server.h:245
int epoll_fd
For waiting on various events in the main thread.
Definition: ipc_server.h:207
void ipc_server_mainloop_deinit(struct ipc_server_mainloop *ml)
De-initialize the mainloop object.
Definition: ipc_server_mainloop_android.c:160
pthread_mutex_t accept_mutex
Mutex for accepting clients.
Definition: ipc_server.h:265
int pipe_read
File descriptor for the read end of our pipe for submitting new clients.
Definition: ipc_server.h:217
int listen_socket
Socket that we accept connections on.
Definition: ipc_server.h:279
int pipe_write
File descriptor for the write end of our pipe for submitting new clients.
Definition: ipc_server.h:224
int ipc_server_mainloop_init(struct ipc_server_mainloop *ml)
Initialize the mainloop object.
Definition: ipc_server_mainloop_android.c:142
char * socket_filename
The socket filename we bound to, if any.
Definition: ipc_server.h:285
pthread_mutex_t client_push_mutex
Mutex for being able to register oneself as a new client.
Definition: ipc_server.h:235
void ipc_server_mainloop_poll(struct ipc_server *vs, struct ipc_server_mainloop *ml)
Poll the mainloop.
Definition: ipc_server_mainloop_android.c:119
HANDLE pipe_handle
Named Pipe that we accept connections on.
Definition: ipc_server.h:299
Main IPC object for the server.
Definition: ipc_server.h:345
struct u_process * process
Handle for the current process, e.g. pidfile on linux.
Definition: ipc_server.h:349
struct xrt_system_compositor * xsysc
System compositor.
Definition: ipc_server.h:363
struct xrt_space_overseer * xso
Space overseer.
Definition: ipc_server.h:360
uint32_t id_generator
Generator for IDs.
Definition: ipc_server.h:394
struct xrt_system * xsys
The XRT interfaces level system.
Definition: ipc_server.h:354
struct xrt_system_devices * xsysd
System devices.
Definition: ipc_server.h:357
A big struct that contains all data that is shared to a client, no pointers allowed in this.
Definition: ipc_protocol.h:190
Information about a single swapchain.
Definition: ipc_server.h:73
Definition: ipc_server.h:173
A wrapper around a native mutex.
Definition: os_threading.h:55
A wrapper around a native thread.
Definition: os_threading.h:284
Definition: u_worker.c:37
Definition: u_process.c:43
Main compositor server interface.
Definition: xrt_compositor.h:2234
Compositor semaphore used for synchronization, needs to be as capable as a Vulkan pipeline semaphore.
Definition: xrt_compositor.h:791
Common compositor client interface/base.
Definition: xrt_compositor.h:998
A single HMD or input device.
Definition: xrt_device.h:282
This interface acts as a root object for Monado.
Definition: xrt_instance.h:117
The XRT representation of XrSession, this object does not have all of the functionality of a session,...
Definition: xrt_session.h:259
Object that oversees and manages spaces, one created for each XR system.
Definition: xrt_space.h:96
A space very similar to a OpenXR XrSpace but not a full one-to-one mapping, but used to power XrSpace...
Definition: xrt_space.h:31
Common swapchain interface/base.
Definition: xrt_compositor.h:539
The system compositor handles composition for a system.
Definition: xrt_compositor.h:2427
A collection of xrt_device, and an interface for identifying the roles they have been assigned.
Definition: xrt_system.h:221
Properties provided by the system.
Definition: xrt_system.h:43
A system is a collection of devices, policies and optionally a compositor that is organised into a ch...
Definition: xrt_system.h:62
A tracking system or device origin.
Definition: xrt_tracking.h:71
Basic logging functionality.
Header holding common defines.
int xrt_ipc_handle_t
The type for an IPC handle.
Definition: xrt_handles.h:74
Header for limits of the XRT interfaces.
Header defining xrt space and space overseer.
Header for system objects.