Strange behaviour of `timer_settime()` - c

I'm trying to set Linux timer so that I get signal each 0.1 seconds (infinitely). I have problem with timer_settime() call. Surprisingly this code seems to work:
#define Msec 1e6
#define Cycle 100 * Msec
//...
#define SIGNO SIGRTMIN
struct sigaction sa = { .sa_handler = &each_cycle };
sigemptyset (&sa.sa_mask);
timer_t timer;
struct sigevent te = {
.sigev_notify = SIGEV_SIGNAL,
.sigev_signo = SIGNO,
.sigev_value.sival_ptr = &timer
};
/* I don't know why this setting works. */
struct itimerspec it = {
.it_interval.tv_nsec = Cycle,
.it_value.tv_nsec = Cycle
};
if (sigaction (SIGNO, &sa, NULL) < 0 ||
timer_create (CLOCK_REALTIME, &te, &timer) != 0 ||
timer_settime (timer, 0, &it, 0) != 0
) {
fprintf (stderr, "Unable to register timer.");
return 1;
}
Surprising because according to my understaning it should cause expiring of timer after one time. Before I was trying .it_value.tv_sec = INT32_MAX — this seems to be most reasonable, because .it_value = {0,0} disarms timer.
Unfortunatelly setting tv_sec to any value results in no signal. I'm running Arch Linux on Raspberry Pi 3 (GCC7), I've tried to remove optimization, no change.

/* I don't know why this setting works. */
struct itimerspec it = {
.it_interval.tv_nsec = Cycle,
.it_value.tv_nsec = Cycle
};
....
[A]ccording to my understanding it should cause expiring of timer after one time.
Setting it_interval arms the timer for intervalic, recurring expiry after the first expiry (scheduled by it_value). That's why you see repeated invocations.

Related

Understanding struct itimerval field tv_usec

Hi I'm studying this code:
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
volatile sig_atomic_t print_flag = true;
static int count = 0;
void timer_handler (int signum)
{
printf ("timer expired %d times\n", ++count);
if(count>20) {
print_flag = false;
}
}
int main ()
{
struct sigaction sa;
struct itimerval timer;
/* Install timer_handler as the signal handler for SIGVTALRM. */
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timer_handler;
sigaction (SIGALRM, &sa, NULL);
/* Configure the timer to expire after 250 msec... */
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 250000;
/* ... and every 250 msec after that. */
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 250000;
/* Start a virtual timer. It counts down whenever this process is
executing. */
setitimer (ITIMER_REAL, &timer, NULL);
/* Do busy work. */
while (print_flag) {
sleep(1);
}
printf("job done bye bye\n");
exit(0);
}
With this settings everything goes fine and i get this output
...
timer expired 17 times
timer expired 18 times
timer expired 19 times
timer expired 20 times
timer expired 21 times
job done bye bye
If i try to alter the code commenting timer.it_interval.tv_usec and timer.it_interval.tv_usecand setting both timer.it_value.tv_sec and timer.it_value.tv_sec equal to, for instance, 3 it doesn't do his job.
However if I maintain an explicit declaration of tv_usec like this it works:
timer.it_value.tv_sec = 3;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 3;
timer.it_interval.tv_usec = 0;
Why I'm bonded on the explicit declaration of tv_usec for both fields?
As far as you don't initialize *.tv_usec fields, theirs values are undefined. If it'd contain a value greater that 999999 or less than 0, the setitimer () will just fail with EINVAL as described on the man page.
You ought to initialize all the data yourself. If you are willing to save a line of code, you may memset the timer struct to 0 the same way you have done it for sa.

is it a kernel freeze

