xrt: Add u_process, backed by libbsd's pidfile

Delete stale ipc files in ipc server when not already running.

If built without libbsd, fall back to previous behavior of complaining about existing ipc files and exit.
This commit is contained in:
Christoph Haag 2020-10-21 22:18:57 +02:00 committed by Ryan Pavlik
parent c92bc0a704
commit 4ea68b89a4
12 changed files with 213 additions and 8 deletions

View file

@ -107,6 +107,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
endif()
find_package(OpenGL COMPONENTS GLX)
pkg_search_module(DBUS dbus-1)
pkg_search_module(LIBBSD libbsd)
pkg_check_modules(GST
gstreamer-1.0
@ -143,6 +144,7 @@ cmake_dependent_option(XRT_HAVE_OPENGLES "Enable OpenGL-ES Graphics API support"
cmake_dependent_option(XRT_HAVE_EGL "Enable OpenGL on EGL Graphics API support" ON "EGL_FOUND; XRT_HAVE_OPENGL OR XRT_HAVE_OPENGLES" OFF)
cmake_dependent_option(XRT_HAVE_DBUS "Enable dbus support (for BLE support)" ON "DBUS_FOUND" OFF)
cmake_dependent_option(XRT_FEATURE_COMPOSITOR_MAIN "Build main compositor host functionality" ON "XRT_HAVE_VULKAN; XRT_HAVE_WAYLAND OR XRT_HAVE_XCB OR ANDROID OR WIN32" OFF)
cmake_dependent_option(XRT_HAVE_LIBBSD "Enable libbsd support" ON "LIBBSD_FOUND" OFF)
cmake_dependent_option(XRT_FEATURE_OPENXR "Build OpenXR runtime target" ON "XRT_FEATURE_COMPOSITOR_MAIN" OFF)
cmake_dependent_option(XRT_FEATURE_SERVICE "Enable separate service module for OpenXR runtime" ON "NOT WIN32 AND XRT_FEATURE_OPENXR" OFF)
cmake_dependent_option(XRT_HAVE_SYSTEMD "Enable systemd support (for socket activation of service)" ON "Systemd_FOUND AND XRT_FEATURE_SERVICE" OFF)
@ -335,6 +337,7 @@ message(STATUS "# OPENGLES: ${XRT_HAVE_OPENGLES}")
message(STATUS "# EGL: ${XRT_HAVE_EGL}")
message(STATUS "# DBUS: ${XRT_HAVE_DBUS}")
message(STATUS "# VF: ${XRT_HAVE_VF}")
message(STATUS "# LIBBSD: ${XRT_HAVE_LIBBSD}")
message(STATUS "# SYSTEMD: ${XRT_HAVE_SYSTEMD}")
message(STATUS "# LIBUSB: ${XRT_HAVE_LIBUSB}")
message(STATUS "# JPEG: ${XRT_HAVE_JPEG}")

View file

@ -72,6 +72,7 @@ zlib = dependency('zlib', required: false)
survive = dependency('survive', required: false)
dbus = dependency('dbus-1', required: get_option('dbus'))
systemd = dependency('libsystemd', required: get_option('systemd'))
libbsd = dependency('libbsd', required: get_option('libbsd'))
gst = dependency('gstreamer-1.0', required: false)
gst_app = dependency('gstreamer-app-1.0', required: false)
gst_video= dependency('gstreamer-video-1.0', required: false)
@ -335,3 +336,9 @@ if not get_option('dbus').disabled() and dbus.found()
else
message(' dbus: no')
endif
if not get_option('libbsd').disabled() and libbsd.found()
message(' libbsd: yes')
else
message(' libbsd: no')
endif

View file

@ -77,6 +77,11 @@ option('dbus',
value: 'auto',
description: 'Enable support for dbus.')
option('libbsd',
type: 'feature',
value: 'auto',
description: 'Enable support for libbsd.')
option('systemd',
type: 'feature',
value: 'auto',

View file

@ -159,6 +159,8 @@ set(UTIL_SOURCE_FILES
util/u_config_json.c
util/u_config_json.h
util/u_verify.h
util/u_process.c
util/u_process.h
)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/util/u_git_tag.c.in" "${CMAKE_CURRENT_BINARY_DIR}/u_git_tag.c" @ONLY)
@ -225,6 +227,10 @@ if(XRT_HAVE_SYSTEM_CJSON)
else()
target_link_libraries(aux_util PUBLIC xrt-external-cjson)
endif()
if(XRT_HAVE_LIBBSD)
target_include_directories(aux_util SYSTEM PRIVATE ${LIBBSD_INCLUDE_DIRS})
target_link_libraries(aux_util PUBLIC ${LIBBSD_LIBRARIES})
endif()
if(ANDROID)
target_link_libraries(aux_util PUBLIC ${ANDROID_LOG_LIBRARY})
endif()

View file

@ -11,6 +11,11 @@ u_git_tag_c = vcs_tag(
replace_string: '@GIT_DESC@',
)
aux_util_deps = [ xrt_config_have ]
if libbsd.found() and not get_option('libbsd').disabled()
aux_util_deps += libbsd
endif
lib_aux_util = static_library(
'aux_util',
files(
@ -65,6 +70,8 @@ lib_aux_util = static_library(
'util/u_config_json.c',
'util/u_config_json.h',
'util/u_verify.h',
'util/u_process.c',
'util/u_process.h',
) + [
u_git_tag_c,
],
@ -73,6 +80,7 @@ lib_aux_util = static_library(
cjson_include,
],
dependencies: [
aux_util_deps,
xrt_config_have,
]
)

View file

@ -0,0 +1,105 @@
// Copyright 2019-2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Simple process handling
* @author Christoph Haag <christoph.haag@collabora.com>
* @ingroup aux_util
*/
#include "xrt/xrt_config.h"
#ifdef XRT_OS_LINUX
#define PID_FILE_NAME "monado.pid"
#ifdef XRT_HAVE_LIBBSD
#include <bsd/libutil.h>
#endif
#include <limits.h>
#include <errno.h>
#include <stdbool.h>
#include "u_misc.h"
#include "u_file.h"
#include "u_logging.h"
struct u_process
{
#ifdef XRT_HAVE_LIBBSD
struct pidfh *pfh;
#else
int pid;
#endif
};
static inline int
get_pidfile_path(char *buf)
{
int size = u_file_get_path_in_runtime_dir(PID_FILE_NAME, buf, PATH_MAX);
if (size == -1) {
U_LOG_W("Failed to determine runtime dir, not creating pidfile");
return -1;
}
return 0;
}
struct u_process *
u_process_create_if_not_running()
{
#ifdef XRT_HAVE_LIBBSD
char tmp[PATH_MAX];
if (get_pidfile_path(tmp) < 0) {
U_LOG_W("Failed to determine runtime dir, not creating pidfile");
return NULL;
}
U_LOG_T("Using pidfile %s", tmp);
pid_t otherpid;
struct pidfh *pfh = pidfile_open(tmp, 0600, &otherpid);
if (errno == EEXIST || pfh == NULL) {
U_LOG_T("Failed to create pidfile (%s): Another Monado instance may be running", strerror(errno));
// other process is locking pid file
return NULL;
}
// either new or stale pidfile opened
int write_ret = pidfile_write(pfh);
if (write_ret != 0) {
pidfile_close(pfh);
return NULL;
}
struct u_process *ret = U_TYPED_CALLOC(struct u_process);
ret->pfh = pfh;
U_LOG_T("No other Monado instance was running, got new pidfile");
return ret;
#else
struct u_process *ret = U_TYPED_CALLOC(struct u_process);
//! @todo alternative implementation
ret->pid = 0;
return ret;
#endif
}
void
u_process_destroy(struct u_process *proc)
{
if (proc == NULL) {
return;
}
#ifdef XRT_HAVE_LIBBSD
pidfile_close(proc->pfh);
#endif
free(proc);
}
#endif

View file

@ -0,0 +1,42 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Simple process handling
* @author Christoph Haag <christoph.haag@collabora.com>
* @ingroup aux_util
*/
#pragma once
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
struct u_process;
/*!
* Creates a handle for this process that is unique to the operating system user. Returns NULL if another process
* holding a handle is already running.
*
* @todo If built without libbsd support, a dummy value is returned that needs to be handled by the caller.
*
* @return a new u_process handle if no monado instance is running, NULL if another instance is already running.
* @ingroup aux_util
*/
struct u_process *
u_process_create_if_not_running();
/*!
* Releases the unique handle of the operating system user.
*
* @ingroup aux_util
*/
void
u_process_destroy(struct u_process *proc);
#ifdef __cplusplus
}
#endif

View file

@ -100,6 +100,10 @@ if get_option('layer_equirect2')
have_conf.set('XRT_FEATURE_OPENXR_LAYER_EQUIRECT2', true)
endif
if libbsd.found() and not get_option('libbsd').disabled()
have_conf.set('XRT_HAVE_LIBBSD', true)
endif
xrt_config_have_h = configure_file(
output: 'xrt_config_have.h',
configuration: have_conf,

View file

@ -10,6 +10,7 @@
#pragma once
#cmakedefine XRT_HAVE_DBUS
#cmakedefine XRT_HAVE_LIBBSD
#cmakedefine XRT_HAVE_EGL
#cmakedefine XRT_HAVE_FFMPEG
#cmakedefine XRT_HAVE_GST

View file

@ -268,6 +268,9 @@ struct ipc_server
{
struct xrt_instance *xinst;
//! Handle for the current process, e.g. pidfile on linux
struct u_process *process;
/* ---- HACK ---- */
void *hack;
/* ---- HACK ---- */

View file

@ -88,15 +88,26 @@ create_listen_socket(struct ipc_server_mainloop *ml, int *out_fd)
strcpy(addr.sun_path, IPC_MSG_SOCK_FILE);
ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
#ifdef XRT_HAVE_LIBBSD
// no other instance is running, or we would have never arrived here
if (ret < 0 && errno == EADDRINUSE) {
U_LOG_W("Removing stale socket file %s", IPC_MSG_SOCK_FILE);
ret = unlink(IPC_MSG_SOCK_FILE);
if (ret < 0) {
U_LOG_E(
"Could not bind socket to path %s: is the "
"service running already?",
IPC_MSG_SOCK_FILE);
U_LOG_E("Failed to remove stale socket file %s: %s", IPC_MSG_SOCK_FILE, strerror(errno));
return ret;
}
ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
}
#endif
if (ret < 0) {
U_LOG_E("Could not bind socket to path %s: %s. Is the service running already?", IPC_MSG_SOCK_FILE,
strerror(errno));
#ifdef XRT_HAVE_SYSTEMD
U_LOG_E(
"Or, is the systemd unit monado.socket or "
"monado-dev.socket active?");
U_LOG_E("Or, is the systemd unit monado.socket or monado-dev.socket active?");
#endif
if (errno == EADDRINUSE) {
U_LOG_E("If monado-service is not running, delete %s before starting a new instance",
@ -113,7 +124,7 @@ create_listen_socket(struct ipc_server_mainloop *ml, int *out_fd)
close(fd);
return ret;
}
U_LOG_D("Created listening socket.");
U_LOG_D("Created listening socket %s.", IPC_MSG_SOCK_FILE);
*out_fd = fd;
return 0;
}

View file

@ -21,6 +21,7 @@
#include "util/u_debug.h"
#include "util/u_trace_marker.h"
#include "util/u_verify.h"
#include "util/u_process.h"
#include "shared/ipc_shmem.h"
#include "server/ipc_server.h"
@ -109,6 +110,7 @@ teardown_all(struct ipc_server *s)
ipc_server_mainloop_deinit(&s->ml);
os_mutex_destroy(&s->global_state.lock);
u_process_destroy(s->process);
}
static int
@ -394,6 +396,14 @@ ipc_server_start_client_listener_thread(struct ipc_server *vs, int fd)
static int
init_all(struct ipc_server *s)
{
s->process = u_process_create_if_not_running();
if (!s->process) {
U_LOG_E("monado-service is already running! Use XRT_LOG=trace for more information.");
teardown_all(s);
return 1;
}
// Yes we should be running.
s->running = true;
s->exit_on_disconnect = debug_get_bool_option_exit_on_disconnect();