SRCS:=$(sort $(wildcard src/*/*.c))
OBJS:=$(SRCS:%.c=%.o)
-DIRS:=$(sort $(wildcard src/*))
+DIRS:=$(filter-out src/common,$(sort $(wildcard src/*)))
NAMES:=$(OBJS:.o=)
SPEC_PATTERNS:=src/common/% src/api/% src/math/%
CFLAGS:=-Isrc/common
LIBS:=$(foreach n,$(NAMES),$($(n).LIBS))
ERRS:=$(BINS:%=%.err)
+debug:
+ @echo MBINS $(MBINS)
+ @echo BINS $(BINS)
+ @echo LIBS $(LIBS)
+ @echo ERRS $(ERRS)
+ @echo DIRS $(DIRS)
+
define target_template
$(1)/all: $(1)/REPORT
$(1)/clean:
$(foreach d,$(DIRS),$(eval $(call target_template,$(d))))
-src/common/all: src/common/libtest.a
+src/common/all: src/common/REPORT
+src/common/REPORT: src/common/run
+ cat src/common/*.err >$@
+REPORT: src/common/REPORT
+src/common/run: src/common/run.o src/common/libtest.a
+$(ERRS): src/common/run
all:REPORT
clean:
- rm -f $(OBJS) $(BINS) $(LIBS) src/common/libtest.a src/*/*.err
+ rm -f $(OBJS) $(BINS) $(LIBS) src/common/libtest.a src/common/run src/*/*.err
cleanall: clean
rm -f REPORT src/*/REPORT
REPORT:
touch $@
%.err: %
# TODO: proper wrapping that records exit status
- ./$< 2>/dev/null >$@ || true
+ src/common/run ./$< 2>/dev/null >$@ || true
.PHONY: all clean cleanall
#include <string.h>
+#include <stdio.h>
#include "test.h"
/* relative path to p */
--- /dev/null
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+volatile int t_status = 0;
+
+int t_printf(const char *s, ...)
+{
+ va_list ap;
+ char buf[512];
+ int n;
+
+ t_status = 1;
+ va_start(ap, s);
+ n = vsnprintf(buf, sizeof buf, s, ap);
+ va_end(ap);
+ if (n < 0)
+ n = 0;
+ else if (n >= sizeof buf) {
+ n = sizeof buf;
+ buf[n - 1] = '\n';
+ buf[n - 2] = '.';
+ buf[n - 3] = '.';
+ buf[n - 4] = '.';
+ }
+ return write(1, buf, n);
+}
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include "test.h"
+
+static void handler(int s)
+{
+}
+
+static void setrl(int r, long lim) {
+ struct rlimit rl;
+
+ if (getrlimit(r, &rl))
+ t_error("getrlimit %d: %s\n", r, strerror(errno));
+ rl.rlim_cur = lim;
+ if (lim < rl.rlim_max)
+ rl.rlim_max = lim;
+ if (setrlimit(r, &rl))
+ t_error("setrlimit %d: %s\n", r, strerror(errno));
+}
+
+static int start(char *argv[])
+{
+ int pid;
+
+ pid = fork();
+ if (pid == 0) {
+ setrl(RLIMIT_STACK, 100*1024);
+ setrl(RLIMIT_CPU, 2);
+ execv(argv[0], argv);
+ t_error("%s exec failed: %s\n", argv[0], strerror(errno));
+ exit(1);
+ }
+ if (pid == -1) {
+ t_error("%s fork failed: %s\n", argv[0], strerror(errno));
+ exit(-1);
+ }
+ return pid;
+}
+
+int main(int argc, char *argv[])
+{
+ int status;
+ sigset_t set;
+ int timeout = 0;
+ int sig = 0;
+ int pid;
+
+ if (argc < 2) {
+ t_error("usage: ./run cmd [args..]\n");
+ return -1;
+ }
+ argv++;
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &set, 0);
+ signal(SIGCHLD, handler);
+ pid = start(argv);
+ if (sigtimedwait(&set, 0, &(struct timespec){5,0}) == -1) {
+ if (errno == EAGAIN)
+ timeout = 1;
+ if (kill(pid, SIGKILL) == -1)
+ t_error("%s kill failed: %s\n", argv[0], strerror(errno));
+ }
+ if (waitpid(pid, &status, 0) != pid) {
+ t_error("%s waitpid failed: %s\n", argv[0], strerror(errno));
+ return -1;
+ }
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 0)
+ return 0;
+ t_printf("FAIL %s [status %d]\n", argv[0], WEXITSTATUS(status));
+ } else if (timeout) {
+ t_printf("FAIL %s [timed out]\n", argv[0]);
+ } else if (WIFSIGNALED(status)) {
+ t_printf("FAIL %s [signal %s]\n", argv[0], strsignal(WTERMSIG(status)));
+ } else
+ t_printf("FAIL %s [unknown]\n", argv[0]);
+ return 1;
+}
--- /dev/null
+#include <string.h>
+#include <errno.h>
+#include <sys/resource.h>
+#include "test.h"
+
+int t_setrlim(int r, long lim)
+{
+ struct rlimit rl;
+
+ if (getrlimit(r, &rl)) {
+ t_error("getrlimit %d: %s\n", r, strerror(errno));
+ return -1;
+ }
+ if (lim > rl.rlim_max)
+ return -1;
+ if (lim == rl.rlim_max && lim == rl.rlim_cur)
+ return 0;
+ rl.rlim_max = lim;
+ rl.rlim_cur = lim;
+ if (setrlimit(r, &rl)) {
+ t_error("setrlimit %d: %s\n", r, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
#include <stdint.h>
-#include <stdio.h>
-#include <stdarg.h>
#include <unistd.h>
/* TODO: not thread-safe nor fork-safe */
-static volatile int t_status;
+extern volatile int t_status;
#define T_LOC2(l) __FILE__ ":" #l
#define T_LOC1(l) T_LOC2(l)
-#define t_error(...) t_printf("ERROR " T_LOC1(__LINE__) ": " __VA_ARGS__)
-
-static int t_printf(const char *s, ...)
-{
- va_list ap;
- char buf[512];
- int n;
-
- t_status = 1;
- va_start(ap, s);
- n = vsnprintf(buf, sizeof buf, s, ap);
- va_end(ap);
- if (n < 0)
- n = 0;
- else if (n >= sizeof buf) {
- n = sizeof buf;
- buf[n - 1] = '\n';
- buf[n - 2] = '.';
- buf[n - 3] = '.';
- buf[n - 4] = '.';
- }
- return write(1, buf, n);
-}
+#define t_error(...) t_printf(T_LOC1(__LINE__) ": " __VA_ARGS__)
+
+int t_printf(const char *s, ...);
int t_vmfill(void **, size_t *, int);
char *t_pathrel(char *buf, size_t n, char *argv0, char *p);
+int t_setrlim(int r, long lim);
+
#include <stdlib.h>
+#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <semaphore.h>
#include <sys/resource.h>
#include "test.h"
-static void setrl(int r, long lim)
-{
- struct rlimit rl;
-
- if (getrlimit(r, &rl))
- t_error("getrlimit %d: %s\n", r, strerror(errno));
- rl.rlim_cur = lim;
- if (setrlimit(r, &rl))
- t_error("setrlimit %d: %s\n", r, strerror(errno));
-}
-
int main(void)
{
enum {n = 8*1024*1024};
if (!s)
return t_error("out of memory");
- setrl(RLIMIT_STACK, 128*1024);
+ t_setrlim(RLIMIT_STACK, 100*1024);
for (i = 0; i < n; i++) s[i] = '1';
s[n-3] = ' ';