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
Related
I have this code:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int cpt = 0;
void handler (int sig) {
cpt++ ;
}
int main() {
int i;
signal(SIGCHLD, handler);
for (i = 0; i < 5; i++) {
if (fork() == 0) {
exit(0);
}
}
while (wait(NULL) != -1) ;
printf("cpt = %d\n", cpt);
return 0;
}
this program to my understanding should always print cpt = 5
but when i run it on my machine it returns different values (3,4,5) why is that?
The SIGCHLD signal is a little funny and doesn't work like you'd expect: we think we should get one signal per child death, but that's not it.
Instead, it's a kind of level-triggered thing where at some unknown intervals it sends the signal if there are any un-waited-for children.
In the loop you provided that burns through the wait(), this loop is consuming multiple children before the signal handler gets around to it, hence less trips through the handler.
Others have pointed out that you should be using a volatile sig_atomic_t variable, and though this is a good idea, it's not why you're seeing this behavior.
I believe the only way to get a guaranteed one-signal-per-child is to actually wait for the child in the signal handler - this makes it appear more like an edge-triggered signal.
Of course, you're pretty limited to what you can do in the signal handler, so if your application already has a good regimen for waiting for child processes, you likely don't need a SIGCHLD handler.
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
static volatile sig_atomic_t cpt = 0;
static void handler(int sig) {
cpt++;
wait(NULL); // ADD ME
}
int main() {
int i;
signal(SIGCHLD, handler);
for (i = 0; i < 5; i++) {
if (fork() == 0) {
exit(0);
}
}
while (wait(NULL) != -1) ;
printf("cpt=%d\n", cpt);
return 0;
}
As an alternative, if the while() loop were not so tight and had other processing (or even an explicit delay), there would not be a race condition and you'd see all five SIGCHLD delivered.
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
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........
I have this code:
#include <stdio.h>
#include <signal.h>
void signal_handler(int signal) {
printf("Caught signal in CHILD.\n");
}
int main(void) {
int s;
signal(SIGTSTP, signal_handler);
while(1){
printf("%s#%s/# ",getlogin(),get_current_dir_name());
scanf("%d",&s);
}
return 0;
}
when i run the code it prints:
something: ^ZCaught signal in CHILD.
As far i understand that the scanf doesn't execute when i press the ctr-z. Although after the printf inside my function it goes straight to the scanf, waits for input and then starts the loop again.Is there any way to avoid scanf when i press ctr-z and start the while loop again? I tried something like that
void signal_handler(int signal) {
printf("Caught signal in CHILD.\n");
printf("%s#%s/# ",getlogin(),get_current_dir_name());
}
but it didn't work. After the second printf goes straight to the scanf, waits for input and then starts the loop again. Can i, somehow, start the loop again?
The signal handler is interrupting scanf during its read of STDIN. However, because of the way you set signal disposition, the read system call restarts immediately upon return of the signal handler. That's why you are "stuck" in the scanf rather than back at the top of your loop.
One important thing you can do is to use sigaction rather than signal. This will force you to specify the behavior of interrupted calls: restart them or not?
The next thing to do is to limit your signal handlers to functions that are async-signal-safe, lest you risk misery.
As an aside, another change to make is to give us all the required includes (<unistd.h>?) and defines (_GNU_SOURCE ?) to make your program work.
As commented the worst solution should be:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
void signal_handler(int signal) {
printf("Caught signal in CHILD.\n");
exit(1);
}
int main(void) {
int s;
signal(SIGTSTP, signal_handler);
while(1){
printf("test\n");
scanf("%d",&s);
}
return 0;
}
Better solution
#include <stdio.h>
#include <signal.h>
static volatile int keepRunning = 1;
void signal_handler(int signal) {
printf("Caught signal in CHILD.\n");
keepRunning = 0;
}
int main(void) {
int s;
signal(SIGTSTP, signal_handler);
while(keepRunning){
printf("test\n");
scanf("%d",&s);
}
return 0;
}
EDIT after comments
#include <stdio.h>
#include <signal.h>
static volatile int skipPrintf= 1;
void signal_handler(int signal) {
printf("Caught signal in CHILD.\n");
skipPrintf= 1;
}
int main(void) {
int s;
signal(SIGTSTP, signal_handler);
while(1){
if (skipPrintf == 0)
{
printf("test\n");
}
else
{
skipPrintf = 0;
}
scanf("%d",&s);
}
return 0;
}
Testing some POSIX codes, I have noticed that the utilisation of signals is not very accurate. Here is a sample code of the client:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#define MESSAGE "hello\n"
#define PAUSE 15000
int main(int argc, char **argv)
{
int pid = atoi(argv[1]);
size_t i;
int j;
for (i = 0; i < sizeof MESSAGE; ++i) {
for (j = 0; j < MESSAGE[i]; ++j) {
kill(pid, SIGUSR1);
usleep(PAUSE);
}
kill(pid, SIGUSR2);
usleep(PAUSE);
}
return 0;
}
Here is the code of the server:
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
static unsigned char index;
static void inc(int sig)
{
++index;
(void) sig;
}
static void prt(int sig)
{
printf("%c", index);
fflush(stdout);
index = 0;
(void) sig;
}
int main(void)
{
printf("%ld\n", (long int)getpid());
signal(SIGUSR1, inc);
signal(SIGUSR2, prt);
for (;;)
;
return 0;
}
The characters received by the server depends on what PAUSE value has the client. Does it come from signals' limits, or did I commit an error? If so, where could I find these environmental considerations (I use Linux 2.6.35)?
NB: To execute the code of the client, you have to write the server's PID in command-line arguments.
Not only is this sort of inter-process communication incredibly inefficient; it's also invalid. Signals are not queued; they're either pending or non-pending (*). So unless the recipient process reads off the signal before the sender sends another one, signals will be lost.
If you really want to do something hideous like this, the recipient needs to acknowledge each signal it receives by signalling back to the sender, and the sender needs to wait to send the next signal until the previous one was acknowledged.
(*) Actually, real-time signals are queued, but the depth of the queue has a limit, and ensuring that it doesn't overrun would require painful and fragile realtime-priority-management logic.