Trouble with Interval Timer - c

Our current project is based on extending more by including scroll. In order to do this, a timer interval has to be set for a certain period. The part I'm not sure about is where the loop for the alarm signal should be. All the examples I've seen have the timer values in the main, then explicitly call the signal handler via pause() in an infinite while loop.
My code is a bit different, since the functionality requirements go like
print first screen of text after getting terminal dimensions
print prompt
if prompt = space, print another screen of text //WORKS
if prompe = q, restore original terminal settings & quit program //WORKS
if prompt = ENTER, initialize scroll at 1 line every 2 seconds //DOESN'T WORK
if prompt == f/s, increase/decrease scroll speed by 20% //DOESN'T WORK
The read in buffer, file pointer and itimerval struct are all global variables to avoid passing as arguments through a chain of functions.
The main function of the program is
void processInput(FILE *fp){
void printLine(int); //prints a single line of text
signal(SIGPROF, printLine);
int c;
//print first screen of text, check for more text to display
info(); //print prompt at bottom of screen
FILE *fterm= fopen("/dev/tty", "r");
while ((c=getc(fterm)) != EOF){
if (c== '\n'){
setTimer(2);
//four more conditionals like this in basic similarity
}
}
My setTimer function has a base interval of 2 seconds, and changes that by plus/minus 20% based on f/s input from the user.
void setTimer(int direction){
int speed=2000000; //2 seconds
int change= 400000; //400 milliseconds, 20% of 2 seconds
if (direction == 1) //slow down by 20%
speed+= change;
if (direction == 0)
speed -= change;
timer.it_value.tv_sec=2;
timer.it_value.tv_usec=0;
timer.it_interval.tv_sec=0;
timer.it_interval.tv_usec= speed;
setitimer(ITIMER_PROF, &timer, NULL);
}
First question: should I use SIGALRM vs SIGPROF, and alter the ITIMER_XXXX variable accordingly?
Second, where should I put in the loop to trigger the signal? I tried
while(1)
pause();
in several of the conditionals, but it had the effect of stopping the execution and ignoring any input.

Without knowing the details of your requirements, couldn't you do this more easily using
select()?
Set your initial select timeout to 2 seconds and adjust according to f/s input, meanwhile if there is any standard input before the timeout you process it.
More or less valid general outline:
int retval;
fd_set rfds;
int input = fileno(fterm);
struct timeval tv, delay;
delay.tv_sec = 2;
delay.tv_usec = 0;
while (true)
{
FD_ZERO(&rfds);
FD_SET(input, &rfds);
tv.tv_sec = delay.tv_sec;
tv.tv_usec = delay.tv_usec;
retval = select(input + 1, &rfds, NULL, NULL, &tv);
if (retval == -1)
perror("select()");
else
if (retval)
{
if (FD_ISSET(input, &rfds))
{
command = readInput(...);
switch(command)
{
case 'q' ... cleanup & quit
case 's' ... calc 20% off delay values
case etc ...
case default...error handling
}
}
}
else //timeout
printLine();
}

Working with pause() is dangerous because it's not an atomic operation ... your program could be interrupted by the OS causing you to "lose" the arrival of a signal. Additionally, when pause() itself returns because of the arrival of a signal, it will simply call pause() again. That means you're going to have to-do all your work inside of a signal handler, which may not be the best thing, i.e., if you're inside the signal handler when the next signal goes off, you can end up with some unpredictable behavior if you haven't planned for that sort of event.
A better approach would be to-do the following:
1) Setup a signal mask that blocks SIGPROF at the start of your program.
2) Rather than using a signal handler to-do your heavy lifting, use sigwait(), and set it up with a sigset_t that contains a mask for SIGPROF.
3) Setup the main flow of your program the following way:
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGPROF);
sigprocmask(SIG_BLOCK, &sigset, NULL); //block the SIGPROF signal
//process your input
//if you need to, initialize your timer and set it to go off
while(SOME_FLAG_IS_TRUE) //maybe this loops forever ... depends on what you want?
{
sigwait(&sigset, &signal_num);
if (signal_num != SIGPROF)
continue;
//process input ...
//... setup new interval timer with correct timeout ...
//... repeat loop and/or exit loop or set flag to exit loop
}
That should always catch the signal from the interval timer since sigwait() will properly return after waiting for a signal to arrive to your process, and the SIGPROF signal is always blocked, meaning you can't "lose" signals ... instead at least one of them will be queued up and waiting for the next call to sigwait() to be detected just in case one arrives while you're processing something in your while-loop.
Hope this helps,
Jason

