#define _POSIX_C_SOURCE 200809L
#define _XOPEN_SOURCE 500
#include <sched.h> /* for sched_setsched */
#include <unistd.h> /* for usleep */
#include <time.h> /* for clock_gettime */
#include <string.h> /* for memset */
#include <stdio.h>
#define MS_to_US(x) ((x)*1000)
void TASK1()
{
printf("hi \n");
}
void TASK2()
{
printf("hi2 \n");
}
void TASK3()
{
printf("hi3 \n");
}
useconds_t delta_t_us(struct timespec const *a, struct timespec const *b)
{
time_t const delta_sec = b->tv_sec - a->tv_sec;
long const delta_nsec = b->tv_nsec - a->tv_nsec;
/* this might actually overflow for "long" time intervalls"
* should be safe for a delta_t < 2ms though */
return delta_sec * 1000000 + delta_nsec / 1000;
}
void rastertask()
{
struct sched_param sparm;
memset(&sparm, 0, sizeof(sparm));
sparm.sched_priority = 10; /* 0 = lowest, 99 = highest */
sched_setscheduler(
0 /* pid, 0 ==> this process */,
SCHED_RR /* policy */,
&sparm);
unsigned int n_loop;
for(n_loop=0;;n_loop++) {
struct timespec ts_start, ts_end;
clock_gettime(CLOCK_REALTIME, &ts_start);
TASK1(); /* gets called every 2ms */
if( (n_loop % 5) == 0) {
TASK2(); /* get called every 5 * 2ms = 10ms */
}
if( (n_loop % 50) == 0) {
TASK2(); /* get called every 50 * 2ms = 100ms */
}
if( (n_loop % 250) == 0 ) {
/* reset loop counter when smallest common
* multiple of timing grid has been reached */
n_loop = 0;
}
clock_gettime(CLOCK_REALTIME, &ts_end);
useconds_t const tasks_execution_time = delta_t_us(&ts_start, &ts_end);
if( tasks_execution_time >= MS_to_US(2) ) {
/* report an error that tasks took longer than 2ms to execute */
}
/* wait for 2ms - task_execution_time so that tasks get called in
* a close 2ms timing grid */
usleep( MS_to_US(2) - tasks_execution_time );
}
}
int main()
{
rastertask();
return 1;
}
I created a scheduler for scheduling the task for every 2ms (milli second), 10ms and 100ms. The above code is compiling and also running. After running for a certain amount of time then the scheduler will stop executing the tasks. There are three Tasks and called by the scheduler for every 2ms, 10 and 100ms. The tasks are printing hi, hi1 and hi3
questions : why the above code is not printing hi3 for 100ms ??
why it will stop after certain amount of time ??
Question 1)
TASK3 isn't executed because your are not calling it. TASK2 is called after both if statements
Question 2)
if (tasks_execution_time is bigger than 2ms: MS_to_US(2) - tasks_execution_time will be negative and usleep will wait very long. I suggest an 'else' just before usleep, as the if is already checking for this.
Related
I am writing the following C code to get the time taken to perform a simple operation using getitimer and setitimer.
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#define INTERVAL 1 /* number of milliseconds to go off */
int main() {
double sum = 0;
struct itimerval initial, updated;
initial.it_value.tv_sec = INTERVAL;
initial.it_value.tv_usec = 999999;
initial.it_interval = initial.it_value;
memcpy(&(initial.it_interval), &(initial.it_value), sizeof( initial.it_value ));
printf("%ld\n", initial.it_value.tv_usec);
if (setitimer(ITIMER_VIRTUAL, &initial, NULL) == -1) {
perror("error calling setitimer()");
exit(1);
}
for (unsigned int i; i < 100; i++)
sum += 1./i;
if (getitimer(ITIMER_REAL, &updated) == -1) {
perror("error calling getitimer()");
exit(1);
}
printf("Time started = %ld\n; Time ended = %ld\n: Time taken = %ld\n",
initial.it_value.tv_usec, updated.it_value.tv_usec,
initial.it_value.tv_usec - updated.it_value.tv_usec);
return 0;
}
I have compiled with:
$ gcc -o timer -std=c99 -Wall -pedantic getitimer.c -lrt -03
However, my answer is always 999999 (I have raised and decreased the 100):
./timer
999999
Time started = 999999
; Time endd = 0
: Time taken = 999999
What is my error? Also, I wanted to ask what is the highest precision I can get using a progrma like this?
Thanks very much!
the main thing I see is the division operations are using integer division. So:
initial.it_value.tv_sec = INTERVAL/1000000;
places 0 in tv.sec
initial.it_value.tv_usec = (INTERVAL/1000000) * 1000000;
places 0 in tv_usec
initial.it_interval = initial.it_value;
in general, when assigning a multi field struct, use memcpy() rather than a direct assignment. (direct assignment will work for initialization but not for assignment.)
So, the posted code sets the 'interval' to 0
so of course, the resulting values are 0
this is a key statement from the man page for setitimer() and getitimer()
"Timers decrement from it_value to zero, generate a signal, and reset to
it_interval. A timer which is set to zero (it_value is zero or the timer expires and it_interval is zero) stops."
Suggest: following edited
initial.it_value.tv_set = INTERVAL;
initial.it_value.tv_usec = 0;
memcpy( &(initial.it_interval), &(initial.it_value), sizeof( initial.it_value ) );
...
the main problem with the latest code is that the call to getitimer() is referencing a different timer than the call to setitime()
However, the following code makes it simple to use
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
//#include <limits.h>
//#include <string.h>
// do not place comments on same line as #define statement
// always surround numeric values with parens to avoid 'text replacement' errors
// wrong comment: number of milliseconds to go off
// number of seconds in interval
#define INTERVAL (1)
// number of usec in interval
#define MICRO_INTERVAL (999999)
int main() {
//double sum = 0;
struct itimerval initial;
struct itimerval updated;
initial.it_value.tv_sec = INTERVAL;
initial.it_value.tv_usec = MICRO_INTERVAL;
initial.it_interval.tv_sec = INTERVAL;
initial.it_interval.tv_usec = MICRO_INTERVAL;
// remove this line: initial.it_interval = initial.it_value;
// remove this line: memcpy(&(initial.it_interval), &(initial.it_value), sizeof( initial.it_value ));
//printf("%ld\n", initial.it_value.tv_usec);
printf( "Time value: %ld.%ld\n", initial.it_value.tv_sec, initial.it_value.tv_usec );
printf( "Time interval: %ld.%ld\n", initial.it_interval.tv_sec, initial.it_interval.tv_usec );
if (setitimer(ITIMER_VIRTUAL, &initial, &updated) == -1)
{
perror("error calling setitimer()");
exit(1);
}
//for (unsigned int i=0; i < 10; i++) // must initialize the 'i' variable
// sum += 1./i;
// the 'which' parameter should be 'ITIMER_VIRTUAL'
// as that is what was started in the call to setitimer()
//if (getitimer(ITIMER_REAL, &updated) == -1)
//{
// perror("error calling getitimer()");
// exit(1);
//}
if (setitimer(ITIMER_VIRTUAL, &initial, &updated) == -1)
{
perror("error calling setitimer()");
exit(1);
}
printf( "end interval counter: %ld.%ld\n", updated.it_interval.tv_sec, updated.it_interval.tv_usec );
printf( "end value counter: %ld.%ld\n", updated.it_value.tv_sec, updated.it_value.tv_usec );
//printf("Time started = %ld\n; Time ended = %ld\n: Time taken = %ld\n",
// initial.it_value.tv_usec, updated.it_value.tv_usec,
// initial.it_value.tv_usec - updated.it_value.tv_usec);
return 0;
}
// accuracy is +/-1 microsecond, not millisecond
The resulting output, even with nothing being done between the two calls to setitimer() is:
Time value: 1.999999
Time interval: 1.999999
end interval counter: 1.999999
end value counter: 2.3999
setitimer and getitimer are not the right functions to use for profiling. They relate to interval timers which are timers that generate an alarm (signal more accurately) when the timer expires.
The main options for achieving what you want are the clock or clock_gettime APIs.
void *rastertask()
{
struct sched_param sparm;
memset(&sparm, 0, sizeof(sparm));
sparm.sched_priority = 10; /* 0 = lowest, 99 = highest */
sched_setscheduler(
0 /* pid, 0 ==> this process */,
SCHED_RR /* policy */,
&sparm);
unsigned int n_loop;
for(n_loop=0;;n_loop++) {
struct timespec ts_start, ts_end;
clock_gettime(CLOCK_REALTIME, &ts_start);
TASK1(Task2ms_Raster); /* gets called every 2ms */
if( (n_loop % 5) == 0) {
TASK2(Task10ms_Raster); /* get called every 5 * 2ms = 10ms */
}
if( (n_loop % 50) == 0) {
TASK3(Task100ms_Raster); /* get called every 50 * 2ms = 100ms */
}
if( (n_loop % 250) == 0 ) {
/* reset loop counter when smallest common
* multiple of timing grid has been reached */
n_loop = 0;
}
clock_gettime(CLOCK_REALTIME, &ts_end);
useconds_t const tasks_execution_time = delta_t_us(&ts_start, &ts_end);
if( tasks_execution_time >= MS_to_US(2) ) {
/* report an error that tasks took longer than 2ms to execute */
}
/* wait for 2ms - task_execution_time so that tasks get called in
* a close 2ms timing grid */
else
usleep( MS_to_US(2) - tasks_execution_time );
}
}
int main(int argc, char *argv[])
{
pthread_t thread_id
if (pthread_create(&thread_id, NULL, &rastertask, NULL)) {
perror ("pthread_create");
exit (1);
}
return 0;
}
I am creating a thread in the main function. Created a scheduler in the function for calling the tasks for every 2milli seconds, 10 milli seconds and 100 milliseconds.
I am getting a warning in the void *rastertask() as NO return, in function returning non-void.
well you promise to return a void pointer but you don't. hence the warning.
void* is not the same as void as a return type.
you probably wanted to define the function as
void rastertask()
edit:
ok so you need the function to be defined as void * in order to be used with pthread_create(). in that case, you need to add a return statement even if it will return the null pointer.
I have this code that I want to use to handle different signals. I don't know why it never goes to timer_handler2(). It just sticks on timer_handler(). Could someone kindly tell me what I am doing wrong
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
struct timeval theTime;
static int count = 0;
void timer_handler2(int signum) {
printf("timer 2 expired %d times\n", ++count);
}
void timer_handler(int signum) {
printf("timer 1 expired %d times\n", ++count);
}
void timer_handler3(int signum) {
printf("timer 3 expired %d times\n", ++count);
}
int main() {
struct itimerval timer, timer2, timer3, got;
signal(SIGVTALRM, timer_handler2);
signal(SIGALRM, timer_handler);
signal(SIGPROF, timer_handler3);
/* ... and every 1000 msec after that. */
timer2.it_interval.tv_sec = 1;
timer2.it_interval.tv_usec = 0;
/* Configure the timer to expire after 1000 msec... */
timer2.it_value.tv_sec = 1;
timer2.it_value.tv_usec = 0;
/* ... and every 1000 msec after that. */
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 0;
/* Configure the timer to expire after 1000 msec... */
timer.it_value.tv_sec = 1;
timer.it_value.tv_usec = 250000;
/* ... and every 1000 msec after that. */
timer3.it_interval.tv_sec = 1;
timer3.it_interval.tv_usec = 0;
/* Configure the timer to expire after 1000 msec... */
timer3.it_value.tv_sec = 1;
timer3.it_value.tv_usec = 0;
/* Start a real timer. It counts down whenever this process is
executing. */
setitimer(ITIMER_VIRTUAL, &timer2, NULL);
setitimer(ITIMER_REAL, &timer, NULL);
setitimer(ITIMER_PROF, &timer3, NULL);
int counter = 0;
while (1) {
sleep(1);
counter++;
}
return 0;
}
How long are you letting the program run? ITIMER_VIRTUAL only decrements when the program is actually using processor time. Since your program is mostly just sleeping, it's not going to use much processor time. To verify, use the unix 'time' command (or your OS equivalent) to see the real, user and system time used by the program. I'll bet only the real time is enough to activate a timer.
You can try making your VIRTUAL and PROF timer intervals (much) smaller, or do something that doesn't block in your infinite loop (ie: remove the sleep(1) ).
In order to create a high accuracy timer, I have written a module that instantiates a POSIX timer using the timer_create() function. It uses CLOCK_REALTIME as its clock kind, SIGEV_SIGNAL as notification method and SIGRTMIN as the signal number. Its signal handler does nothing but a sem_post(). The timer is started using timer_settime(), with any number of milliseconds as the timer interval.
The user of the module can wait for a timer-tick; the wait functionality is essentially implemented by a sem_wait(). My single-threaded test application creates the timer and starts it with the desired interval of i milliseconds. Then it loops, waiting x times for the timer to trigger. It uses gettimeofday() to time all this.
The expectation is that the total time for the loop would be x*i milliseconds. In stead, it only takes exactly 0.5*x*i milliseconds. I have tried several combinations of x and i, with the total execution time of the test ranging from a few seconds to tens of seconds. The result is consistently that the timer runs at twice the expected/desired frequency.
This runs on CentOS 5.5 Linux 2.6.18-194.el5 #1 SMP Fri Apr 2 14:58:14 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux with gcc 4.1.2
I have uploaded a stripped down version of the code which includes a script to compile the code and a test to reproduce the issue.
The code of the timer class itself is as follows:
/* PosixTimer: simple class for high-accuracy timer functionality */
/* Interface */
#include "PosixTimer.h"
/* Implementation */
#include <pthread.h>
#include <time.h>
#include <signal.h>
#include <semaphore.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define TIMER_SIGNAL SIGRTMIN
#define ALLOCATE_AND_CLEAR(pVar) \
pVar = malloc(sizeof(*pVar)); \
memset(pVar, 0, sizeof(*pVar))
#define FREE_AND_NULL(pVar) \
free(pVar); \
pVar = NULL
struct PosixTimerImpl {
timer_t timerId;
struct itimerspec timeOut;
sem_t semaphore;
};
static void
PosixTimer_sigHandler(
int sig,
siginfo_t *info,
void *ptr)
{
PosixTimer *self = (PosixTimer *)(info->si_value.sival_ptr);
if (NULL != self) {
sem_post(&self->semaphore);
}
}
static void
PosixTimer_setTimeoutValue(
PosixTimer *self,
unsigned int msecInterval)
{
if (NULL != self) {
self->timeOut.it_value.tv_sec = msecInterval / 1000;
self->timeOut.it_value.tv_nsec = (msecInterval % 1000) * 1000000;
self->timeOut.it_interval.tv_sec = msecInterval / 1000;
self->timeOut.it_interval.tv_nsec = (msecInterval % 1000) * 1000000;
}
}
/* Public methods */
/**
* Constructor for the PosixTimer class. Ticks happen every <interval> and are not queued
*/
PosixTimer *
PosixTimer_new(
unsigned int msecInterval)
{
PosixTimer *self = NULL;
int clockId = CLOCK_REALTIME;
struct sigevent evp;
int status;
/* Construction */
ALLOCATE_AND_CLEAR(self);
/* Initialization */
PosixTimer_setTimeoutValue(self, msecInterval);
evp.sigev_signo = TIMER_SIGNAL;
evp.sigev_notify = SIGEV_SIGNAL;
evp.sigev_value.sival_ptr = self;
status = timer_create(clockId, &evp, &self->timerId);
if (0 == status) {
sem_init(&self->semaphore, 0, 0);
} else {
printf("Error creating timer, retVal = %d\n", status);
FREE_AND_NULL(self);
}
return self;
}
/**
* Destructor
*/
void
PosixTimer_delete(
PosixTimer *self)
{
int status;
sem_post(&self->semaphore);
status = sem_destroy(&self->semaphore);
if (0 != status) {
printf("sem_destroy failed\n");
}
status = timer_delete(self->timerId);
if (0 != status) {
printf("timer_delete failed\n");
}
FREE_AND_NULL(self);
}
/**
* Kick off timer
*/
void
PosixTimer_start(
PosixTimer *self)
{
#define FLAG_RELATIVE 0
int status;
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, TIMER_SIGNAL);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = PosixTimer_sigHandler;
status = sigaction(TIMER_SIGNAL, &sa, NULL);
if (0 != status) {
printf("sigaction failed\n");
} else {
status = timer_settime(self->timerId, FLAG_RELATIVE,
&self->timeOut, NULL);
if (0 != status) {
printf("timer_settime failed\n");
}
}
}
/**
* Wait for next timer tick
*/
void
PosixTimer_wait(
PosixTimer *self)
{
/* Just wait for the semaphore */
sem_wait(&self->semaphore);
}
The test used to show the issue:
/* Simple test app to test PosixTimer */
#include "PosixTimer.h"
#include <sys/time.h>
#include <stdio.h>
int main(
int argc,
const char ** argv)
{
#define USEC_PER_MSEC (1000)
#define NSEC_PER_MSEC (1000000)
#define MSEC_PER_SEC (1000)
PosixTimer *timer1 = NULL;
struct timeval before, after;
double dElapsedMsecs;
int elapsedMsecs;
int iCount1;
printf("Running PosixTimer tests\n");
#define DURATION_MSEC (10000)
#define INTERVAL_MSEC_TEST1 (5)
#define ACCURACY_MSEC_TEST1 (100)
timer1 = PosixTimer_new(INTERVAL_MSEC_TEST1);
iCount1 = DURATION_MSEC/INTERVAL_MSEC_TEST1;
printf("Running test: %d milliseconds in %d cycles\n", DURATION_MSEC, iCount1);
gettimeofday(&before, NULL);
PosixTimer_start(timer1);
while (0 < iCount1) {
PosixTimer_wait(timer1);
//printf(".");
iCount1--;
}
gettimeofday(&after, NULL);
//printf("\n");
dElapsedMsecs = (after.tv_sec - before.tv_sec) * MSEC_PER_SEC;
dElapsedMsecs += (after.tv_usec - before.tv_usec) / USEC_PER_MSEC;
elapsedMsecs = dElapsedMsecs+0.5;
if ((ACCURACY_MSEC_TEST1 > (elapsedMsecs - DURATION_MSEC)) &&
(ACCURACY_MSEC_TEST1 > (DURATION_MSEC - elapsedMsecs))) {
printf("success");
} else {
printf("failure");
}
printf(" (expected result in range (%d -- %d), got %d)\n",
DURATION_MSEC - ACCURACY_MSEC_TEST1,
DURATION_MSEC + ACCURACY_MSEC_TEST1,
elapsedMsecs);
return 0;
}
The result is
-bash-3.2$ ./DesignBasedTest
Running PosixTimer tests
Running test: 10000 milliseconds in 2000 cycles
failure (expected result in range (9900 -- 10100), got 5000)
The root cause of this problem was that sem_wait() was woken up twice: once because it was interrupted by the signal, and once because it really needed to wake up due to the semaphore being released by sem_post(). Checking for the return value of sem_wait() and errno = EINTR resolved the issue:
/**
* Wait for next timer tick
*/
int
PosixTimer_wait(
PosixTimer *self)
{
int result;
/* Just wait for the semaphore */
do {
result = (0 == sem_wait(&self->semaphore));
if (!result) {
result = errno;
}
} while (EINTR == result);
return result;
}
Thanks to Basile Starynkevitch for suggesting the use of strace, which revealed the cause of the problem.
Could somebody please explain how to make a countdown timer using clock_gettime, under Linux. I know you can use the clock() function to get cpu time, and multiply it by CLOCKS_PER_SEC to get actual time, but I'm told the clock() function is not well suited for this.
So far I have attempted this (a billion is to pause for one second)
#include <stdio.h>
#include <time.h>
#define BILLION 1000000000
int main()
{
struct timespec rawtime;
clock_gettime(CLOCK_MONOTONIC_RAW, &rawtime);
unsigned long int current = ( rawtime.tv_sec + rawtime.tv_nsec );
unsigned long int end = (( rawtime.tv_sec + rawtime.tv_nsec ) + BILLION );
while ( current < end )
{
clock_gettime(CLOCK_MONOTONIC_RAW, &rawtime);
current = ( rawtime.tv_sec + rawtime.tv_nsec );
}
return 0;
}
I know this wouldn't be very useful on its own, but once I've found out how to time correctly I can use this in my projects. I know that sleep() can be used for this purpose, but I want to code the timer myself so that I can better integrate it in my projects - such as the possibility of it returning the time left, as opposed to pausing the whole program.
Please, do not do that. You're burning CPU power for nothing in a busy loop.
Why not use the nanosleep() function instead? It's perfectly suited to the use case you outlined. Or, if you want an easier interface, perhaps something like
#define _POSIX_C_SOURCE 200809L
#include <time.h>
#include <errno.h>
/* Sleep for the specified number of seconds,
* and return the time left over.
*/
double dsleep(const double seconds)
{
struct timespec req, rem;
/* No sleep? */
if (seconds <= 0.0)
return 0.0;
/* Convert to seconds and nanoseconds. */
req.tv_sec = (time_t)seconds;
req.tv_nsec = (long)((seconds - (double)req.tv_sec) * 1000000000.0);
/* Take care of any rounding errors. */
if (req.tv_nsec < 0L)
req.tv_nsec = 0L;
else
if (req.tv_nsec > 999999999L)
req.tv_nsec = 999999999L;
/* Do the nanosleep. */
if (nanosleep(&req, &rem) != -1)
return 0.0;
/* Error? */
if (errno != EINTR)
return 0.0;
/* Return remainder. */
return (double)rem.tv_sec + (double)rem.tv_nsec / 1000000000.0;
}
The difference is that using this one the CPU is free to do something else, rather than spin like a crazed squirrel on speed.
This is not an answer, but an example of how to use signals and a POSIX timer to implement a timeout timer; intended as a response to the OP's followup question in a comment to the accepted answer.
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
/* Timeout timer.
*/
static timer_t timeout_timer;
static volatile sig_atomic_t timeout_state = 0;
static volatile sig_atomic_t timeout_armed = 2;
static const int timeout_signo = SIGALRM;
#define TIMEDOUT() (timeout_state != 0)
/* Timeout signal handler.
*/
static void timeout_handler(int signo, siginfo_t *info, void *context __attribute__((unused)))
{
if (timeout_armed == 1)
if (signo == timeout_signo && info && info->si_code == SI_TIMER)
timeout_state = ~0;
}
/* Unset timeout.
* Returns nonzero if timeout had expired, zero otherwise.
*/
static int timeout_unset(void)
{
struct itimerspec t;
const int retval = timeout_state;
/* Not armed? */
if (timeout_armed != 1)
return retval;
/* Disarm. */
t.it_value.tv_sec = 0;
t.it_value.tv_nsec = 0;
t.it_interval.tv_sec = 0;
t.it_interval.tv_nsec = 0;
timer_settime(timeout_timer, 0, &t, NULL);
return retval;
}
/* Set timeout (in wall clock seconds).
* Cancels any pending timeouts.
*/
static int timeout_set(const double seconds)
{
struct itimerspec t;
/* Uninitialized yet? */
if (timeout_armed == 2) {
struct sigaction act;
struct sigevent evt;
/* Use timeout_handler() for timeout_signo signal. */
sigemptyset(&act.sa_mask);
act.sa_sigaction = timeout_handler;
act.sa_flags = SA_SIGINFO;
if (sigaction(timeout_signo, &act, NULL) == -1)
return errno;
/* Create a monotonic timer, delivering timeout_signo signal. */
evt.sigev_value.sival_ptr = NULL;
evt.sigev_signo = timeout_signo;
evt.sigev_notify = SIGEV_SIGNAL;
if (timer_create(CLOCK_MONOTONIC, &evt, &timeout_timer) == -1)
return errno;
/* Timeout is initialzied but unarmed. */
timeout_armed = 0;
}
/* Disarm timer, if armed. */
if (timeout_armed == 1) {
/* Set zero timeout, disarming the timer. */
t.it_value.tv_sec = 0;
t.it_value.tv_nsec = 0;
t.it_interval.tv_sec = 0;
t.it_interval.tv_nsec = 0;
if (timer_settime(timeout_timer, 0, &t, NULL) == -1)
return errno;
timeout_armed = 0;
}
/* Clear timeout state. It should be safe (no pending signals). */
timeout_state = 0;
/* Invalid timeout? */
if (seconds <= 0.0)
return errno = EINVAL;
/* Set new timeout. Check for underflow/overflow. */
t.it_value.tv_sec = (time_t)seconds;
t.it_value.tv_nsec = (long)((seconds - (double)t.it_value.tv_sec) * 1000000000.0);
if (t.it_value.tv_nsec < 0L)
t.it_value.tv_nsec = 0L;
else
if (t.it_value.tv_nsec > 999999999L)
t.it_value.tv_nsec = 999999999L;
/* Set it repeat once every millisecond, just in case the initial
* interrupt is missed. */
t.it_interval.tv_sec = 0;
t.it_interval.tv_nsec = 1000000L;
if (timer_settime(timeout_timer, 0, &t, NULL) == -1)
return errno;
timeout_armed = 1;
return 0;
}
int main(void)
{
char *line = NULL;
size_t size = 0;
ssize_t len;
fprintf(stderr, "Please supply input. The program will exit automatically if\n");
fprintf(stderr, "it takes more than five seconds for the next line to arrive.\n");
fflush(stderr);
while (1) {
if (timeout_set(5.0)) {
const char *const errmsg = strerror(errno);
fprintf(stderr, "Cannot set timeout: %s.\n", errmsg);
return 1;
}
len = getline(&line, &size, stdin);
if (len == (ssize_t)-1)
break;
if (len < (ssize_t)1) {
/* This should never occur (except for -1, of course). */
errno = EIO;
break;
}
/* We do not want *output* to be interrupted,
* so we cancel the timeout. */
timeout_unset();
if (fwrite(line, (size_t)len, 1, stdout) != 1) {
fprintf(stderr, "Error writing to standard output.\n");
fflush(stderr);
return 1;
}
fflush(stdout);
/* Next line. */
}
/* Remember to cancel the timeout. Also check it. */
if (timeout_unset())
fprintf(stderr, "Timed out.\n");
else
if (ferror(stdin) || !feof(stdin))
fprintf(stderr, "Error reading standard input.\n");
else
fprintf(stderr, "End of input.\n");
fflush(stderr);
/* Free line buffer. */
free(line);
line = NULL;
size = 0;
/* Done. */
return 0;
}
If you save the above as timer.c, you can compile it using e.g.
gcc -W -Wall -O3 -std=c99 -pedantic timer.c -lrt -o timer
and run it using ./timer.
If you read the code above carefully, you'll see that it is actually a periodic timer signal (at millisecond intervals), with a variable delay before the first signal. That is just a technique I like to use to make sure I don't miss the signal. (The signal repeats until the timeout is unset.)
Note that although you can do computation in an signal handler, you should only use functions that are async-signal-safe; see man 7 signal. Also, only the sig_atomic_t type is atomic wrt. normal single-threaded code and a signal handler. So, it is better to just use the signal as an indicator, and do the actual code in your own program.
If you wanted to e.g. update monster coordinates in a signal handler, it is possible but a bit tricky. I'd use three arrays containing the monster information, and use GCC __sync_bool_compare_and_swap() to update the array pointers -- very much the same technique as triple-buffering in graphics.
If you need more than one concurrent timeout, you could use multiple timers (there is a number of them available), but the best option is to define timeout slots. (You can use generation counters to detect "forgotten" timeouts, and so on.) Whenever a new timeout is set or unset, you update the timeout to reflect the next timeout that expires. It's a bit more code, but really a straightforward extension of the above.