We are missing interrupts in an linux embedded system having multi-core running at 1.25GHz.
Background:
kernel version: 2.6.32.27
we have user space processes which need real time performance.
They operate in a 1ms boundary.
That is to say within 1ms they are expected to complete a set of task, which at the max may take about 800uS.
We have a external component FPGA which provides, 1ms and 10ms interrupts to the multi-core processor through GPIO pins configured as edge triggerred interrupts.
These interrupts are handled in kernel driver.
The software architecture is in such a way that the user process, after completing its work will do an ioctl to the GPIO driver.
In this ioctl the driver will put the process to wakeup_interruptible state.
Whenever the next 1ms interrupt is received, the ISR will wakeup the process. This cycle repeats.
Both the 1ms and 10ms interrupts are routed to a single core of the processor using smp_affinity.
Problem:
Sometimes we find that some interrupts are missed.
(ie ISR itself doesnt get invoked).
After 12 to 20ms ISR's are hit normally.
This we are able to understand by profiling the duration between consecutive ISR calls, and having counters incremented first thing in the ISR.
This mostly happens during high system load at process level, and is random and hard to reproduce.
I have attached the skeletal code.
First I have to isolate whether it is a hardware or software problem. As it is a FPGA which is giving the interrupts, we dont have much doubt on the hardware.
Is this kernel freezing? It is the most likely case since the cpu cycles are incrementing.
Can it be a case of cpu freeze due to thermal conditions? If so, then the cpu cycles wouldn't have incremented in first place.
Any pointers to debug/isolate the root cause will be of great help
considering the kernel version we are working on and the profiling/debugging
facilities available in this kernel version.
skeletal code:
/* Build time Configuration */
/* Macros */
DECLARE_WAIT_QUEUE_HEAD(wait);
/** Structure Definitions */
/** Global Variables */
gpio_dev_t gpio1msDev, gpio10msDev;
GpioIntProfileSectorData_t GpioSigProfileData[MAX_GPIO_INT_CONSUMERS];
GpioIntProfileSectorData_t *ProfilePtrSector;
GpioIntProfileData_t GpioProfileData;
GpioIntProfileData_t *GpioIntProfilePtr;
CurrentTickProfile_t TimeStamp;
uint64_t ModuleInitDone = 0, FirstTimePIDWrite = 0;
uint64_t PrevCycle = 0, NowCycle = 0;
volatile uint64_t TenMsFlag, OneMsFlag;
uint64_t OneMsCounter;
uint64_t OneMsIsrTime, TenMsIsrTime;
uint64_t OneMsCounter, OneMsTime, TenMsTime, SyncStarted;
uint64_t Prev = 0, Now = 0, DiffTen = 0, DiffOne, SesSyncHappened;
static spinlock_t GpioSyncLock = SPIN_LOCK_UNLOCKED;
static spinlock_t IoctlSyncLock = SPIN_LOCK_UNLOCKED;
uint64_t EventPresent[MAX_GPIO_INT_CONSUMERS];
GpioEvent_t CurrentEvent = KERN_NO_EVENT;
TickSyncSes_t *SyncSesPtr = NULL;
/** Function Declarations */
ssize_t write_pid(struct file *filep, const char __user * buf, size_t count, loff_t * ppos);
long Gpio_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
static const struct file_operations my_fops = {
write:write_pid,
compat_ioctl:Gpio_compat_ioctl,
};
/**
* IOCTL function for GPIO interrupt module
*
* #return
*/
long Gpio_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
int len = 1, status = 0;
uint8_t Instance;
uint64_t *EventPtr;
GpioIntProfileSectorData_t *SectorProfilePtr, *DebugProfilePtr;
GpioEvent_t EventToGive = KERN_NO_EVENT;
pid_t CurrentPid = current->pid;
spin_lock(&IoctlSyncLock); // Take the spinlock
Instance = GetSector(CurrentPid);
SectorProfilePtr = &GpioSigProfileData[Instance];
EventPtr = &EventPresent[Instance];
spin_unlock(&IoctlSyncLock);
if (Instance <= MAX_GPIO_INT_CONSUMERS)
{
switch (cmd)
{
case IOCTL_WAIT_ON_EVENT:
if (*EventPtr)
{
/* Dont block here since this is a case where interrupt has happened
* before process calling the polling API */
*EventPtr = 0;
/* some profiling code */
}
else
{
status = wait_event_interruptible(wait, (*EventPtr == 1));
*EventPtr = 0;
}
/* profiling code */
TimeStamp.CurrentEvent = EventToGive;
len = copy_to_user((char *)arg, (char *)&TimeStamp, sizeof(CurrentTickProfile_t));
break;
default:
break;
}
}
else
{
return -EINVAL;
}
return 0;
}
/**
* Send signals to registered PID's.
*
* #return
*/
static void WakeupWaitQueue(GpioEvent_t Event)
{
int i;
/* some profile code */
CurrentEvent = Event;
// we dont wake up debug app hence "< MAX_GPIO_INT_CONSUMERS" is used in for loop
for (i = 0; i < MAX_GPIO_INT_CONSUMERS; i++)
{
EventPresent[i] = 1;
}
wake_up_interruptible(&wait);
}
/**
* 1ms Interrupt handler
*
* #return
*/
static irqreturn_t gpio_int_handler_1ms(int irq, void *irq_arg)
{
uint64_t reg_read, my_core_num;
unsigned long flags;
GpioEvent_t event = KERN_NO_EVENT;
/* code to clear the interrupt registers */
/************ profiling start************/
NowCycle = get_cpu_cycle();
GpioIntProfilePtr->TotalOneMsInterrupts++;
/* Check the max diff between consecutive interrupts */
if (PrevCycle)
{
DiffOne = NowCycle - PrevCycle;
if (DiffOne > GpioIntProfilePtr->OneMsMaxDiff)
GpioIntProfilePtr->OneMsMaxDiff = DiffOne;
}
PrevCycle = NowCycle;
TimeStamp.OneMsCount++; /* increment the counter */
/* Store the timestamp */
GpioIntProfilePtr->Gpio1msTimeStamp[GpioIntProfilePtr->IndexOne] = NowCycle;
TimeStamp.OneMsTimeStampAtIsr = NowCycle;
GpioIntProfilePtr->IndexOne++;
if (GpioIntProfilePtr->IndexOne == GPIO_PROFILE_ARRAY_SIZE)
GpioIntProfilePtr->IndexOne = 0;
/************ profiling end************/
/*
* Whenever 10ms Interrupt happens we send only one event to the upper layers.
* Hence it is necessary to sync between 1 & 10ms interrupts.
* There is a chance that sometimes 1ms can happen at first and sometimes 10ms.
*
*/
/******** Sync mechanism ***********/
spin_lock_irqsave(&GpioSyncLock, flags); // Take the spinlock
OneMsCounter++;
OneMsTime = NowCycle;
DiffOne = OneMsTime - TenMsTime;
if (DiffOne < MAX_OFFSET_BETWEEN_1_AND_10MS) //ten ms has happened first
{
if (OneMsCounter == 10)
{
event = KERN_BOTH_EVENT;
SyncStarted = 1;
}
else
{
if (SyncStarted)
{
if (OneMsCounter < 10)
{
GpioIntProfilePtr->TickSyncErrAt1msLess++;
}
else if (OneMsCounter > 10)
{
GpioIntProfilePtr->TickSyncErrAt1msMore++;
}
}
}
OneMsCounter = 0;
}
else
{
if (OneMsCounter < 10)
{
if (SyncStarted)
{
event = KERN_ONE_MS_EVENT;
}
}
else if (OneMsCounter > 10)
{
OneMsCounter = 0;
if (SyncStarted)
{
GpioIntProfilePtr->TickSyncErrAt1msMore++;
}
}
}
TimeStamp.SFN = OneMsCounter;
spin_unlock_irqrestore(&GpioSyncLock, flags);
/******** Sync mechanism ***********/
if(event != KERN_NO_EVENT)
WakeupWaitQueue(event);
OneMsIsrTime = get_cpu_cycle() - NowCycle;
if (GpioIntProfilePtr->Max1msIsrTime < OneMsIsrTime)
GpioIntProfilePtr->Max1msIsrTime = OneMsIsrTime;
return IRQ_HANDLED;
}
/**
* 10ms Interrupt handler
*
* #return
*/
static irqreturn_t gpio_int_handler_10ms(int irq, void *irq_arg)
{
uint64_t reg_read, my_core_num;
unsigned long flags;
GpioEvent_t event = KERN_NO_EVENT;
/* clear the interrupt */
/************ profiling start************/
GpioIntProfilePtr->TotalTenMsInterrupts++;
Now = get_cpu_cycle();
if (Prev)
{
DiffTen = Now - Prev;
if (DiffTen > GpioIntProfilePtr->TenMsMaxDiff)
GpioIntProfilePtr->TenMsMaxDiff = DiffTen;
}
Prev = Now;
TimeStamp.OneMsCount++; /* increment the counter */
TimeStamp.TenMsCount++;
GpioIntProfilePtr->Gpio10msTimeStamp[GpioIntProfilePtr->IndexTen] = Now;
TimeStamp.TenMsTimeStampAtIsr = Now;
//do_gettimeofday(&TimeOfDayAtIsr.TimeAt10MsIsr);
GpioIntProfilePtr->IndexTen++;
if (GpioIntProfilePtr->IndexTen == GPIO_PROFILE_ARRAY_SIZE)
GpioIntProfilePtr->IndexTen = 0;
/************ profiling end************/
/******** Sync mechanism ***********/
spin_lock_irqsave(&GpioSyncLock, flags);
TenMsTime = Now;
DiffTen = TenMsTime - OneMsTime;
if (DiffTen < MAX_OFFSET_BETWEEN_1_AND_10MS) //one ms has happened first
{
if (OneMsCounter == 10)
{
TimeStamp.OneMsTimeStampAtIsr = Now;
event = KERN_BOTH_EVENT;
SyncStarted = 1;
}
OneMsCounter = 0;
}
else
{
if (SyncStarted)
{
if (OneMsCounter < 9)
{
GpioIntProfilePtr->TickSyncErrAt10msLess++;
OneMsCounter = 0;
}
else if (OneMsCounter > 9)
{
GpioIntProfilePtr->TickSyncErrAt10msMore++;
OneMsCounter = 0;
}
}
else
{
if (OneMsCounter != 9)
OneMsCounter = 0;
}
}
TimeStamp.SFN = OneMsCounter;
spin_unlock_irqrestore(&GpioSyncLock, flags);
/******** Sync mechanism ***********/
if(event != KERN_NO_EVENT)
WakeupWaitQueue(event);
TenMsIsrTime = get_cpu_cycle() - Now;
if (GpioIntProfilePtr->Max10msIsrTime < TenMsIsrTime)
GpioIntProfilePtr->Max10msIsrTime = TenMsIsrTime;
return IRQ_HANDLED;
}
Reseting EventPresent after waiting the event in wait_event_interruptible()
EventPtr = &EventPresent[Instance];
...
status = wait_event_interruptible(wait, (*EventPtr == 1));
*EventPtr = 0;
looks suspicious.
If WakeupWaitQueue() will be executed concurrently, then setting of the event
for (i = 0; i < MAX_GPIO_INT_CONSUMERS; i++)
{
EventPresent[i] = 1;
}
wake_up_interruptible(&wait);
will be lost.
It is better to have two independent counters for raised events and for processed events:
uint64_t EventPresent[MAX_GPIO_INT_CONSUMERS]; // Number if raised events
uint64_t EventProcessed[MAX_GPIO_INT_CONSUMERS]; // Number of processed events
In that case condition could be a comparision of these counters:
Gpio_compat_ioctl()
{
...
EventPresentPtr = &EventPresent[Instance];
EventProcessedPtr = &EventProcessed[Instance];
...
status = wait_event_interruptible(wait, (*EventPresentPtr != *EventProcessedPtr));
(*EventProcessedPtr)++;
...
}
WakeupWaitQueue()
{
...
for (i = 0; i < MAX_GPIO_INT_CONSUMERS; i++)
{
EventPresent[i]++;
}
wake_up_interruptible(&wait);
}
This was not a kernel freeze.
We had a free core in the system which was running baremetal. We routed the 1ms interrupts to this baremetal core as well. When the issue occurs, we compared with the baremetal core profile info. In baremetal core ISRs were hit properly linear to the time elapsed.
By this we ruled out that there are not HW issues or thermal issues.
Next on close look of the code, we started suspecting whether spinlock is causing to miss the interrupts. To experiment, we changed the logic to run the ISRs without spinlock. Now we see that there are not missed interrupts.
So the issues seems solved, however with spinlock present also the system was working properly under normal load conditions. This issue arises only during very high CPU load. This is something for which i dont have an answer though ie only during high load condition, why calling spinlock makes the other interrupt to be missed.

