I want to use a virtual timer to pause a while loop till the timer expires. The goal is to have a function run periodically given a time interval.
I read on the gnu.org site that using pause() can be troublesome and they suggest using sigsuspend instead. I am using the code given in the example. My program looks as follows.
void handler_SIGALRM(int signo)
{
signo = 0; /* Get rid of warning "unused parameter ‘signo’" (in a portable way). */
puts(" ***********Cleared Alarm");
return;
}
int main(int argc, char *argv[]) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler_SIGALRM;
if (-1 == sigaction(SIGALRM, &sa, NULL ))
{
perror("sigaction() failed");
exit(EXIT_FAILURE);
}
struct itimerval it_val; /* for setting itimer */
it_val.it_value.tv_sec = 3; // INTERVAL/1000;
it_val.it_value.tv_usec = 0;//simData.misc
it_val.it_interval = it_val.it_value;
if (setitimer(ITIMER_REAL, &it_val, NULL) == -1) {
perror("error calling setitimer()");
exit(1);
}
sigset_t mask, oldmask;
sigemptyset(&mask);
sigaddset(&mask,SIGALRM);
/* Wait for a signal to arrive. */
sigprocmask(SIG_BLOCK, &mask, &oldmask);
sigsuspend(&oldmask);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
puts("unblocked");
sigprocmask(SIG_BLOCK, &mask, &oldmask);
while(1)
{
//...
sigsuspend(&oldmask);
//...
}
sigprocmask(SIG_UNBLOCK, &mask, NULL);
return 0;
}
The code above accomplishes the "pause" that I need. However, when I run it embedded in another program (threaded). It just hangs, and just keeps calling _handler_SIGALRM_.
Am I doing something wrong? Why could my program be hanging?
Related
I m trying to induce EINTR failure with semop call.
key_t semkey;
int semid;
struct sembuf sbuf;
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
struct semid_ds ds;
/* Get unique key for semaphore. */
if ((semkey = ftok("/tmp", 'a')) == (key_t) -1) {
perror("IPC error: ftok"); exit(1);
}
/* Get semaphore ID associated with this key. */
if ((semid = semget(semkey, 0, 0)) == -1) {
/* Semaphore does not exist - Create. */
if ((semid = semget(semkey, 1, IPC_CREAT | IPC_EXCL | S_IRUSR |
S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) != -1)
{
/* Initialize the semaphore. */
arg.val = 0;
sbuf.sem_num = 0;
sbuf.sem_op = 2; /* This is the number of runs without queuing. */
sbuf.sem_flg = 0;
if (semctl(semid, 0, SETVAL, arg) == -1
|| semop(semid, &sbuf, 1) == -1) {
perror("IPC error: semop"); exit(1);
}
}
else if (errno == EEXIST) {
if ((semid = semget(semkey, 0, 0)) == -1) {
perror("IPC error 1: semget"); exit(1);
}
goto check_init;
}
else {
perror("IPC error 2: semget"); exit(1);
}
}
else
{
/* Check that semid has completed initialization. */
/* An application can use a retry loop at this point rather than
exiting. */
check_init:
arg.buf = &ds;
if (semctl(semid, 0, IPC_STAT, arg) < 0) {
perror("IPC error 3: semctl"); exit(1);
}
if (ds.sem_otime == 0) {
perror("IPC error 4: semctl"); exit(1);
}
}
sbuf.sem_num = 0;
sbuf.sem_op = -1;
sbuf.sem_flg = SEM_UNDO;
while (semop(semid, &sbuf, 1) == -1)
{
if (errno != EINTR)
{
perror("IPC Error: semop"); exit(1);
break;
}
}
Most i get is Resource unavailable failure or Resource busy. I even tried multiple semaphores running in two different threads or two different processes. but i dint able to get EINTR failure. i even tried sending signal as SIGCHLD to the process when sometime semop is waiting for the semaphores.
As per zwol suggestion,
Here is what i tried but it still dint work, i mean i can't get EINTR.
int g_global_variable = 0;
void *sigusr1_block_thread (void *vargp)
{
while (1)
{
sleep (10);
printf ("sigusr1_block_thread\n");
}
return NULL;
}
void *semop_wait_thread (void *vargp)
{
int sem;
struct sembuf sops[2];
if((sem = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600))==-1){
return NULL;
}
if(semctl(sem,0,SETVAL,2)==-1){
exit(1);
}
sops[0].sem_num=0;
sops[0].sem_op=-1;
sops[0].sem_flg=0;
sops[1].sem_num=0;
sops[1].sem_op=0;
sops[1].sem_flg=0;
g_global_variable = 1;
printf ("Starting semop call \n");
if(eintr_check_semop(sem, sops,2)<0)
printf("Error semop\n");
return NULL;
}
int main()
{
pthread_t tid, tid1, tid2, tid3, tid4;
sigset_t set;
int s;
pthread_create(&tid, NULL, semop_wait_thread, NULL);
pthread_create(&tid2, NULL, semop_wait_thread, NULL);
pthread_create(&tid3, NULL, semop_wait_thread, NULL);
pthread_create(&tid4, NULL, semop_wait_thread, NULL);
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGCHLD);
s = pthread_sigmask(SIG_BLOCK, &set, NULL);
if (s != 0)
printf ("Error during pthread_sigmask");
pthread_create(&tid1, NULL, sigusr1_block_thread, NULL);
while (1)
{
sleep (1);
if (g_global_variable == 1)
{
sleep (10);
printf ("Send SIGUSR1/SIGCHLD signals \n");
/* Send signal */
pthread_kill( tid, SIGCHLD);
pthread_kill( tid2, SIGCHLD);
pthread_kill( tid3, SIGCHLD);
pthread_kill( tid4, SIGCHLD);
pthread_kill( tid1, SIGCHLD);
pthread_kill( tid1, SIGUSR1);
break;
}
else
continue;
}
pthread_join(tid, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
pthread_join(tid4, NULL);
return 0;
}
eintr_check_semop just a function in which semop error and return values are checked. if EINTR it prints the message saying same.
if i send sigusr1 to blocking thread (t, t2, t3, t4) semop call break and comes of the loop.
I didnt get EINTR by any means. Then i checked kernel source code.
https://elixir.bootlin.com/linux/latest/source/ipc/sem.c
During EINTR, i see they are looping and not reporting the same.
EINTR only happens when a process receives a signal while it's blocked on a blocking system call, and that signal has a handler, and that handler is configured to interrupt rather than restart system calls. (There are a few exceptions to this principle, but none of them involve semop.) Your program hasn't got any signal handlers, so EINTR won't happen, even if you do send it signals.
I can't tell you exactly how to do this off the top of my head, but the overall pattern that should work is:
Establish a signal handler for some signal. if you have no reason to pick some other specific signal, use SIGUSR1 . Use sigaction to do this, not signal, and do not include SA_RESTART in sa_flags. The handler doesn't have to do anything; it just has to exist.
If the program has more than one thread, use pthread_sigmask to block SIGUSR1 in every thread but one.
In the thread that has SIGUSR1 unblocked, perform a semop operation that will block (a "wait-for-zero" on a semaphore with a nonzero value, without IPC_NOWAIT).
After the above thread is definitely blocked on semop, from another thread within the program, use pthread_kill to send SIGUSR1 to the blocked thread. Or, from outside the program, use regular kill to send SIGUSR1 to the whole process; because the signal is unblocked in exactly one thread, that thread will receive the signal.
The hardest part is being sure that the thread is blocked on semop before the signal is sent. I'm not sure this is possible from inside the program, without a race condition.
I found SIGIO signal documented in GNU library. It is stated that there is a possibility the system to send a signal whenever I have input (particularly in socket).
According to documentation to create such signal I should set O_ASYNC flag to corresponding filedescritor.
My problem is that my GNU version (gcc 6.3.0) doesn't recognize such a keyword:
error: ‘O_ASYNC’ undeclared (first use in this function)
I used following block to set a flag:
/* Set socket status async */
int status = fcntl(sockfd, F_SETFL, O_ASYNC);;
if (status < 0) error("Can't set async mode");
else printf("Async is set for signal %d\n", SIGIO);
I use Cigwin GCC 6.3.0
The code is below:
static void OnTimer(int sig)
{
/* write request to socket BIO */
}
static void OnTick(int sig)
{
char read[BUFSIZE] = {};
int received;
received = SSL_read(ssl, read, sizeof(read));
/* Handle errors here */
/* print the server's reply */
printf("%s\n\n", read);
}
void connectSSL()
{
/* do all socket set-up and connection */
/* Establish handler for I/O signal */
saction.sa_flags = 0;
saction.sa_handler = OnTick;
sigemptyset(&saction.sa_mask);
sigaddset(&saction.sa_mask, SIGALRM);
if (sigaction(SIGIO, &saction, NULL) == -1) error("sigaction");
else printf("OnTick handler created\n");
/* Set socket status async */
int status = fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | FASYNC);
if (status < 0) error("Can't set async mode");
else printf("Async is set for signal %d\n", SIGIO);
/* Select the process to receive the signal */
int process = fcntl(sockfd, F_SETOWN, getpid());
if (process < 0) error("Can't set address process");
else printf("Process %d is set\n", getpid());
/* do the rest SSL staff here */
}
int main(int argc, char argv[])
{
sigset_t mask, oldmask;
/* Wait for OnTimer event*/
sigemptyset(&oldmask);
sigaddset(&oldmask, SIGALRM);
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
sigaddset(&mask, SIGIO);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
connectSSL();
createTimer(500000000);
while(1)
{
printf("\nWaiting OnTimer %d\n", count + 1);
sigsuspend(&oldmask);
}
return 0;
}
Most probably you forgot to include sys/fcntl.h, either indirectly or directly. This is the place that defines the flags.
In case O_ASYNC is not defined, you can try and use the functionally equivalent predecessor of that flag, FASYNC.
Also make sure you have executed a
int flags;
/* Install signal handler here... */
/* Set flags to receive SIGIO (and SIGURG) signals */
flags = fcntl (F_GETFL, 0);
flags = fcntl (F_SETFL, flags | FASYNC);
/* Bind our process as receiver of SIGIO signals */
flags = fcntl (F_SETOWN, getpid ());
My daemon (linux only) has the following signal handler:
static void signal_handler(int id, siginfo_t *si, void *context) {
if (id == SIGTERM) {
/* prevent suicide - see below */
if (si->si_pid == getpid()) {
printf("Warning: received SIGTERM from own process\n");
return;
}
/* rest of code omitted */
}
/* rest of code omitted */
}
... which is installed like this in main():
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = &signal_handler;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
The reason for the suicide check in the signal handler is that from time to time (once in 4 weeks) my daemon terminated because it received a SIGTERM from itself.
I am unable to find the cause. The only single kill() call used in the program is this one:
int kill_wrapper(pid_t pid, int sig) {
if (pid <= 0 || pid == getpid())
return -1;
return kill(pid, sig);
}
The code has no single raise() or abort() calls.
I wonder which possible (maybe external) reasons might exist that can cause this program to receive SIGTERM from itself under Linux ?
See this discussion. The bottom line is that si_pid is meaningful in very few cases.
I am developing a small application where in I want to call a function every 1 second. This is how I implemented
Timerspec.it_interval.tv_sec=1;
Timerspec.it_interval.tv_nsec=0;
Timerspec.it_value.tv_sec=1;
Timerspec.it_value.tv_nsec=0;
timer_t timerId;
struct sigaction sa;
sa.sa_handler=&TimerFn;
sa.sa_flags=0;
sigemptyset(&sa.sa_mask);
sigaction(SIGALRM,&sa,NULL);
timer_create(CLOCK_REALTIME,NULL,&timerId);
timer_settime(timerId,0,(const itimerspec*)Timerspec,NULL);
But I want to run the TimerFn function in a separate pthread(basically a timer for pthread function). Can somebody please tell how to do this?
If you can accept the creation of a new thread for every timer tick, you can use SIGEV_THREAD:
struct sigevent evp;
memset((void *)&evp, 0, sizeof(evp));
evp.sigev_notify = SIGEV_THREAD;
evp.sigev_notify_function = &sig_alrm_handler;
evp.sigev_signo = SIGALRM;
evp.sigev_value.sigval_ptr = (void *)this;
int ret = timer_create(CLOCK_REALTIME, &evp, &_timerId);
This will create a new thread for every tick.
If you need to handle the signal in a specific thread, a little more work is required:
static void *
sig_threadproc(void *thrarg)
{
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
/* endless loop to wait for and handle a signal repeatedly */
for (;;) {
int sig;
int error;
error = sigwait(&sigset, &sig);
if (error == 0) {
assert(sig == SIGALRM);
printf("got SIGALRM\n");
} else {
perror("sigwait");
}
}
return NULL;
}
static void
sig_alrm_handler(int signo)
{
/**
* dummy signal handler,
* the signal is actually handled in sig_threadproc()
**/
}
int
main(int argc, char *argv[])
{
sigset_t sigset;
struct sigaction sa;
pthread_t sig_thread;
struct itimerspec tspec;
timer_t timer_id;
/* mask SIGALRM in all threads by default */
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
sigprocmask(SIG_BLOCK, &sigset, NULL);
/* we need a signal handler.
* The default is to call abort() and
* setting SIG_IGN might cause the signal
* to not be delivered at all.
**/
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sig_alrm_handler;
sigaction(SIGALRM, &sa, NULL);
/* create SIGALRM looper thread */
pthread_create(&sig_thread, NULL, sig_threadproc, NULL);
/* setup timer */
tspec.it_interval.tv_sec = 1;
tspec.it_interval.tv_nsec = 0;
tspec.it_value.tv_sec = 1;
tspec.it_value.tv_nsec = 0;
timer_create(CLOCK_REALTIME, NULL, &timer_id);
timer_settime(timer_id, 0, &tspec, NULL);
/**
* this might return early if usleep() is interrupted (by a signal)
* It should not happen, since SIGALRM is blocked on the
* main thread
**/
usleep(10000000);
return 0;
}
You might get away with selectively unblocking SIGARLM only in the signal handler thread, causing it the only thread to be eligible to handle that signal, but that may not be portable across systems.
Other versions (including use of pthread_cond_signal()) are already discussed in this answer.
If you just want to call a function every second, here's a simple solution:
#include <pthread.h>
#include <unistd.h>
void TimerFn(void)
{
...
}
void* timer(void* arg)
{
for (;;) {
TimerFn();
sleep(1);
}
return NULL;
}
...
pthread_t timerThread;
pthread_create(&timerThread, NULL, timer, NULL);
Is there some reason this wouldn't suffice?
I'm trying to write a process in C/linux that ignores the SIGINT and SIGQUIT signals and exits for the SIGTERM. For the other signals it should write out the signal and the time. I'm having trouble cathing all the signals because i'm familiar only with catching 1 signal. If anyone could help me with this I'd appreciate it very much. Here is my code:
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
int done = 0;
void term(int signum)
{
if (signum == 15)
{
//printf("%d\n",signum);
printf("Received SIGTERM, exiting ... \n");
done = 1;
}
else
{
time_t mytime = time(0);
printf("%d: %s\n", signum, asctime(localtime(&mytime)));
printf("%d\n",signum);
}
}
int main(int argc, char *argv[])
{
struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_handler = term;
sigaction(SIGTERM, &action, NULL);
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
sigaction(SIGQUIT, &act, NULL);
sigaction(SIGINT, &act, NULL);
int loop = 0;
while(!done)
{
sleep(1);
}
printf("done.\n");
return 0;
}
Here is the easy way
void sig_handler(int signo)
{
if (signo == SIGINT)
printf("received SIGINT\n");
}
int main(void)
{
if (signal(SIGINT, sig_handler) == SIG_ERR)
and so on.
signal() and sighandler() is the least complicated way to do this.
Call signal for each signal that you want to catch. But as some have said earlier you can only catch certain signals. Best to have a way to gracefully shut the program down.