compositor: refactor client forking code

shell.c and tablet-shell.c had almost the same code for forking their
special shell client. Generalise this code and put it into
wlsc_client_launch() in compositor.c.

Improve error cleanup and reporting in wlsc_client_launch().

Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
This commit is contained in:
Pekka Paalanen 2011-12-02 15:30:21 +02:00
parent fd83b6d70f
commit 409ef0a5c8
4 changed files with 91 additions and 79 deletions

View File

@ -34,6 +34,8 @@
#include <assert.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
@ -83,6 +85,75 @@ wlsc_watch_process(struct wlsc_process *process)
wl_list_insert(&child_process_list, &process->link);
}
static void
child_client_exec(int sockfd, const char *path)
{
int flags;
char s[32];
/* SOCK_CLOEXEC closes both ends, so we need to unset
* the flag on the client fd. */
flags = fcntl(sockfd, F_GETFD);
if (flags != -1)
fcntl(sockfd, F_SETFD, flags & ~FD_CLOEXEC);
snprintf(s, sizeof s, "%d", sockfd);
setenv("WAYLAND_SOCKET", s, 1);
if (execl(path, path, NULL) < 0)
fprintf(stderr, "compositor: executing '%s' failed: %m\n",
path);
}
WL_EXPORT struct wl_client *
wlsc_client_launch(struct wlsc_compositor *compositor,
struct wlsc_process *proc,
const char *path,
wlsc_process_cleanup_func_t cleanup)
{
int sv[2];
pid_t pid;
struct wl_client *client;
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
fprintf(stderr, "wlsc_client_launch: "
"socketpair failed while launching '%s': %m\n",
path);
return NULL;
}
pid = fork();
if (pid == -1) {
close(sv[0]);
close(sv[1]);
fprintf(stderr, "wlsc_client_launch: "
"fork failed while launching '%s': %m\n", path);
return NULL;
}
if (pid == 0) {
child_client_exec(sv[1], path);
exit(-1);
}
close(sv[1]);
client = wl_client_create(compositor->wl_display, sv[0]);
if (!client) {
close(sv[0]);
fprintf(stderr, "wlsc_client_launch: "
"wl_client_create failed while launching '%s'.\n",
path);
return NULL;
}
proc->pid = pid;
proc->cleanup = cleanup;
wlsc_watch_process(proc);
return client;
}
static void
surface_handle_buffer_destroy(struct wl_listener *listener,
struct wl_resource *resource, uint32_t time)

View File

@ -418,12 +418,22 @@ uint32_t *
wlsc_load_image(const char *filename,
int32_t *width_arg, int32_t *height_arg, uint32_t *stride_arg);
struct wlsc_process;
typedef void (*wlsc_process_cleanup_func_t)(struct wlsc_process *process,
int status);
struct wlsc_process {
pid_t pid;
void (*cleanup)(struct wlsc_process *process, int status);
wlsc_process_cleanup_func_t cleanup;
struct wl_list link;
};
struct wl_client *
wlsc_client_launch(struct wlsc_compositor *compositor,
struct wlsc_process *proc,
const char *path,
wlsc_process_cleanup_func_t cleanup);
int
wlsc_data_device_manager_init(struct wlsc_compositor *compositor);
void

View File

@ -27,9 +27,6 @@
#include <string.h>
#include <unistd.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <assert.h>
#include <wayland-server.h>
@ -880,44 +877,14 @@ static int
launch_desktop_shell_process(struct wl_shell *shell)
{
const char *shell_exe = LIBEXECDIR "/wayland-desktop-shell";
struct wlsc_compositor *compositor = shell->compositor;
char s[32];
int sv[2], flags;
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
fprintf(stderr, "socketpair failed\n");
shell->child.client = wlsc_client_launch(shell->compositor,
&shell->child.process,
shell_exe,
desktop_shell_sigchld);
if (!shell->child.client)
return -1;
}
shell->child.process.pid = fork();
shell->child.process.cleanup = desktop_shell_sigchld;
switch (shell->child.process.pid) {
case 0:
/* SOCK_CLOEXEC closes both ends, so we need to unset
* the flag on the client fd. */
flags = fcntl(sv[1], F_GETFD);
if (flags != -1)
fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
snprintf(s, sizeof s, "%d", sv[1]);
setenv("WAYLAND_SOCKET", s, 1);
if (execl(shell_exe, shell_exe, NULL) < 0)
fprintf(stderr, "%s: running '%s' failed: %m\n",
__func__, shell_exe);
exit(-1);
default:
close(sv[1]);
shell->child.client =
wl_client_create(compositor->wl_display, sv[0]);
wlsc_watch_process(&shell->child.process);
break;
case -1:
fprintf(stderr, "%s: fork failed: %m\n", __func__);
return -1;
}
return 0;
}

View File

@ -25,9 +25,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <linux/input.h>
#include "compositor.h"
@ -369,43 +366,10 @@ static void
launch_ux_daemon(struct tablet_shell *shell)
{
const char *shell_exe = LIBEXECDIR "/wayland-tablet-shell";
struct wlsc_compositor *compositor = shell->compositor;
char s[32];
int sv[2], flags;
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
fprintf(stderr, "socketpair failed\n");
return;
}
shell->process.pid = fork();
shell->process.cleanup = tablet_shell_sigchld;
switch (shell->process.pid) {
case 0:
/* SOCK_CLOEXEC closes both ends, so we need to unset
* the flag on the client fd. */
flags = fcntl(sv[1], F_GETFD);
if (flags != -1)
fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
snprintf(s, sizeof s, "%d", sv[1]);
setenv("WAYLAND_SOCKET", s, 1);
if (execl(shell_exe, shell_exe, NULL) < 0)
fprintf(stderr, "exec failed: %m\n");
exit(-1);
default:
close(sv[1]);
shell->client =
wl_client_create(compositor->wl_display, sv[0]);
wlsc_watch_process(&shell->process);
break;
case -1:
fprintf(stderr, "failed to fork\n");
break;
}
shell->client = wlsc_client_launch(shell->compositor,
&shell->process,
shell_exe, tablet_shell_sigchld);
}
static void