linux pthread running in a loop for specified time (avoiding signals)

hello what i want do is:
thread (pthread.h) need to execute code in a while loop for some period of time that will be defined at run time
after that the thread will finish correctly the last loop and continue for some other work.
right now I am using signals: This is the loop
setTimer(sec);
while(flag)
{
//do some work
}
// continue to run
and i use signal to call for function that will set flag to false:
void setTimer(int sec)
{
struct sigaction sa;
struct itimerval timer;
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &alarm_end_of_loop; // this is the function to change flag to false
sigaction (SIGVTALRM, &sa, NULL);
timer.it_value.tv_sec = sec;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 0;
setitimer (ITIMER_REAL, &timer, NULL);
}
void alarm_end_of_loop()
{
flag = 0; //flag is global but only one thread will access it
}
My question is there a way to avoid using signals?
Seems to be a timeout pattern.
double get_delta_time_to_now(const time_t timeout_time)
{
time_t now;
time(&now);
return difftime(now, timeout_time);
}
void do_it(int sec)
{
time_t timeout_time;
double diff;
time(&timeout_time);
timeout_time += sec; /* this is not necessarily correct */
diff = get_delta_time_to_now(timeout_time);
while (diff <= 0.0)
{
/* do your stuff */
diff = get_delta_time_to_now(timeout_time);
}
}

