Timer disarms when interval is too small - c

Timers seem to disarm after process is resumed (SIGCONT) ONLY when interval is too small.
I use timer_create with CLOCK_REALTIME.
My linux distribution is ubuntu 20.04.1
This is the code that shows the problem
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>
#include <memory.h>
volatile siginfo_t sigInfo;
void childFunction();
void parentFunction(pid_t pid);
void ignoreChild();
void signalFunction(int signo, siginfo_t* SI, void* data);
int main(int argc, char* argv[])
{
ignoreChild();
pid_t pid;
pid = fork();
switch(pid)
{
case -1:
{
perror("Error in fork!\n");
exit(EXIT_FAILURE);
}
case 0:
{
childFunction();
exit(EXIT_SUCCESS);
}
default:
{
parentFunction(pid);
break;
}
}
return 0;
}
void signalFunction(int signo, siginfo_t* SI, void* data)
{
sigInfo = *SI;
}
void parentFunction(pid_t pid)
{
struct sigaction sa;
struct timespec sleepTime = { .tv_sec = 1, .tv_nsec = 0};
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = signalFunction;
if (sigaction(SIGCHLD, &sa, NULL) == -1)
{
perror("Error in sigaction!\n");
exit(EXIT_FAILURE);
}
//---- for blocking
sigset_t set = {0};
if (sigaddset(&set, SIGCHLD) == -1)
{
perror("Error in sigaddset!\n");
exit(EXIT_FAILURE);
}
while (1)
{
if (pause() == -1)
{
if (errno == EINTR)
{
if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
{
perror("Error in sigprocmask!\n");
exit(EXIT_FAILURE);
}
if (sigInfo.si_status == SIGSTOP)
{
printf("Child received SIG_STOP signal\n");
nanosleep(&sleepTime, NULL);
kill(pid, SIGCONT);
}
if (sigInfo.si_status == SIGCONT)
{
printf("Child received SIGCONT signal!\n");
}
if (sigInfo.si_code == CLD_EXITED)
{
printf("Child is dead!\n");
break;
}
if (sigprocmask(SIG_UNBLOCK, &set, NULL) == -1)
{
perror("Error in sigprocmask2!\n");
exit(EXIT_FAILURE);
}
}
}
}
}
void ignoreChild()
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NOCLDWAIT;
if (sigaction(SIGCHLD, &sa, NULL) == -1)
{
perror("Error in sigaction!\n");
exit(EXIT_FAILURE);
}
}
void childFunction()
{
struct sigevent sev;
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGSTOP;
struct timespec timeForTimer = { .tv_sec = 1, .tv_nsec = 0}; // set time for timer here!
struct itimerspec ts = { .it_interval = timeForTimer, .it_value = timeForTimer };
timer_t timer;
if (timer_create(CLOCK_REALTIME, &sev,&timer) == -1)
{
perror("Error in timer_create!\n");
exit(EXIT_FAILURE);
}
if (timer_settime(timer, 0, &ts, NULL) == -1)
{
perror("Error in timer_settime!\n");
exit(EXIT_FAILURE);
}
struct timespec timeToWaitInLoop = { .tv_sec = 0, .tv_nsec = 300000000};
for (int i=0; i<1000; ++i)
{
printf("I'm working!\n");
nanosleep(&timeToWaitInLoop,NULL);
}
}
When I set timeForTimer to 3 seconds the program works correctly, for 2 seconds it still works but for 1 second it doesn't.
To compile:
gcc -Wall main.c -lrt
This is shorter example
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
struct sigevent sev;
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGSTOP;
struct timespec timeForTimer = { .tv_sec = 1, .tv_nsec = 0}; // set time for timer here!
struct itimerspec ts = { .it_interval = timeForTimer, .it_value = timeForTimer };
timer_t timer;
if (timer_create(CLOCK_REALTIME, &sev,&timer) == -1)
{
perror("Error in timer_create!\n");
exit(EXIT_FAILURE);
}
if( timer_settime(timer, 0, &ts, NULL) == -1)
{
perror("Error in timer_settime!\n");
exit(EXIT_FAILURE);
}
struct timespec timeToWaitInLoop = { .tv_sec = 0, .tv_nsec = 300000000};
for (int i=0; i<1000; ++i)
{
printf("I'm working! (PID) %d\n", getpid());
nanosleep(&timeToWaitInLoop,NULL);
}
}
In above example only one SIGSTOP signal occured. After sending SIGCONT with command kill -18 <pid> there was no more SIGSTOP signals.It looks like my timer disarmed.

Related

why child can't send signal to parent

