// SPDX-License-Identifier: LGPL-2.1-or-later
/*****************************************************************************
* process.c: posix implementation of process management
*****************************************************************************
* Copyright © 2025 Videolabs, VideoLAN and VLC authors
*
* Authors: Gabriel Lafond Thenaille <gabriel@videolabs.io>
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_POLL_H
# include <poll.h>
#endif
#include <assert.h>
#include <signal.h>
#include <sys/poll.h>
#include <vlc_common.h>
#include <vlc_process.h>
#include <vlc_interrupt.h>
#include <vlc_spawn.h>
#include <vlc_poll.h>
#include <vlc_fs.h>
#include <vlc_network.h>
static_assert(HAVE_VLC_PROCESS_SPAWN == 1, "mismatching HAVE_VLC_PROCESS_SPAWN declaration");
struct vlc_process {
/* Pid of the linked process */
pid_t pid;
/* File descriptor of the socketpair */
int fd;
};
struct vlc_process*
vlc_process_Spawn(const char *path, int argc, const char *const *argv)
{
assert(path != NULL);
if (argc > 0) {
assert(argv != NULL);
assert(argv[0] != NULL);
}
int ret = VLC_EGENERIC;
int fds[2] = { -1, -1 };
int extfd_in = -1;
int extfd_out = -1;
const char **args = NULL;
struct vlc_process *process = malloc(sizeof(*process));
if (process == NULL) {
return NULL;
}
ret = vlc_socketpair(PF_LOCAL, SOCK_STREAM, 0, fds, false);
if (ret != 0) {
goto end;
}
extfd_in = vlc_dup(fds[1]);
if (extfd_in == -1) {
ret = -1;
goto end;
}
extfd_out = vlc_dup(fds[1]);
if (extfd_out == -1) {
ret = -1;
goto end;
}
process->fd = fds[0];
int process_fds[4] = {extfd_in, extfd_out, STDERR_FILENO, -1};
/* `argc + 2`, 1 for the process->path and the last to be NULL */
args = malloc((argc + 2) * sizeof(*args));
if (args == NULL) {
ret = VLC_ENOMEM;
goto end;
}
args[0] = path;
for (int i = 0; i < argc; i++) {
args[i + 1] = argv[i];
}
args[argc + 1] = NULL;
ret = vlc_spawnp(&process->pid, path, process_fds, args);
if (ret != 0) {
goto end;
}
end:
free(args);
if (extfd_in != -1) {
vlc_close(extfd_in);
}
if (extfd_out != -1) {
vlc_close(extfd_out);
}
if (fds[1] != -1) {
net_Close(fds[1]);
}
if (ret != 0) {
if (fds[0] != -1) {
shutdown(fds[0], SHUT_RDWR);
net_Close(fds[0]);
}
free(process);
return NULL;
}
return process;
}
VLC_API void
vlc_process_Kill(struct vlc_process *process)
{
assert(process != NULL);
kill(process->pid, SIGTERM);
shutdown(process->fd, SHUT_RDWR);
}
VLC_API int
vlc_process_Terminate(struct vlc_process *process, bool kill_process)
{
assert(process != NULL);
if (kill_process) {
vlc_process_Kill(process);
}
shutdown(process->fd, SHUT_RDWR);
net_Close(process->fd);
int status = vlc_waitpid(process->pid);
process->pid = 0;
process->fd = -1;
free(process);
return status;
}
ssize_t
vlc_process_fd_Read(struct vlc_process *process, uint8_t *buf, size_t size,
vlc_tick_t timeout_ms)
{
assert(process != NULL);
assert(process->fd != -1);
assert(buf != NULL);
struct pollfd fds = {
.fd = process->fd, .events = POLLIN, .revents = 0
};
int ret = vlc_poll_i11e(&fds, 1, timeout_ms);
if (ret < 0) {
return -1;
} else if (ret == 0) {
errno = ETIMEDOUT;
return -1;
} else if (!(fds.revents & POLLIN)) {
errno = EINVAL;
return -1;
}
return recv(process->fd, buf, size, 0);
}
ssize_t
vlc_process_fd_Write(struct vlc_process *process, const uint8_t *buf,
size_t size, vlc_tick_t timeout_ms)
{
assert(process != NULL);
assert(process->fd != -1);
assert(buf != NULL);
struct pollfd fds = {
.fd = process->fd, .events = POLLOUT, .revents = 0
};
int ret = vlc_poll_i11e(&fds, 1, timeout_ms);
if (ret < 0) {
return -1;
} else if (ret == 0) {
errno = ETIMEDOUT;
return -1;
} else if (!(fds.revents & POLLOUT)) {
errno = EINVAL;
return -1;
}
return vlc_send_i11e(process->fd, buf, size, 0);
}
¤ Dauer der Verarbeitung: 0.4 Sekunden
¤
*© Formatika GbR, Deutschland