diff options
| -rw-r--r-- | include/limits.h | 1 | ||||
| -rw-r--r-- | include/signal.h | 22 | ||||
| -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 | 
7 files changed, 160 insertions, 6 deletions
| diff --git a/include/limits.h b/include/limits.h index 55ad8231..3953aea5 100644 --- a/include/limits.h +++ b/include/limits.h @@ -31,6 +31,7 @@  #define PTHREAD_DESTRUCTOR_ITERATIONS 4  #define SEM_VALUE_MAX 0x7fffffff  #define SEM_NSEMS_MAX 256 +#define DELAYTIMER_MAX 0x7fffffff  /* Arbitrary numbers... */ diff --git a/include/signal.h b/include/signal.h index f5e87c78..6116fb43 100644 --- a/include/signal.h +++ b/include/signal.h @@ -17,6 +17,7 @@ extern "C" {  #define __NEED_uid_t  #define __NEED_struct_timespec  #define __NEED_pthread_t +#define __NEED_pthread_attr_t  #define __NEED_time_t  #define __NEED_clock_t  #define __NEED_sigset_t @@ -24,8 +25,7 @@ extern "C" {  #include <bits/alltypes.h> -struct sigaction -{ +struct sigaction {  	union {  		void (*sa_handler)(int);  		void (*sa_sigaction)(int, siginfo_t *, void *); @@ -37,19 +37,29 @@ struct sigaction  #define sa_handler   __sa_handler.sa_handler  #define sa_sigaction __sa_handler.sa_sigaction -typedef struct -{ +typedef struct {  	void *ss_sp;  	int ss_flags;  	size_t ss_size;  } stack_t; -union sigval -{ +union sigval {  	int sival_int;  	void *sival_ptr;  }; +struct sigevent { +	union sigval sigev_value; +	int sigev_signo; +	int sigev_notify; +	void (*sigev_notify_function)(union sigval); +	pthread_attr_t *sigev_notify_attributes; +}; + +#define SIGEV_SIGNAL 0 +#define SIGEV_NONE 1 +#define SIGEV_THREAD 2 +  int __libc_current_sigrtmin(void);  int __libc_current_sigrtmax(void); 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); +} | 