Related

How to I interrupt sleep()

So, I have a while(1) loop with a sleep(60) seconds at the end. The problem is, my program can receive an instruction in the meantime, but will have to wait the 60 seconds until it's executed. I've tried with a handler and my other program sending a signal (with kill(daemonid,SIGCONT)), but it doesn't seep to interrupt sleep() (i.e. make it return).
void handler(){
write(1,"bonjour",7);
alarm(1);
}
/*code blocks irrelevant to the question*/
int main(){
/*reads and opens files*/
struct sigaction execaction;
memset(&execaction,0,sizeof(struct sigaction));
execaction.sa_handler=handler;
sigaction(SIGCONT,&execaction,NULL);
while(1){
pf[0].fd=request_pipe;
pf[0].events=POLLIN;
int p=poll(pf,1,timeout);
if(pf[0].revents & POLLIN){
read(request_pipe,&operation,sizeof(uint16_t));
switch (operation){
case CLIENT_REQUEST_CREATE_TASK:
printf("create\n");
reply_pipe=open(path2,O_WRONLY);
rep=SERVER_REPLY_OK;
write(reply_pipe,&rep,sizeof(int));
taskid=htobe64(0);
write(reply_pipe,&taskid,sizeof(uint64_t));
close(reply_pipe);
break;
case CLIENT_REQUEST_LIST_TASKS:
printf("list\n");
reply_pipe=open(path2,O_WRONLY);
rep=SERVER_REPLY_OK;
write(reply_pipe,&rep,sizeof(int));
close(reply_pipe);
break;
default:
printf(":(");
}
}else{
printf("Timed out\n");
printf("coucou \n");
}
close(request_pipe);
int t=60;
sleep(t);
}
return 0;
}
}
So the program that writes in these pipes, at the end of every option sends a kill signal to this daemon process.I know it writes things well because after a minute it's executed.
So how can I stop sleep() in this case if I receive something in the pipe to read (and then restart it at the end of the loop)? I've tried with SIGCONT, it doesn't seem to be working.
You could implement a function that
receives the number of total seconds to sleep
breaks down the sleep 60 into 60 sleeps of 1
loops a variable between 1 and the number of seconds to sleep
on each iteration of the loop runs the function pointer to check whether the sleep process should continue
And then you can implement a function that checks whether the sleep should be ended and pass this function pointer to the function that handles the sleep along with the number of seconds to sleep.

to interrupt a sleeping thread when main thread is to exit

