Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 60b1bf58bd
Fetching contributors…

Cannot retrieve contributors at this time

264 lines (192 sloc) 4.953 kb
/*
Copyright (C) 2010-2012, Parrot Foundation.
=head1 NAME
src/alarm.c - Implements a mechanism for alarms, setting a flag after a delay.
=head1 DESCRIPTION
This program implements a mechanism for alarms, setting a flag after a delay.
=cut
*/
#include "parrot/parrot.h"
#include "parrot/alarm.h"
/* Some per-process state */
static volatile UINTVAL alarm_serial = 0;
static volatile FLOATVAL alarm_set_to = 0.0;
/* This file relies on POSIX. Probably need two other versions of it:
* one for Windows and one for platforms with no signals or threads. */
#ifdef _WIN32
# include <time.h>
#else
# include <sys/time.h>
# include <signal.h>
# ifdef PARROT_HAS_HEADER_PTHREAD
# include <pthread.h>
# endif
#endif
#include <errno.h>
/* HEADERIZER HFILE: include/parrot/alarm.h */
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
static void posix_alarm_set(FLOATVAL wait);
#define ASSERT_ARGS_posix_alarm_set __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
/*
=over 4
=item C<void Parrot_alarm_init(void)>
Initialize the alarm queue. This function should only be called from the initial
pthread. Any other pthreads should make sure to mask out SIGALRM.
=cut
*/
void
Parrot_alarm_init(void)
{
ASSERT_ARGS(Parrot_alarm_init)
#ifdef _WIN32
/* TODO: Implement on Windows */
#else
struct sigaction sa;
memset(&sa, 0, sizeof (struct sigaction));
sa.sa_handler = Parrot_alarm_callback;
sa.sa_flags = SA_RESTART;
if (sigaction(SIGALRM, &sa, 0) == -1)
Parrot_x_force_error_exit(NULL, 1, "sigaction failed in Parrot_timers_init");
Parrot_alarm_unmask(NULL);
#endif
}
/*
=item C<static void posix_alarm_set(FLOATVAL wait)>
A helper function to set an alarm.
=cut
*/
static void
posix_alarm_set(FLOATVAL wait)
{
ASSERT_ARGS(posix_alarm_set)
#ifdef _WIN32
/* TODO: Implement on Windows */
#else
const int MIL = 1000000;
const int sec = (int) wait;
const int usec = (int) ((wait - sec) * MIL);
struct itimerval itmr;
itmr.it_value.tv_sec = sec;
itmr.it_value.tv_usec = usec;
itmr.it_interval.tv_sec = 0;
itmr.it_interval.tv_usec = 0;
if (setitimer(ITIMER_REAL, &itmr, 0) == -1) {
if (errno == EINVAL) {
Parrot_alarm_callback(SIGALRM);
}
else
Parrot_x_force_error_exit(NULL, 1, "setitimer failed in set_posix_alarm");
}
#endif
}
/*
=item C<void Parrot_alarm_mask(PARROT_INTERP)>
=item C<void Parrot_alarm_unmask(PARROT_INTERP)>
These block or unblock the signal for alarms. Any thread with signals
unblocked should avoid waiting on a lock or condition variable.
=cut
*/
void
Parrot_alarm_mask(SHIM_INTERP)
{
ASSERT_ARGS(Parrot_alarm_mask)
#ifdef _WIN32
/* TODO: Implement on Windows */
#else
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
pthread_sigmask(SIG_BLOCK, &mask, 0);
#endif
}
void
Parrot_alarm_unmask(SHIM_INTERP)
{
ASSERT_ARGS(Parrot_alarm_unmask)
#ifdef _WIN32
/* TODO: Implement on Windows */
#else
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
pthread_sigmask(SIG_UNBLOCK, &mask, 0);
#endif
}
/*
=item C<void Parrot_alarm_callback(int sig_number)>
Callback for SIGALRM. When this is called, a timer should be ready to fire.
=cut
*/
void
Parrot_alarm_callback(SHIM(int sig_number))
{
ASSERT_ARGS(Parrot_alarm_callback)
/* Not atomic; only one thread ever writes this value */
alarm_serial += 1;
}
/*
=item C<int Parrot_alarm_check(UINTVAL* last_serial)>
Has any alarm triggered since we last checked?
Possible design improvement: Alert only the thread that
set the alarm.
=cut
*/
PARROT_EXPORT
int
Parrot_alarm_check(ARGMOD(UINTVAL* last_serial))
{
ASSERT_ARGS(Parrot_alarm_check)
if (*last_serial == alarm_serial) {
return 0;
}
else {
*last_serial = alarm_serial;
return 1;
}
}
/*
=item C<void Parrot_alarm_set(FLOATVAL when)>
Sets an alarm to trigger at time 'when'.
=cut
*/
PARROT_EXPORT
void
Parrot_alarm_set(FLOATVAL when)
{
ASSERT_ARGS(Parrot_alarm_set)
#ifdef _WIN32
/* TODO: Implement on Windows */
#else
const FLOATVAL now = Parrot_floatval_time();
/* Better late than early */
when += 0.0001;
if (alarm_set_to > now && alarm_set_to < when)
return;
alarm_set_to = when;
posix_alarm_set(when - now);
#endif
}
/*
=item C<void Parrot_alarm_now(void)>
Trigger an alarm wakeup.
=cut
*/
void
Parrot_alarm_now(void)
{
ASSERT_ARGS(Parrot_alarm_now)
#ifdef _WIN32
/* TODO: Implement on Windows */
#else
kill(getpid(), SIGALRM);
#endif
}
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/
Jump to Line
Something went wrong with that request. Please try again.