How to print all pending signals using a SYSCALL in UNIX? - c

I've been attempting to create a custom syscall that prints various information about a process. Of that information is the pending signals. I understand that under task_struct is another struct called sigpending, which is defined as follows:
struct sigpending {
struct list_head list;
sigset_t signal; };
So I originally attempted using list_for_each_entry but that requires knowing the name of the member in the struct that stores the pending signals which I can't seem to find.
So how would I go about printing them?

One idea is checking [pending] sigset_t bits and print signals as numbers, or strings, or a mix.
Easily adapted to a kernel version, this example is shown as working user code:
#include <stdio.h>
#include <signal.h>
#include <string.h>
// partial list for printing as strings:
static char *sigstrs[_NSIG] = {
[SIGHUP] = "HUP",
[SIGSEGV] = "SEGV",
};
static void show_pending(char *str, sigset_t *ssetp)
{
int signo;
printf(str);
for (signo = 1; signo < _NSIG; signo++) {
if (sigismember(ssetp, signo) == 0)
continue;
else if (sigstrs[signo])
printf(" SIG%s", sigstrs[signo]);
else
printf(" %d", signo);
}
printf("\n");
}
int main(void)
{
// user simulation, &taskp->pending.signal;
sigset_t pending;
memset(&pending, 0, sizeof (pending));
sigaddset(&pending, SIGHUP);
sigaddset(&pending, SIGSEGV);
show_pending("pending:", &pending);
return (0);
}
Output:
pending: SIGHUP SIGSEGV

Related

Unable to reassign signal handler second time

I have a simple code which uses two signal handlers for "Segmentation fault" signal. First one works when signal happens and after longjmp, I do reassigning of handler with second one for that signal. Unfortunately, the flow of code doesn't reach necessary handler and I still get "Segmentation fault".
#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
int i;
int ci;
jmp_buf m_env_buffer;
jmp_buf max_env_buffer;
void handler(int signum){
printf("sigsegv on i:[%d]", i);
ci = (++i);
longjmp(m_env_buffer,1);
}
void top_handler(int signum){
printf("sigsegv on max i:[%d]", i);
longjmp(max_env_buffer,10);
}
int main(void) {
signal(SIGSEGV, handler);
char * pstart = "loremipsum";
int m_cell = 0;
char m_cell_v;
int point;
point = setjmp(m_env_buffer);
if(point == 0){
for(i=0; ;i--){
m_cell_v = pstart[i];
}
}
//this wasn't invoked
signal(SIGSEGV, top_handler);
point = setjmp(max_env_buffer);
if(point == 0){
for(i=ci; ;i++){
char cur = pstart[i];
if(cur==10)
printf("\n");
printf("%c",cur);
}
}
puts("finish");
return 0;
}
signal() should not be used. It has unreliable semantics. On your system the default action (termination) is performed when the second SIGSEGV is received. The second call to signal() has effectively no effect.
You should use sigaction() instead. In your case you can use the following function instead of signal():
void set_signal (int signum, void (*handler)(int))
{
struct sigaction act;
act.sa_handler = handler;
sigemptyset (&act.sa_mask);
act.sa_flags = SA_NODEFER;
act.sa_restorer = NULL;
sigaction (signum, &act, NULL);
}
In the future, read the documentation at your disposal. A good ressource is the glibc manual. It has a good chapter on signal handling.

C - Processes in linux handle with any signal

I'm writing code that have process who have to handle with any signal i gave him. I read that i should do something like that
void signalHandler(int sig_num)
{
// some stuff
}
//My process
int i;
for (i = 1; i <= 64; i++)
signal(i, signalHandler);
Is this correct solution ??
Although #Dylan's solution seems good and it is but it poses the a common problem and that is compatibility issue with signal function. It is hence recommended that you use sigaction always. Here is an example
#include <stdio.h>
#include <signal.h>
static void handler(int signo){
write(stdout, &signo, sizeof(int));
}
int main() {
struct sigaction sa;
sa.sa_handler = handler;
int i;
for (i = 1; i <= 64; i++) {
sigaction(i, &sa, NULL);
}
while(1);
return 0;
}
Try to avoid the use of signal as much as possible
Never use any function which are not Reentrant or not Async-signal-safe functions in signal handler like printf
Check the list of allowed functions in signal handler from here
POSIX.1-2004 (also known as POSIX.1-2001 Technical Corrigendum 2)
requires an implementation to guarantee that the following functions
can be safely called inside a signal handler:
You are on the right track if you want to handle signals 1 through 64 with the same signal handler. This test program will handle signals 1 through 64 by printing out its number.
#include <stdio.h>
#include <signal.h>
void signalHandler(int sig_num)
{
printf("Signal %d caught!\n", sig_num);
}
int main(int argc, char const *argv[])
{
//My process
int i;
for (i = 1; i <= 64; i++) {
signal(i, signalHandler);
}
while (1);
return 0;
}
For example, when you press CTRL+C while this program is running. The kernel sends signal 2 SIGINT to the program, and calls signalHandler(2). This program prints "Signal 2 caught!"
Post-Facepalm edit: this program obviously needs to be terminated with a kill -9 command........

