The open source OpenXR runtime

ipc: Refactor folders

authored by

Jakob Bornecrantz and committed by
Ryan Pavlik
3008e548 5ba34866

+546 -517
+1 -1
settings.gradle
··· 4 4 rootProject.name = 'monado' 5 5 6 6 include ':src:xrt:auxiliary:android' 7 - include ':src:xrt:ipc_android' 7 + include ':src:xrt:ipc:android' 8 8 include ':src:xrt:targets:openxr_android'
+17 -17
src/xrt/ipc/CMakeLists.txt
··· 7 7 8 8 function(proto_gen output) 9 9 add_custom_command(OUTPUT ${output} 10 - COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/proto.py 11 - ${CMAKE_CURRENT_SOURCE_DIR}/proto.json 10 + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py 11 + ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.json 12 12 ${output} 13 - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/proto.py 14 - ${CMAKE_CURRENT_SOURCE_DIR}/ipcproto/common.py 15 - ${CMAKE_CURRENT_SOURCE_DIR}/proto.json 13 + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py 14 + ${CMAKE_CURRENT_SOURCE_DIR}/shared/ipcproto/common.py 15 + ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.json 16 16 ) 17 17 endfunction(proto_gen) 18 18 ··· 24 24 25 25 set(IPC_COMMON_SOURCES 26 26 ${CMAKE_CURRENT_BINARY_DIR}/ipc_protocol_generated.h 27 - ipc_shmem.c 28 - ipc_shmem.h 29 - ipc_utils.c 30 - ipc_utils.h) 27 + shared/ipc_shmem.c 28 + shared/ipc_shmem.h 29 + shared/ipc_utils.c 30 + shared/ipc_utils.h) 31 31 ### 32 32 # Client 33 33 ··· 35 35 ${CMAKE_CURRENT_BINARY_DIR}/ipc_client_generated.c 36 36 ${CMAKE_CURRENT_BINARY_DIR}/ipc_client_generated.h 37 37 ${IPC_COMMON_SOURCES} 38 - ipc_client.h 39 - ipc_client_compositor.c 40 - ipc_client_device.c 41 - ipc_client_hmd.c 42 - ipc_client_instance.c 38 + client/ipc_client.h 39 + client/ipc_client_compositor.c 40 + client/ipc_client_device.c 41 + client/ipc_client_hmd.c 42 + client/ipc_client_instance.c 43 43 ) 44 44 target_include_directories(ipc_client INTERFACE 45 45 ${CMAKE_CURRENT_SOURCE_DIR} ··· 65 65 ${CMAKE_CURRENT_BINARY_DIR}/ipc_server_generated.c 66 66 ${CMAKE_CURRENT_BINARY_DIR}/ipc_server_generated.h 67 67 ${IPC_COMMON_SOURCES} 68 - ipc_server.h 69 - ipc_server_client.c 70 - ipc_server_process.c 68 + server/ipc_server.h 69 + server/ipc_server_client.c 70 + server/ipc_server_process.c 71 71 ) 72 72 target_include_directories(ipc_server 73 73 INTERFACE
+2 -2
src/xrt/ipc/ipc_client.h src/xrt/ipc/client/ipc_client.h
··· 11 11 #pragma once 12 12 13 13 #include "xrt/xrt_compiler.h" 14 - #include "ipc_protocol.h" 15 - #include "ipc_utils.h" 14 + #include "shared/ipc_protocol.h" 15 + #include "shared/ipc_utils.h" 16 16 17 17 #include "util/u_threading.h" 18 18
+2 -2
src/xrt/ipc/ipc_client_compositor.c src/xrt/ipc/client/ipc_client_compositor.c
··· 16 16 17 17 #include "os/os_time.h" 18 18 19 - #include "ipc_protocol.h" 20 - #include "ipc_client.h" 19 + #include "shared/ipc_protocol.h" 20 + #include "client/ipc_client.h" 21 21 #include "ipc_client_generated.h" 22 22 23 23 #include <string.h>
+1 -1
src/xrt/ipc/ipc_client_device.c src/xrt/ipc/client/ipc_client_device.c
··· 25 25 #include "util/u_debug.h" 26 26 #include "util/u_device.h" 27 27 28 - #include "ipc_client.h" 28 + #include "client/ipc_client.h" 29 29 #include "ipc_client_generated.h" 30 30 31 31
+1 -1
src/xrt/ipc/ipc_client_hmd.c src/xrt/ipc/client/ipc_client_hmd.c
··· 26 26 #include "util/u_device.h" 27 27 #include "util/u_distortion_mesh.h" 28 28 29 - #include "ipc_client.h" 29 + #include "client/ipc_client.h" 30 30 #include "ipc_client_generated.h" 31 31 32 32
+2 -2
src/xrt/ipc/ipc_client_instance.c src/xrt/ipc/client/ipc_client_instance.c
··· 14 14 #include "util/u_misc.h" 15 15 #include "util/u_var.h" 16 16 17 - #include "ipc_protocol.h" 18 - #include "ipc_client.h" 17 + #include "shared/ipc_protocol.h" 18 + #include "client/ipc_client.h" 19 19 #include "ipc_client_generated.h" 20 20 21 21 #include <stdio.h>
-39
src/xrt/ipc/ipc_documentation.h
··· 1 - // Copyright 2020, Collabora, Ltd. 2 - // SPDX-License-Identifier: BSL-1.0 3 - /*! 4 - * @file 5 - * @brief IPC documentation. 6 - * @author Jakob Bornecrantz <jakob@collabora.com> 7 - * @ingroup ipc 8 - */ 9 - 10 - #pragma once 11 - 12 - 13 - /*! 14 - * @defgroup ipc Inter-Process Communication 15 - * @ingroup xrt 16 - * 17 - * @brief Inter-Process Communication layer for Monado. 18 - */ 19 - 20 - /*! 21 - * @defgroup ipc_client Client IPC 22 - * @ingroup ipc 23 - * 24 - * @brief Client side IPC code. 25 - */ 26 - 27 - /*! 28 - * @defgroup ipc_server Server IPC 29 - * @ingroup ipc 30 - * 31 - * @brief Server side IPC code. 32 - */ 33 - 34 - /*! 35 - * @dir xrt/ipc 36 - * @ingroup xrt 37 - * 38 - * @brief Inter-Process Communication layer 39 - */
src/xrt/ipc/ipc_protocol.h src/xrt/ipc/shared/ipc_protocol.h
+2 -2
src/xrt/ipc/ipc_server.h src/xrt/ipc/server/ipc_server.h
··· 16 16 17 17 #include "os/os_threading.h" 18 18 19 - #include "ipc_protocol.h" 20 - #include "ipc_utils.h" 19 + #include "shared/ipc_protocol.h" 20 + #include "shared/ipc_utils.h" 21 21 22 22 #include <stdio.h> 23 23
+1 -1
src/xrt/ipc/ipc_server_client.c src/xrt/ipc/server/ipc_server_client.c
··· 11 11 12 12 #include "util/u_misc.h" 13 13 14 - #include "ipc_server.h" 14 + #include "server/ipc_server.h" 15 15 #include "ipc_server_generated.h" 16 16 17 17 #include <stdlib.h>
+2 -2
src/xrt/ipc/ipc_server_process.c src/xrt/ipc/server/ipc_server_process.c
··· 18 18 #include "util/u_misc.h" 19 19 #include "util/u_debug.h" 20 20 21 - #include "ipc_server.h" 22 - #include "ipc_shmem.h" 21 + #include "shared/ipc_shmem.h" 22 + #include "server/ipc_server.h" 23 23 24 24 #include <stdlib.h> 25 25 #include <unistd.h>
+1 -1
src/xrt/ipc/ipc_shmem.c src/xrt/ipc/shared/ipc_shmem.c
··· 11 11 12 12 #include <xrt/xrt_config_os.h> 13 13 14 - #include "ipc_shmem.h" 14 + #include "shared/ipc_shmem.h" 15 15 16 16 #if defined(XRT_OS_UNIX) 17 17 #include <sys/mman.h>
src/xrt/ipc/ipc_shmem.h src/xrt/ipc/shared/ipc_shmem.h
+2 -2
src/xrt/ipc/ipc_utils.c src/xrt/ipc/shared/ipc_utils.c
··· 11 11 12 12 #include "xrt/xrt_config_os.h" 13 13 14 - #include "ipc_utils.h" 15 - #include "ipc_protocol.h" 14 + #include "shared/ipc_utils.h" 15 + #include "shared/ipc_protocol.h" 16 16 17 17 #include <errno.h> 18 18 #include <sys/socket.h>
src/xrt/ipc/ipc_utils.h src/xrt/ipc/shared/ipc_utils.h
src/xrt/ipc/ipcproto/__init__.py src/xrt/ipc/shared/ipcproto/__init__.py
src/xrt/ipc/ipcproto/common.py src/xrt/ipc/shared/ipcproto/common.py
+13 -13
src/xrt/ipc/meson.build
··· 9 9 prog_python = import('python').find_installation('python3') 10 10 11 11 common_sources = [ 12 - 'ipc_shmem.c', 13 - 'ipc_shmem.h', 14 - 'ipc_utils.c', 15 - 'ipc_utils.h', 12 + 'shared/ipc_shmem.c', 13 + 'shared/ipc_shmem.h', 14 + 'shared/ipc_utils.c', 15 + 'shared/ipc_utils.h', 16 16 ] 17 17 18 18 generated = custom_target('protocol code', 19 19 command: [prog_python, '@INPUT@', '@OUTPUT@'], 20 - input: ['proto.py', 'proto.json'], 20 + input: ['shared/proto.py', 'shared/proto.json'], 21 21 output: [ 22 22 'ipc_protocol_generated.h', 23 23 'ipc_client_generated.c', ··· 38 38 generated[0], 39 39 generated[1], 40 40 generated[2], 41 - 'ipc_client.h', 42 - 'ipc_client_compositor.c', 43 - 'ipc_client_device.c', 44 - 'ipc_client_hmd.c', 45 - 'ipc_client_instance.c', 41 + 'client/ipc_client.h', 42 + 'client/ipc_client_compositor.c', 43 + 'client/ipc_client_device.c', 44 + 'client/ipc_client_hmd.c', 45 + 'client/ipc_client_instance.c', 46 46 ], 47 47 include_directories: [ 48 48 xrt_include, ··· 60 60 generated[0], 61 61 generated[3], 62 62 generated[4], 63 - 'ipc_server.h', 64 - 'ipc_server_client.c', 65 - 'ipc_server_process.c', 63 + 'server/ipc_server.h', 64 + 'server/ipc_server_client.c', 65 + 'server/ipc_server_process.c', 66 66 ], 67 67 include_directories: [ 68 68 xrt_include,
src/xrt/ipc/proto.json src/xrt/ipc/shared/proto.json
-429
src/xrt/ipc/proto.py
··· 1 - #!/usr/bin/env python3 2 - # Copyright 2020, Collabora, Ltd. 3 - # SPDX-License-Identifier: BSL-1.0 4 - """Generate code from a JSON file describing the IPC protocol.""" 5 - 6 - import argparse 7 - 8 - from ipcproto.common import (Proto, write_decl, write_invocation, 9 - write_result_handler) 10 - 11 - header = '''// Copyright 2020, Collabora, Ltd. 12 - // SPDX-License-Identifier: BSL-1.0 13 - /*! 14 - * @file 15 - * @brief {brief}. 16 - * @author Jakob Bornecrantz <jakob@collabora.com> 17 - * @ingroup ipc{suffix} 18 - */ 19 - ''' 20 - 21 - 22 - def generate_h(file, p): 23 - """Generate protocol header. 24 - 25 - Defines command enum, utility functions, and command and reply structures. 26 - """ 27 - f = open(file, "w") 28 - f.write(header.format(brief='Generated IPC protocol header', suffix='')) 29 - f.write(''' 30 - #pragma once 31 - 32 - 33 - // clang-format off 34 - 35 - struct ipc_connection; 36 - ''') 37 - 38 - f.write(''' 39 - typedef enum ipc_command 40 - { 41 - \tIPC_ERR = 0,''') 42 - for call in p.calls: 43 - f.write("\n\t" + call.id + ",") 44 - f.write("\n} ipc_command_t;\n") 45 - 46 - f.write(''' 47 - struct ipc_command_msg 48 - { 49 - \tenum ipc_command cmd; 50 - }; 51 - 52 - struct ipc_result_reply 53 - { 54 - \txrt_result_t result; 55 - }; 56 - 57 - ''') 58 - 59 - f.write(''' 60 - static inline const char * 61 - ipc_cmd_to_str(ipc_command_t id) 62 - { 63 - \tswitch (id) { 64 - \tcase IPC_ERR: return "IPC_ERR";''') 65 - for call in p.calls: 66 - f.write("\n\tcase " + call.id + ": return \"" + call.id + "\";") 67 - f.write("\n\tdefault: return \"IPC_UNKNOWN\";") 68 - f.write("\n\t}\n}\n") 69 - 70 - for call in p.calls: 71 - # Should we emit a msg struct. 72 - if call.needs_msg_struct: 73 - f.write("\nstruct ipc_" + call.name + "_msg\n") 74 - f.write("{\n") 75 - f.write("\tenum ipc_command cmd;\n") 76 - for arg in call.in_args: 77 - f.write("\t" + arg.get_struct_field() + ";\n") 78 - if call.in_handles: 79 - f.write("\t%s %s;\n" % (call.in_handles.count_arg_type, 80 - call.in_handles.count_arg_name)) 81 - f.write("};\n") 82 - # Should we emit a reply struct. 83 - if call.out_args: 84 - f.write("\nstruct ipc_" + call.name + "_reply\n") 85 - f.write("{\n") 86 - f.write("\txrt_result_t result;\n") 87 - for arg in call.out_args: 88 - f.write("\t" + arg.get_struct_field() + ";\n") 89 - f.write("};\n") 90 - 91 - f.write("\n// clang-format on\n") 92 - f.close() 93 - 94 - 95 - def generate_client_c(file, p): 96 - """Generate IPC client proxy source.""" 97 - f = open(file, "w") 98 - f.write(header.format(brief='Generated IPC client code', suffix='_client')) 99 - f.write(''' 100 - #include "ipc_client.h" 101 - #include "ipc_protocol_generated.h" 102 - 103 - 104 - // clang-format off 105 - \n''') 106 - 107 - # Loop over all of the calls. 108 - for call in p.calls: 109 - call.write_call_decl(f) 110 - f.write("\n{\n") 111 - 112 - # Message struct 113 - if call.needs_msg_struct: 114 - f.write("\tstruct ipc_" + call.name + "_msg _msg = {\n") 115 - else: 116 - f.write("\tstruct ipc_command_msg _msg = {\n") 117 - f.write("\t .cmd = " + str(call.id) + ",\n") 118 - for arg in call.in_args: 119 - if arg.is_aggregate: 120 - f.write("\t ." + arg.name + " = *" + arg.name + ",\n") 121 - else: 122 - f.write("\t ." + arg.name + " = " + arg.name + ",\n") 123 - if call.in_handles: 124 - f.write("\t ." + call.in_handles.count_arg_name + 125 - " = " + call.in_handles.count_arg_name + ",\n") 126 - f.write("\t};\n") 127 - 128 - # Reply struct 129 - if call.out_args: 130 - f.write("\tstruct ipc_" + call.name + "_reply _reply;\n") 131 - else: 132 - f.write("\tstruct ipc_result_reply _reply = {0};\n") 133 - if call.in_handles: 134 - f.write("\tstruct ipc_result_reply _sync = {0};\n") 135 - 136 - f.write(""" 137 - \t// Other threads must not read/write the fd while we wait for reply 138 - \tos_mutex_lock(&ipc_c->mutex); 139 - """) 140 - cleanup = "os_mutex_unlock(&ipc_c->mutex);" 141 - 142 - # Prepare initial sending 143 - func = 'ipc_send' 144 - args = ['&ipc_c->imc', '&_msg', 'sizeof(_msg)'] 145 - f.write("\n\t// Send our request") 146 - write_invocation(f, 'xrt_result_t ret', func, args, indent="\t") 147 - f.write(';') 148 - write_result_handler(f, 'ret', cleanup, indent="\t") 149 - 150 - if call.in_handles: 151 - f.write("\n\t// Send our handles separately\n") 152 - f.write("\n\t// Wait for server sync") 153 - # Must sync with the server so it's expecting the next message. 154 - write_invocation( 155 - f, 156 - 'ret', 157 - 'ipc_receive', 158 - ( 159 - '&ipc_c->imc', 160 - '&_sync', 161 - 'sizeof(_sync)' 162 - ), 163 - indent="\t" 164 - ) 165 - f.write(';') 166 - write_result_handler(f, 'ret', cleanup, indent="\t") 167 - 168 - # Must send these in a second message 169 - # since the server doesn't know how many to expect. 170 - f.write("\n\t// We need this message data as filler only\n") 171 - f.write("\tstruct ipc_command_msg _handle_msg = {\n") 172 - f.write("\t .cmd = " + str(call.id) + ",\n") 173 - f.write("\t};\n") 174 - write_invocation( 175 - f, 176 - 'ret', 177 - 'ipc_send_handles_' + call.in_handles.stem, 178 - ( 179 - '&ipc_c->imc', 180 - "&_handle_msg", 181 - "sizeof(_handle_msg)", 182 - call.in_handles.arg_name, 183 - call.in_handles.count_arg_name 184 - ), 185 - indent="\t" 186 - ) 187 - f.write(';') 188 - write_result_handler(f, 'ret', cleanup, indent="\t") 189 - 190 - f.write("\n\t// Await the reply") 191 - func = 'ipc_receive' 192 - args = ['&ipc_c->imc', '&_reply', 'sizeof(_reply)'] 193 - if call.out_handles: 194 - func += '_handles_' + call.out_handles.stem 195 - args.extend(call.out_handles.arg_names) 196 - write_invocation(f, 'ret', func, args, indent="\t") 197 - f.write(';') 198 - write_result_handler(f, 'ret', cleanup, indent="\t") 199 - 200 - for arg in call.out_args: 201 - f.write("\t*out_" + arg.name + " = _reply." + arg.name + ";\n") 202 - f.write("\n\t" + cleanup) 203 - f.write("\n\treturn _reply.result;\n}\n") 204 - f.write("\n// clang-format off\n") 205 - f.close() 206 - 207 - 208 - def generate_client_h(file, p): 209 - """Generate IPC client header. 210 - 211 - Contains prototypes for generated IPC proxy call functions. 212 - """ 213 - f = open(file, "w") 214 - f.write(header.format(brief='Generated IPC client code', suffix='_client')) 215 - f.write(''' 216 - #pragma once 217 - 218 - #include "ipc_protocol.h" 219 - #include "ipc_protocol_generated.h" 220 - #include "ipc_client.h" 221 - 222 - 223 - // clang-format off 224 - 225 - ''') 226 - 227 - for call in p.calls: 228 - call.write_call_decl(f) 229 - f.write(";\n") 230 - f.write("\n// clang-format on\n") 231 - f.close() 232 - 233 - 234 - def generate_server_c(file, p): 235 - """Generate IPC server stub/dispatch source.""" 236 - f = open(file, "w") 237 - f.write(header.format(brief='Generated IPC server code', suffix='_server')) 238 - f.write(''' 239 - #include "ipc_server_generated.h" 240 - 241 - #include "ipc_protocol.h" 242 - #include "ipc_server.h" 243 - #include "ipc_utils.h" 244 - 245 - 246 - // clang-format off 247 - 248 - #define MAX_HANDLES 16 249 - ''') 250 - 251 - f.write(''' 252 - xrt_result_t 253 - ipc_dispatch(volatile struct ipc_client_state *ics, ipc_command_t *ipc_command) 254 - { 255 - \tswitch (*ipc_command) { 256 - ''') 257 - 258 - for call in p.calls: 259 - f.write("\tcase " + call.id + ": {\n") 260 - if call.needs_msg_struct: 261 - f.write( 262 - "\t\tstruct ipc_{}_msg *msg =\n".format(call.name)) 263 - f.write( 264 - "\t\t (struct ipc_{}_msg *)ipc_command;\n".format( 265 - call.name)) 266 - if call.out_args: 267 - f.write("\t\tstruct ipc_%s_reply reply = {0};\n" % call.name) 268 - else: 269 - f.write("\t\tstruct ipc_result_reply reply = {0};\n") 270 - if call.in_handles: 271 - f.write("\tstruct ipc_result_reply _sync = {XRT_SUCCESS};\n") 272 - if call.out_handles: 273 - f.write("\t\t%s %s[MAX_HANDLES] = {0};\n" % ( 274 - call.out_handles.typename, call.out_handles.arg_name)) 275 - f.write("\t\t%s %s = {0};\n" % ( 276 - call.out_handles.count_arg_type, 277 - call.out_handles.count_arg_name)) 278 - f.write("\n") 279 - 280 - if call.in_handles: 281 - # We need to fetch these handles separately 282 - f.write("\t\t%s in_%s[MAX_HANDLES] = {0};\n" % ( 283 - call.in_handles.typename, call.in_handles.arg_name)) 284 - f.write("\t\tstruct ipc_command_msg _handle_msg = {0};\n") 285 - 286 - # Let the client know we are ready to receive the handles. 287 - write_invocation( 288 - f, 289 - 'xrt_result_t sync_result', 290 - 'ipc_send', 291 - ( 292 - "(struct ipc_message_channel *)&ics->imc", 293 - "&_sync", 294 - "sizeof(_sync)" 295 - ), 296 - indent="\t\t" 297 - ) 298 - f.write(";") 299 - write_result_handler(f, "sync_result", 300 - indent="\t\t") 301 - write_invocation( 302 - f, 303 - 'xrt_result_t receive_handle_result', 304 - 'ipc_receive_handles_' + call.in_handles.stem, 305 - ( 306 - "(struct ipc_message_channel *)&ics->imc", 307 - "&_handle_msg", 308 - "sizeof(_handle_msg)", 309 - "in_" + call.in_handles.arg_name, 310 - "msg->"+call.in_handles.count_arg_name 311 - ), 312 - indent="\t\t" 313 - ) 314 - f.write(";") 315 - write_result_handler(f, "receive_handle_result", 316 - indent="\t\t") 317 - f.write("\t\tif (_handle_msg.cmd != %s) {\n" % str(call.id)) 318 - f.write("\t\t\treturn XRT_ERROR_IPC_FAILURE;\n") 319 - f.write("\t\t}\n") 320 - 321 - # Write call to ipc_handle_CALLNAME 322 - args = ["ics"] 323 - for arg in call.in_args: 324 - args.append(("&msg->" + arg.name) 325 - if arg.is_aggregate 326 - else ("msg->" + arg.name)) 327 - args.extend("&reply." + arg.name for arg in call.out_args) 328 - if call.out_handles: 329 - args.extend(("MAX_HANDLES", 330 - call.out_handles.arg_name, 331 - "&" + call.out_handles.count_arg_name)) 332 - 333 - if call.in_handles: 334 - args.extend(("&in_%s[0]" % call.in_handles.arg_name, 335 - "msg->"+call.in_handles.count_arg_name)) 336 - write_invocation(f, 'reply.result', 'ipc_handle_' + 337 - call.name, args, indent="\t\t") 338 - f.write(";\n") 339 - 340 - # TODO do we check reply.result and 341 - # error out before replying if it's not success? 342 - 343 - func = 'ipc_send' 344 - args = ["(struct ipc_message_channel *)&ics->imc", 345 - "&reply", 346 - "sizeof(reply)"] 347 - if call.out_handles: 348 - func += '_handles_' + call.out_handles.stem 349 - args.extend(call.out_handles.arg_names) 350 - write_invocation(f, 'xrt_result_t ret', func, args, indent="\t\t") 351 - f.write(";") 352 - f.write("\n\t\treturn ret;\n") 353 - f.write("\t}\n") 354 - f.write('''\tdefault: 355 - \t\tprintf("UNHANDLED IPC MESSAGE! %d\\n", *ipc_command); 356 - \t\treturn XRT_ERROR_IPC_FAILURE; 357 - \t} 358 - } 359 - 360 - // clang-format on 361 - ''') 362 - f.close() 363 - 364 - 365 - def generate_server_header(file, p): 366 - """Generate IPC server header. 367 - 368 - Declares handler prototypes to implement, 369 - as well as the prototype for the generated dispatch function. 370 - """ 371 - f = open(file, "w") 372 - f.write(header.format(brief='Generated IPC server code', suffix='_server')) 373 - f.write(''' 374 - #pragma once 375 - 376 - #include "ipc_protocol.h" 377 - #include "ipc_protocol_generated.h" 378 - #include "ipc_server.h" 379 - 380 - 381 - // clang-format off 382 - ''') 383 - # This decl is constant, but we must write it here 384 - # because it depends on a generated enum. 385 - write_decl( 386 - f, 387 - "xrt_result_t", 388 - "ipc_dispatch", 389 - [ 390 - "volatile struct ipc_client_state *ics", 391 - "ipc_command_t *ipc_command" 392 - ] 393 - ) 394 - f.write(";\n") 395 - 396 - for call in p.calls: 397 - call.write_handler_decl(f) 398 - f.write(";\n") 399 - f.write("\n// clang-format on\n") 400 - f.close() 401 - 402 - 403 - def main(): 404 - """Handle command line and generate a file.""" 405 - parser = argparse.ArgumentParser(description='Protocol generator.') 406 - parser.add_argument( 407 - 'proto', help='Protocol file to use') 408 - parser.add_argument( 409 - 'output', type=str, nargs='+', 410 - help='Output file, uses the name to choose output type') 411 - args = parser.parse_args() 412 - 413 - p = Proto.load_and_parse(args.proto) 414 - 415 - for output in args.output: 416 - if output.endswith("ipc_protocol_generated.h"): 417 - generate_h(output, p) 418 - if output.endswith("ipc_client_generated.c"): 419 - generate_client_c(output, p) 420 - if output.endswith("ipc_client_generated.h"): 421 - generate_client_h(output, p) 422 - if output.endswith("ipc_server_generated.c"): 423 - generate_server_c(output, p) 424 - if output.endswith("ipc_server_generated.h"): 425 - generate_server_header(output, p) 426 - 427 - 428 - if __name__ == "__main__": 429 - main()
src/xrt/ipc/proto.schema.json src/xrt/ipc/shared/proto.schema.json
+67
src/xrt/ipc/shared/ipc_documentation.h
··· 1 + // Copyright 2020, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief IPC documentation. 6 + * @author Jakob Bornecrantz <jakob@collabora.com> 7 + * @ingroup ipc 8 + */ 9 + 10 + #pragma once 11 + 12 + 13 + /*! 14 + * @defgroup ipc Inter-Process Communication 15 + * @ingroup xrt 16 + * 17 + * @brief Inter-Process Communication layer for Monado. 18 + */ 19 + 20 + /*! 21 + * @defgroup ipc_client Client IPC 22 + * @ingroup ipc 23 + * 24 + * @brief Client side IPC code. 25 + */ 26 + 27 + /*! 28 + * @defgroup ipc_server Server IPC 29 + * @ingroup ipc 30 + * 31 + * @brief Server side IPC code. 32 + */ 33 + 34 + /*! 35 + * @dir xrt/ipc 36 + * @ingroup xrt 37 + * 38 + * @brief Inter-Process Communication layer 39 + */ 40 + 41 + /*! 42 + * @dir xrt/ipc/shared 43 + * @ingroup ipc 44 + * 45 + * @brief Inter-Process Communication layer shared code 46 + */ 47 + 48 + /*! 49 + * @dir xrt/ipc/server 50 + * @ingroup ipc 51 + * 52 + * @brief Inter-Process Communication layer server code 53 + */ 54 + 55 + /*! 56 + * @dir xrt/ipc/client 57 + * @ingroup ipc 58 + * 59 + * @brief Inter-Process Communication layer client code 60 + */ 61 + 62 + /*! 63 + * @dir xrt/ipc/android 64 + * @ingroup ipc 65 + * 66 + * @brief Inter-Process Communication layer android code 67 + */
+430
src/xrt/ipc/shared/proto.py
··· 1 + #!/usr/bin/env python3 2 + # Copyright 2020, Collabora, Ltd. 3 + # SPDX-License-Identifier: BSL-1.0 4 + """Generate code from a JSON file describing the IPC protocol.""" 5 + 6 + import argparse 7 + 8 + from ipcproto.common import (Proto, write_decl, write_invocation, 9 + write_result_handler) 10 + 11 + header = '''// Copyright 2020, Collabora, Ltd. 12 + // SPDX-License-Identifier: BSL-1.0 13 + /*! 14 + * @file 15 + * @brief {brief}. 16 + * @author Jakob Bornecrantz <jakob@collabora.com> 17 + * @ingroup ipc{suffix} 18 + */ 19 + ''' 20 + 21 + 22 + def generate_h(file, p): 23 + """Generate protocol header. 24 + 25 + Defines command enum, utility functions, and command and reply structures. 26 + """ 27 + f = open(file, "w") 28 + f.write(header.format(brief='Generated IPC protocol header', suffix='')) 29 + f.write(''' 30 + #pragma once 31 + 32 + 33 + // clang-format off 34 + 35 + struct ipc_connection; 36 + ''') 37 + 38 + f.write(''' 39 + typedef enum ipc_command 40 + { 41 + \tIPC_ERR = 0,''') 42 + for call in p.calls: 43 + f.write("\n\t" + call.id + ",") 44 + f.write("\n} ipc_command_t;\n") 45 + 46 + f.write(''' 47 + struct ipc_command_msg 48 + { 49 + \tenum ipc_command cmd; 50 + }; 51 + 52 + struct ipc_result_reply 53 + { 54 + \txrt_result_t result; 55 + }; 56 + 57 + ''') 58 + 59 + f.write(''' 60 + static inline const char * 61 + ipc_cmd_to_str(ipc_command_t id) 62 + { 63 + \tswitch (id) { 64 + \tcase IPC_ERR: return "IPC_ERR";''') 65 + for call in p.calls: 66 + f.write("\n\tcase " + call.id + ": return \"" + call.id + "\";") 67 + f.write("\n\tdefault: return \"IPC_UNKNOWN\";") 68 + f.write("\n\t}\n}\n") 69 + 70 + for call in p.calls: 71 + # Should we emit a msg struct. 72 + if call.needs_msg_struct: 73 + f.write("\nstruct ipc_" + call.name + "_msg\n") 74 + f.write("{\n") 75 + f.write("\tenum ipc_command cmd;\n") 76 + for arg in call.in_args: 77 + f.write("\t" + arg.get_struct_field() + ";\n") 78 + if call.in_handles: 79 + f.write("\t%s %s;\n" % (call.in_handles.count_arg_type, 80 + call.in_handles.count_arg_name)) 81 + f.write("};\n") 82 + # Should we emit a reply struct. 83 + if call.out_args: 84 + f.write("\nstruct ipc_" + call.name + "_reply\n") 85 + f.write("{\n") 86 + f.write("\txrt_result_t result;\n") 87 + for arg in call.out_args: 88 + f.write("\t" + arg.get_struct_field() + ";\n") 89 + f.write("};\n") 90 + 91 + f.write("\n// clang-format on\n") 92 + f.close() 93 + 94 + 95 + def generate_client_c(file, p): 96 + """Generate IPC client proxy source.""" 97 + f = open(file, "w") 98 + f.write(header.format(brief='Generated IPC client code', suffix='_client')) 99 + f.write(''' 100 + #include "client/ipc_client.h" 101 + #include "ipc_protocol_generated.h" 102 + 103 + 104 + // clang-format off 105 + \n''') 106 + 107 + # Loop over all of the calls. 108 + for call in p.calls: 109 + call.write_call_decl(f) 110 + f.write("\n{\n") 111 + 112 + # Message struct 113 + if call.needs_msg_struct: 114 + f.write("\tstruct ipc_" + call.name + "_msg _msg = {\n") 115 + else: 116 + f.write("\tstruct ipc_command_msg _msg = {\n") 117 + f.write("\t .cmd = " + str(call.id) + ",\n") 118 + for arg in call.in_args: 119 + if arg.is_aggregate: 120 + f.write("\t ." + arg.name + " = *" + arg.name + ",\n") 121 + else: 122 + f.write("\t ." + arg.name + " = " + arg.name + ",\n") 123 + if call.in_handles: 124 + f.write("\t ." + call.in_handles.count_arg_name + 125 + " = " + call.in_handles.count_arg_name + ",\n") 126 + f.write("\t};\n") 127 + 128 + # Reply struct 129 + if call.out_args: 130 + f.write("\tstruct ipc_" + call.name + "_reply _reply;\n") 131 + else: 132 + f.write("\tstruct ipc_result_reply _reply = {0};\n") 133 + if call.in_handles: 134 + f.write("\tstruct ipc_result_reply _sync = {0};\n") 135 + 136 + f.write(""" 137 + \t// Other threads must not read/write the fd while we wait for reply 138 + \tos_mutex_lock(&ipc_c->mutex); 139 + """) 140 + cleanup = "os_mutex_unlock(&ipc_c->mutex);" 141 + 142 + # Prepare initial sending 143 + func = 'ipc_send' 144 + args = ['&ipc_c->imc', '&_msg', 'sizeof(_msg)'] 145 + f.write("\n\t// Send our request") 146 + write_invocation(f, 'xrt_result_t ret', func, args, indent="\t") 147 + f.write(';') 148 + write_result_handler(f, 'ret', cleanup, indent="\t") 149 + 150 + if call.in_handles: 151 + f.write("\n\t// Send our handles separately\n") 152 + f.write("\n\t// Wait for server sync") 153 + # Must sync with the server so it's expecting the next message. 154 + write_invocation( 155 + f, 156 + 'ret', 157 + 'ipc_receive', 158 + ( 159 + '&ipc_c->imc', 160 + '&_sync', 161 + 'sizeof(_sync)' 162 + ), 163 + indent="\t" 164 + ) 165 + f.write(';') 166 + write_result_handler(f, 'ret', cleanup, indent="\t") 167 + 168 + # Must send these in a second message 169 + # since the server doesn't know how many to expect. 170 + f.write("\n\t// We need this message data as filler only\n") 171 + f.write("\tstruct ipc_command_msg _handle_msg = {\n") 172 + f.write("\t .cmd = " + str(call.id) + ",\n") 173 + f.write("\t};\n") 174 + write_invocation( 175 + f, 176 + 'ret', 177 + 'ipc_send_handles_' + call.in_handles.stem, 178 + ( 179 + '&ipc_c->imc', 180 + "&_handle_msg", 181 + "sizeof(_handle_msg)", 182 + call.in_handles.arg_name, 183 + call.in_handles.count_arg_name 184 + ), 185 + indent="\t" 186 + ) 187 + f.write(';') 188 + write_result_handler(f, 'ret', cleanup, indent="\t") 189 + 190 + f.write("\n\t// Await the reply") 191 + func = 'ipc_receive' 192 + args = ['&ipc_c->imc', '&_reply', 'sizeof(_reply)'] 193 + if call.out_handles: 194 + func += '_handles_' + call.out_handles.stem 195 + args.extend(call.out_handles.arg_names) 196 + write_invocation(f, 'ret', func, args, indent="\t") 197 + f.write(';') 198 + write_result_handler(f, 'ret', cleanup, indent="\t") 199 + 200 + for arg in call.out_args: 201 + f.write("\t*out_" + arg.name + " = _reply." + arg.name + ";\n") 202 + f.write("\n\t" + cleanup) 203 + f.write("\n\treturn _reply.result;\n}\n") 204 + f.write("\n// clang-format off\n") 205 + f.close() 206 + 207 + 208 + def generate_client_h(file, p): 209 + """Generate IPC client header. 210 + 211 + Contains prototypes for generated IPC proxy call functions. 212 + """ 213 + f = open(file, "w") 214 + f.write(header.format(brief='Generated IPC client code', suffix='_client')) 215 + f.write(''' 216 + #pragma once 217 + 218 + #include "shared/ipc_protocol.h" 219 + #include "ipc_protocol_generated.h" 220 + #include "client/ipc_client.h" 221 + 222 + 223 + // clang-format off 224 + 225 + ''') 226 + 227 + for call in p.calls: 228 + call.write_call_decl(f) 229 + f.write(";\n") 230 + f.write("\n// clang-format on\n") 231 + f.close() 232 + 233 + 234 + def generate_server_c(file, p): 235 + """Generate IPC server stub/dispatch source.""" 236 + f = open(file, "w") 237 + f.write(header.format(brief='Generated IPC server code', suffix='_server')) 238 + f.write(''' 239 + #include "ipc_server_generated.h" 240 + 241 + #include "shared/ipc_protocol.h" 242 + #include "shared/ipc_utils.h" 243 + 244 + #include "server/ipc_server.h" 245 + 246 + 247 + // clang-format off 248 + 249 + #define MAX_HANDLES 16 250 + ''') 251 + 252 + f.write(''' 253 + xrt_result_t 254 + ipc_dispatch(volatile struct ipc_client_state *ics, ipc_command_t *ipc_command) 255 + { 256 + \tswitch (*ipc_command) { 257 + ''') 258 + 259 + for call in p.calls: 260 + f.write("\tcase " + call.id + ": {\n") 261 + if call.needs_msg_struct: 262 + f.write( 263 + "\t\tstruct ipc_{}_msg *msg =\n".format(call.name)) 264 + f.write( 265 + "\t\t (struct ipc_{}_msg *)ipc_command;\n".format( 266 + call.name)) 267 + if call.out_args: 268 + f.write("\t\tstruct ipc_%s_reply reply = {0};\n" % call.name) 269 + else: 270 + f.write("\t\tstruct ipc_result_reply reply = {0};\n") 271 + if call.in_handles: 272 + f.write("\tstruct ipc_result_reply _sync = {XRT_SUCCESS};\n") 273 + if call.out_handles: 274 + f.write("\t\t%s %s[MAX_HANDLES] = {0};\n" % ( 275 + call.out_handles.typename, call.out_handles.arg_name)) 276 + f.write("\t\t%s %s = {0};\n" % ( 277 + call.out_handles.count_arg_type, 278 + call.out_handles.count_arg_name)) 279 + f.write("\n") 280 + 281 + if call.in_handles: 282 + # We need to fetch these handles separately 283 + f.write("\t\t%s in_%s[MAX_HANDLES] = {0};\n" % ( 284 + call.in_handles.typename, call.in_handles.arg_name)) 285 + f.write("\t\tstruct ipc_command_msg _handle_msg = {0};\n") 286 + 287 + # Let the client know we are ready to receive the handles. 288 + write_invocation( 289 + f, 290 + 'xrt_result_t sync_result', 291 + 'ipc_send', 292 + ( 293 + "(struct ipc_message_channel *)&ics->imc", 294 + "&_sync", 295 + "sizeof(_sync)" 296 + ), 297 + indent="\t\t" 298 + ) 299 + f.write(";") 300 + write_result_handler(f, "sync_result", 301 + indent="\t\t") 302 + write_invocation( 303 + f, 304 + 'xrt_result_t receive_handle_result', 305 + 'ipc_receive_handles_' + call.in_handles.stem, 306 + ( 307 + "(struct ipc_message_channel *)&ics->imc", 308 + "&_handle_msg", 309 + "sizeof(_handle_msg)", 310 + "in_" + call.in_handles.arg_name, 311 + "msg->"+call.in_handles.count_arg_name 312 + ), 313 + indent="\t\t" 314 + ) 315 + f.write(";") 316 + write_result_handler(f, "receive_handle_result", 317 + indent="\t\t") 318 + f.write("\t\tif (_handle_msg.cmd != %s) {\n" % str(call.id)) 319 + f.write("\t\t\treturn XRT_ERROR_IPC_FAILURE;\n") 320 + f.write("\t\t}\n") 321 + 322 + # Write call to ipc_handle_CALLNAME 323 + args = ["ics"] 324 + for arg in call.in_args: 325 + args.append(("&msg->" + arg.name) 326 + if arg.is_aggregate 327 + else ("msg->" + arg.name)) 328 + args.extend("&reply." + arg.name for arg in call.out_args) 329 + if call.out_handles: 330 + args.extend(("MAX_HANDLES", 331 + call.out_handles.arg_name, 332 + "&" + call.out_handles.count_arg_name)) 333 + 334 + if call.in_handles: 335 + args.extend(("&in_%s[0]" % call.in_handles.arg_name, 336 + "msg->"+call.in_handles.count_arg_name)) 337 + write_invocation(f, 'reply.result', 'ipc_handle_' + 338 + call.name, args, indent="\t\t") 339 + f.write(";\n") 340 + 341 + # TODO do we check reply.result and 342 + # error out before replying if it's not success? 343 + 344 + func = 'ipc_send' 345 + args = ["(struct ipc_message_channel *)&ics->imc", 346 + "&reply", 347 + "sizeof(reply)"] 348 + if call.out_handles: 349 + func += '_handles_' + call.out_handles.stem 350 + args.extend(call.out_handles.arg_names) 351 + write_invocation(f, 'xrt_result_t ret', func, args, indent="\t\t") 352 + f.write(";") 353 + f.write("\n\t\treturn ret;\n") 354 + f.write("\t}\n") 355 + f.write('''\tdefault: 356 + \t\tprintf("UNHANDLED IPC MESSAGE! %d\\n", *ipc_command); 357 + \t\treturn XRT_ERROR_IPC_FAILURE; 358 + \t} 359 + } 360 + 361 + // clang-format on 362 + ''') 363 + f.close() 364 + 365 + 366 + def generate_server_header(file, p): 367 + """Generate IPC server header. 368 + 369 + Declares handler prototypes to implement, 370 + as well as the prototype for the generated dispatch function. 371 + """ 372 + f = open(file, "w") 373 + f.write(header.format(brief='Generated IPC server code', suffix='_server')) 374 + f.write(''' 375 + #pragma once 376 + 377 + #include "shared/ipc_protocol.h" 378 + #include "ipc_protocol_generated.h" 379 + #include "server/ipc_server.h" 380 + 381 + 382 + // clang-format off 383 + ''') 384 + # This decl is constant, but we must write it here 385 + # because it depends on a generated enum. 386 + write_decl( 387 + f, 388 + "xrt_result_t", 389 + "ipc_dispatch", 390 + [ 391 + "volatile struct ipc_client_state *ics", 392 + "ipc_command_t *ipc_command" 393 + ] 394 + ) 395 + f.write(";\n") 396 + 397 + for call in p.calls: 398 + call.write_handler_decl(f) 399 + f.write(";\n") 400 + f.write("\n// clang-format on\n") 401 + f.close() 402 + 403 + 404 + def main(): 405 + """Handle command line and generate a file.""" 406 + parser = argparse.ArgumentParser(description='Protocol generator.') 407 + parser.add_argument( 408 + 'proto', help='Protocol file to use') 409 + parser.add_argument( 410 + 'output', type=str, nargs='+', 411 + help='Output file, uses the name to choose output type') 412 + args = parser.parse_args() 413 + 414 + p = Proto.load_and_parse(args.proto) 415 + 416 + for output in args.output: 417 + if output.endswith("ipc_protocol_generated.h"): 418 + generate_h(output, p) 419 + if output.endswith("ipc_client_generated.c"): 420 + generate_client_c(output, p) 421 + if output.endswith("ipc_client_generated.h"): 422 + generate_client_h(output, p) 423 + if output.endswith("ipc_server_generated.c"): 424 + generate_server_c(output, p) 425 + if output.endswith("ipc_server_generated.h"): 426 + generate_server_header(output, p) 427 + 428 + 429 + if __name__ == "__main__": 430 + main()
src/xrt/ipc_android/build.gradle src/xrt/ipc/android/build.gradle
src/xrt/ipc_android/proguard-rules.pro src/xrt/ipc/android/proguard-rules.pro
src/xrt/ipc_android/src/main/AndroidManifest.xml src/xrt/ipc/android/src/main/AndroidManifest.xml
src/xrt/ipc_android/src/main/aidl/org/freedesktop/monado/ipc/IMonado.aidl src/xrt/ipc/android/src/main/aidl/org/freedesktop/monado/ipc/IMonado.aidl
src/xrt/ipc_android/src/main/java/org/freedesktop/monado/ipc/Client.java src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/Client.java
src/xrt/ipc_android/src/main/java/org/freedesktop/monado/ipc/MonadoImpl.java src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoImpl.java
src/xrt/ipc_android/src/main/java/org/freedesktop/monado/ipc/MonadoService.java src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoService.java
src/xrt/ipc_android/src/main/res/values/strings.xml src/xrt/ipc/android/src/main/res/values/strings.xml
+1 -1
src/xrt/targets/ctl/main.c
··· 7 7 * @ingroup ipc 8 8 */ 9 9 10 - #include "ipc_client.h" 10 + #include "client/ipc_client.h" 11 11 #include "ipc_client_generated.h" 12 12 13 13 #include <sys/socket.h>
+1 -1
src/xrt/targets/openxr_android/build.gradle
··· 58 58 } 59 59 60 60 dependencies { 61 - outOfProcessImplementation project(':src:xrt:ipc_android') 61 + outOfProcessImplementation project(':src:xrt:ipc:android') 62 62 implementation project(':src:xrt:auxiliary:android') 63 63 implementation 'androidx.appcompat:appcompat:1.2.0' 64 64 implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"