I have a main thread which create child threads to do various task. There is a child thread which is tasked to report on the status every 100s
My current mechanism of stopping the thread is to observe a global boolean. Somewhat like this
Child thread
void* ReportThread(bool* operation)
{
while(*operation)
{
// do its reporting task
// ........
int counter = 0;
while( counter < 100 && operation )
{
// let it sleep for 1 seconds and wake up to check
sleep(1);
sleepCounter += 1;
}
}
}
Parent (Main) Thread:
bool operation = false;
int main(){
pthread_t tid;
err = pthread_create(&tid), NULL, &ReportThread, &operation);
printf("Please input esc to end operation \n");
while ((ch = getchar()) != 27);
operation =true;
pthread_join(tid,NULL);
return 0;
}
The problem:
It seem that using sleep(n). The number of seconds seem very inconsistent. When the program is stopped, this thread takes a while maybe 10 second to actually stop
Is there a way to interrupt a thread to sleep? I heard you could use signal. I am coding in linux
Can I just simply just use a pthread_cancel(tid) instead of pthread_join(tid)?
Regards
This part
while( counter < 100 || operation )
{
// let it sleep for 1 seconds and wake up to check
sleep(1);
sleepCounter += 1;
}
is wrong.
First I assume that sleepCounter += 1; is really a typo and that it should be:
while( counter < 100 || operation )
{
// let it sleep for 1 seconds and wake up to check
sleep(1);
counter += 1;
}
Then the problem is that even if operation is set to false by some other thread, the while will not finish until counter reach 100.
The code should be
while( counter < 100 && operation )
{
// let it sleep for 1 seconds and wake up to check
sleep(1);
counter += 1;
}
Further, in main you never set operation to false. Another typo?
You don't need two while loops. And if you want to set a timer, use time functions for it, because sleep is a cancellation point and it is not guaranteed that sleep actually sleeps that amount of time.
Example:
void* ReportThread(void *args)
{
time_t start = time(NULL);
time_t now;
bool *operation = (bool*) args;
while (*operation) { //while active
now = time(NULL); //get current time
if (now - start >= 100) { //if the threshold is exceeded
start = now; //reset timer
//and probably do other stuff
}
sleep(1); //sleep for one second
}
return NULL;
}
The example above has a max lag of one second, that means if you set operation to false right at that moment when the thread entered the sleep state, you have to wait until sleep returns, only then it will recognize the modified state. The example also has the advantage, that you can easily modify the threshold value (since it depends on the 'real' time, instead of a counter and a non accurate sleep time).
Btw. the variable operation should be either an atomic boolean or protected by a mutex (since it is accessed from different threads).
To answer the questions of your problem:
should be answered by the example above
since i mentioned it before, sleep is a cancellation point, that means it gets interrupted if the process handles a signal (see man pthreads - section Cancellation points).
see man pthread_cancel - section Notes
On Linux, cancellation is implemented using signals. Under the NPTL threading implementation, the first real-time signal (i.e., signal 32) is used for this purpose. On LinuxThreads, the second real-time signal is used, if real-time signals are available, otherwise SIGUSR2 is used.
You cannot use pthread_cancel over pthread_join! You have to use pthread_join in either case (described in detail in the man page).
I don't know if this will fix all your problems, but it's a bit too much for a comment. One problem, your ReportThread function signature is wrong. It should be:
void* ReportThread(void* args);
And then in that function you need to do something like:
void* ReportThread(void* args)
{
bool* operation = (bool*)args;
while(*operation)
{
...
}
}
I'm not sure how it's working right now, but your compiler should at least be issuing a warning trying to convert a bool* type to a bool.
Also be aware of race conditions on operation

How to wait for a signal for a certain time only, in C language?

