Preface - i use "task" and "thread" interchangeably here even though i know they are different. In my program a task is wrapped in a thread - the latter constantly waiting for an cond event to awaken the task.
During a context switch, the ContextSwitchHandler checks the incoming task for invalid info. However, it is returning a failure for tasks even when they have valid data.
By putting an infinite loop inside the task-data check, and then placing another in the signal handler, i can see that signals are interrupting this execution - even though i have supposedly masked signals before entering the ContextSwitchHandler.
This where the context switch starts:
void vPortYieldWithinAPI( void )
{
portUnsignedBaseType xInterruptsAlreadyMasked;
portcompatASSERT_PRIVILEGED_MODE(); // currently defined as nothing
xInterruptsAlreadyMasked = uxPortSetInterruptMaskFromISR();
vPortSwitchContext();
vPortClearInterruptMaskFromISR( xInterruptsAlreadyMasked );
}
and here is the implementation of the signal mask function - xPortIsrNormalSignalMask is a full signal mask except SIGINT being unblocked, as is shown further down.
portUnsignedBaseType uxPortSetInterruptMaskFromISR( void )
{
sigset_t xOriginalMask;
portUnsignedBaseType uxOriginalPriority;
pthread_sigmask( SIG_BLOCK, &xPortIsrNormalSignalMask, &xOriginalMask );
if( sigismember( &xOriginalMask, configPORT_SIGNAL_FOR_IRQ ) )
{
uxOriginalPriority = 1U; /* interrupts were originally masked */
}
else
{
uxOriginalPriority = 0U; /* interrupts were originally unmasked */
}
return uxOriginalPriority;
}
During the context switch, the task validity check is performed (signals should still be masked at this point).
KERNEL_FUNCTION portBaseType xPortIsTaskHandleValid( portTaskHandleType xTaskToCheck )
{
portBaseType xReturn;
const xTCB *pxTCB;
static portUInt32Type ulFailCount = 0;
/* THIS FUNCTION MUST ONLY BE CALLED FROM WITHIN A CRITICAL SECTION. */
/* First, ensure we've not been given a NULL pointer to check. */
if( NULL == xTaskToCheck )
{
xReturn = pdFALSE;
}
else
{
/* Set a pointer to the TCB buffer. */
pxTCB = ( const xTCB * ) xTaskToCheck;
if( ( portDataAddressType )( pxTCB->pxStackLimit ) != ~( pxTCB->uxStackLimitMirror ) )
{
/* The stack limit mirror is not as expected. */
xReturn = pdFALSE;
}
else if( ( portDataAddressType )( pxTCB->pxTopOfStack ) != ~( pxTCB->uxTopOfStackMirror ) )
{
/* The top of stack mirror is not as expected. */
xReturn = pdFALSE;
/* I have tried adding another signal mask here before i enter the while
* loop, but this also doesn't seem to prevent the SIGALARM from firing. */
sigset_t set;
sigemptyset(&set); /* initialize the signal set */
sigaddset(&set, SIGALRM); /* add SIGALRM to the set */
pthread_sigmask( SIG_BLOCK, &set, NULL );
/* */
while( 1 )
{
/* put a breakpoint here... to check if we are getting interrupts */
xReturn++;
xReturn--;
}
}
...
return xReturn;
}
What im finding is the incoming task fails this second check, even though when i inspect the data the mirror is indeed correct for the stack address. So my belief is that interrupts are occurring and messing with the statement.
As i said, if i place a breakpoint in this while loop, run to that point and the put another in the signal handler, i can still see signals occurring.
My configuration of the signals and signal handlers is as follows:
portBaseType iPortIsrSetupDefaultThreadSignalMask( void )
{
portBaseType xReturn;
/* Disable all signals except SIGINT. From main thread, other threads
* should inherit this. We leave SIGINT so we can stop it. */
xReturn = ( portBaseType )sigfillset( &xPortIsrNormalSignalMask );
if( 0 == xReturn )
{
xReturn = ( portBaseType )sigdelset( &xPortIsrNormalSignalMask, SIGINT );
}
if( 0 == xReturn )
{
xReturn = ( portBaseType )pthread_sigmask( SIG_SETMASK, &xPortIsrNormalSignalMask, &xPortOriginalSignalMask );
}
return xReturn;
}
/*---------------------------------------------------------------------------*/
void vPortInitialiseINTC( void )
{
struct sigaction xSigActIRQ, xTestSigActIRQ;
if( iPortIsrSetupDefaultThreadSignalMask() != 0 )
{
portERRORHOOKSTR( NULL, "Failed to set up default signal mask", errINVALID_PARAMETERS );
}
xSigActIRQ.sa_flags = SA_SIGINFO;
xSigActIRQ.sa_sigaction = vPortIsrIRQHandler;
// we set two sigmasks, one here and one in iPortIsrSetupDefaultThreadSignalMask(), which one is actually masking irq's?
sigemptyset( &xSigActIRQ.sa_mask );
if( sigaction( configPORT_SIGNAL_FOR_IRQ, &xSigActIRQ, NULL ) )
{
portERRORHOOKSTR( NULL, "Failed to set up simulated interrupt system", errINVALID_PARAMETERS );
}
}
/*---------------------------------------------------------------------------*/
portWEAK_FUNCTION void vApplicationSetupTickInterruptHook( portUInt32Type ulClockHz, portUInt32Type ulRateHz )
{
struct sigevent xTimerEv;
struct itimerspec xSysTickTimerSpec;
int iSysRet;
long lNanosecondsPerTick;
( void )ulClockHz; /* Unused in this port */
portcompatASSERT_PRIVILEGED_MODE();
lNanosecondsPerTick = ( long ) PORT_ONE_SECOND_IN_NS / ( long ) ulRateHz;
vPortDisableInterrupts();
xTimerEv.sigev_notify = SIGEV_SIGNAL;
xTimerEv.sigev_signo = configPORT_SIGNAL_FOR_IRQ;
xTimerEv.sigev_value.sival_int = configPORT_SYSTICK_INTERRUPT_NUM; // defined as 14, same as SIGALARM
xTimerEv.sigev_notify_function = NULL;
iSysRet = timer_create( CLOCK_MONOTONIC, &xTimerEv, &xPortSysTickTimer );
if(iSysRet)
{
portERRORHOOKSTR( NULL, "Failed to create tick timer", errINVALID_PARAMETERS );
}
xSysTickTimerSpec.it_interval.tv_sec = 0;
xSysTickTimerSpec.it_interval.tv_nsec = lNanosecondsPerTick;
xSysTickTimerSpec.it_value.tv_sec = 0;
xSysTickTimerSpec.it_value.tv_nsec = lNanosecondsPerTick;
iSysRet = timer_settime( xPortSysTickTimer, 0, &xSysTickTimerSpec, NULL );
if(iSysRet)
{
portERRORHOOKSTR( NULL, "failed to set & start tick timer", errINVALID_PARAMETERS );
}
}
Is there some point in my configuration that isnt setting up the signal masks properly? Signals and threads are quite new to me so please feel free to ask for extra info or clarification if required.
Thank you
Related
In this example code I set up an ALSA client, create a sequencer queue and output port. Then I output a scheduled note on and note off event to this port and wait for a keystroke. At this point I set up midisnoop to read from the port.
When keystroke arrives I start the queue and read the realtime ticks. I am expecting the note to show on the output port which I am monitoring. Nothing appears.
#include <stdio.h>
#include <alsa/asoundlib.h>
int queue, out_port;
snd_seq_t *seq_handle;
snd_seq_tick_time_t current_tick;
snd_seq_queue_status_t *status;
int main (int argc, char **argv) {
// open sequencer and create queue
snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT | SND_SEQ_OPEN_OUTPUT, 0);
queue = snd_seq_alloc_queue( seq_handle );
fprintf(stderr,"queue id=%d\n", queue);
// create an output port
out_port = snd_seq_create_simple_port(seq_handle, "test:out",
SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,
SND_SEQ_PORT_TYPE_APPLICATION);
if( out_port < 0 ) return 1;
// set up a midi event for scheduling noteon and noteoff
snd_seq_event_t event;
snd_seq_ev_clear( &event );
// set up source address
snd_seq_addr_t addr;
addr.client = snd_seq_client_id( seq_handle);
addr.port = out_port;
event.source = addr;
// set destination addressing to all subscribers
snd_seq_ev_set_subs( &event );
// note specifics
int chan = 0;
int note = 64;
int veloc = 127;
int tick = 0;
// note on at zero
snd_seq_ev_set_noteon( &event, chan, note, veloc);
snd_seq_ev_schedule_tick( &event, queue, 0, tick );
snd_seq_event_output( seq_handle, &event );
// note off at 96
tick = 96;
snd_seq_ev_set_noteoff( &event, chan, note, veloc);
snd_seq_ev_schedule_tick( &event, queue, 0, tick );
snd_seq_event_output( seq_handle, &event );
// drain output
snd_seq_drain_output( seq_handle );
// wait here for keystroke, so we can set up midisnoop
fgetc( stdin );
// start queue and read ticks
snd_seq_start_queue( seq_handle, queue, NULL );
snd_seq_drain_output( seq_handle );
for(int i=0;i<4;i++) {
snd_seq_queue_status_malloc(&status);
snd_seq_get_queue_status(seq_handle, queue, status);
current_tick = snd_seq_queue_status_get_tick_time(status);
snd_seq_queue_status_free(status);
fprintf(stderr,"tick=%d\n", current_tick );
sleep(1);
}
snd_seq_stop_queue( seq_handle, queue, NULL );
snd_seq_free_queue( seq_handle, queue );
return 0;
}
Starting a queue clears it.
You must send the queue start event before the actual events. (You do not need to drain it separately.)
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.
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.
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.
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");
}