POSIX-RT-Timer

 view release on metacpan or  search on metacpan

lib/POSIX/RT/Timer.xs  view on Meta::CPAN

static timer_t S_timer_new(pTHX_ timer_init* para) {
	timer_t timer;
	struct sigevent event = { 0 };

	if (para->signo < 0)
		Perl_croak(aTHX_ "No valid signal was given");

#ifdef gettid
	event.sigev_notify           = SIGEV_THREAD_ID;
	event.sigev_notify_thread_id = gettid();
#else
	event.sigev_notify           = SIGEV_SIGNAL;
#endif
	event.sigev_signo            = para->signo;
	event.sigev_value.sival_int  = para->ident;

	if (timer_create(para->clockid, &event, &timer) < 0)
		die_sys("Couldn't create timer: %s");
	if (timer_settime(timer, para->flags, &para->itimer, NULL) < 0)
		die_sys("Couldn't set_time: %s");

	return timer;
}
#define timer_new(para) S_timer_new(aTHX_ para)

void timespec_add(struct timespec* left, const struct timespec* right) {
	left->tv_sec += right->tv_sec;
	left->tv_nsec += right->tv_nsec;
	while (left->tv_nsec > 1000000000) {
		left->tv_nsec -= 1000000000;
		left->tv_sec++;
	}
}

static const struct timespec no_time = { 0, 0 };

typedef timer_t POSIX__RT__Timer;
typedef clockid_t POSIX__RT__Clock;

#define XS_unpack_clockid_t(sv) get_clockid(sv)

MODULE = POSIX::RT::Timer  PACKAGE = POSIX::RT::Timer

PROTOTYPES: DISABLED

POSIX::RT::Timer new(SV* class, timer_init args, ...)
	CODE:
		RETVAL = timer_new(&args);
	OUTPUT:
		RETVAL

UV handle(POSIX::RT::Timer timer)
	CODE:
		RETVAL = (UV)timer;
	OUTPUT:
		RETVAL

void get_timeout(POSIX::RT::Timer timer)
	PREINIT:
		struct itimerspec value;
	PPCODE:
		if (timer_gettime(timer, &value) == -1)
			die_sys("Couldn't get_time: %s");
		mXPUSHn(timespec_to_nv(&value.it_value));
		if (GIMME_V == G_ARRAY)
			mXPUSHn(timespec_to_nv(&value.it_interval));

void set_timeout(POSIX::RT::Timer timer, struct timespec new_value, struct timespec new_interval = no_time, bool abstime = FALSE)
	PREINIT:
		struct itimerspec old_itimer;
	PPCODE:
		struct itimerspec new_itimer = { new_value, new_interval };
		if (timer_settime(timer, (abstime ? TIMER_ABSTIME : 0), &new_itimer, &old_itimer) == -1)
			die_sys("Couldn't set_time: %s");
		mXPUSHn(timespec_to_nv(&old_itimer.it_value));
		if (GIMME_V == G_ARRAY)
			mXPUSHn(timespec_to_nv(&old_itimer.it_interval));

IV get_overrun(POSIX::RT::Timer timer)
	CODE:
		RETVAL = timer_getoverrun(timer);
		if (RETVAL == -1) 
			die_sys("Couldn't get_overrun: %s");
	OUTPUT:
		RETVAL

void DESTROY(POSIX::RT::Timer timer)
	CODE:
		timer_delete(timer);

MODULE = POSIX::RT::Timer				PACKAGE = POSIX::RT::Clock

PROTOTYPES: DISABLED

POSIX::RT::Clock new(SV* class, clockid_t clockid = CLOCK_REALTIME)
	CODE:
		RETVAL = clockid;
	OUTPUT:
		RETVAL

UV handle(POSIX::RT::Clock clock)
	CODE:
		RETVAL = (UV)clock;
	OUTPUT:
		RETVAL

#if defined(_POSIX_CPUTIME) && _POSIX_CPUTIME >= 0
POSIX::RT::Clock get_cpuclock(SV* class, SV* pid = undef)
	CODE:
		if (SvOK(pid) && SvROK(pid) && sv_derived_from(pid, "threads")) {
#if defined(USE_ITHREADS) && defined(_POSIX_THREAD_CPUTIME) && _POSIX_THREAD_CPUTIME >= 0
			pthread_t* handle = get_pthread(pid);
			if (pthread_getcpuclockid(*handle, &RETVAL) != 0)
				die_sys("Could not get cpuclock: %s");
#else
			Perl_croak(aTHX_ "Can't get CPU time for threads");
#endif
		}
		else {
			if (clock_getcpuclockid(SvOK(pid) ? SvIV(pid) : 0, &RETVAL) != 0)
				die_sys("Could not get cpuclock: %s");
		}
	OUTPUT:
		RETVAL

#endif

void get_clocks(...)
	PREINIT:
		size_t i;
		const size_t max = sizeof clocks / sizeof *clocks;
	PPCODE:
		for (i = 0; i < max; ++i)
			mXPUSHp(clocks[i].key, clocks[i].key_length);
		PUTBACK;

struct timespec get_time(POSIX::RT::Clock clockid)
	CODE:
		if (clock_gettime(clockid, &RETVAL) == -1)
			die_sys("Couldn't get time: %s");
	OUTPUT:
		RETVAL

void set_time(POSIX::RT::Clock clockid, struct timespec time)
	CODE:
		if (clock_settime(clockid, &time) == -1)
			die_sys("Couldn't set time: %s");

struct timespec get_resolution(POSIX::RT::Clock clockid)
	CODE:
		if (clock_getres(clockid, &RETVAL) == -1)
			die_sys("Couldn't get resolution: %s");
	OUTPUT:
		RETVAL

POSIX::RT::Timer timer(POSIX::RT::Clock clockid, timer_init args, ...)
	CODE:
		args.clockid = clockid;
		RETVAL = timer_new(&args);
	OUTPUT:
		RETVAL

#if defined(_POSIX_CLOCK_SELECTION) && _POSIX_CLOCK_SELECTION >= 0
struct timespec sleep(POSIX::RT::Clock clockid, struct timespec time, bool abstime = FALSE)
	PREINIT:
		struct timespec remain_time;
		int flags;
	CODE:
		flags = abstime ? TIMER_ABSTIME : 0;

		if (clock_nanosleep(clockid, flags, &time, &remain_time) == EINTR)
			RETVAL = abstime ? time : remain_time;
		else 
			RETVAL = no_time;
	OUTPUT:
		RETVAL

NV sleep_deeply(POSIX::RT::Clock clockid, struct timespec time, bool abstime = FALSE)
	PREINIT:
	CODE:
		if (!abstime) {
			struct timespec current_time;
			if (clock_gettime(clockid, &current_time) == -1)
				die_sys("Couldn't get time: %s");
			timespec_add(&time, &current_time);
		}
		while (clock_nanosleep(clockid, TIMER_ABSTIME, &time, NULL) == EINTR);
		RETVAL = 0;
	OUTPUT:
		RETVAL

#endif



( run in 1.465 second using v1.01-cache-2.11-cpan-5511b514fd6 )