pipe free fork is implemented (LTP fork09)

This commit is contained in:
Tomoki Shirasawa
2015-03-04 17:40:58 +09:00
parent daec7de828
commit 9946ccd6b1

View File

@@ -55,6 +55,7 @@
#include <dirent.h> #include <dirent.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <pthread.h> #include <pthread.h>
#include <semaphore.h>
#include <signal.h> #include <signal.h>
#include "../include/uprotocol.h" #include "../include/uprotocol.h"
@@ -120,6 +121,20 @@ static char *altroot;
static const char rlimit_stack_envname[] = "MCKERNEL_RLIMIT_STACK"; static const char rlimit_stack_envname[] = "MCKERNEL_RLIMIT_STACK";
static int ischild; static int ischild;
struct fork_sync {
pid_t pid;
int status;
sem_t sem;
};
struct fork_sync_container {
struct fork_sync_container *next;
struct fork_sync *fs;
};
struct fork_sync_container *fork_sync_top;
pthread_mutex_t fork_sync_mutex = PTHREAD_MUTEX_INITIALIZER;
pid_t gettid(void) pid_t gettid(void)
{ {
return syscall(SYS_gettid); return syscall(SYS_gettid);
@@ -1647,25 +1662,36 @@ int main_loop(int fd, int cpu, pthread_mutex_t *lock)
} }
case __NR_fork: { case __NR_fork: {
int child; struct fork_sync *fs;
int sync_pipe_fd[2]; struct fork_sync_container *fsc;
char sync_msg; struct fork_sync_container *fp;
struct fork_sync_container *fb;
int rc = -1;
pid_t pid;
if (pipe(sync_pipe_fd) != 0) { fsc = malloc(sizeof(struct fork_sync_container));
fprintf(stderr, "fork(): error creating sync pipe\n"); memset(fsc, '\0', sizeof(struct fork_sync_container));
do_syscall_return(fd, cpu, -1, 0, 0, 0, 0); pthread_mutex_lock(&fork_sync_mutex);
break; fsc->next = fork_sync_top;
fork_sync_top = fsc;
pthread_mutex_unlock(&fork_sync_mutex);
fsc->fs = fs = mmap(NULL, sizeof(struct fork_sync),
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if(fs == (void *)-1){
goto fork_err;
} }
child = fork(); memset(fs, '\0', sizeof(struct fork_sync));
sem_init(&fs->sem, 1, 0);
switch (child) { pid = fork();
switch (pid) {
/* Error */ /* Error */
case -1: case -1:
fprintf(stderr, "fork(): error forking child process\n"); fprintf(stderr, "fork(): error forking child process\n");
close(sync_pipe_fd[0]); rc = -errno;
close(sync_pipe_fd[1]);
do_syscall_return(fd, cpu, -1, 0, 0, 0, 0);
break; break;
/* Child process */ /* Child process */
@@ -1679,11 +1705,9 @@ int main_loop(int fd, int cpu, pthread_mutex_t *lock)
close(fd); close(fd);
fd = open(dev, O_RDWR); fd = open(dev, O_RDWR);
if (fd < 0) { if (fd < 0) {
/* TODO: tell parent something went wrong? */ fs->status = -errno;
fprintf(stderr, "ERROR: opening %s\n", dev); fprintf(stderr, "ERROR: opening %s\n", dev);
/* Tell parent something went wrong */
sync_msg = 1;
goto fork_child_sync_pipe; goto fork_child_sync_pipe;
} }
@@ -1699,21 +1723,24 @@ int main_loop(int fd, int cpu, pthread_mutex_t *lock)
!= 0) { != 0) {
fprintf(stderr, "Error: open_exec() fails for %s: %d (fd: %d)\n", fprintf(stderr, "Error: open_exec() fails for %s: %d (fd: %d)\n",
exec_path, ret, fd); exec_path, ret, fd);
fs->status = -errno;
goto fork_child_sync_pipe; goto fork_child_sync_pipe;
} }
/* Tell parent everything went OK */
sync_msg = 0;
fork_child_sync_pipe: fork_child_sync_pipe:
if (write(sync_pipe_fd[1], &sync_msg, 1) != 1) { sem_post(&fs->sem);
fprintf(stderr, "ERROR: writing sync pipe\n"); if (fs->status)
goto fork_child_out; exit(1);
}
ret = 0; for (fp = fork_sync_top; fp;) {
fork_child_out: fb = fp->next;
close(sync_pipe_fd[0]); if (fp->fs)
close(sync_pipe_fd[1]); munmap(fp->fs, sizeof(struct fork_sync));
free(fp);
fp = fb;
}
fork_sync_top = NULL;
pthread_mutex_init(&fork_sync_mutex, NULL);
npdesc.pid = getpid(); npdesc.pid = getpid();
ioctl(fd, MCEXEC_UP_NEW_PROCESS, &npdesc); ioctl(fd, MCEXEC_UP_NEW_PROCESS, &npdesc);
@@ -1728,27 +1755,44 @@ fork_child_out:
/* Parent */ /* Parent */
default: default:
fs->pid = pid;
while ((rc = sem_trywait(&fs->sem)) == -1 && (errno == EAGAIN || errno == EINTR)) {
int st;
int wrc;
while ((ret = read(sync_pipe_fd[0], &sync_msg, 1)) == -1 && errno == EINTR); wrc = waitpid(pid, &st, WNOHANG);
if (ret != 1) { if(wrc == pid) {
fprintf(stderr, "fork(): error reading sync message\n"); fs->status = -ENOMEM;
child = -1; break;
goto sync_out; }
sched_yield();
} }
if (sync_msg != 0) { if (fs->status != 0) {
fprintf(stderr, "fork(): error with child process after fork\n"); fprintf(stderr, "fork(): error with child process after fork\n");
child = -1; rc = fs->status;
goto sync_out;
}
sync_out:
close(sync_pipe_fd[0]);
close(sync_pipe_fd[1]);
do_syscall_return(fd, cpu, child, 0, 0, 0, 0);
break; break;
} }
rc = pid;
break;
}
sem_destroy(&fs->sem);
munmap(fs, sizeof(struct fork_sync));
fork_err:
pthread_mutex_lock(&fork_sync_mutex);
for(fp = fork_sync_top, fb = NULL; fp; fb = fp, fp = fp->next)
if(fp == fsc)
break;
if(fp){
if(fb)
fb->next = fsc->next;
else
fork_sync_top = fsc->next;
}
pthread_mutex_unlock(&fork_sync_mutex);
do_syscall_return(fd, cpu, rc, 0, 0, 0, 0);
break; break;
} }