parent:
volatile int signalval = 0;
void signal_handle_c(int sig_num)
{
printf("child SIGUSR1 ok\n");
signalval = 1;
};
int main(int argc,char**argv){
struct sigaction act, oldact;
act.sa_handler = signal_handle_c;
act.sa_flags = SA_NOMASK;//SA_ONESHOT |
pid_t pid=fork();
if (pid < 0)
printf("error in fork!");
else if (pid == 0) {
printf("exec child!%s\n",argv[1]);
int res = execl(argv[1], "testc", NULL);
printf("res=%d", res);
}
else {
sleep(3);
sigaction(SIGUSR1, &act, &oldact);
printf("now parent\n");
}
waitpid(pid,NULL,0);
return 0;
}
child:
volatile int signal_pipe_end = 0;
void signal_handle_c(int sig_num)
{
printf("child IGUSR1 ok\n");
signal_pipe_end = 1;
};
int main(int argc, char *argv[])
{
printf("now child run!");
while (1)
{
printf("now child send siganl\n");
kill(getpid(), SIGUSR1);
sleep(1);
}
}
parent try to receive the SIGUSR1 signal from child.but none!
run result:
exec child!./testc
now child run!now child
now parent
i hope can printf "child SIGUSR1 ok".
why child "kill" send signal fail.

Why doensn't Ctrl+C doesn't work in my terminal?

I've the following problem:
I'm creating two threads in main. These threads never stop (they're always listening for messages).
So, in main, after creating this two threads, I've this snippet code to keep the program running:
for (;;)
{
sleep(10);
}
return 0;
It works, but the problem is that when I execute the program, in the terminal, Ctrl+C doesn't allow me to exit from the program. I've to exit with Ctrl+\. I've this function (not made by me). Where is the problem?
void app_signal_handler(int sig_num)
{
if (sig_num == SIGINT) {
printf("SIGINT signal!\n");
}
if (sig_num == SIGTERM) {
printf("SIGTERM signal!\n");
}
app_running = false;
}
char app_sigaltstack[SIGSTKSZ];
int app_setup_signals(void)
{
stack_t sigstack;
struct sigaction sa;
int ret = -1;
sigstack.ss_sp = app_sigaltstack;
sigstack.ss_size = SIGSTKSZ;
sigstack.ss_flags = 0;
if (sigaltstack(&sigstack, NULL) == -1) {
perror("signalstack()");
goto END;
}
sa.sa_handler = app_signal_handler;
sa.sa_flags = SA_ONSTACK;
if (sigaction(SIGINT, &sa, 0) != 0) {
perror("sigaction()");
goto END;
}
if (sigaction(SIGTERM, &sa, 0) != 0) {
perror("sigaction()");
goto END;
}
ret = 0;
END:
return ret;
}
You never use app_running. Replace
for (;;)
{
sleep(10);
}
with
while (app_running)
{
sleep(10);
}

Implement siginterrupt() using sigaction()?

Implement siginterrupt() using sigaction() with one example.
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void helpAndLeave(const char *progname, int status);
void pexit(const char *fCall);
int interrupt(int, int);
void handler(int);
int main(int argc, char *argv[]) {
if (argc != 1) {
helpAndLeave(argv[0], EXIT_FAILURE);
}
/* struct sigaction act;
act.sa_handler = &handler;
*/
interrupt(2,1);
// while(1);
exit(EXIT_SUCCESS);
}
void helpAndLeave(const char *progname, int status) {
FILE *stream = stderr;
if (status == EXIT_SUCCESS) {
stream = stdout;
}
fprintf(stream, "Usage: %s", progname);
exit(status);
}
void pexit(const char *fCall) {
perror(fCall);
exit(EXIT_FAILURE);
}
int interrupt(int signal, int flag) {
printf("interrupt block\n");
struct sigaction act;
act.sa_handler = &handler;
if (sigaction(SIGINT, NULL, &act) == -1) {
return -1;
}
if (flag) {
act.sa_flags &= ~SA_RESTART;
} else {
act.sa_flags &= SA_RESTART;
}
if (sigaction(SIGINT, &act, NULL) == -1) {
printf("sigaction error\n");
return -1;
}
printf("exit occur\n");
while(1);
}
void handler(int signal) {
printf("OMG, INTERRUPTION!!!!!\n");
}
here it is not going to handler function when i enter (ctrl+c).
so please give some solution to this.
you can find this example on the this link.
When you call sigaction(SIGINT, NULL, &act) it overwrites act with the current handler for the signal. So your assignment to act.sa_handler is overwritten. You need to do that assignment after the call, not before it.
And the way to turn a bit on in a bit mask is with |, not &, so
act.sa_flags &= SA_RESTART;
should be:
act.sa_flags |= SA_RESTART;
So the whole function should be:
int interrupt(int signal, int flag) {
printf("interrupt block\n");
struct sigaction act;
if (sigaction(SIGINT, NULL, &act) == -1) {
return -1;
}
act.sa_handler = &handler;
if (flag) {
act.sa_flags &= ~SA_RESTART;
} else {
act.sa_flags |= SA_RESTART;
}
if (sigaction(SIGINT, &act, NULL) == -1) {
printf("sigaction error\n");
return -1;
}
printf("exit occur\n");
while(1);
}

