diff options
Diffstat (limited to 'src/time')
-rw-r--r-- | src/time/timer_create.c | 110 | ||||
-rw-r--r-- | src/time/timer_delete.c | 12 | ||||
-rw-r--r-- | src/time/timer_getoverrun.c | 7 | ||||
-rw-r--r-- | src/time/timer_gettime.c | 7 | ||||
-rw-r--r-- | src/time/timer_settime.c | 7 |
5 files changed, 143 insertions, 0 deletions
diff --git a/src/time/timer_create.c b/src/time/timer_create.c new file mode 100644 index 00000000..1ac1906b --- /dev/null +++ b/src/time/timer_create.c @@ -0,0 +1,110 @@ +#include <time.h> +#include "pthread_impl.h" + +struct ksigevent { + union sigval sigev_value; + int sigev_signo; + int sigev_notify; + int sigev_tid; +}; + +struct start_args { + pthread_barrier_t b; + struct sigevent *sev; + timer_t t; +}; + +static void sighandler(int sig, siginfo_t *si, void *ctx) +{ + int st; + timer_t t = si->si_value.sival_ptr; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &st); + t->notify(t->val); + pthread_setcancelstate(st, 0); +} + +static void killtimer(void *arg) +{ + timer_t t = arg; + if (t->timerid >= 0) __syscall(SYS_timer_delete, t->timerid); +} + +static void *start(void *arg) +{ + struct start_args *args = arg; + struct __timer t = { + .notify = args->sev->sigev_notify_function, + .val = args->sev->sigev_value, + }; + + args->t = &t; + + pthread_barrier_wait(&args->b); + + pthread_cleanup_push(killtimer, &t); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0); + /* Loop on async-signal-safe cancellation point */ + for (;;) sleep(1); + pthread_cleanup_pop(1); + return 0; +} + +int timer_create(clockid_t clk, struct sigevent *evp, timer_t *res) +{ + struct sigevent sev = { + .sigev_notify = SIGEV_SIGNAL, + .sigev_signo = SIGALRM + }; + pthread_t td; + pthread_attr_t attr; + int r; + struct start_args args; + timer_t t; + struct ksigevent ksev; + + if (evp) sev = *evp; + + switch (sev.sigev_notify) { + case SIGEV_NONE: + case SIGEV_SIGNAL: + if (!(t = calloc(1, sizeof *t))) + return -1; + ksev.sigev_value = evp ? sev.sigev_value + : (union sigval){.sival_ptr=t}; + ksev.sigev_signo = sev.sigev_signo; + ksev.sigev_notify = sev.sigev_notify; + ksev.sigev_tid = 0; + break; + case SIGEV_THREAD: + if (sev.sigev_notify_attributes) + attr = *sev.sigev_notify_attributes; + else + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_barrier_init(&args.b, 0, 2); + args.sev = &sev; + r = pthread_create(&td, &attr, start, &args); + if (r) { + errno = r; + return -1; + } + pthread_barrier_wait(&args.b); + t = args.t; + t->thread = td; + ksev.sigev_value.sival_ptr = t; + ksev.sigev_signo = SIGCANCEL; + ksev.sigev_notify = 4; /* SIGEV_THREAD_ID */ + ksev.sigev_tid = td->tid; + if (!libc.sigtimer) libc.sigtimer = sighandler; + break; + } + + t->timerid = -1; + if (syscall(SYS_timer_create, clk, &ksev, &t->timerid) < 0) { + timer_delete(t); + return -1; + } + + *res = t; + return 0; +} diff --git a/src/time/timer_delete.c b/src/time/timer_delete.c new file mode 100644 index 00000000..d7c7670f --- /dev/null +++ b/src/time/timer_delete.c @@ -0,0 +1,12 @@ +#include <time.h> +#include "pthread_impl.h" + +int timer_delete(timer_t t) +{ + if (t->thread) pthread_cancel(t->thread); + else { + if (t->timerid >= 0) __syscall(SYS_timer_delete, t->timerid); + free(t); + } + return 0; +} diff --git a/src/time/timer_getoverrun.c b/src/time/timer_getoverrun.c new file mode 100644 index 00000000..1334e451 --- /dev/null +++ b/src/time/timer_getoverrun.c @@ -0,0 +1,7 @@ +#include <time.h> +#include "pthread_impl.h" + +int timer_getoverrun(timer_t t) +{ + return syscall(SYS_timer_getoverrun, t->timerid); +} diff --git a/src/time/timer_gettime.c b/src/time/timer_gettime.c new file mode 100644 index 00000000..3d3156a0 --- /dev/null +++ b/src/time/timer_gettime.c @@ -0,0 +1,7 @@ +#include <time.h> +#include "pthread_impl.h" + +int timer_gettime(timer_t t, struct itimerspec *val) +{ + return syscall(SYS_timer_gettime, t->timerid, val); +} diff --git a/src/time/timer_settime.c b/src/time/timer_settime.c new file mode 100644 index 00000000..d109570b --- /dev/null +++ b/src/time/timer_settime.c @@ -0,0 +1,7 @@ +#include <time.h> +#include "pthread_impl.h" + +int timer_settime(timer_t t, int flags, const struct itimerspec *val, struct itimerspec *old) +{ + return syscall(SYS_timer_settime, t->timerid, flags, val, old); +} |