I am trying to manually interrupt the main thread of a program when it is blocked on a read() system call. I do this in a second thread with a call to pthread_kill() however a segmentation fault occurs. However if I place the call to read() in the scond thread, i.e. NOT the main thread and call pthread_kill() from the main thread then all works as expected.
For example, the following code results in a segmentation fault, where I call pthread_kill() in the second thread, approximatelt 2 seconds after it is started. It uses the pthread_t of the main thread obtained by a call (in the main thread) to pthread_self():
Example 1
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <unistd.h>
#include <signal.h>
static int fd = 0;
unsigned char buf[255];
static pthread_t s;
void sigHandler(int sig){
printf("Signal handler called.\n");
}
void * closeFD(void *arg){
printf("Second thread started.\n");
sleep(2);
int r = pthread_kill(s, SIGUSR1);
}
int main(char *argv[], int argc){
struct termios newtio;
pthread_t t1;
unsigned char buf[255];
void *res;
struct sigaction int_handler = {.sa_handler=sigHandler};
sigaction(SIGUSR1,&int_handler,0);
s = pthread_self();
printf("Process id is: %d.\n", getpid());
fd = open("/dev/ttyS0", O_RDONLY | O_NOCTTY);
if (fd != -1){
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = B2400 | CS7 | CLOCAL | CREAD ;
newtio.c_iflag = ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ~ICANON;
newtio.c_cc[VMIN] = 14;
tcsetattr(fd,TCSANOW,&newtio);
pthread_create(&t1, NULL, closeFD, NULL);
printf("Reading ..\n");
read(fd,buf,255);
close(fd);
}
return 0;
}
The following code is the same except I place the call to read() in the second thread (in closeFD()) and works as expected. The second thread unblocks and terminates while the main thread waits for it to exit then exits itself.
Example 2:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <unistd.h>
#include <signal.h>
static int fd = 0;
unsigned char buf[255];
static pthread_t s;
void sigHandler(int sig){
printf("Signal handler called.\n");
}
void * closeFD(void *arg){
printf("Second thread started.\n");
read(fd,buf,255);
printf("Read interrupted.\n");
}
int main(char *argv[], int argc){
struct termios newtio;
pthread_t t1;
unsigned char buf[255];
void *res;
struct sigaction int_handler = {.sa_handler=sigHandler};
sigaction(SIGUSR1,&int_handler,0);
s = pthread_self();
printf("Process id is: %d.\n", getpid());
fd = open("/dev/ttyS0", O_RDONLY | O_NOCTTY);
if (fd != -1){
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = B2400 | CS7 | CLOCAL | CREAD ;
newtio.c_iflag = ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ~ICANON;
newtio.c_cc[VMIN] = 14;
tcsetattr(fd,TCSANOW,&newtio);
pthread_create(&t1, NULL, closeFD, NULL);
sleep(2);
int r = pthread_kill(t1, SIGUSR1);
pthread_join(t1, &res);
close(fd);
}
return 0;
}
So far I have not been able to find a specific reference stating that terminating the main thread from a second (within the same process) is an illegal operation, so is there something I am doing wrong?
UPDATE #1
Thanks for all those that have replied, however I should make a few points clear:
I am aware that using printf in the signal handler is unsafe however this is an example and it's not the cause of the segmentation fault, though it is a valid point. Taking the printf() out of the signal handler still results in a segmentation fault. Example 2 works with printf() either in or out of the signal handler.
I know sending a SIGUSR will not terminate the program. However by using the pthread_kill(pthread_t thread, int signal) it WILL send a signal to the thread thread and it will unblock (if indeed it is blocked). This is the action I desire, this is what actually happens in Example 2 and this is what I understand should happen in either example, but does not in example 1.
When describing example 1, I used the term 'method' when I meant 'thread', where I mention the call to pthread_kill().
Further, quoting from 'Programming with POSIX Threads', David R. Butenhof, section 6.6.3 p217 'pthread_kill':
Within a process, one thread can send a signal to a specific thread
(including itself) by calling pthread_kill.
With that said, the following example ALSO gives a segmentation fault:
Example 3
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <signal.h>
static pthread_t s;
int value = 0;
void sigHandler(int sig){
value = 1;
}
int main(char *argv[], int argc){
struct sigaction int_handler = {.sa_handler=sigHandler};
sigaction(SIGUSR1,&int_handler,0);
s = pthread_self();
printf("The value of 'value' is %d.\n", value);
printf("Process id is: %d.\n", getpid());
int r = pthread_kill(s, SIGUSR1);
printf("The value of 'value' is %d.\n", value);
return 0;
}
This also fails if instead of a call to sigaction() is replaced by the (non-portable) call to signal(). With the third example in mind, which is very simple, I am not able to find any documentation that expressly states it is an illegal action. In fact the quoted reference indicates it's allowable!
You forgot to #include <pthread.h>. That fixes your segfault for me in example #3 on a recent Linux system.
--- pthread_kill-self.c.orig 2015-01-06 14:08:54.949000690 -0600
+++ pthread_kill-self.c 2015-01-06 14:08:59.820998965 -0600
## -1,6 +1,6 ##
#include <stdio.h>
#include <string.h>
-#include <string.h>
+#include <pthread.h>
#include <signal.h>
and then...
$:- gcc -o pthread_kill-self pthread_kill-self.c -pthread
$:- ./pthread_kill-self
The value of 'value' is 0.
Process id is: 3152.
The value of 'value' is 1.
You're using printf(), which is not async-signal safe, and you're not initializing your struct sigaction properly (in particular, the signal mask is left undefined).
Third, sending a SIGUSR1 signal, with a handler installed, does not and should not terminate the main thread. You're just sending it a signal, that's all.
As Jens Gustedt mentioned in his comment to the original question, both of the programs have undefined behaviour. Therefore, I'm not going to try and guess exactly what part of the undefined behaviour causes the segmentation fault (in the first program).
Instead, I'll show you a working example.
For debugging/testing purposes, I like to start with async-signal safe output functions, based on write(2):
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <termios.h>
#include <pthread.h>
#include <errno.h>
#include <time.h>
#define MYSIGNAL SIGUSR1
#define SECONDS 10
static int wrstr(const int descriptor, const char *p, const char *const q)
{
while (p < q) {
ssize_t n;
n = write(descriptor, p, (size_t)(q - p));
if (n > (ssize_t)0)
p += n;
else
if (n != (ssize_t)-1)
return EIO;
else
if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)
return errno;
}
return 0;
}
static const char *ends(const char *s)
{
if (s)
while (*s != '\0')
s++;
return s;
}
static int wrout(const char *const p)
{
if (p != NULL && *p != '\0') {
int saved_errno, result;
saved_errno = errno;
result = wrstr(STDOUT_FILENO, p, ends(p));
errno = saved_errno;
return result;
} else
return 0;
}
static int wrouti(const int value)
{
char buffer[32];
char *p = buffer + sizeof buffer;
unsigned int u;
if (value < 0)
u = -(long)value;
else
u = value;
do {
*(--p) = '0' + (u % 10U);
u /= 10U;
} while (u > 0U);
if (value < 0)
*(--p) = '-';
return wrstr(STDOUT_FILENO, p, buffer + sizeof buffer);
}
static int wrerr(const char *const p)
{
if (p != NULL && *p != '\0') {
int saved_errno, result;
saved_errno = errno;
result = wrstr(STDERR_FILENO, p, ends(p));
errno = saved_errno;
return result;
} else
return 0;
}
The above functions are async-signal safe, and therefore okay to use in a signal handler. wrout() and wrerr() also retain errno unchanged, which is useful. Saving and restoring errno in a signal handler is usually omitted, by the way, although I do believe there are some odd corner cases it might matter. The wrouti() is just a crude decimal signed integer printer, also async-signal-safe, but it does not retain errno unchanged.
Next, let's define the signal handler itself, and an installer function for it. (I like to do it this way, to make the main() simpler.)
static volatile sig_atomic_t handled = 0;
static void handler(int signum)
{
wrerr("Signal received.\n");
handled = signum;
}
static int install_handler(const int signum)
{
struct sigaction act;
/* memset(&act, 0, sizeof act); */
sigemptyset(&act.sa_mask);
act.sa_handler = handler;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL))
return errno;
return 0;
}
The commented-out memset is recommended, but not required for proper operation. The sigemptyset(), however, is required, to clear the set of blocked signals.
Next, let's look at the thread function. You shouldn't use sleep(), as that interacts with signals; use POSIX.1-2001 nanosleep() instead.
static void *worker(void *target)
{
struct timespec duration, left;
int retval;
wrout("Worker started. Sleeping ");
wrouti((int)SECONDS);
wrout(" seconds...\n");
duration.tv_sec = SECONDS;
duration.tv_nsec = 0;
left.tv_sec = 0;
left.tv_nsec = 0;
while (1) {
retval = nanosleep(&duration, &left);
if (retval == 0)
break;
if (left.tv_sec <= 0 ||
(left.tv_sec == 0 && left.tv_nsec <= 0))
break;
duration = left;
left.tv_sec = 0;
left.tv_nsec = 0;
}
wrout("Sleep complete.\n");
if (target) {
wrout("Sending signal...\n");
retval = pthread_kill(*(pthread_t *)target, MYSIGNAL);
if (retval == 0)
wrout("Signal sent successfully.\n");
else {
const char *const errmsg = strerror(retval);
wrout("Failed to send signal: ");
wrout(errmsg);
wrout(".\n");
}
}
wrout("Thread done.\n");
return NULL;
}
The pointer given to the thread function should point to the thread identifier (pthread_t) the signal is directed to.
Note that above, nanosleep() can be interrupted by a signal delivery, if the signal is delivered to or caught by this particular thread. If that occurs, nanosleep() tells us how much time was left to sleep. The loop above shows how to make sure you sleep at least the specified time, even if interrupted by signal delivery.
Finally, the main(). Instead of opening a specific device, I use standard input. To reproduce OP's program, redirect standard input from /dev/ttyUSB0, i.e. ./program < /dev/ttyUSB0, when executing it.
int main(void)
{
pthread_t main_thread, worker_thread;
pthread_attr_t attrs;
struct termios original, settings;
int result;
if (!isatty(STDIN_FILENO)) {
wrerr("Standard input is not a terminal.\n");
return EXIT_FAILURE;
}
if (tcgetattr(STDIN_FILENO, &original) != 0 ||
tcgetattr(STDIN_FILENO, &settings) != 0) {
const char *const errmsg = strerror(errno);
wrerr("Cannot get terminal settings: ");
wrerr(errmsg);
wrerr(".\n");
return EXIT_FAILURE;
}
settings.c_lflag = ~ICANON;
settings.c_cc[VMIN] = 14;
if (tcsetattr(STDIN_FILENO, TCSANOW, &settings) != 0) {
const char *const errmsg = strerror(errno);
tcsetattr(STDIN_FILENO, TCSAFLUSH, &original);
wrerr("Cannot set terminal settings: ");
wrerr(errmsg);
wrerr(".\n");
return EXIT_FAILURE;
}
wrout("Terminal is now in raw mode.\n");
if (install_handler(MYSIGNAL)) {
const char *const errmsg = strerror(errno);
wrerr("Cannot install signal handler: ");
wrerr(errmsg);
wrerr(".\n");
return EXIT_FAILURE;
}
main_thread = pthread_self();
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, 65536);
result = pthread_create(&worker_thread, &attrs, worker, &main_thread);
if (result != 0) {
const char *const errmsg = strerror(errno);
tcsetattr(STDIN_FILENO, TCSAFLUSH, &original);
wrerr("Cannot create a worker thread: ");
wrerr(errmsg);
wrerr(".\n");
return EXIT_FAILURE;
}
pthread_attr_destroy(&attrs);
wrout("Waiting for input...\n");
while (1) {
char buffer[256];
ssize_t n;
if (handled) {
wrout("Because signal was received, no more input is read.\n");
break;
}
n = read(STDIN_FILENO, buffer, sizeof buffer);
if (n > (ssize_t)0) {
wrout("Read ");
wrouti((int)n);
wrout(" bytes.\n");
continue;
} else
if (n == (ssize_t)0) {
wrout("End of input.\n");
break;
} else
if (n != (ssize_t)-1) {
wrout("read() returned an invalid value.\n");
break;
} else {
result = errno;
wrout("read() == -1, errno == ");
wrouti(result);
wrout(": ");
wrout(strerror(result));
wrout(".\n");
break;
}
}
wrout("Reaping the worker thread..\n");
result = pthread_join(worker_thread, NULL);
if (result != 0) {
wrout("Failed to reap worker thread: ");
wrout(strerror(result));
wrout(".\n");
} else
wrout("Worker thread reaped successfully.\n");
tcsetattr(STDIN_FILENO, TCSAFLUSH, &original);
wrout("Terminal reverted back to original mode.\n");
return EXIT_SUCCESS;
}
Because it's much more fun to test using the terminal, the above tries hard to restore the terminal to its original state before returning.
Note that since the VMIN field in the termios structure is set to 14, the read() blocks until at least 14 bytes are available in the buffer. If a signal is delivered, a short count is returned if there is at least one byte in the buffer. Therefore, you cannot expect the read() to always return 14 bytes, and you cannot expect it to return -1 with errno == EINTR whenever a signal is delivered! Experimenting with this program is very useful, to clarify these in your mind.
I don't remember whether the USB serial drivers in Linux ever produce EPIPE or raise SIGPIPE, but that can definitely occur when using pipes. When using pipes, the most common reason is trying to read after read has already returned zero (end of input). Unless ignored or caught with a signal handler, the process dies much like in a segmentation fault, except that the cause is SIGPIPE signal instead of SIGSEGV. With terminal-like character devices, it depends on the driver, I seem to recall.
Finally, I wrote the above code under the weather (flu), so there might be bugs in tharrr. It should be POSIX.1 C99 code, and gcc -Wall -pedantic does not complain, but having a stuffed head, I'm not making any promises here. Fixes are more than welcome!
Questions? Comments?
Related
I'm a newbie in c development. Recently, I noticed a problem when I was learning multi-threaded development, when I set a signal in the main thread of Action and when I try to block the signal action set by the main thread in the child thread, I find that it does not work.
Here is a brief description of the code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
void *thread_start(void *_arg) {
sleep(2);
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR2);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
printf("child-thread executed\n");
while (true) {
sleep(1);
}
return NULL;
}
void sig_handler(int _sig) {
printf("executed\n");
}
int main(int argc, char *argv[]) {
pthread_t t_id;
int s = pthread_create(&t_id, NULL, thread_start, NULL);
if (s != 0) {
char *msg = strerror(s);
printf("%s\n", msg);
}
printf("main-thread executed, create [%lu]\n", t_id);
signal(SIGUSR2, sig_handler);
while (true) {
sleep(1);
}
return EXIT_SUCCESS;
}
The signal mask is a per-thread property, a thread will inherit whatever the parent has at time of thread creation but, after that, it controls its own copy.
In other words, blocking a signal in a thread only affects the delivery of signals for that thread, not for any other.
In any case, even if it were shared (it's not), you would have a potential race condition since you start the child thread before setting up the signal in the main thread. Hence it would be indeterminate as to whether the order was "parent sets up signal, then child blocks" or vice versa. But, as stated, that's irrelevant due to the thread-specific nature of the signal mask.
If you want a thread to control the signal mask of another thread, you will need to use some form of inter-thread communication to let the other thread do it itself.
As I wrote in a comment, any USR1 signal sent to the process will be delivered using the main thread. It's output will not tell you exactly what happened, so it is not really a good way to test threads and signal masks. Additionally, it uses printf() in a signal handler, which may or may not work: printf() is not an async-signal safe function, so it must not be used in a signal handler.
Here is a better example:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
/* This function writes a message directly to standard error,
without using the stderr stream. This is async-signal safe.
Returns 0 if success, errno error code if an error occurs.
errno is kept unchanged. */
static int write_stderr(const char *msg)
{
const char *end = msg;
const int saved_errno = errno;
int retval = 0;
ssize_t n;
/* If msg is non-NULL, find the string-terminating '\0'. */
if (msg)
while (*end)
end++;
/* Write the message to standard error. */
while (msg < end) {
n = write(STDERR_FILENO, msg, (size_t)(end - msg));
if (n > 0) {
msg += n;
} else
if (n != 0) {
/* Bug, should not occur */
retval = EIO;
break;
} else
if (errno != EINTR) {
retval = errno;
break;
}
}
/* Paranoid check that exactly the message was written */
if (!retval)
if (msg != end)
retval = EIO;
errno = saved_errno;
return retval;
}
static volatile sig_atomic_t done = 0;
pthread_t main_thread;
pthread_t other_thread;
static void signal_handler(int signum)
{
const pthread_t id = pthread_self();
const char *thread = (id == main_thread) ? "Main thread" :
(id == other_thread) ? "Other thread" : "Unknown thread";
const char *event = (signum == SIGHUP) ? "HUP" :
(signum == SIGUSR1) ? "USR1" :
(signum == SIGINT) ? "INT" :
(signum == SIGTERM) ? "TERM" : "Unknown signal";
if (signum == SIGTERM || signum == SIGINT)
done = 1;
write_stderr(thread);
write_stderr(": ");
write_stderr(event);
write_stderr(".\n");
}
static int install_handler(int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = signal_handler;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return -1;
return 0;
}
void *other(void *unused __attribute__((unused)))
{
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGHUP);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
while (!done)
sleep(1);
return NULL;
}
int main(void)
{
pthread_attr_t attrs;
sigset_t mask;
int result;
main_thread = pthread_self();
other_thread = pthread_self(); /* Just to initialize it to a sane value */
/* Install HUP, USR1, INT, and TERM signal handlers. */
if (install_handler(SIGHUP) ||
install_handler(SIGUSR1) ||
install_handler(SIGINT) ||
install_handler(SIGTERM)) {
fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
/* Create the other thread. */
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, 2*PTHREAD_STACK_MIN);
result = pthread_create(&other_thread, &attrs, other, NULL);
pthread_attr_destroy(&attrs);
if (result) {
fprintf(stderr, "Cannot create a thread: %s.\n", strerror(result));
return EXIT_FAILURE;
}
/* This thread blocks SIGUSR1. */
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
/* Ready to handle signals. */
printf("Send a HUP, USR1, or TERM signal to process %d.\n", (int)getpid());
fflush(stdout);
while (!done)
sleep(1);
pthread_join(other_thread, NULL);
return EXIT_SUCCESS;
}
Save it as e.g. example.c, and compile and run using
gcc -Wall -O2 example.c -pthread -o exprog
./exprog
It will block the USR1 signal in the main thread, and HUP and TERM in the other thread. It will also catch the INT signal (Ctrl+C), which is not blocked in either thread. When you send it the INT or TERM signal, the program will exit.
If you send the program the USR1 signal, you'll see that it will always be delivered using the other thread.
If you send the program a HUP signal, you'll see that it will always be delivered using the main thread.
If you send the program a TERM signal, it too will be delivered using the main thread, but it will also cause the program to exit (nicely).
If you send the program an INT signal, it will be delivered using one of the threads. It depends on several factors whether you'll always see it being delivered using the same thread or not, but at least in theory, it can be delivered using either thread. This signal too will cause the program to exit (nicely).
I wrote a program deamon which copy files with one folder to another .I have to implement SIGUSR1 which immediately wake up the daemon by sending him a SIGUSR1 signal. I do not know what I did wrong ,I use command kill -SIGUSR1 ,maybe wrong command?.Somebody know what is wrong with this code ?I did not have any warning after compiled this program,but just nothing happend
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
#define _XOPEN_SOURCE ;
int recursion = 0; //1 if enabled, otherwise 0
int sleepTime = 300;
int fileLimit = 0;
int signaL = 0;
int exitSignal = 0;
int buffer = 1000;
//Returns 0 if arguments are correct otherwise returns 1
int readArguments(int number, char **argv, char *source, char *goal);
int checkFileType(struct stat file);
int copy(char *source, char *target, mode_t mask);
int copy_map(char *source, char *target, struct stat *Source);
void syncCopy(char *source, char *target);
void syncRemove(char *source, char *target);
void my_handler(int sig)
{
syslog(LOG_INFO, "Daemon received signal SIGUSR1\n");
signaL = 1;
}
void exitFunction(int sig)
{
syslog(LOG_INFO, "Daemon received signal SIGUSR2\n");
exitSignal = 1;
}
int main(int argc, char **argv)
{
//char tables for paths
char source[500], goal[500];
struct stat Source, Goal;
struct sigaction my_action, old_action;
//checking and reading arguments
if (readArguments(argc, argv, source, goal) == 1)
exit(-1);
//checking paths
//checking if argv[1] and argv[2] are existing paths
if (lstat(source, &Source) != 0 || lstat(goal, &Goal) != 0) //bad result
{
printf("One of the paths or both dont exist\n");
exit(-1);
}
if (checkFileType(Source) != 0)
{
printf("Source path is not path to folder");
exit(-1);
}
if (checkFileType(Goal) != 0)
{
printf("Goal path is not path to folder");
exit(-1);
}
//forking the parent process
pid_t pid;
// Fork off the parent process and create new
pid = fork();
//if failure
if (pid < 0)
{
exit(-1);
}
// if it is native process
else if (pid > 0)
{
return 0;
}
//if pid==0 then it is childs process
//now we have to umask in order to write to any files(for exmaple logs)
umask(0);
openlog("logFile", LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "Deamon has just started running\n");
pid_t sid = setsid();
if (sid < 0)
{
syslog(LOG_ERR, "Error with session opening\n");
exit(-1);
}
//SIGNAL SIGUSR1
my_action.sa_handler = my_handler;
sigfillset(&my_action.sa_mask);
my_action.sa_flags = 0;
if (sigaction(SIGUSR1, &my_action, &old_action) < 0)
{
syslog(LOG_ERR, "Error with the use of SIGUSR1 signal\n");
exit(-1);
}
//SIGNAL SIGUSR2 for exiting daemon
my_action.sa_handler = exitFunction;
sigfillset(&my_action.sa_mask);
my_action.sa_flags = 0;
if (sigaction(SIGUSR2, &my_action, &old_action) < 0)
{
syslog(LOG_ERR, "Error with the use of SIGUSR2 signal\n");
exit(-1);
}
while (!exitSignal)
{
sleep(sleepTime);
switch (signaL)
{
case 0:
syslog(LOG_INFO, "Demon started working after %ds\n", sleepTime);
break;
case 1:
{
syslog(LOG_INFO, "Demon started working after SIGUSR1 signal\n");
signaL = 0; //Need to reeset signaL
break;
}
}
syncCopy(source, goal);
syncRemove(source, goal);
syslog(LOG_INFO, "Demon has just gone to sleep");
}
//at the end of program we need to close log using
syslog(LOG_INFO, "Demon has stopped\n");
closelog();
return 0;
}
Use command as kill -10 <pid> for SIGUSR1 and kill -12 <pid> for SIGUSR2.
kill -l // command to know the signal number.
Also make variable signaL , exitSignal as volatile sig_atomic_t type.
WHY volatile?
when a global variable updated in signal handler is periodically checked in some other function for appropriate action, we should always declare them using the volatile attribute in order to prevent the compiler from performing optimizations that result in the variable being stored in a register. In worst case, updated value of variable(updated in handler context) won't be visible to function polling for the variable.
WHY sig_atomic_t?
Reading and writing global variables may involve more than one machine- language instruction, and a signal handler may interrupt the main program in the middle of such an instruction sequence. (We say that access to the variable is nonatomic.) For this reason, the C language standards and SUSv3 specify an integer data type, sig_atomic_t, for which reads and writes are guaranteed to be atomic. Thus, a global flag variable that is shared between the main program and a signal handler should be declared as follows:
volatile sig_atomic_t signaL;
I implemented in C a shared memory to let forked child comunicate eachother, here's a Minimal, Complete, and Verificable example:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define SHMEMORY
#define NUM_SEMS 2
#define LOCK \
sops.sem_num = 1; \
sops.sem_op = -1; \
semop(sem_Id, &sops, 1);
#define UNLOCK \
sops.sem_num = 1; \
sops.sem_op = 1; \
semop(sem_Id, &sops, 1);
#define TEST_ERROR if (errno) {dprintf(STDERR_FILENO, \
"%s:%d: PID=%5d: Error %d (%s)\n", \
__FILE__, \
__LINE__, \
getpid(), \
errno, \
strerror(errno));}
#define POP_SIZE 100 //number of child
#define TRUE 1
struct shared_data {
/* index where next write will happen */
unsigned long cur_idx;
int invite_sent[POP_SIZE][POP_SIZE];
};
static void init();
static int invite_sent_check(int stud);
int maxMin_rand(int max,int min);
void handle_signal(int sig);
int sim_time = 10;
unsigned long next_num;
struct sembuf sops;
pid_t *kid_pids;
int mem_Id, sem_Id;
int main() {
int i = 0;
int j = 0;
int status, cur_i;
struct shared_data* corso;
pid_t child_pid, my_pid;
int stud = 0;
int exit_loop = 0;
/*********************************************************/
struct sigaction sa;
sigset_t my_mask;
/* handler SIGALRM
*/
sa.sa_handler = handle_signal;
sa.sa_flags = 0;
sigemptyset(&my_mask);
sa.sa_mask = my_mask;
sigaction(SIGALRM, &sa, NULL);
/**********************************************************/
mem_Id = shmget(IPC_PRIVATE, sizeof(*corso), 0600);
TEST_ERROR;
/* Attach the shared memory to a pointer */
corso = shmat(mem_Id, NULL, 0);
TEST_ERROR;
corso->cur_idx = 0; /* init first counter */
/*********************************************************/
sem_Id = semget(IPC_PRIVATE, NUM_SEMS, 0600);
TEST_ERROR;
/* Sem 0 to syncronize the start of child processes */
semctl(sem_Id, 0, SETVAL, 0);
#ifdef SHMEMORY
semctl(sem_Id, 1, SETVAL, 1);
#endif
TEST_ERROR;
sops.sem_num = 0; /* check the 0-th semaphore */
sops.sem_flg = 0; /* no flag */
init();
kid_pids = malloc(POP_SIZE*sizeof(*kid_pids));
for (i = 0; i < POP_SIZE; i++) {
switch (kid_pids[i] = fork()) {
case -1:
/* Handle error */
TEST_ERROR;
break;
case 0:
/* Wait for the green light */
sops.sem_op = -1;
semop(sem_Id, &sops, 1);
while(exit_loop==0 || exit_loop==1){
LOCK;
if(exit_loop == 0){
stud = corso->cur_idx;
printf("%d %d\n",stud,getpid());
corso->cur_idx++;
exit_loop = 1;
}
if(invite_sent_check(stud) == 1){
}
UNLOCK;
}
exit(0);
break;
default:
break;
}
}
alarm(sim_time);
while (shmctl(mem_Id, IPC_RMID, NULL)) { TEST_ERROR; }
sops.sem_op = POP_SIZE;
semop(sem_Id, &sops, 1);
/* Waiting for all child POP_SIZEesses to terminate */
while ((child_pid = wait(&status)) != -1) {
dprintf(2,"PID=%d. Sender (PID=%d) terminated with status 0x%04X\n",
getpid(),
child_pid,
status);
}
/* Now the semaphore may be deallocated */
semctl(sem_Id, 0, IPC_RMID);
exit(0);
}
static void init(){
printf("INIT\n");
struct shared_data * corso;
corso = shmat(mem_Id, NULL, 0);
corso->cur_idx=0;
int r, q, j;
j = 0;
q = 0;
while(j < POP_SIZE){
q = 0;
while(q < POP_SIZE){
corso->invite_sent[j][q] = -1;
q++;
}
j++;
}
}
int maxMin_rand(int max, int min){
int reset;
int randomics=12345;
int w=0;
while(w<reset) {
randomics++;
w++;
}
next_num = next_num+randomics;
next_num = next_num*1103515245 +12345;
unsigned int result=(unsigned int) ((next_num*65536)%(max+1))+min;
int reload;
w=0;
while(w<reload) {
next_num++;
w++;
}
return result;
}
static int invite_sent_check(int stud){
struct shared_data * corso;
corso = shmat(mem_Id, NULL, 0);
int i = 0;
int q = 0;
while(i < POP_SIZE){
if(i == stud){
q = 0;
while(q < POP_SIZE){
if(corso->invite_sent[i][q] != -1){
return 1;
}
q++;
}
}
i++;
}
return 0;
}
void handle_signal(int signal){
int child_pid;
int status;
struct shared_data * corso;
corso = shmat(mem_Id, NULL, 0);
switch (signal) {
case SIGALRM:
for(int i = 0; i < POP_SIZE; i++){
kill(kid_pids[i], SIGKILL);
}
while (shmctl(mem_Id, IPC_RMID, NULL)) {
TEST_ERROR;
}
while ((child_pid = wait(&status)) != -1) {
dprintf(2,"PID=%d. Sender (PID=%d) terminated with status 0x%04X\n",
getpid(),
child_pid,
status);
}
semctl(sem_Id, 0, IPC_RMID);
exit(0);
break;
}
}
The forked children keep LOCK and UNLOCK as long as the timer goes (sim_time = 10). Then the SIGNAL_HANDLER kills all the children, and terminate.
I keep getting a SIGSEGV error from a RANDOM child that terminate with status 008B and stops his "brothers" until the handler kills all the other processes. As long as I know, this error concern pointer in the shared memory, is that right? Or I'm missing/I wrote something really wrong? Even this little method that checks if in the INVITE_SENT matrix, at least 1 value is different from -1 cause a crash, instead of just returning 0.
Thank you for your time.
I have been unable to reproduce the segfault locally, and Valgrind does not detect any invalid memory accesses. There are other possible causes for a segfault, but they are uncommon. Not being able to reproduce the issue locally, I cannot be confident about identifying its source, but there are a number of issues in the code, mostly minor.
The only issue that seems to have scope to be related to your problem is your redundant attachment of the shared memory segment in function invite_sent_check(), especially in view of the fact that you use the return value of shmat() without checking it ((void*)-1 is returned on failure). Redundant attachments such as that are explicitly allowed, but it would be cleaner and more efficient for the caller to just pass its existing pointer to the original attachment point of the segment. Moreover, if you form a local attachment in that function, then you must be certain to detach again before the function returns. Failing to do so could plausibly be the source of the problem, as the metadata and address-space reservations for the resulting many, many attachments could exhaust available resources.
Other issues include
dprintf() is not async-signal-safe, but is called from a signal handler (both explicitly and via macro TEST_ERROR).
shmat() is not async-signal-safe, but it is called from a signal handler. Moreover, this seems unnecessary, because the new segment attachment is not used in the handler. Furthermore, it is not detached, either.
semctl() is not async-signal-safe, but it is called from a signal handler.
exit() is not async-signal-safe, but it is called from a signal handler. You may use _Exit() or _exit() instead, but it seems off that this handler should exit the program at all, since the main process seems to have other work that it wants to do to clean up.
Considering all the things you seem to want to do when you receive the SIGALRM, many of them not async-signal-safe, you should consider using sigsupend() to receive the signal synchronously, and afterward calling a regular function to do that work. If you go that direction, then the safest, most reliable approach would involve first blocking SIGALRM before stting your alarm, then passing a signal mask to sigsuspend() that allows that signal. That will prevent any chance of the signal being delivered before the process is ready for it.
Function init() redundantly attaches the shared memory segment. This is allowed, but it would be better form for the caller to just pass a pointer to the struct shared_data that is to be initialized. This function, too, fails to detach.
If you want to check for errors by examining errno, you must be certain to set it to 0 before the call you want to check (and test it immediately after, before doing anything else). However, it is better practice to use functions' return values to detect whether an error has occurred, and to rely on errno only to discern which one.
The name and signature of function maxMin_rand() suggest it is intended to return a number between max and min, but it looks like it can return a number as large as max + min.
I want to delete the FIFO file when I suddenly click "ctrl+c" . I want to catch that signal and then delete the after before actually killing the process .
here is my code and I don't know what went wrong :
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#define MAX_BUF 512
void sigintHandler(int sig_num,char * myfifo)
{
puts("hello you there .please don't leave ");
unlink(myfifo);
exit(0);
}
int main()
{
printf("Access-Control-Allow-Origin: *\n");
printf("Content-Type: text/event-stream\n\n");
int fd;
char buf[MAX_BUF];
char * myfifo = "/tmp/omcipipe";
struct stat st;
//catch ctrl c
sigaction(SIGINT, sigintHandler);
//Create FIFO file
if (stat(myfifo, &st) != 0)
mkfifo(myfifo, 0666);
fd = open(myfifo, O_RDONLY);
while (read(fd, buf, MAX_BUF)>0)
{
printf("data: %s", buf);
printf("\n");
fflush(stdout);
}
puts( "----closing----");
close(fd);
unlink(myfifo);
return 0;
}
Firstly your way of setting a signal handler using sigaction() is not correct as you didn't fill all the member of struct sigaction. Fill all required member
struct sigaction info;
info.sa_handler = sigintHandler;
sigaction(SIGINT,&info,NULL);
Secondly, to read data from fifo file while loop is not required as you are reading MAX_BUF at a time. Loop is not required, read like this
int ret = read(fd, buf, MAX_BUF);
buf[ret-1] = '\0'; /*it should be null terminated */
Thirdly, sigintHandler() excepts only one argument. From the manual page of sigaction()
struct sigaction {
void (*sa_handler)(int); /*handler expects only 1 argument */
/* other member */
}
Finally & most importantly it is not safe to call functions like printf() & exit() from within a signal handler.
your sigHandler() looks like
static void sigintHandler(int sig_num) {
write(1,"in isr\n",strlen("in isr\n"));
/* set some flag variable here & use that
flag variable in main() function to remove the fifo */
}
see this How to avoid using printf in a signal handler?
Here is the example code
static int fifo_flag = 0;
static void sigintHandler(int sig_num) {
write(1,"in isr\n",strlen("in isr\n"));
fifo_flag = 1;
}
int main(void){
printf("Access-Control-Allow-Origin: *\n");
printf("Content-Type: text/event-stream\n\n");
int fd = 0, index = 0;
char buf[MAX_BUF];
#if 0
char *myfifo = "data";
#endif
//char * myfifo = "/tmp/omcipipe";
struct stat st;
struct sigaction info;
info.sa_handler = sigintHandler;
//info.sa_flags = /* set to defaulgs a/c to your requirement*/
if (stat(myfifo, &st) != 0) {
mkfifo(myfifo, 0666);
perror("mkfifo");
}
fd = open(myfifo, O_RDONLY | 0666);
if(fd == -1){
perror("open");
return 0;
}
char ch = 0;
while(read(fd, &ch, 1) > 0) {
sigaction(SIGINT,&info,NULL);/* if ctrl+c is called */
buf[index] = ch;
//sleep(1);/* just to observe ctrl+c behaviour, not advised to use */
printf("%c\n",buf[index]);
index++;
}
buf[index] = '\0';
printf("data: %s", buf);
printf("\n");
puts( "----closing----");
close(fd);
if(fifo_flag == 1) { /*if flag is set, unlink fifo */
unlink(myfifo); /* you can unlink fifo file here */
}
return 0;
}
There are numerous problems with your code.
This code assumes read() terminates data with a '\0' character:
while (read(fd, buf, MAX_BUF)>0)
{
printf("data: %s", buf);
printf("\n");
fflush(stdout);
}
read() merely reads raw bytes and nothing more. It will not properly terminate strings with a '\0' character. So the printf() will almost certainly invoke undefined behavior.
This code
sigaction(SIGINT, sigintHandler);
is just wrong. sigaction() takes three parameters:
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
You also can only make async-signal-safe function calls from within a signal handler. This code
void sigintHandler(int sig_num,char * myfifo)
{
puts("hello you there .please don't leave ");
unlink(myfifo);
exit(0);
}
calls puts() and exit(), neither of which are async-signal-safe.
And as noted in the comments, the signal handler code assumes that myfifo is passed as the second parameter. It isn't. Per the sigaction man page the second parameter is a struct siginfo * that contains information regarding the signal context - but only if the struct sigaction passed to the sigaction() call that registered the signal handler had the SA_SIGINFO flag set, and the handler set using the sa_sigaction member instead of the sa_handler member.
I'm attempting communications between a user-level program and a kernel module. My user-level program starts a timer then goes to sleep and is woken up by the kernel module when the time is completed, then a message is printed.
The problem I'm having is if I Ctrl+C while the user-level program is sleeping, when the timer expires it still prints the message (which I don't want it to do). This is my first time using <signal.h> and I'm having trouble figuring out how to implement this. I found a website which said that SIGHUP is the signal that is sent when Ctrl+C is pressed, so I think I should implement some case for this signal in my sighandler() function, but I'm pretty lost at the moment on how to go about this. Here's what I've pieced together so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
void sighandler(int);
int main(int argc, char **argv) {
char line[256];
int lenNum, lenName;
struct sigaction action, oa;
int pFile, oflags;
pFile = open("/dev/mytimer", O_RDWR);
if (pFile < 0) {
fprintf (stderr, "mytimer module isn't loaded\n");
return 1;
}
// Setup signal handler
memset(&action, 0, sizeof(action));
action.sa_handler = sighandler;
action.sa_flags = SA_SIGINFO;
sigemptyset(&action.sa_mask);
sigaction(SIGIO, &action, NULL);
fcntl(pFile, F_SETOWN, getpid()); // process ID o owner saved to filp->f_owner
oflags = fcntl(pFile, F_GETFL);
fcntl(pFile, F_SETFL, oflags | FASYNC); // enable asynchronous notification
// Check if timer set
if (argc >= 4 && strcmp(argv[1], "-s") == 0) {
lenNum = strlen(argv[2]);
lenName = strlen(argv[3]);
char *ptr;
int i;
i = asprintf(&ptr, "%s %s %s", argv[1], argv[2], argv[3]);
write(pFile, ptr, i+1);
while (read(pFile, line, strlen(line)) != 0) { //257?
printf("%s", line);
}
free(ptr);
//printf("Sleep!\n");
pause();
printf("%s\n", argv[3]);
}
// List all active timers
else if (argc == 2 && strcmp(argv[1], "-l") == 0) {
char *ptr;
int i;
i = asprintf(&ptr, "%s 0", argv[1]);
write(pFile, ptr, i);
while (read(pFile, line, strlen(line)) != 0) {
printf("%s", line);
}
free(ptr);
}
close(pFile);
return 0;
}
// SIGIO handler
void sighandler(int signo) {
//printf("Awaken!\n");
/* maybe something like this?
if (signo == SIGHUP) {
// clear timer
} */
}
Any suggestions are greatly appreciated.