Process communication with semaphore in C

I'm writing two files:
a father.c with a parent process, and a son.c with a child process. They should use semaphore for synchronization. When I launch the father (compiled), the father process waits forever after the child process message:
Child ftok done.
father.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
typedef union _semun {
int val;
struct semid_ds *buf;
ushort *array;
} semun;
int initsem(key_t key){
int status = 0, semid;
semid = semget(key, 1, 0600 | IPC_CREAT | IPC_EXCL);
if(semid == -1){
if(errno == EEXIST){
semid = semget(key, 1, 0);
}
else{
semun arg;
arg.val = 1;
status = semctl(semid, 0, SETVAL, arg);
}
if(semid == -1 || status == -1){
perror("initsem failed\n");
return -1;
}
return (semid);
}
}
int waitSem(int semid) {
struct sembuf wait_buf;
wait_buf.sem_num = 0;
wait_buf.sem_op = -1;
if(semop(semid, &wait_buf, 1) == -1) {
perror("waitSem failed");
exit(1);
}
return(0);
}
int signalSem(int semid) {
struct sembuf signal_buf;
signal_buf.sem_num = 0;
signal_buf.sem_op = 1;
if(semop(semid, &signal_buf, 1) == -1) {
perror("signalSem failed");
exit(1);
}
return(0);
}
int main(){
pid_t pid;
key_t key;
int semid;
if(key = ftok("/home/user/Scrivania/test.txt", 'a') == -1){
perror("IPC error: ftok\n");
exit(1);
}
else{
printf("Ftok done\n");
}
semid = initsem(key);
pid = fork();
if(pid < 0){
printf("failed fork()\n");
}
else if(pid == 0){
printf("Child process with PID: %d\n", pid);
execl("/home/user/Desktop/son", "son", "",(char *)0);
}
else{
printf("Father process with PID: %d\n", pid);
printf("Waiting for my son\n");
waitSem(semid);
printf("My son has done\n");
signalSem(semid);
}
return 0;
}
son.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
typedef union _semun {
int val;
struct semid_ds *buf;
ushort *array;
} semun;
int initsem(key_t key){
int status = 0, semid;
semid = semget(key, 1, 0600 | IPC_EXCL);
if(semid == -1){
if(errno == EEXIST){
semid = semget(key, 1, 0);
}
else{
semun arg;
arg.val = 1;
status = semctl(semid, 0, SETVAL, arg);
}
if(semid == -1 || status == -1){
perror("initsem failed\n");
return -1;
}
return (semid);
}
}
int waitSem(int semid) {
struct sembuf wait_buf;
wait_buf.sem_num = 0;
wait_buf.sem_op = -1;
if(semop(semid, &wait_buf, 1) == -1) {
perror("waitSem failed");
exit(1);
}
return(0);
}
int signalSem(int semid) {
struct sembuf signal_buf;
signal_buf.sem_num = 0;
signal_buf.sem_op = 1;
if(semop(semid, &signal_buf, 1) == -1) {
perror("signalSem failed");
exit(1);
}
return(0);
}
int main(){
pid_t pid;
key_t key;
int semid;
if(key = ftok("/home/user/Desktop/test.txt", 'a') == -1){
perror("IPC error: ftok\n");
exit(1);
}
else{
printf("Ftok done\n");
}
semid = initsem(key);
waitSem(semid);
printf("Pre signal\n");
signalSem(semid);
printf("My operation\n");
return 0;
}

popen2: reading works, writing doesn't

