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.
Related
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 have a multi-process program that receives a file as input from the command line. Creates shared memory, and forks for a producer/consumer styled problem. It switches every other byte making abcdef badcef. However, I had not realized this must also allow for non-ASCII input, and I do not know how to do this. I believe wchar_t allows for non-ASCII input. But what about my functions such as fgets/strcpy that do not work with wchar_t data type? I cannot find supported function replacements.
Please don't do the entire problem for me, this is an assignment for my class but general advice is greatly appreciated.
I've tried using wchar_t in place of char. I tried to use fgetsws in place of fgets but even when include the compiler doesn't recognize fgetsws as a library function. I'm running this on ubuntu linux 64 bit machine.
pa2.h================================================
#ifndef pa2_h
#define pa2_h
int shflag;
sigset_t new, old, nomask;
struct shbuff
{
char data[1024];
int size;
};
void flagfunc();
void block();
void sortstring(char input[]);
void waitchild();
void waitparent();
void parentsig(pid_t pid);
void childsig(pid_t pid);
#endif
pa2.c==========================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <pthread.h>
#include "pa2.h"
int main(int argc, char* argv[])
{
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pid_t pid;
int mem;
FILE* fpinput;
FILE* fpout;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
char buff[1024]; // Do I conver this to wchar_t data type?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
key_t shkey;
void *ptr =0;
struct shbuff* shmem;
if(argc < 2)
{
printf("Input a file name including .txt!");
exit(1);
}
block(); //block sigusr1
pid=fork(); // child gets pid 0, parent is positive int
if(pid != 0) // parent process
{
fpinput= fopen(argv[1], "r"); // read from file
mem= shmget(shkey, sizeof(struct shbuff), IPC_CREAT | 0666); //size rounded up to nearest page size / 0666 required for server read/write
ptr= shmat(mem, (void *)0, 0); // Attach the shared memory
shmem= (struct shbuff *) ptr;
shmem->size= 0;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
while (fgets(buff,1023,fpinput) != NULL) //read in from file to buffer leaving room for terminating character
// Do I use fgetsws to replace this fgets?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
pthread_mutex_lock(&mutex1);
sortstring(buff); //switch bytes in the buffer
pthread_mutex_unlock(&mutex1);
while (shmem->size != 0)
{
waitchild(); // wait for child to read from buff
}
pthread_mutex_lock(&mutex1);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
strcpy(shmem->data, buff); //replacement for strcpy?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pthread_mutex_unlock(&mutex1);
pthread_mutex_lock(&mutex1);
shmem->size= strlen(shmem->data); //set size to strlen of data
pthread_mutex_unlock(&mutex1);
childsig(pid); // signal to parent
}
while (shmem->size != 0)
{
waitchild(); // wait for child to read from buff
}
shmem->size= -1; //end of file
childsig(pid); //send signal
fclose(fpinput); //close file
shmdt(shmem); // detach from shared memory
printf("Transferred.\n\n");
} //end of else if (pid != 0)
else //if pid is 0 then process the child
{
fpout= fopen("output.txt", "w");
mem= shmget(shkey, sizeof(struct shbuff), IPC_CREAT | 0666); //size rounded up to nearest page size / 0666 required for server read/write
ptr= shmat(mem, (void *)0, 0); // attach to shared memory
shmem= (struct shbuff*) ptr; //convert the sharedMemory into struct
while (shmem->size != -1) // while not EOF
{
while (shmem->size == 0)
{
waitparent(); //wait for the child to read from shared memory
}
if (shmem->size != -1) //if not EOF
{
fputs(shmem->data,fpout); //copy the contents into the outFile
shmem->size = 0; //re-zero size after emptying data buffer
parentsig(getppid()); //parent signal
}
}
fclose(fpout); // closes output file
shmdt(shmem); // detach shared memory
kill(getpid(),SIGTERM); // Kills this process politely with sigterm rather than sigkill, We are civilized
}
exit(0);
}
void flagfunc()
{
shflag = 1;
}
void sortstring(char input[]){
char temp;
int i= 0;
for(i=0; i<strlen(input); i+=2){
temp= input[i];
input[i]= input[i+1];
input[i+1]= temp;
}
}
void block()
{
signal(SIGUSR1,flagfunc);
sigemptyset(&nomask); //empty mask
sigemptyset(&new);
sigaddset(&new, SIGUSR1); //add sigusr1 signal to mask
sigprocmask(SIG_BLOCK,&new,&old); //block new/old signals
}
void waitchild()
{
while (shflag==0)
{
sigsuspend(&nomask); //wait on child signal
}
shflag=0; //reset flag
sigprocmask(SIG_SETMASK,&old,NULL);
}
void waitparent()
{
while (shflag==0)
{
sigsuspend(&nomask); //wait for parent
}
shflag=0; //reset flag
sigprocmask(SIG_SETMASK,&old,NULL);
}
void childsig(pid_t pid)
{
kill(pid,SIGUSR1); //sends parent signal
}
void parentsig(pid_t pid)
{
kill(pid,SIGUSR1); //sends child signal
}
I got a Synthasizer yesterday as a gift, and was interested in writing data to it. I got this much working, here is a program that scales through some notes.
Then I thought it would be neat to have it catch the Ctrl+C singal, and close.
The problem with just closing the file descriptor is that the MIDI device still processes the last note it was given, so I wrote the mute function, which tells the midi device to mute. That works.
so then I tried to have the signal handler mute the device before exiting, and I have been struggling ever since. The signal(SIGINT, intHandler); function wont take additional arguments. So I thought I would be clever, and write a function mySig that calls the signal function and takes the device file descriptor, and data pointer, and would be able to do one last write, before exiting.
IDK, that might even work, but mySig function, seems to be called from the start, and scaling never happens.
How can I call my mute function, before exiting the program with the signal function?
This is my first signal handing program, Im running linux, and the program is in C.
#include <sys/soundcard.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
static volatile int keepRunning = 1;
char* device = "/dev/midi1";
//function headers:
void mute(int fd, char *data);
void intHandler(int dummy);
void mySig(void (*intHandler)(int dummy), int fd, char *data);
int main(void){
unsigned int note=50;
char data[3] = {0x90, note, 33}; //device address, note, volume
int fd = open(device, O_WRONLY, 0);
if( fd < 0 ){
printf("Error: cannot open Synth %s\n", device);
exit(1);
}
signal(SIGINT, intHandler);
// mySig(intHandler,fd,data);
while(keepRunning){
for( note=30; note < 95; note++ ){
data[1]=note;//change note
write( fd, data, sizeof(data) );
usleep(100000);
if(note>=89){
note =30;
}
}
mute(fd,data); //mutes the data stream.
close(fd); // close device
return 0;
}
}
//functions:
void mute(int fd, char *data){
data[2]=0;//setVolume to 0
write(fd, data, sizeof(data));
close(fd);
}
void mySig(void (*intHandler)(int dummy), int fd, char *data){
printf("my Sig has been called\n");
mute(fd,data);
signal(SIGINT, intHandler);
}
void intHandler(int dummy) {
printf("my Sig has been called\n");
keepRunning = 1;
printf("ctrl+c was pressed, exiting\n");
usleep(10000);
exit(1);
}
Use the signal handler to only clear your keepRunning flag.
Personally, I prefer the opposite flag, as in done:
static volatile sig_atomic_t done = 0;
static void done_handler(int signum)
{
done = 1; /* Or, in Linux, done = signum. */
}
static int install_done(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = done_handler;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
If the user runs the program in a terminal, and they close the terminal unexpectedly, the program will receive a SIGHUP signal; Ctrl+C causes a SIGINT signal; and SIGTERM is often used to ask a program to exit. So, I personally like to do
if (install_done(SIGINT) ||
install_done(SIGHUP) ||
install_done(SIGTERM)) {
fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
early in my main().
All you need to do, is to have your loop -- in my case,
while (!done) {
/* Play notes or whatever */
}
and after the loop, mute the last note played, then close the device.
Consider the signal just a request to exit, as soon as is convenient; not a demand to exit immediately. It is expected that programs do necessary cleanup when they receive a signal asking them to exit. If one wants a program to exit right then, one can always kill the process with SIGKILL.
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.
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?