Is there any method to wait until task catch SIGALRM signal in intel arch?

I'm programming iwth gcc version 4.4.3 on Ubuntu 10.04
I don't know how to catch SIGALRM with sigtimedwait(),sigwait().
If timer handler is set , sigtimedwait(),sigwait() always returns EINTR(4).
If timer handler is not set, SIGALRM never received.
Is there any method to wait until task catch SIGALRM signal in intel arch?
void handler( int signo )
{
...
}
int main( void )
{
timer_t timer_id;
struct sigaction sigact;
struct itimerspec itval;
int ret;
struct timespec pTimeout;
siginfo_t pInfo;
pTimeout.tv_sec = 10;
pTimeout.tv_nsec = 0;
// set signal handler for SIGALRM
sigact.sa_handler = handler;
sigact.sa_flags = 0;
sigemptyset( &sigact.sa_mask );
sigaction( SIGALRM, &sigact, NULL );
// create timer
timer_create( CLOCK_REALTIME, NULL, &timer_id );
itval.it_value.tv_sec = 3;
itval.it_value.tv_nsec = 0;
itval.it_interval.tv_sec = 0;
itval.it_interval.tv_nsec = 250 * 1000 * 1000;
// set timer
timer_settime( timer_id, 0, &itval, NULL );
int count;
for ( count = 0; count < 10; count++ )
{
// wait for SIGALRM
ret = sigtimedwait
(
&sigact.sa_mask, /* the signal mask while suspended */
&pInfo, /* return value */
&pTimeout
);
.....
}
Is this helpful?
do {
ret = sigtimedwait(&sigact.sa_mask, &pInfo, &pTimeout);
} while (ret < 0 && errno == EINTR);
Similar question.
Some of the 'wait until a signal is received' functions are:
pause()
sigsuspend()
sigpause()
The sigpause() function is actually part of a deprecated set of functions; it is best not to use it in new code.
There is also:
sigtimedwait()
which may do what you want more directly.

need programs that illustrate use of settimer and alarm functions in GNU C

Can anyone illustrate the use of settimer or alarm function in gnu C , with some program examples ,please ?
I have a program that continuously processes some data , and i need to set a timer / alarm that goes off every t seconds , in response to which , i need to store the processed data into a file. This file writing has to be asynchronous < i.e. the data processing and file writing must not wait for each other > . I went through the GNU C Library pages , but i couldn't understand much..
[EDIT]
I got this program :
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#define INTERVAL 1
int howmany = 0;
void alarm_wakeup (int i)
{
struct itimerval tout_val;
signal(SIGALRM,alarm_wakeup);
howmany += INTERVAL;
printf("\n%d sec up partner, Wakeup!!!\n",howmany);
tout_val.it_interval.tv_sec = 0;
tout_val.it_interval.tv_usec = 0;
tout_val.it_value.tv_sec = INTERVAL; /* 10 seconds timer */
tout_val.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &tout_val,0);
}
void exit_func (int i)
{
signal(SIGINT,exit_func);
printf("\nBye Bye!!!\n");
exit(0);
}
int main ()
{
struct itimerval tout_val;
tout_val.it_interval.tv_sec = 0;
tout_val.it_interval.tv_usec = 0;
tout_val.it_value.tv_sec = INTERVAL; /* 10 seconds timer */
tout_val.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &tout_val,0);
signal(SIGALRM,alarm_wakeup); /* set the Alarm signal capture */
signal(SIGINT,exit_func);
while (1)
{
//printf("!");
}
return 0;
}
But seems like i cannot do anything while the timer is on..
What should i modify to suit my needs ? Pl suggest..
[/EDIT]
Here's an example from here which uses setitimer() to periodically call DoStuff().
The key here is that calling setitimer() results in the OS scheduling a SIGALRM to be sent to your process after the specified time has elapsed, and it is up to your program to handle that signal when it comes. You handle the signal by registering a signal handler function for the signal type (DoStufF() in this case) after which the OS will know to call that function when the timer expires.
You can read the setitimer() man page to figure out what the arguments are and how to cancel a timer.
Note: if you want the timer to trigger only once, you will have to call alarm() or ualarm() instead of setitimer().
/*
* setitimer.c - simple use of the interval timer
*/
#include <sys/time.h> /* for setitimer */
#include <unistd.h> /* for pause */
#include <signal.h> /* for signal */
#define INTERVAL 500 /* number of milliseconds to go off */
/* function prototype */
void DoStuff(void);
int main(int argc, char *argv[]) {
struct itimerval it_val; /* for setting itimer */
/* Upon SIGALRM, call DoStuff().
* Set interval timer. We want frequency in ms,
* but the setitimer call needs seconds and useconds. */
if (signal(SIGALRM, (void (*)(int)) DoStuff) == SIG_ERR) {
perror("Unable to catch SIGALRM");
exit(1);
}
it_val.it_value.tv_sec = INTERVAL/1000;
it_val.it_value.tv_usec = (INTERVAL*1000) % 1000000;
it_val.it_interval = it_val.it_value;
if (setitimer(ITIMER_REAL, &it_val, NULL) == -1) {
perror("error calling setitimer()");
exit(1);
}
while (1)
pause();
}
/*
* DoStuff
*/
void DoStuff(void) {
printf("Timer went off.\n");
}

Resources