The following function executes a process, returns its PID and provides file descriptors for reading and writing:
pid_t popen2(const char **command, int *infp, int *outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) {
return -1;
}
pid = fork();
if (pid < 0) {
return pid;
} else if (pid == 0) {
close(p_stdin[WRITE]);
dup2(p_stdin[READ], READ);
close(p_stdout[READ]);
dup2(p_stdout[WRITE], WRITE);
execvp(*command, command);
}
if (infp == NULL) {
close(p_stdin[WRITE]);
} else {
*infp = p_stdin[WRITE];
}
if (outfp == NULL) {
close(p_stdout[READ]);
} else {
*outfp = p_stdout[READ];
}
return pid;
}
I call the above function with
pid = popen2(..., &in, &out);
and read from the file descriptor out with
nBytes = read(out, line, sizeof(line));
and what I read makes perfect sense. It is the output normally displayed on the console. However, when I try to write a command to the program which it would normally receive via the console with
nBytes = write(in, cmd, strlen(cmd)+1);
nothing happens. The program shows no reaction whatsoever.
What am I missing here?
I did change it a bit, but it works now. Remove the fprintf(stderr,... after verification:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#define READ_END 0
#define WRITE_END 1
pid_t popen2(const char **command, int fdarray[]);
pid_t popen2(const char **command, int fdarray[])
{
int p_stdin[2], p_stdout[2];
pid_t pid;
int rc;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) {
return -1;
}
pid = fork();
if (pid < 0) {
return pid;
} else if (pid == 0) {
close(p_stdin[WRITE_END]);
dup2(p_stdin[READ_END], STDIN_FILENO);
close(p_stdin[READ_END]);
close(p_stdout[READ_END]);
dup2(p_stdout[WRITE_END], STDOUT_FILENO);
close(p_stdout[WRITE_END]);
rc = execvp(*command, command);
_exit(EXIT_FAILURE);
}
close(p_stdout[WRITE_END]);
close(p_stdin[READ_END]);
if (fdarray == NULL) {
close(p_stdin[WRITE_END]);
close(p_stdout[READ_END]);
} else {
fdarray[READ_END] = p_stdout[READ_END];
fdarray[WRITE_END] = p_stdin[WRITE_END];
}
return pid;
}
#define BUFF_SIZE 1024
struct buff {
size_t used;
size_t size;
char data[BUFF_SIZE];
}
ibuf = {0,BUFF_SIZE,}
, obuf = {0,BUFF_SIZE,}
;
int readbuff(int fd, struct buff *bp);
int writebuff(int fd, struct buff *bp);
int readbuff(int fd, struct buff *bp)
{
size_t done;
int rc=0;
for (done=0; bp->used < bp->size; bp->used+=rc, done+=rc) {
if (done) break;
fprintf(stderr, "Read(%d,%zu)\n", fd, bp->size - bp->used );
rc = read(fd, bp->data+bp->used, bp->size - bp->used);
if (rc== -1) switch (errno) {
#if (EWOULDBLOCK != EAGAIN)
case EWOULDBLOCK:
#endif
case EAGAIN:
case EINTR: rc=0; continue;
default:
fprintf(stderr, "Error on readbuff: %d: %s\n", errno, strerror(errno));
goto failed;
}
fprintf(stderr, "Readbuff(%d) := %d\n", fd, rc);
if (rc==0) { rc = -1; break; }
}
failed:
return done ? done : rc;
}
int writebuff(int fd, struct buff *bp)
{
size_t done;
int rc= 0;
for (done=0; done < bp->used ; done+=rc) {
if (done) break;
fprintf(stderr, "Write(%d,%zu)\n", fd, bp->used - done);
rc = write(fd, bp->data+done, bp->used - done);
if (rc== -1) switch (errno) {
#if (EWOULDBLOCK != EAGAIN)
case EWOULDBLOCK:
#endif
case EINTR:
case EAGAIN:rc=0; continue;
default:
fprintf(stderr, "Error on writebuff: %d: %s\n", errno, strerror(errno));
goto failed;
}
fprintf(stderr, "Writebuff(%d) := %d\n", fd, rc);
if (rc==0) { rc = -1; break; }
}
failed:
if (done == bp->used ) bp->used =0;
else { memmove(bp->data, bp->data+done, bp->used - done); bp->used -= done; }
return done ? done : rc;
}
int main (void)
{
int pipes[2] = {-1,-1};
int rc1, rc2,err;
char *commands[] = { "tee", "teapot", NULL};
// signal(SIGCHLD, SIG_IGN);
// signal(SIGPIPE, SIG_IGN);
rc1 = popen2( commands, pipes);
err = errno;
fprintf(stderr, "Rc=%d:%d(%s) pipes[0]=%d, pipes[1]=%d\n"
, rc1 , rc1 == -1 ? err : 0
, strerror(rc1 == -1?err:0)
, pipes[0]
, pipes[1]
);
if (rc1 == -1) return EXIT_FAILURE;
while(1) {
fprintf(stderr, "#----------------------------------------\n" );
rc1 = readbuff(STDIN_FILENO, &ibuf);
#if 1
if (rc1 == -1 && ibuf.used ==0) {
fprintf(stderr, "Rc1=%d Close %d\n", rc1, pipes[WRITE_END]);
close(pipes[WRITE_END]);
}
else
#endif
writebuff(pipes[WRITE_END] , &ibuf);
rc2 = readbuff(pipes[READ_END] , &obuf);
writebuff(STDOUT_FILENO, &obuf);
fprintf(stderr, "Rc=%d/%d Ibuf[0]=%zu/%zu, Obuf[0]=%zu/%zu\n"
, rc1, rc2
, ibuf.used, ibuf.size
, obuf.used, obuf.size
);
if (rc1 < 0 && rc2 < 0) break;
}
wait(NULL);
return 0;
}

Resources