Skip to content

Commit

Permalink
update ct
Browse files Browse the repository at this point in the history
  • Loading branch information
kr committed Apr 14, 2013
1 parent e4b375e commit 59b5cfc
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 43 deletions.
2 changes: 1 addition & 1 deletion ct/License
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright 2010, 2011 Keith Rarick
Copyright © 2010–2013 Keith Rarick

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
193 changes: 159 additions & 34 deletions ct/ct.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include "internal.h"
#include "ct.h"


static Test *curtest;
static int rjobfd = -1, wjobfd = -1;


void
ctlogpn(char *p, int n, char *fmt, ...)
{
Expand All @@ -35,6 +42,14 @@ ctfail(void)
}


char *
ctdir(void)
{
mkdir(curtest->dir, 0700);
return curtest->dir;
}


static void
die(int code, int err, char *msg)
{
Expand All @@ -59,46 +74,80 @@ failed(int s)


static void
run(T t[])
waittest(void)
{
int pid;
FILE *out;
Test *t;
int pid, stat;

for (; t->f; t++) {
out = tmpfile();
if (!out) {
die(1, errno, "tmpfile");
}
t->fd = fileno(out);
pid = fork();
if (pid < 0) {
die(1, errno, "fork");
} else if (!pid) {
if (dup2(t->fd, 1) == -1) {
die(3, errno, "dup2");
}
if (close(t->fd) == -1) {
die(3, errno, "fclose");
}
if (dup2(1, 2) == -1) {
die(3, errno, "dup2");
pid = wait3(&stat, 0, 0);
if (pid == -1) {
die(3, errno, "wait");
}
killpg(pid, 9);

for (t=ctmain; t->f; t++) {
if (t->pid == pid) {
t->status = stat;
if (!t->status) {
putchar('.');
} else if (failed(t->status)) {
putchar('F');
} else {
putchar('E');
}
t->f();
exit(0);
fflush(stdout);
}
}
}

if (waitpid(pid, &t->status, 0) != pid) {
die(3, errno, "wait");

static void
start(Test *t)
{
FILE *out;
out = tmpfile();
if (!out) {
die(1, errno, "tmpfile");
}
t->fd = fileno(out);
strcpy(t->dir, TmpDirPat);
mktemp(t->dir);
t->pid = fork();
if (t->pid < 0) {
die(1, errno, "fork");
} else if (!t->pid) {
setpgid(0, 0);
if (dup2(t->fd, 1) == -1) {
die(3, errno, "dup2");
}
if (close(t->fd) == -1) {
die(3, errno, "fclose");
}
if (dup2(1, 2) == -1) {
die(3, errno, "dup2");
}
curtest = t;
t->f();
_exit(0);
}
setpgid(t->pid, t->pid);
}

if (!t->status) {
putchar('.');
} else if (failed(t->status)) {
putchar('F');
} else {
putchar('E');

static void
runall(Test t[], int limit)
{
int nrun = 0;
for (; t->f; t++) {
if (nrun >= limit) {
waittest();
nrun--;
}
fflush(stdout);
start(t);
nrun++;
}
for (; nrun; nrun--) {
waittest();
}
}

Expand All @@ -117,13 +166,55 @@ copyfd(FILE *out, int in)
}


// Removes path and all of its children.
// Writes errors to stderr and keeps going.
// If path doesn't exist, rmtree returns silently.
static void
rmtree(char *path)
{
int r = unlink(path);
if (r == 0 || errno == ENOENT) {
return; // success
}
int unlinkerr = errno;

DIR *d = opendir(path);
if (!d) {
if (errno == ENOTDIR) {
fprintf(stderr, "ct: unlink: %s\n", strerror(unlinkerr));
} else {
perror("ct: opendir");
}
fprintf(stderr, "ct: path %s\n", path);
return;
}
struct dirent *ent;
while ((ent = readdir(d))) {
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
continue;
}
int n = strlen(path) + 1 + strlen(ent->d_name);
char s[n+1];
sprintf(s, "%s/%s", path, ent->d_name);
rmtree(s);
}
closedir(d);
r = rmdir(path);
if (r == -1) {
perror("ct: rmdir");
fprintf(stderr, "ct: path %s\n", path);
}
}


static int
report(T t[])
report(Test t[])
{
int nfail = 0, nerr = 0;

putchar('\n');
for (; t->f; t++) {
rmtree(t->dir);
if (!t->status) {
continue;
}
Expand Down Expand Up @@ -157,9 +248,43 @@ report(T t[])
}


int
readtokens()
{
int n = 1;
char c, *s;
if ((s = strstr(getenv("MAKEFLAGS"), " --jobserver-fds="))) {
rjobfd = (int)strtol(s+17, &s, 10); // skip " --jobserver-fds="
wjobfd = (int)strtol(s+1, NULL, 10); // skip comma
}
if (rjobfd >= 0) {
fcntl(rjobfd, F_SETFL, fcntl(rjobfd, F_GETFL)|O_NONBLOCK);
while (read(rjobfd, &c, 1) > 0) {
n++;
}
}
return n;
}


void
writetokens(int n)
{
char c = '+';
if (wjobfd >= 0) {
fcntl(wjobfd, F_SETFL, fcntl(wjobfd, F_GETFL)|O_NONBLOCK);
for (; n>1; n--) {
write(wjobfd, &c, 1); // ignore error; nothing we can do anyway
}
}
}


int
main()
{
run(ctmain);
int n = readtokens();
runall(ctmain, n);
writetokens(n);
return report(ctmain);
}
5 changes: 3 additions & 2 deletions ct/ct.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
void ctfail(void);
void ctlogpn(char*, int, char*, ...) __attribute__((format(printf, 3, 4)));
char *ctdir(void);
void ctfail(void);
void ctlogpn(char*, int, char*, ...) __attribute__((format(printf, 3, 4)));
#define ctlog(...) ctlogpn(__FILE__, __LINE__, __VA_ARGS__)
#define assert(x) do if (!(x)) {\
ctlog("%s", "test: " #x);\
Expand Down
6 changes: 3 additions & 3 deletions ct/gen
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ gen() {
done
printf '\n'

printf 'T ctmain[] = {\n'
printf 'Test ctmain[] = {\n'
for t in "$@"
do printf ' {%s, "%s", 0, 0},\n' $t $t
do printf ' {%s, "%s", 0, 0, 0, {}},\n' $t $t
done
printf ' {0, 0, 0, 0},\n'
printf ' {0, 0, 0, 0, 0, {}},\n'
printf '};\n'
}

Expand Down
10 changes: 7 additions & 3 deletions ct/internal.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
typedef struct T T;
#define TmpDirPat "/tmp/ct.XXXXXX"

struct T {
typedef struct Test Test;

struct Test {
void (*f)(void);
char *name;
int status;
int fd;
int pid;
char dir[sizeof TmpDirPat];
};

extern T ctmain[];
extern Test ctmain[];

0 comments on commit 59b5cfc

Please sign in to comment.