simple signal code in C, some confusion

So here is some simple signal code in C. I have just a few questions on the concept behind this code. I don't have Linux on my computer, so please consider explaining the concept behind this code to me; I really appreciate this!
What does the array int list[] store? Is it just number of handler?
What does the list[i] = sig after sleep() mean?
What should be the output for this code; I don't have Linux on my computer.
What does the function void Dump() do exactly?
Here is the code
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
int list[10] = {0,0,0,0,0,0,0,0,0,0};
void handler(int sig) {
int i = 0;
while(list[i]!=0) { i++;}
sleep(10);
list[i] = sig;
write(1, "Outta here\n" , 11) ;
}
void dump(int sig) {
int i;
for (i=0; i<10; i++) {
printf("list[%d]=%d\n" , i, list[i]);
}
_exit(0);
}
main( ) {
signal(SIGUSR1, handler);
signal(SIGUSR2, handler) ;
signal(SIGTERM, dump);
printf("Handlers installed\n");
while (1);
}
It's an array storing the last 10 signals handled, the value is the number that corresponds to the signal itself
It's adding the signal number to the array, at the next free index
The output should be a list of handled signals, the numeric value corresponding to one of either SIGUSR1, SIGUSR2, or 0, once the SIGTERM signal is received by the program.
The dump() function outputs all signal values stored in the list

pthread_kill() gives segmentation fault when called from second thread

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?

Signal handler using sigaction and instruction SIGINT. fail with struct variable: no storage size of sa is known

I'm a noob with C programming. I'm just trying to make a program that registers if the user taps three times CRTL+C in three seconds. My problem is that the terminal says always that: no storage size of 'sa' is known. I searched for many examples in the web but it appears always the same problem. Maybe it's a problem withe the include section so I post all my code.
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
int counter=0;
int counter2=0;
//time timestart;
//time timeend;
void signalHandler(int signum);
void ALARMhandler(int sig);
void SIGHUPhandler();
void SIGUSR1handler();
void signalHandler(int signum){
alarm(3);
//printf("the signal caught %d\n", signum);
if (signum == SIGUSR1){
printf("received SIGUSR1\n");
signal(SIGUSR1, SIGUSR1handler);
counter++;
}else if (signum == SIGKILL){
printf("received SIGKILL\n");
counter++;
}else if (signum == SIGSTOP){
printf("received SIGSTOP\n");
counter++;
}else if(counter>=3){
printf("shut program");
}else if (signum == SIGINT){// sorry sigint can't be handled
printf("received SIGint\n");
counter++;
}else if(signum== SIGALRM ){
printf("recived SIGALRM\n");
signal(SIGALRM, ALARMhandler);
counter++;
}else if(signum== SIGHUP){
printf("recived SIGHUP\n");
signal(SIGHUP, SIGHUPhandler);
}
//exit(signum);
}
int main( void )
{
/* Place your handler somewhere around here */
clock_t timeStart, timeEnd;
printf( "Hello World!\n" );
//for ( ;; )
//{
/* infinite loop */
//}
struct sigaction sa;
memset (&sa, 0, sizeof(sa));
sa.sa_handler = signalHandler;
//sigemptyset(&sa.sa_mask);
//sa.sa_flags = SA_RESTART;
counter++;
while(counter2<3){
printf("please press CRTL+C\n");
timeStart=clock();
//sigaction(SIGINT, &sa, NULL);
pause();
timeEnd=clock();
if (timeEnd - timeStart < 3){
counter++;
}else if(timeEnd - timeStart ==3){
printf("shutting down\n");
exit(1);
}//end esle if
counter2++;
}
printf("shutting down\n");
return 0;
}
The problem seems to be in this declaration: struct sigaction sa;
The terminal says: no storage size of 'sa' is known.
I know that the parameters of struct must be declared but I've seen many examples on the net that doesn't have this declaration. What I'm doing wrong?
I'm guessing that you're compiling under C99. If you are, you need to #define the macro _XOPEN_SOURCE for sigaction and friends to be available. If you compile with the option -D_XOPEN_SOURCE it should work.
Your suspicion is probably correct. You need to include the signal header file, which contains the struct declaration:
#include <signal.h>

Resources