static int sq_test_random(squeue_t *sq) { unsigned long size, i; unsigned long long numbers[EVT_ARY], *d, max = 0; struct timeval now; size = squeue_size(sq); now.tv_sec = time(NULL); srand((int)now.tv_sec); for (i = 0; i < EVT_ARY; i++) { now.tv_usec = (time_t)rand(); squeue_add_tv(sq, &now, &numbers[i]); numbers[i] = evt_compute_pri(&now); t(squeue_size(sq) == i + 1 + size); } t(pqueue_is_valid(sq)); /* * make sure we pop events in increasing "priority", * since we calculate priority based on time and later * is lower prio */ for (i = 0; i < EVT_ARY; i++) { d = (unsigned long long *)squeue_pop(sq); t(max <= *d, "popping randoms. i: %lu; delta: %lld; max: %llu; *d: %llu\n", i, max - *d, max, *d); max = *d; t(squeue_size(sq) == size + (EVT_ARY - i - 1)); } t(pqueue_is_valid(sq)); return 0; }
squeue_event *squeue_add_usec(squeue_t *q, time_t when, time_t usec, void *data) { struct timeval tv; tv.tv_sec = when; tv.tv_usec = usec; assert(usec < 1000000); return squeue_add_tv(q, &tv, data); }
squeue_event *squeue_add(squeue_t *q, time_t when, void *data) { struct timeval tv; /* * we fetch real microseconds first, so events with same * timestamp get different priorities for FIFO ordering. */ gettimeofday(&tv, NULL); tv.tv_sec = when; return squeue_add_tv(q, &tv, data); }
/* * "What can the harvest hope for, if not for the care * of the Reaper Man?" * -- Terry Pratchett, Reaper Man * * We end up here no matter if the job is stale (ie, the child is * stuck in uninterruptable sleep) or if it's the first time we try * to kill it. * A job is considered reaped once we reap our direct child, in * which case init will become parent of our grandchildren. * It's also considered fully reaped if kill() results in ESRCH or * EPERM, or if wait()ing for the process group results in ECHILD. */ static void kill_job(child_process *cp, int reason) { int ret, status, reaped = 0; int pid = cp ? cp->ei->pid : 0; /* * first attempt at reaping, so see if we just failed to * notice that things were going wrong her */ if (reason == ETIME && !check_completion(cp, WNOHANG)) { timeouts++; wlog("job %d with pid %d reaped at timeout. timeouts=%u; started=%u", cp->id, pid, timeouts, started); return; } /* brutal but efficient */ if (kill(-cp->ei->pid, SIGKILL) < 0) { if (errno == ESRCH) { reaped = 1; } else { wlog("kill(-%d, SIGKILL) failed: %s\n", cp->ei->pid, strerror(errno)); } } /* * we must iterate at least once, in case kill() returns * ESRCH when there's zombies */ do { ret = waitpid(cp->ei->pid, &status, WNOHANG); if (ret < 0 && errno == EINTR) continue; if (ret == cp->ei->pid || (ret < 0 && errno == ECHILD)) { reaped = 1; break; } if (!ret) { struct timeval tv; gettimeofday(&tv, NULL); /* * stale process (signal may not have been delivered, or * the child can be stuck in uninterruptible sleep). We * can't hang around forever, so just reschedule a new * reap attempt later. */ if (reason == ESTALE) { tv.tv_sec += 5; wlog("Failed to reap child with pid %d. Next attempt @ %lu.%lu", cp->ei->pid, tv.tv_sec, tv.tv_usec); } else { tv.tv_usec = 250000; if (tv.tv_usec > 1000000) { tv.tv_usec -= 1000000; tv.tv_sec += 1; } cp->ei->state = ESTALE; finish_job(cp, reason); } squeue_remove(sq, cp->ei->sq_event); cp->ei->sq_event = squeue_add_tv(sq, &tv, cp); return; } } while (!reaped); if (cp->ei->state != ESTALE) finish_job(cp, reason); else wlog("job %d (pid=%d): Dormant child reaped", cp->id, cp->ei->pid); destroy_job(cp); }