libuv/test/runner-unix.c
Bert Belder a3be5339e2 Rename test-runner to just runner
And a minor fix to the VS solution.
2011-04-18 14:44:01 +02:00

164 lines
3.4 KiB
C

#include "runner-unix.h"
#include "runner.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <string.h>
#define PATHMAX 1024
static char executable_path[PATHMAX] = { '\0' };
/* Linux-only */
static void get_executable_path() {
if (!executable_path[0]) {
readlink("/proc/self/exe", executable_path, PATHMAX - 1);
}
}
/* Invoke "arv[0] test-name". Store process info in *p. */
/* Make sure that all stdio output of the processes is buffered up. */
int process_start(char* name, process_info_t* p) {
FILE* stdout_file = tmpfile();
if (!stdout_file) {
perror("tmpfile");
return -1;
}
p->terminated = 0;
p->status = 0;
get_executable_path();
pid_t pid = vfork();
if (pid < 0) {
perror("vfork");
return -1;
}
if (pid == 0) {
/* child */
dup2(fileno(stdout_file), STDOUT_FILENO);
dup2(fileno(stdout_file), STDERR_FILENO);
char* args[3] = { executable_path, name, NULL };
execvp(executable_path, args);
perror("execvp()");
_exit(127);
}
/* parent */
p->pid = pid;
p->name = strdup(name);
p->stdout_file = stdout_file;
return 0;
}
/* Wait for all `n` processes in `vec` to terminate. */
/* Time out after `timeout` msec, or never if timeout == -1 */
/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */
int process_wait(process_info_t* vec, int n, int timeout) {
int i;
process_info_t* p;
for (i = 0; i < n; i++) {
p = (process_info_t*)(vec + i * sizeof(process_info_t));
if (p->terminated) continue;
int status = 0;
int r = waitpid(p->pid, &(p->status), 0);
if (r < 0) {
return -1;
}
p->terminated = 1;
}
return 0;
}
/* Returns the number of bytes in the stdio output buffer for process `p`. */
long int process_output_size(process_info_t *p) {
/* Size of the p->stdout_file */
struct stat buf;
int r = fstat(fileno(p->stdout_file), &buf);
if (r < 0) {
return -1;
}
return (long)buf.st_size;
}
/* Copy the contents of the stdio output buffer to `fd`. */
int process_copy_output(process_info_t *p, int fd) {
int r = fseek(p->stdout_file, 0, SEEK_SET);
if (r < 0) {
perror("fseek");
return -1;
}
size_t nread, nwritten;
char buf[1024];
while ((nread = read(fileno(p->stdout_file), buf, 1024)) > 0) {
nwritten = write(fd, buf, nread);
/* TODO: what if write doesn't write the whole buffer... */
if (nwritten < 0) {
perror("write");
return -1;
}
}
if (nread < 0) {
perror("read");
return -1;
}
return 0;
}
/* Return the name that was specified when `p` was started by process_start */
char* process_get_name(process_info_t *p) {
return p->name;
}
/* Terminate process `p`. */
int process_terminate(process_info_t *p) {
return kill(p->pid, SIGTERM);
}
/* Return the exit code of process p. */
/* On error, return -1. */
int process_reap(process_info_t *p) {
if (WIFEXITED(p->status)) {
return WEXITSTATUS(p->status);
} else {
return p->status; /* ? */
}
}
/* Clean up after terminating process `p` (e.g. free the output buffer etc.). */
void process_cleanup(process_info_t *p) {
fclose(p->stdout_file);
free(p->name);
}
/* Move the console cursor one line up and back to the first column. */
int rewind_cursor() {
printf("\033[1A\033[80D");
return 0;
}