#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define gettid() syscall(__NR_gettid) static int do_print; static int do_quit; static size_t loops; #ifndef __NR_sched_setattr #ifdef __x86_64__ #define __NR_sched_setattr 314L #define __NR_sched_getattr 315L #endif #endif struct sched_attr { __u32 size; __u32 sched_policy; __u64 sched_flags; __s32 sched_nice; __s32 sched_priority; __u64 sched_runtime; __u64 sched_deadline; __u64 sched_period; }; long sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags) { return syscall(__NR_sched_setattr, pid, attr, flags); } long sched_getattr(pid_t pid, struct sched_attr *attr, unsigned int size, unsigned int flags) { return syscall(__NR_sched_getattr, pid, attr, size, flags); } static void sig_handler(int signum) { switch (signum) { case SIGQUIT: case SIGTERM: case SIGINT: signal(SIGINT, SIG_DFL); do_quit = 1; __attribute__((fallthrough)); case SIGUSR1: do_print = 1; break; case SIGHUP: loops = 0; default: break; } } static int deadline(size_t period_ms) { int rc = 0; #ifndef EDF int tfd = -1; struct itimerspec itval; tfd = timerfd_create(CLOCK_MONOTONIC, 0); if (tfd == -1) err(-1, "timerfd"); itval.it_interval.tv_sec = 0; itval.it_interval.tv_nsec = period_ms * 1000 * 1000; itval.it_value.tv_sec = 0; itval.it_value.tv_nsec = itval.it_interval.tv_nsec; rc = timerfd_settime(tfd, 0, &itval, NULL); if (rc) err(-1, "timerfd_settime"); do { static unsigned long long overrun; rc = read(tfd, &overrun, sizeof overrun); if (rc == -1) { err(-1, "Timer read"); } ++loops; if (do_print) { do_print = 0; fprintf(stdout, "Loops: %zu.\n", loops); } } while(!do_quit); #else struct sched_attr attr; unsigned int flags = 0; attr.size = sizeof attr; attr.sched_flags = 0; attr.sched_nice = 0; attr.sched_priority = 0; attr.sched_policy = SCHED_DEADLINE; attr.sched_runtime = (period_ms - 1) * 1000 * 1000; attr.sched_period = attr.sched_deadline = period_ms * 1000 * 1000; rc = sched_setattr(0, &attr, flags); if (rc) err(EXIT_FAILURE, "sched_setattr"); do { ++loops; if (do_print) { do_print = 0; fprintf(stdout, "Loops: %zu.\n", loops); } sched_yield(); } while(!do_quit); #endif printf("last counter => %zu.\n", loops); } #define SEC_NSEC 1000000000U static __attribute__((const)) u_int64_t timespec_sub_to_ns(struct timespec t1, struct timespec t2) { u_int64_t diff; if (t1.tv_nsec < t2.tv_nsec) { diff = SEC_NSEC * (u_int64_t)(t1.tv_sec - t2.tv_sec -1); diff += (u_int64_t)(t1.tv_nsec - t2.tv_nsec); diff += SEC_NSEC; } else { diff = SEC_NSEC * (u_int64_t)(t1.tv_sec - t2.tv_sec); diff += (u_int64_t)(t1.tv_nsec - t2.tv_nsec); } return diff; } int main(int argc, char *argv[]) { int rc; struct sigaction sa = {0}; struct timespec t0, t1; /* Set up the structure to specify the new action. */ sigemptyset (&sa.sa_mask); sigaddset(&sa.sa_mask, SIGINT); sa.sa_handler = &sig_handler; sa.sa_flags = 0; sigaddset(&sa.sa_mask, SIGTERM); sigaddset(&sa.sa_mask, SIGINT); sigaddset(&sa.sa_mask, SIGHUP); sigaddset(&sa.sa_mask, SIGUSR1); sigaddset(&sa.sa_mask, SIGQUIT); if (sigaction (SIGINT, &sa, NULL) == -1) { perror("sigaction"); exit(EXIT_FAILURE); } sigaction (SIGTERM, &sa, NULL); sigaction (SIGQUIT, &sa, NULL); sigaction (SIGUSR1, &sa, NULL); sigaction (SIGHUP, &sa, NULL); printf("[%d] Starting deadline thread.\n", getpid()); clock_gettime(CLOCK_MONOTONIC, &t0); rc = deadline(5); clock_gettime(CLOCK_MONOTONIC, &t1); size_t to = timespec_sub_to_ns(t1, t0) / 1000000; printf("Time: %lums. average : %lums.\n", to, to / loops); return rc ? EXIT_FAILURE : EXIT_SUCCESS; }