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.
Related
I want to implement a robust timer for an embedded linux application. The goal of this is to control over functions's time of execution and if they take too long, generate an interruption to stop the function's loop.
I searched all over the internet and the firs proposition was to use clock() function.
The solution with clock() function could be :
#include <time.h>
int func(void){
//the starting time of the function
clock_t initial_time;
clock_t elapsed_time;
initial_time = clock()*1000/CLOCKS_PER_SEC;
do{
//some stuff
elapsed_time = clock()*1000/CLOCKS_PER_SEC - initial_time;
}while(elapsed_time < timeout_ms);
printf("time to get command : %ld\n", elapsed_time);
//send an error if a timeout was reached
if(elapsed_time >= timeout_ms){
return -1;
}
else{
return 1;
}
}
But this is not really robust as clock() could cause an overflow in between the function calculations and so, elapsed time will go negative and it will never get out of the loop. This was corrected in the edit section bellow
Second solution was to use the linux kernel timers as following :
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/timer.h>
int g_time_interval = 10000;
struct timer_list g_timer;
void timer_handler (unsigned long data)
{
// do your timer stuff here
}
int init_timer(void)
{
setup_timer(&g_timer, timer_handler, 0);
mod_timer( &g_timer, jiffies + msecs_to_jiffies(g_time_interval));
return 0;
}
void close_timer(void)
{
del_timer(&g_timer);
}
This option seems ok, but I did some research and jiffies (the number of ticks since startup) could overflow too and I don't know if this could affect my usage of this timer. This was corrected in the edit section bellow
Finally, the last option I found was to use timer_create with a signal. As far as I know, this does not has the overflow issue if used with CLOCK_MONOTONIC :
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <stdbool.h>
#define SIG SIG_RTMIN
int init_timer((void *) handler(int, siginfo_t, void*)){
// Establish handler for timer signal
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIG, &sa, NULL) == -1)
printf("Error initializing timer\n");
// Block timer signal temporarily
printf("Blocking signal %d\n", SIG);
sigemptyset(&mask);
sigaddset(&mask, SIG);
// Create the timer
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIG;
sev.sigev_value.sival_ptr = &timerid;
}
static void handler(int sig, siginfo_t *si, void *uc)
{
//put a flag to 1 for example
signal(sig, SIG_IGN);
}
//Much other stuff ...
But google told me that we can only set one handler per signal and I dont know if the other processus that are in my linux board use SIG_RTMIN. And as I do not want to break everything by redefining its handler, it is not a convinient solution.
Am I getting something wrong here?
Is there a way to define a timer in linux without having this issues?
Thank you very much to all :)
Edit
Overflow will not cause an issue so option 1 and 2 are valid. Now which one would be the most robust?
Here is the explanation on why I was wrong about overflow. Giving the case where we want to calculate elapsed_time and the maximum clock value is MAX. We have as above :
elapsed_time = clock()*1000/CLOCKS_PER_SEC - initial_time;
Lets rename clock()*1000/CLOCKS_PER_SEC as x. If there is overflow, then theorically theoric_x > MAX, but as there was overflow, x = theoric_x - MAX (hope is clear ':D). So :
elapsed_time = (theoric_x - MAX) - initial_time;
Which can be written as :
elapsed_time = (theoric_x - initial_time) - MAX;
And this is equivalent to : elapsed_time = (theoric_x - initial_time) because substracting the maximum value is like getting back to the same value (it works like modulo). This is ok while the theoric_x is below initial_time + MAX, if we get over, the elapsed time will reset.
I hope it was clear enough.
But google told me that we can only set one handler per signal and I dont know if the other processus that are in my linux board use SIG_RTMIN.
No, it is one handler per signal per process.
That is, having a signal handler for SIGRTMIN in your own program will not interfere with SIGRTMIN handlers of any other processes. Similarly, creating a timer will not affect any other processes' timers either. All you need to worry about, is your own process.
(Technically, there are only a limited number of timers available, so you don't want to create hundreds of them in a single process.)
If you have only one thread in the process, consider the following timeout scheme:
// SPDX-License-Identifier: CC0-1.0
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <stdio.h>
#define TIMEOUT_SIGNAL (SIGRTMIN+0)
#define TIMEOUT_REPEAT_NS 1000000 /* Repeat every millisecond until canceled */
static volatile sig_atomic_t timeout_elapsed; /* Nonzero if timeout has elapsed */
static timer_t timeout_timer;
static void timeout_handler(int signum)
{
(void)signum; /* Silences warning about unused parameter; generates no code. */
timeout_elapsed = 1;
}
static int timeout_init(void)
{
struct sigaction act;
struct sigevent evt;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = timeout_handler;
act.sa_flags = 0;
if (sigaction(TIMEOUT_SIGNAL, &act, NULL) == -1)
return errno;
memset(&evt, 0, sizeof evt);
evt.sigev_notify = SIGEV_SIGNAL;
evt.sigev_signo = TIMEOUT_SIGNAL;
evt.sigev_value.sival_ptr = (void *)0;
if (timer_create(CLOCK_BOOTTIME, &evt, &timeout_timer) == -1)
return errno;
timeout_elapsed = 0;
return 0;
}
static void timeout_cancel(void)
{
struct itimerspec zero;
zero.it_value.tv_sec = 0;
zero.it_value.tv_nsec = 0;
zero.it_interval.tv_sec = 0;
zero.it_interval.tv_nsec = 0;
timer_settime(timeout_timer, 0, &zero, NULL);
}
static void timeout_set(double seconds)
{
struct itimerspec when;
sigset_t mask;
/* Block the timeout signal for now. */
sigemptyset(&mask);
sigaddset(&mask, TIMEOUT_SIGNAL);
sigprocmask(SIG_BLOCK, &mask, NULL);
/* Make sure any previous timeouts have been canceled. */
timeout_cancel();
/* Calculate the next (relative) timeout. */
if (seconds >= 0.000000001) {
long sec = (long)seconds;
long nsec = (long)(1000000000.0*(seconds - (double)sec));
if (nsec < 0)
nsec = 0;
if (nsec > 999999999) {
nsec = 0;
sec++;
}
when.it_value.tv_sec = sec;
when.it_value.tv_nsec = nsec;
} else {
when.it_value.tv_sec = 0;
when.it_value.tv_nsec = 1;
}
/* Set it to repeat, so that it is not easily missed. */
when.it_interval.tv_sec = 0;
when.it_interval.tv_nsec = TIMEOUT_REPEAT_NS;
/* Update the timer. */
timer_settime(timeout_timer, 0, &when, NULL);
/* Clear the flag, and unblock the signal. */
timeout_elapsed = 0;
sigprocmask(SIG_UNBLOCK, &mask, NULL);
}
int main(void)
{
char *line_ptr = NULL;
size_t line_max = 0;
ssize_t line_len;
if (timeout_init()) {
fprintf(stderr, "Cannot set up timeouts: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
timeout_set(5.0);
printf("Please type input lines. This will timeout in five seconds.\n");
fflush(stdout);
while (!timeout_elapsed) {
line_len = getline(&line_ptr, &line_max, stdin);
if (line_len > 0) {
/* Remove trailing newlines */
line_ptr[strcspn(line_ptr, "\r\n")] = '\0';
printf("Read %zd bytes: \"%s\".\n", line_len, line_ptr);
fflush(stdout);
}
}
timeout_cancel();
free(line_ptr);
line_ptr = NULL;
line_max = 0;
printf("Done.\n");
return EXIT_SUCCESS;
}
Compile using gcc -Wall -Wextra -O2 example1.c -lrt -o example1 and run ./example1.
For a multithreaded process, the signal must be delivered to a specific thread, almost always the thread that sets the timeout in the first place. Here, I recommend a different approach: use a helper thread, a list or an array or a binary min-heap of CLOCK_REALTIME absolute times of the respective timeouts, waiting in pthread_cond_timedwait() for the next soonest timeout, or for a signal on the condition variable indicating the timeout list/array/heap has been updated.
POSIX defines clock_gettime. Linux also has extensions for it.
The functions clock_gettime() and clock_settime() retrieve and set the time of the specified clock clockid.
You can simply do the following:
#include <time.h>
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
// Your code here...
clock_gettime(CLOCK_MONOTONIC, &end);
Then end.tv_nsec - start.tv_nsec will provide you nanoseconds with the resolution as specified by clock_getres. Sometimes this is just microseconds or even mere milliseconds. Make sure to check the value and adjust accordingly.
struct timespec res;
clock_getres(CLOCK_MONOTONIC, &res);
switch (res.tv_nsec) {
case 1000: // microseconds
case 10000000: // milliseconds
// cases ...
}
EDIT:
Rereading the original person's post I realize that this doesn't quite answer it. Still, I am leaving it here as it might be useful if applied to the problem. You are free to downvote this if you like as to allow actual answers to rise to the top.
I have written some code that tries to call a function (called worker) every x seconds (in this example, I chose 1s as the interval time). The code is a minimal working example that in reality is way more complex than this.
The code works when it is this simple, but I stumble across errors when running the more complex version for a longer period of time. Thus, I want to increase the robustness of this code an would like to get some ideas on how to do that.
Basically, the worker gets some data, processes it an writes it to a file. I open the file during every call to the worker. In the tests, after some time I get an error that the file cannot be opened anymore. In this regard I also noticed that this happens (maybe just by chance) everytime the worker execution time exceeds the interval time. Reason for this is the getter function which pulls data from remote and this can take some time, depending on the network traffic.
I've been thinking of trying a multithreaded approach, but I am not sure if this is worth the hassle. I would be grateful for any pointers on how to do this in a more robust way.
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
#include <signal.h>
#include <stdint.h>
#include <time.h>
#define ALARM_INTERVAL_SEC 1
#define ALARM_INTERVAL_USEC 0
static bool running = true;
static struct itimerval alarm_interval;
static struct timeval previous_time;
static uint64_t loop_count = 0;
static FILE* testfile;
static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM)
{
running = false;
}
}
static void
worker(int signum)
{
// Reset the alarm interval
if(setitimer(ITIMER_REAL, &alarm_interval, NULL) < 0)
{
perror("Error: setitimer");
raise(SIGTERM);
return;
}
struct timeval current_time;
gettimeofday(¤t_time, NULL);
printf("Loop count: %lu\n", loop_count);
printf("Loop time: %f us\n\n", (current_time.tv_sec - previous_time.tv_sec) * 1e6 +
(current_time.tv_usec - previous_time.tv_usec));
previous_time = current_time;
// convert time to human-readable format
char tmbuf[64];
char buf[64];
time_t nowtime = current_time.tv_sec;
struct tm *nowtm = localtime(&nowtime);
strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d %H:%M:%S", nowtm);
snprintf(buf, sizeof(buf), "%s.%06ld", tmbuf, current_time.tv_usec);
sleep(0.5);
// DO STH
testfile = fopen("testfile.txt", "ab+");
if(testfile == NULL)
{
printf("Error: open testfile");
raise(SIGTERM);
return;
}
fprintf(testfile, "[%s] Loop count: %lu\n", buf, loop_count);
fclose(testfile);
loop_count++;
}
int
main(int argc, char* argv[])
{
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGALRM, worker);
// Set the alarm interval
alarm_interval.it_interval.tv_sec = 0;
alarm_interval.it_interval.tv_usec = 0;
alarm_interval.it_value.tv_sec = ALARM_INTERVAL_SEC;
alarm_interval.it_value.tv_usec = ALARM_INTERVAL_USEC;
if(setitimer(ITIMER_REAL, &alarm_interval, NULL) < 0)
{
perror("Error: setitimer");
return -1;
}
gettimeofday(&previous_time, NULL);
while(running)
{
sleep(1);
}
alarm_interval.it_value.tv_sec = 0;
alarm_interval.it_value.tv_usec = 0;
if(setitimer(ITIMER_REAL, &alarm_interval, NULL) < 0)
{
perror("Error: resetting itimer failed");
return -1;
}
return 0;
}
#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.
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.
Actually I want to implement non-blocking timer, when the timer expires a handler will be called and will do something (for now it prints data). I google and realized that timer_create, timer_settimer are non-blocking timer. BUT still I've issue, I have to wait for my timer to expire (sleep(MAX) or while(1) {;}). But then if I'm calling my start_timer method with different "expiry" time, it should work accordingly, should not block other. e.g. here first time I'm calling timer, and expecting to call handler in 5 sec but before that 2nd call should print its data as, that interval I've given is 1sec only. And of course its not behaving same. Any idea?
#include <time.h>
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
typedef struct _data{
char *name;
}data;
void handler(union sigval val)
{
data *data_handler = val.sival_ptr;
printf("Handler entered with value :%s\n", data_handler->name);
}
void mod_timer(timer_t timerid, struct sigevent sig, struct itimerspec in, struct itimerspec out)
{
printf("mod_timer\n");
timer_settime(timerid, 0, &in, &out);
while(1)
sleep(1);
//delete the timer.
timer_delete(timerid);
}
void start_timer(void* val, int interval)
{
int Ret;
pthread_attr_t attr;
pthread_attr_init( &attr );
struct sched_param parm;
parm.sched_priority = 255;
pthread_attr_setschedparam(&attr, &parm);
struct sigevent sig;
sig.sigev_notify = SIGEV_THREAD;
sig.sigev_notify_function = handler;
// sig.sigev_value.sival_int = val;
sig.sigev_value.sival_ptr = val;
sig.sigev_notify_attributes = &attr;
//create a new timer.
timer_t timerid;
Ret = timer_create(CLOCK_REALTIME, &sig, &timerid);
if (Ret == 0)
{
struct itimerspec in, out;
in.it_value.tv_sec = 1;
in.it_value.tv_nsec = 0;
in.it_interval.tv_sec = interval;
in.it_interval.tv_nsec = 0;
mod_timer(timerid, sig, in, out);
}
}
void main()
{
// start_timer(1, 5);
// start_timer(2, 1);
data handler_data1 = {"Handler Data 1"};
data handler_data2 = {"Handler Data 2"};
void *data1 = &handler_data1;
void *data2 = &handler_data2;
start_timer(data1, 5);
start_timer(data2, 1);
}
You can use the alarm function to generate a signal, and the signal function to specify the handler to that signal.