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.
Related
I have a main proccess which sends signal to the children, like this:
void handleInputs(query_data *q_data)
{
char input[DEFAULT_INPUT_SIZE];
while(1)
{
if(fgets(input,DEFAULT_INPUT_SIZE,stdin)==NULL) ERR("FGETS");
input[strlen(input)-1] = '\0';
if(!strcmp(input,"exit"))
{
kill(0,SIGTERM);
exit(EXIT_SUCCESS);
}
else if(!strcmp(input,"index"))
kill(0,SIGUSR2);
else if(!strcmp(input,"status"))
kill(0,SIGUSR1);
else
{
char* token = strtok(input, " ");
if(!token) printf("Wrong input\n");
else
{
if(!strcmp(token,"query"))
{
initializeQueryNumbers(q_data,token);
createQueryThread(q_data);
}
else printf("Wrong input\n");
}
}
}
}
Then I have a child processes which wait for signals using sigwait in a loop like this:
void waitForSignals(data* ch_data)
{
char* pid_directory = strConcat(ch_data->dir, "/.numf_pid");
int signo;
for(;;)
{
//how to make this block independent to the sigwait
printf("time elapse: %ld interval: %d\n",time(NULL)-ch_data->end, ch_data->i);
if((time(NULL)- ch_data->end)>ch_data->i && ch_data->status ==0)
{
printf("Time elapsed from the last indexing > %d\n",ch_data->i);
createIndexingThread(ch_data);
}
//end here
if(sigwait(&(ch_data->mask), &signo)) ERR("SIGWAIT");
switch(signo)
{
case SIGUSR1:
if(ch_data->status == 1)
{
printf("Indexing in progress for directory: %s\n",ch_data->dir);
printf("Time elapsed: %ld\n", time(NULL)- ch_data->start);
}
else printf("No indexing in progress for directory: %s\n",ch_data->dir);
break;
case SIGUSR2:
if(ch_data->status ==0)
createIndexingThread(ch_data);
else printf("Indexing already in progess for directory: %s\n",ch_data->dir);
break;
case SIGTERM:
if(remove(pid_directory)<0) ERR("REMOVE");
free(pid_directory);
if(pthread_cancel(ch_data->tid)==0)
printf("Stopped the indexing of directory %s\n",ch_data->dir);
exit(EXIT_SUCCESS);
}
}
if(pthread_join(ch_data->tid,NULL)) ERR("PTHREAD_JOIN");
}
My child proccess creates thread which does some indexing. I want to create such thread when signaled SIGUSR2 from main proccess (which is working fine) or when time elapsed from last indexing is bigger than some user-given time (stored in ch_data->i). However right now the block between the comments only comes alive after I send some signal from the main proccess. What is the best way to make it work in parallel?
If I understand correctly, you are asking how to schedule a threaded operation performed either upon a signal or upon time elapsed since the most recent operation, whichever comes first.
You might use sigtimedwait(interesting_sigs, NULL, timeout) instead of sigwait, recomputing your timeout as needed.
You might arm a POSIX timer to launch the operation (or, perhaps, to signal yourself). You'll need to check that the operation hasn't been performed too recently, and you'll need to re-arm (reschedule) the next timer appropriately, perhaps at the end of every operation.
You might simply have an idle-looping background thread that does what a timer would do. Sometimes these are easier to reason about than sigevent timers.
You might incorporate an event-driven framework like libevent that knows how to handle timeouts and signals and not worry about the implementation. You'll likely still need to recompute the expiry, however.
I'm trying to complete an assignment for uni and I'm encountering an issue. I want to create something like a "timer" for my program. What I mean is that I want to run the program for 30 seconds, and after those have passed I want to print some stats before closing it. Since it is a process related project I would like this timer to be passed to the child processes as well if possible. Here is some pseudo-code of what I'm trying to accomplish.
/* Timer starts from here */
- forking childs
- child execute
- other actions
/* Timer finishes here */
Printing statistics
exit(0)
I tried reading up something on alarm, time and others but I wasn't able to find anything that could help me. Hope you can help me out and thanks in advance.
Try to read the man pages of alarm(). check the man page of alarm
unsigned int alarm(unsigned int seconds);
What alarm returns ? alarm() returns the number of seconds remaining until any previously scheduled alarm was due to be delivered, or zero if there
was no previously scheduled alarm.
you can set multiple alarm() for N seconds, but not all at a time.
Here is the simple code to understand alarm().
#include<signal.h>
#include<stdio.h>
int al = 5;
void my_isr(int n)
{
static int count = 0;//count variable
if(n == 17) {
/** this child will execute if child completer before 5 seconds**/
int ret = wait(0);//releases child resources
printf("child %d completed \n",ret);
}
if(n == 14) {
printf("in sigalarm isr \n");
/** do task here **/
if(count<3) {
alarm(5);// after doing some task set another alarm
}
count++;
}
}
int main()
{
if(fork()==0)
{
printf("child : pid = %d ppid = %d\n",getpid(),getppid());
/** letting the child to run for 20 seconds **/
sleep(20);
printf("child exits after task over \n");
exit(0);
}
else
{
alarm(al);//setting 5 seconds timer for child to finish job
signal(SIGALRM,my_isr);
/** to avoid child to become zombie. when child completes parents will receive SIGCHLD signal, upon receving this parent needs to free the resources associated with it using wait */
signal(SIGCHLD,my_isr);
while(1);//to keep main process alive for observation
}
}
I hope it helps you.
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.
I want to write a program in C that performs some function and then sleeps for some minutes.
During this sleep period I would like to do something and exit if a key is pressed.
int main()
{
while(1)
{
/*body*/
sleep(300);
}
/*some lines here*/
return 0;
}
Is there anyway that I can exit the loop during either the sleep period or at any time using a non-blocking key listener?
Just don't sleep for 300 seconds but rather 300 x for 1 second and check for key press:
int main()
{
while(1)
{
/*body*/
for ( int i=0; i<300; i++ )
{
if (keypressed())
doSomething();
}
}
/*some lines here*/
return 0;
}
EDIT: Why the while (1) in your code? Do you really want to run your program endlessly? (In that case, /*some lines here*/ doesn't make sense.)
there are several possible solutions:
use a timed select
use 2 threads - one waiting on the input and the other sleeping and doing the operation
As #Axel suggested, split the big sleep to several smaller sleep. To get an interval smaller than 1 sec, you can use usleep() or nanosleep()
The simplest solution would probably be 3, but is slightly less efficient, as it's using polling instead of event driven
During this sleep period I would like to do something and exit if a key is pressed. - It is not possible.
Because during the sleeping period Process will go to suspend state. Once the process suspended, you cant do anything until it woke up again. In that sleeping time if you pressed any keys also your process won't come to know which what happened? or what key is pressed?. Because already Your process is suspended.
And in your code why you are using while(1)? -
while(1)
{
/*body*/
sleep(300);
}
/*some lines here*/ // Your program wont execute this part. Because you have while(1) before. It wont comes out of the loop.
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