I am trying to communicate between 2 processes ( parent and child process in linux ) using signals in C programming language.
The first process does some calculation and provides a data. Then, it sends a signal to the second, which is in a suspended state, waiting for a signal to wake up and collect that data shared by the first process using a shared memory.
How to make the second process wait for a certain time or let's say a period of time ?
Within that period, if the first process provides data and sends a signal to the second, everything is OK. Otherwise, if it doesn't receive any signal from the first within that period, it will do another thing.
How can I make the second process respond to that need ?
Which algorithms and signals should I use to implement this ?
POSIX defines a function for exactly your purpose: sigtimedwait(). It will suspend execution of the calling process until either one of the signals in a specified set becomes pending, or a specified timeout expires. Its return value indicates which of those occurred.
Within that period, if the first process provides data and sends a signal to the second, everything is OK. Otherwise, if it doesn't receive any signal from the first within that period, it will do another thing.
How can I make the second process respond to that need ?
The second process sets up the arguments for sigtimedwait. It then blocks the expected signal (via sigprocmask), so that the default disposition does not occur when that signal is received, and afterward calls sigtimedwait. The return value of the latter indicates whether one of the specified signals was received (and if so, which), or whether the function returned for some other reason -- typically, because the timeout expired. In the latter case, the errno variable can be examined to determine whether indeed it was a timeout. The manual page linked above provides some additional usage notes.
Specifically, you need two main arguments:
a sigset_t defining the signals to block and to wait upon. The "See also" section at the end of the manual page refers you to the documentation for related and similar functions, including sigsetops(3), which tells you about how to manipulate such objects. For example,
#include <signal.h>
// ...
sigset_t sigs;
sigemptyset(&sigs);
sigaddset(&sigs, SIGUSER2);
a struct timespec, whose definition is provided inline in the manual page. That definition should be sufficient for you to come up with something like
struct timespec timeout = { .tv_sec = 10 };
Per the docs, you may specify the second argument of sigtimedwait as NULL if you do not need the information that otherwise could be conveyed back to you by that means, which you don't.
You can use the signal set already prepared as described above for setting up signal blocking, for example:
sigprocmask(SIG_BLOCK, &sigs, NULL);
This may seem a bit counterintuitive, since you do want to receive the signal, but the effect is to block whatever disposition has been established for the signal from occurring, which is a different path from handling it via sigtimedwait.
At this point, then, you are ready to make the call to sigtimedwait():
int sig_num = sigtimedwait(&sigs, NULL, &timeout);
The result will be a signal number if one of the specified signals (only SIGUSER2 in this example) is received within the specified time, or -1 otherwise. Therefore,
if (sig_num == SIGUSER2) {
// I received the signal
// do something ...
} else {
// assert(sig_num == -1);
// I did not receive the signal within the alotted time
// do something else ...
}
You might choose to assume that a timeout occurred in the case where the signal is not received, but the most robust code would check errno to verify that:
if (errno == EAGAIN) {
// it was a timeout
} else if (errno = EINTR) {
// a signal outside the set was received
// ... might want to calculate how much wait time is left and try again
// (left as an exercise)
} else {
// some other error occurred
// ... aborting with an error might be best:
perror("signal wait failed unexpectedly");
exit(1);
}
Call to sleep until 10 seconds or signal would be:
struct timeval t = {10, 0};
int rc = select(0, NULL, NULL, NULL, &t);
if (rc == 0) {
// timeout
} else if (errno == EINTR) {
// signal
} else {
// some error
You may include the first process of your code inside an infinite while loop(eg-; while(1){}) and once the data calculated by first process use functions to send data to the second process. Within the second process use sleep() function. For example;
main()
{
printf("Sleep for 10 milisecond to exit.\n");
sleep(0.10);
return ;
}
you may change the time.

Signals and sleep not working properly

i have an assignment to make, for university, it is almost done, most thing working, there is just one aspect that is not working and i'm not quite sure how to fix it..
The objetivo is to make the problem wait for 2 ctrl+C and close.. But if he catch a first ctrl+C and pass more then 3 seconds the program must forget about it and wait again for another 2 ctrl+C. This is how i'm doing it:
/*Problem 2. Write a program that sleeps forever until the user interrupts it twice with a Ctrl-C, and
then exits. Once the first interrupt is received, tell the user: “Interrupt again to exit.”. The first
interrupt should be forgotten 3 seconds after it has occurred. Additionally, the program should block
the SIGQUIT signal, and ignore the SIGTSTP signal. The program should start by printing “Interrupt
twice with Ctrl-C to quit.” on the screen.*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
//handler to catch the first ctrl_c and ask user to do it another time(no reference to time limit)
void ctrl_c(int sig){
signal(sig, SIG_IGN);
printf("\nInterrupt again to exit.\n");
}
//handler for second ctrl_c. If called, program will end
void second_catch(int sig){
if(sig == SIGINT){
printf("\n");
exit(0);
}
}
//handler to always ignore ctrl_z
void ctrl_z(int sig){
signal(sig, SIG_IGN);
}
int main(){
//blocking SIQUIT (Ctrl+\) using series of command to change the mask value of SIGQUIT
sigset_t sg;
sigemptyset (&sg);
sigaddset(&sg, SIGQUIT);
sigprocmask(SIG_BLOCK, &sg, NULL);
//installing handler to ignore SIGTSTP (Ctrl+Z)
signal(SIGTSTP, ctrl_z);
//two part SIGINT handling
printf("\nInterrupt twice with Ctrl+C to quit.\n");
signal(SIGINT, ctrl_c); //first handler install
do{ //cycle for second hanler install and 3 second timer
if(sleep(3) == 0){
main(); //if second_catch handler is not called within 3 seconds, program will restart
}
else {
signal(SIGINT, second_catch); //upon call, program will end
}
}while(1);
return 0;
}
What's happening is that it keeps reseting after 3 seconds, in a loop.. But i want to reset only 1 time after i click ctrl+c and 3 seconds passed..
What must i change?
Your approach is unlikely to lead to a working program.
First, use a signal handler that only sets a global variable (of volatile sig_atomic_t type) whenever a SIGINT signal is caught. Do not try to print anything from the signal handler, as standard I/O is not async-signal safe.
Second, use sigaction() to install the signal handler. Use zero flags. In other words, do NOT use SA_RESTART flag when installing the handler. This way, when a signal is delivered to your handler, it will interrupt most syscalls (including sleeps). (The functions will return -1 with errno == EINTR.)
This way, after your main() has installed the signal handler, you can have it print the instruction, and enter into a loop.
In the loop, clear the interrupt flag, and sleep for a few seconds. It does not matter how long. If the interrupt flag is not set after the sleep completes, continue (at the beginning of the loop).
Otherwise, you know that the user has pressed Ctrl+C. So, clear the interrupt flag, and sleep for another three seconds. If the flag is set after the sleep completes, you know the user supplied another Ctrl+C, and you can break out of the loop. Otherwise, you just continue the loop again.
Technically, there is a race condition here, as the user might press Ctrl+C twice in a row, rapidly enough so that the main() only sees one.
Unfortunately, increments (flag++) are not atomic; the compiler or the hardware may actually do temp = flag; temp = temp + 1; flag = temp; and the signal may be delivered just before the third step, leading to the signal handler and main() seeing different values of flag.
One way around that is to use C11 atomics (if the architecture and C library provides them, in <stdatomic.h>, with macro ATOMIC_INT_LOCK_FREE defined): volatile atomic_int flag; for the flag, __atomic_add_fetch(&flag, 1, __ATOMIC_SEQ_CST) to increment it, and __atomic_sub_fetch(&flag, 1, __ATOMIC_SEQ_CST) to decrement it.
Another way would be to use a POSIX semaphore. The signal handler can increment it (using sem_post()) safely. In main(), you can use sem_timedwait() to wait for the signal for a limited time, and sem_trywait() to decrement it.
A third way would be to use sigtimedwait() to catch the signal in main() with a timeout, without any signal handlers. This last one is, I believe, the most robust and simple to implement, so that's what I'd use in a real application.
It turns out that there is another way to achieve this, one that responds to two consecutive Ctrl+C presses within three seconds, without leaving any nasty corner cases.
This is NOT exactly what was asked of OP, and as such is not a valid answer to their exercise, but this would be a good approach otherwise.
The idea is to use alarm() and a SIGALRM handler, and two sig_atomic_t flags: one that counts the Ctrl+C keypresses, and one that flags the case when there have been two in a three-second period.
Unfortunately, sleep() cannot be used in this case -- you have to use nanosleep() instead --, as sleep(), alarm(), and SIGALRM signal handling may interfere with each other.
Essentially, we use
#define INTR_SECONDS 3
static volatile sig_atomic_t done = 0;
static volatile sig_atomic_t interrupted = 0;
static void handle_sigalrm(int signum)
{
if (interrupted > 1)
done = 1;
interrupted = 0;
}
static void handle_sigint(int signum)
{
interrupted++;
if (interrupted > 1) {
done = 1;
alarm(1);
} else
alarm(INTR_SECONDS);
}
handle_sigalrm() is installed as the SIGALRM handler, with SIGINT in its signal mask; handle_sigint() is installed as the SIGINT handler, with SIGALRM in its signal mask. This way the two signal handlers block each other, and won't be interrupted by each other.
When a first SIGINT is received, the alarm is primed. If this is the second (or third etc.) SIGINT without an intervening SIGALRM, we also set the done flag, and prime the alarm to occur in one second, to ensure we catch the state change in at most one second.
When a SIGALRM is received, the interrupt count is zeroed. If it was two or more, the done flag is also set.
In main(), we only check done and interrupted, never modify them. This avoids the corner cases I was worried about.
In the worst case, there is one second delay to quitting, if the second Ctrl+C is delivered after we check, but just before we sleep. The alarm(1) in handle_sigint() is for just that case.
The loop in main is then just
while (!done) {
while (!done && !interrupted)
nanosleep(&naptime, NULL);
if (done)
break;
printf("Ctrl+C again to quit!\n");
fflush(stdout);
while (interrupted == 1 && !done)
nanosleep(&naptime, NULL);
}
The first inner loop only sleeps when it has been over three seconds since the last SIGINT (or we never received one). It will be interrupted by both SIGINT and SIGALRM, so the duration does not matter.
The if (done) break; case just avoids printing anything if the user had lightning hands and typed Ctrl+C twice really fast.
The second inner loop only sleep when we are waiting for a second Ctrl+C. It too will be interrupted by both signals, so the duration here does not matter either. Note, however, that we do wish to check interrupted first, to ensure we catch all changes reliably. (If we checked done first, we might be interrupted before we check interrupted, and it is possible, in theory, that done changes to nonzero and interrupt to zero and then to 1 in the mean time. But, if we check interrupted first, and it is 1, any additional interrupts will just set done, which we'll catch. So, interrupted == 1 && done == 0 is the correct check in the correct order here.)
As noted above, the duration specified for nanosleep() does not actually matter, as it will be interrupted by the signal delivery anyway. Something like ten seconds should be fine,
struct timespec naptime = { .tv_sec = 10, .tv_nsec = 0L };
If the lecturer had recommended POSIX.1 functions (sigaction(), nanosleep()), this would have been surprisingly interesting exercise.

how to use signals to print every specific time and generate keyboard interrupt?

I have the program below and I want to use signals to print the every 5 seconds, and handle keyboard interrupt like ctrl + c to terminate the process and ctrl + p to print the result.
int i=1;
while(i>0)
{
i++;
if(i%2==0)
{
printf("%d \n",i)
}
}
In my experience signal handling difficult to do reliably, prone to subtle race conditions and the like (and whoever thought EINTR was a good idea should be shot.) Then again I suppose I never really got the UNIX way of doing things.
My advise is to do as little work as humanly possible inside of the handlers themselves and to try to keep the signals masked anywhere you're not directly interested in them.
The following is my attempt at installing a SIGALRM handler and printing a message every 5 seconds:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/select.h>
// Raise a flag once the event occurs
volatile sig_atomic_t event;
void handler(int sig) { event = 1; }
int main(void) {
sigset_t mask;
// Install our alarm handler
struct sigaction action = { 0 };
action.sa_handler = handler;
sigaction(SIGALRM, &action, NULL);
// Mask out the alarm signal during normal operation to avoid races
// and having to handle EINTR everywhere
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
sigprocmask(SIG_SETMASK, &mask, &mask);
// Here goes the main loop..
for(;;) {
// Set the alarm
alarm(5);
// Wait for the alarm to happen with the alarm signal unblocked.
// Add whatever other I/O you're waiting for here
pselect(0, NULL, NULL, NULL, NULL, &mask);
// Did we get woken up by an alarm signal?
if(event) {
event = 0;
puts("Alarm!");
}
}
}
In your specific computationally-bound case I would suggest strategically polling the event flag from the loop instead of attempting to extract and print the present number from within the signal handler.
If you decide to go the latter route then beware that you cannot rely on being able to atomically read and write the value. Instead I would suggest a double-buffering scheme placing the two most recent values in a circular buffer with a (volatile sig_atomic_t) index pointing out the right slot. Oh, and you'll have to do the I/O through manual string manipulation and write() since printf is forbidden in a signal handler. The real kicker, though, is that you won't be able to synchronize with other standard output text in any sane fashion.
In essence using multithreading with a separate calculation thread is a far superior means of achieving the same end.

Resources