#include #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_QUEUE_DIR "." #define MAX_JOBS 1 int cur_jobs = 0; void run_job(char *queuedir, int fd) { char *run; switch(fork()) { case -1: return; case 0: asprintf(&run, "%s/run", queuedir); dup2(fd, STDIN_FILENO); close(fd); execl(run, "run", (char*)NULL); perror("execle()"); _exit(1); break; } } void process_queue(char *queuedir, int dfd) { int fd; DIR *dir; struct dirent *de; char *name; dir = fdopendir(dfd); while ((de = readdir(dir))) { if (cur_jobs >= MAX_JOBS) break; if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue; asprintf(&name, "new/%s", de->d_name); fd = open(name, O_RDONLY); if (fd == -1) { free(name); continue; } unlink(name); run_job(queuedir, fd); close(fd); free(name); cur_jobs++; } rewinddir(dir); fdclosedir(dir); } void wait_all() { for (;;) { int r = waitpid(-1, NULL, WNOHANG); if (r == -1) { if (errno == ECHILD) break; else if (errno == EWOULDBLOCK) break; else err(1, "waitpid()"); } cur_jobs--; } } int main(int argc, char **argv) { int kq, dfd, ret; struct kevent kv[2]; char *queuedir = NULL, *newdir = NULL; if (argc > 1) { queuedir = strdup(argv[1]); } else { queuedir = strdup(DEFAULT_QUEUE_DIR); } asprintf(&newdir, "%s/new", queuedir); dfd = open(newdir, O_RDONLY | O_DIRECTORY); if (dfd == -1) err(1, "open()"); kq = kqueue(); if (kq == -1) err(1, "kqueue()"); EV_SET(&kv[0], dfd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, NULL); EV_SET(&kv[1], SIGCHLD, EVFILT_SIGNAL, EV_ADD | EV_CLEAR, 0, 0, NULL); if (kevent(kq, kv, 2, NULL, 0, NULL) == -1) err(1, "kevent()"); process_queue(queuedir, dfd); for (;;) { ret = kevent(kq, NULL, 0, kv, 2, NULL); if (ret == 0) continue; else if (ret == -1) { if (errno == EINTR) continue; else break; } int i; for (i = 0; i < ret; i++) { if (kv[i].filter == EVFILT_SIGNAL) { if (kv[i].ident == SIGCHLD) { wait_all(); process_queue(queuedir, dfd); } } else if (kv[i].filter == EVFILT_VNODE) { process_queue(queuedir, dfd); } } } return 0; }