2
0
mirror of git://github.com/lxc/lxc synced 2025-09-05 13:59:35 +00:00
Files
lxc/src/lxc/sync.c
Christian Brauner 6bc4165d3c start: simplify startup synchronization
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
2021-05-21 17:58:01 +02:00

160 lines
4.0 KiB
C

/* SPDX-License-Identifier: LGPL-2.1+ */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include "config.h"
#include "log.h"
#include "start.h"
#include "sync.h"
#include "utils.h"
lxc_log_define(sync, lxc);
bool sync_wait(int fd, int sequence)
{
int sync = -1;
ssize_t ret;
ret = lxc_read_nointr(fd, &sync, sizeof(sync));
if (ret < 0)
return log_error_errno(false, errno, "Sync wait failure");
if (!ret)
return true;
if ((size_t)ret != sizeof(sync))
return log_error(false, "Unexpected sync size: %zu expected %zu", (size_t)ret, sizeof(sync));
if (sync == SYNC_ERROR)
return log_error(false, "An error occurred in another process (expected sequence number %d)", sequence);
if (sync != sequence)
return log_error(false, "Invalid sequence number %d. Expected sequence number %d", sync, sequence);
return true;
}
bool sync_wake(int fd, int sequence)
{
int sync = sequence;
if (lxc_write_nointr(fd, &sync, sizeof(sync)) < 0)
return log_error_errno(false, errno, "Sync wake failure");
return true;
}
static bool __sync_barrier(int fd, int sequence)
{
if (!sync_wake(fd, sequence))
return false;
return sync_wait(fd, sequence + 1);
}
static inline const char *start_sync_to_string(int state)
{
switch (state) {
case START_SYNC_STARTUP:
return "startup";
case START_SYNC_CONFIGURE:
return "configure";
case START_SYNC_POST_CONFIGURE:
return "post-configure";
case START_SYNC_CGROUP_LIMITS:
return "cgroup-limits";
case START_SYNC_IDMAPPED_MOUNTS:
return "idmapped-mounts";
case START_SYNC_FDS:
return "fds";
case START_SYNC_READY_START:
return "ready-start";
case START_SYNC_RESTART:
return "restart";
case START_SYNC_POST_RESTART:
return "post-restart";
case SYNC_ERROR:
return "error";
default:
return "invalid sync state";
}
}
bool lxc_sync_barrier_parent(struct lxc_handler *handler, int sequence)
{
TRACE("Child waking parent with sequence %s and waiting for sequence %s",
start_sync_to_string(sequence), start_sync_to_string(sequence + 1));
return __sync_barrier(handler->sync_sock[0], sequence);
}
bool lxc_sync_barrier_child(struct lxc_handler *handler, int sequence)
{
TRACE("Parent waking child with sequence %s and waiting with sequence %s",
start_sync_to_string(sequence), start_sync_to_string(sequence + 1));
return __sync_barrier(handler->sync_sock[1], sequence);
}
bool lxc_sync_wake_parent(struct lxc_handler *handler, int sequence)
{
TRACE("Child waking parent with sequence %s", start_sync_to_string(sequence));
return sync_wake(handler->sync_sock[0], sequence);
}
bool lxc_sync_wait_parent(struct lxc_handler *handler, int sequence)
{
TRACE("Child waiting for parent with sequence %s", start_sync_to_string(sequence));
return sync_wait(handler->sync_sock[0], sequence);
}
bool lxc_sync_wait_child(struct lxc_handler *handler, int sequence)
{
TRACE("Parent waiting for child with sequence %s", start_sync_to_string(sequence));
return sync_wait(handler->sync_sock[1], sequence);
}
bool lxc_sync_wake_child(struct lxc_handler *handler, int sequence)
{
TRACE("Child waking parent with sequence %s", start_sync_to_string(sequence));
return sync_wake(handler->sync_sock[1], sequence);
}
bool lxc_sync_init(struct lxc_handler *handler)
{
int ret;
ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, handler->sync_sock);
if (ret)
return log_error_errno(false, errno, "failed to create synchronization socketpair");
/* Be sure we don't inherit this after the exec */
ret = fcntl(handler->sync_sock[0], F_SETFD, FD_CLOEXEC);
if (ret < 0)
return log_error_errno(false, errno, "Failed to make socket close-on-exec");
TRACE("Initialized synchronization infrastructure");
return true;
}
void lxc_sync_fini_child(struct lxc_handler *handler)
{
close_prot_errno_disarm(handler->sync_sock[0]);
}
void lxc_sync_fini_parent(struct lxc_handler *handler)
{
close_prot_errno_disarm(handler->sync_sock[1]);
}
void lxc_sync_fini(struct lxc_handler *handler)
{
lxc_sync_fini_child(handler);
lxc_sync_fini_parent(handler);
}