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_system.h"
16 #include "xrt/xrt_space.h"
17 
18 #include "os/os_threading.h"
19 
20 #include "util/u_logging.h"
21 
22 #include "shared/ipc_protocol.h"
24 
25 #include <stdio.h>
26 
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 /*
33  *
34  * Logging
35  *
36  */
37 
38 #define IPC_TRACE(d, ...) U_LOG_IFL_T(d->log_level, __VA_ARGS__)
39 #define IPC_DEBUG(d, ...) U_LOG_IFL_D(d->log_level, __VA_ARGS__)
40 #define IPC_INFO(d, ...) U_LOG_IFL_I(d->log_level, __VA_ARGS__)
41 #define IPC_WARN(d, ...) U_LOG_IFL_W(d->log_level, __VA_ARGS__)
42 #define IPC_ERROR(d, ...) U_LOG_IFL_E(d->log_level, __VA_ARGS__)
43 
44 
45 /*
46  *
47  * Structs
48  *
49  */
50 
51 #define IPC_MAX_CLIENT_SEMAPHORES 8
52 #define IPC_MAX_CLIENT_SWAPCHAINS 32
53 #define IPC_MAX_CLIENT_SPACES 128
54 
55 struct xrt_instance;
56 struct xrt_compositor;
58 
59 
60 /*!
61  * Information about a single swapchain.
62  *
63  * @ingroup ipc_server
64  */
66 {
67  uint32_t width;
68  uint32_t height;
69  uint64_t format;
70  uint32_t image_count;
71 
72  bool active;
73 };
74 
75 /*!
76  * Holds the state for a single client.
77  *
78  * @ingroup ipc_server
79  */
81 {
82  //! Link back to the main server.
83  struct ipc_server *server;
84 
85  //! Session for this client.
86  struct xrt_session *xs;
87 
88  //! Compositor for this client.
89  struct xrt_compositor *xc;
90 
91  //! Is the inputs and outputs active.
92  bool io_active;
93 
94  //! Number of swapchains in use by client
95  uint32_t swapchain_count;
96 
97  //! Ptrs to the swapchains
98  struct xrt_swapchain *xscs[IPC_MAX_CLIENT_SWAPCHAINS];
99 
100  //! Data for the swapchains.
101  struct ipc_swapchain_data swapchain_data[IPC_MAX_CLIENT_SWAPCHAINS];
102 
103  //! Number of compositor semaphores in use by client
105 
106  //! Ptrs to the semaphores.
107  struct xrt_compositor_semaphore *xcsems[IPC_MAX_CLIENT_SEMAPHORES];
108 
109  struct
110  {
111  uint32_t root;
112  uint32_t local;
113  uint32_t stage;
114  uint32_t unbounded;
115  } semantic_spaces;
116 
117  //! Number of spaces.
118  uint32_t space_count;
119 
120  //! Ptrs to the spaces.
121  struct xrt_space *xspcs[IPC_MAX_CLIENT_SPACES];
122 
123  //! Which of the references spaces is the client using.
125 
126  //! Socket fd used for client comms
127  struct ipc_message_channel imc;
128 
129  struct ipc_app_state client_state;
130 
131  int server_thread_index;
132 };
133 
134 enum ipc_thread_state
135 {
136  IPC_THREAD_READY,
137  IPC_THREAD_STARTING,
138  IPC_THREAD_RUNNING,
139  IPC_THREAD_STOPPING,
140 };
141 
143 {
144  struct os_thread thread;
145  volatile enum ipc_thread_state state;
146  volatile struct ipc_client_state ics;
147 };
148 
149 
150 /*!
151  *
152  */
154 {
155  //! The actual device.
156  struct xrt_device *xdev;
157 
158  //! Is the IO suppressed for this device.
159  bool io_active;
160 };
161 
162 /*!
163  * Platform-specific mainloop object for the IPC server.
164  *
165  * Contents are essentially implementation details, but are listed in full here so they may be included by value in the
166  * main ipc_server struct.
167  *
168  * @see ipc_design
169  *
170  * @ingroup ipc_server
171  */
173 {
174 
175 #if defined(XRT_OS_ANDROID) || defined(XRT_OS_LINUX) || defined(XRT_DOXYGEN)
176  //! For waiting on various events in the main thread.
177  int epoll_fd;
178 #endif
179 
180 #if defined(XRT_OS_ANDROID) || defined(XRT_DOXYGEN)
181  /*!
182  * @name Android Mainloop Members
183  * @{
184  */
185 
186  //! File descriptor for the read end of our pipe for submitting new clients
188 
189  /*!
190  * File descriptor for the write end of our pipe for submitting new clients
191  *
192  * Must hold client_push_mutex while writing.
193  */
195 
196  /*!
197  * Mutex for being able to register oneself as a new client.
198  *
199  * Locked only by threads in `ipc_server_mainloop_add_fd()`.
200  *
201  * This must be locked first, and kept locked the entire time a client is attempting to register and wait for
202  * confirmation. It ensures no acknowledgements of acceptance are lost and moves the overhead of ensuring this
203  * to the client thread.
204  */
205  pthread_mutex_t client_push_mutex;
206 
207 
208  /*!
209  * The last client fd we accepted, to acknowledge client acceptance.
210  *
211  * Also used as a sentinel during shutdown.
212  *
213  * Must hold accept_mutex while writing.
214  */
216 
217  /*!
218  * Condition variable for accepting clients.
219  *
220  * Signalled when @ref last_accepted_fd is updated.
221  *
222  * Associated with @ref accept_mutex
223  */
224  pthread_cond_t accept_cond;
225 
226  /*!
227  * Mutex for accepting clients.
228  *
229  * Locked by both clients and server: that is, by threads in `ipc_server_mainloop_add_fd()` and in the
230  * server/compositor thread in an implementation function called from `ipc_server_mainloop_poll()`.
231  *
232  * Exists to operate in conjunction with @ref accept_cond - it exists to make sure that the client can be woken
233  * when the server accepts it.
234  */
235  pthread_mutex_t accept_mutex;
236 
237 
238  /*! @} */
239 #define XRT_IPC_GOT_IMPL
240 #endif
241 
242 #if (defined(XRT_OS_LINUX) && !defined(XRT_OS_ANDROID)) || defined(XRT_DOXYGEN)
243  /*!
244  * @name Desktop Linux Mainloop Members
245  * @{
246  */
247 
248  //! Socket that we accept connections on.
250 
251  //! Were we launched by socket activation, instead of explicitly?
253 
254  //! The socket filename we bound to, if any.
256 
257  /*! @} */
258 
259 #define XRT_IPC_GOT_IMPL
260 #endif
261 
262 #if defined(XRT_OS_WINDOWS) || defined(XRT_DOXYGEN)
263  /*!
264  * @name Desktop Windows Mainloop Members
265  * @{
266  */
267 
268  //! Named Pipe that we accept connections on.
269  HANDLE pipe_handle;
270 
271  //! Name of the Pipe that we accept connections on.
272  char *pipe_name;
273 
274  /*! @} */
275 
276 #define XRT_IPC_GOT_IMPL
277 #endif
278 
279 #ifndef XRT_IPC_GOT_IMPL
280 #error "Need port"
281 #endif
282 };
283 
284 /*!
285  * De-initialize the mainloop object.
286  * @public @memberof ipc_server_mainloop
287  */
288 void
290 
291 /*!
292  * Initialize the mainloop object.
293  *
294  * @return <0 on error.
295  * @public @memberof ipc_server_mainloop
296  */
297 int
299 
300 /*!
301  * @brief Poll the mainloop.
302  *
303  * Any errors are signalled by calling ipc_server_handle_failure()
304  * @public @memberof ipc_server_mainloop
305  */
306 void
308 
309 /*!
310  * Main IPC object for the server.
311  *
312  * @ingroup ipc_server
313  */
315 {
316  struct xrt_instance *xinst;
317 
318  //! Handle for the current process, e.g. pidfile on linux
320 
321  struct u_debug_gui *debug_gui;
322 
323  //! The @ref xrt_iface level system.
324  struct xrt_system *xsys;
325 
326  //! System devices.
328 
329  //! Space overseer.
331 
332  //! System compositor.
334 
335  struct ipc_device idevs[XRT_SYSTEM_MAX_DEVICES];
337 
338  struct ipc_shared_memory *ism;
339  xrt_shmem_handle_t ism_handle;
340 
341  struct ipc_server_mainloop ml;
342 
343  // Is the mainloop supposed to run.
344  volatile bool running;
345 
346  // Should we exit when a client disconnects.
347  bool exit_on_disconnect;
348 
349  enum u_logging_level log_level;
350 
351  struct ipc_thread threads[IPC_MAX_CLIENTS];
352 
353  volatile uint32_t current_slot_index;
354 
355  //! Generator for IDs.
356  uint32_t id_generator;
357 
358  struct
359  {
360  int active_client_index;
361  int last_active_client_index;
362 
363  struct os_mutex lock;
364  } global_state;
365 };
366 
367 
368 /*!
369  * Get the current state of a client.
370  *
371  * @ingroup ipc_server
372  */
374 ipc_server_get_client_app_state(struct ipc_server *s, uint32_t client_id, struct ipc_app_state *out_ias);
375 
376 /*!
377  * Set the new active client.
378  *
379  * @ingroup ipc_server
380  */
382 ipc_server_set_active_client(struct ipc_server *s, uint32_t client_id);
383 
384 /*!
385  * Toggle the io for this client.
386  *
387  * @ingroup ipc_server
388  */
390 ipc_server_toggle_io_client(struct ipc_server *s, uint32_t client_id);
391 
392 /*!
393  * Called by client threads to set a session to active.
394  *
395  * @ingroup ipc_server
396  */
397 void
398 ipc_server_activate_session(volatile struct ipc_client_state *ics);
399 
400 /*!
401  * Called by client threads to set a session to deactivate.
402  *
403  * @ingroup ipc_server
404  */
405 void
406 ipc_server_deactivate_session(volatile struct ipc_client_state *ics);
407 
408 /*!
409  * Called by client threads to recalculate active client.
410  *
411  * @ingroup ipc_server
412  */
413 void
415 
416 /*!
417  * Thread function for the client side dispatching.
418  *
419  * @ingroup ipc_server
420  */
421 void *
422 ipc_server_client_thread(void *_ics);
423 
424 /*!
425  * This destroys the native compositor for this client and any extra objects
426  * created from it, like all of the swapchains.
427  */
428 void
430 
431 /*!
432  * @defgroup ipc_server_internals Server Internals
433  * @brief These are only called by the platform-specific mainloop polling code.
434  * @ingroup ipc_server
435  * @{
436  */
437 /*!
438  * Called when a client has connected, it takes the client's ipc handle.
439  * Handles all things needed to be done for a client connecting, like starting
440  * it's thread.
441  *
442  * @param vs The IPC server.
443  * @param ipc_handle Handle to communicate over.
444  * @memberof ipc_server
445  */
446 void
448 
449 /*!
450  * Perform whatever needs to be done when the mainloop polling encounters a failure.
451  * @memberof ipc_server
452  */
453 void
455 
456 /*!
457  * Perform whatever needs to be done when the mainloop polling identifies that the server should be shut down.
458  *
459  * Does something like setting a flag or otherwise signalling for shutdown: does not itself explicitly exit.
460  * @memberof ipc_server
461  */
462 void
464 
466 ipc_server_get_system_properties(struct ipc_server *vs, struct xrt_system_properties *out_properties);
467 //! @}
468 
469 /*
470  *
471  * Helpers
472  *
473  */
474 
475 /*!
476  * Get a xdev with the given device_id.
477  */
478 static inline struct xrt_device *
479 get_xdev(volatile struct ipc_client_state *ics, uint32_t device_id)
480 {
481  return ics->server->idevs[device_id].xdev;
482 }
483 
484 /*!
485  * Get a idev with the given device_id.
486  */
487 static inline struct ipc_device *
488 get_idev(volatile struct ipc_client_state *ics, uint32_t device_id)
489 {
490  return &ics->server->idevs[device_id];
491 }
492 
493 
494 #ifdef __cplusplus
495 }
496 #endif
Generic typedef for platform-specific shared memory handle.
u_logging_level
Logging level enum.
Definition: u_logging.h:40
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:906
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:900
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:893
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:803
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:867
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:833
void ipc_server_update_state(struct ipc_server *s)
Called by client threads to recalculate active client.
Definition: ipc_server_process.c:882
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:813
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:823
void * ipc_server_client_thread(void *_ics)
Thread function for the client side dispatching.
Definition: ipc_server_per_client_thread.c:328
#define XRT_SYSTEM_MAX_DEVICES
Maximum number of devices simultaneously usable by an implementation of xrt_system_devices.
Definition: xrt_system.h:140
#define XRT_SPACE_REFERENCE_TYPE_COUNT
The number of enumerations in xrt_reference_space_type.
Definition: xrt_defines.h:612
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:297
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:488
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:479
Wrapper around OS threading native functions.
State for a connected application.
Definition: ipc_protocol.h:303
Holds the state for a single client.
Definition: ipc_server.h:81
uint32_t swapchain_count
Number of swapchains in use by client.
Definition: ipc_server.h:95
struct xrt_swapchain * xscs[32]
Ptrs to the swapchains.
Definition: ipc_server.h:98
struct xrt_session * xs
Session for this client.
Definition: ipc_server.h:86
struct ipc_message_channel imc
Socket fd used for client comms.
Definition: ipc_server.h:127
struct ipc_server * server
Link back to the main server.
Definition: ipc_server.h:83
uint32_t compositor_semaphore_count
Number of compositor semaphores in use by client.
Definition: ipc_server.h:104
struct xrt_space * xspcs[128]
Ptrs to the spaces.
Definition: ipc_server.h:121
bool ref_space_used[XRT_SPACE_REFERENCE_TYPE_COUNT]
Which of the references spaces is the client using.
Definition: ipc_server.h:124
struct xrt_compositor_semaphore * xcsems[8]
Ptrs to the semaphores.
Definition: ipc_server.h:107
uint32_t space_count
Number of spaces.
Definition: ipc_server.h:118
bool io_active
Is the inputs and outputs active.
Definition: ipc_server.h:92
struct xrt_compositor * xc
Compositor for this client.
Definition: ipc_server.h:89
struct ipc_swapchain_data swapchain_data[32]
Data for the swapchains.
Definition: ipc_server.h:101
Definition: ipc_server.h:154
bool io_active
Is the IO suppressed for this device.
Definition: ipc_server.h:159
struct xrt_device * xdev
The actual device.
Definition: ipc_server.h:156
Wrapper for a socket and flags.
Definition: ipc_message_channel.h:30
Platform-specific mainloop object for the IPC server.
Definition: ipc_server.h:173
bool launched_by_socket
Were we launched by socket activation, instead of explicitly?
Definition: ipc_server.h:252
pthread_cond_t accept_cond
Condition variable for accepting clients.
Definition: ipc_server.h:224
char * pipe_name
Name of the Pipe that we accept connections on.
Definition: ipc_server.h:272
int last_accepted_fd
The last client fd we accepted, to acknowledge client acceptance.
Definition: ipc_server.h:215
int epoll_fd
For waiting on various events in the main thread.
Definition: ipc_server.h:177
void ipc_server_mainloop_deinit(struct ipc_server_mainloop *ml)
De-initialize the mainloop object.
Definition: ipc_server_mainloop_android.c:161
pthread_mutex_t accept_mutex
Mutex for accepting clients.
Definition: ipc_server.h:235
int pipe_read
File descriptor for the read end of our pipe for submitting new clients.
Definition: ipc_server.h:187
int listen_socket
Socket that we accept connections on.
Definition: ipc_server.h:249
int pipe_write
File descriptor for the write end of our pipe for submitting new clients.
Definition: ipc_server.h:194
int ipc_server_mainloop_init(struct ipc_server_mainloop *ml)
Initialize the mainloop object.
Definition: ipc_server_mainloop_android.c:143
char * socket_filename
The socket filename we bound to, if any.
Definition: ipc_server.h:255
pthread_mutex_t client_push_mutex
Mutex for being able to register oneself as a new client.
Definition: ipc_server.h:205
void ipc_server_mainloop_poll(struct ipc_server *vs, struct ipc_server_mainloop *ml)
Poll the mainloop.
Definition: ipc_server_mainloop_android.c:120
HANDLE pipe_handle
Named Pipe that we accept connections on.
Definition: ipc_server.h:269
Main IPC object for the server.
Definition: ipc_server.h:315
struct u_process * process
Handle for the current process, e.g. pidfile on linux.
Definition: ipc_server.h:319
struct xrt_system_compositor * xsysc
System compositor.
Definition: ipc_server.h:333
struct xrt_space_overseer * xso
Space overseer.
Definition: ipc_server.h:330
uint32_t id_generator
Generator for IDs.
Definition: ipc_server.h:356
struct xrt_system * xsys
The XRT interfaces level system.
Definition: ipc_server.h:324
struct xrt_system_devices * xsysd
System devices.
Definition: ipc_server.h:327
A big struct that contains all data that is shared to a client, no pointers allowed in this.
Definition: ipc_protocol.h:195
Information about a single swapchain.
Definition: ipc_server.h:66
Definition: ipc_server.h:143
A wrapper around a native mutex.
Definition: os_threading.h:55
A wrapper around a native thread.
Definition: os_threading.h:272
Definition: u_worker.c:37
Definition: u_process.c:43
Main compositor server interface.
Definition: xrt_compositor.h:2196
Compositor semaphore used for synchronization, needs to be as capable as a Vulkan pipeline semaphore.
Definition: xrt_compositor.h:788
Common compositor client interface/base.
Definition: xrt_compositor.h:986
A single HMD or input device.
Definition: xrt_device.h:230
This interface acts as a root object for Monado.
Definition: xrt_instance.h:67
The XRT representation of XrSession, this object does not have all of the functionality of a session,...
Definition: xrt_session.h:233
Object that oversees and manages spaces, one created for each XR system.
Definition: xrt_space.h:95
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:30
Common swapchain interface/base.
Definition: xrt_compositor.h:536
The system compositor handles composition for a system.
Definition: xrt_compositor.h:2386
A collection of xrt_device, and an interface for identifying the roles they have been assigned.
Definition: xrt_system.h:218
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:61
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 defining xrt space and space overseer.
Header for system objects.