Trying to implement an alarm in my shell program. C Signal handling - c

I am building my own shell in C. I want to implement an builtin called alarm that takes in an integer argument for the number of seconds. The builtin just sends the user a message after i seconds (once) but the shell functionality should continue working in the meantime.
Heres what I have so far:
int seconds;
int main(int argc, char const *argv[], char* envp[]){
...
signal(SIGALRM, alarmHandler);
...
}
void alarmHandler(int sig) {
signal(sig, SIG_IGN);
alarm(seconds);
printf("%s\n", "message");
signal(SIGALRM, alarmHandler);
}
void mainProgram(char* string, char* argument){
... //built ins that don't require forking
pid_t processID = fork();
if(processID==0){ //child
if(strcmp(string, "alarm") == 0){
seconds = atoi(argument);
signal(SIGALRM, alarmHandler);
}else{ // parent
usleep(100000)
}
Clearly that doesn't work. I'm kinda lost. I've been trying this for the past couple of hours and I'm unsure of what to do.

Perhaps you've got the wrong idea of what signal does...
The signal system call can be used for setting up handling of signals. Generally speaking, use the kill system call for sending signals.
OTOH, perhaps it's the difference between BSD signal handling semantics and System V signal handling semantics that's contributing to the confusion. System V signal handling semantics can necessitate calling signal (again) within the signal handler function. Newer linux systems at least stick with the BSD signal handling semantics which are reliable and don't require signal to be called again unless you wanted to change the handler that gets invoked.
As a side note, once you get past using signal correctly, I'd recommend using sigaction instead. You can read the 'Portability' section of the signal manual page that I linked to learn more about why you should use sigaction instead of signal.
But onwards...
There are other system calls that can be used to send signals in addition to the kill system call. Like in your case you may want to use alarm or setitimer.
Alternatively, if you wanted to implement something like what alarm does (without using alarm or setitimer), you could use a separate process (via a call to fork perhaps) that calls a sleep function followed by calling kill like this:
usleep(100000);
kill(pid, SIGALRM);
In this example then, pid would be the process ID of the process that you wanted to send the SIGALRM signal to (which is the signal that alarm sends).
Hope this helps answer your question.

Related

Stop/continue a C program

In my C program, I want to get the PID of the process, send a SIGSTOP to that and wait until a SIGCONT arrives from another terminal. So, the procedure looks like
int pid_t = getpid();
printf("PID %d has been stopped\n", pid_t);
STOP(pid_t);
while (not_received_CONT(pid_t))
;
// continue the program
How can I complete that?
What you're writing doesn't make sense. When you stop the process, there is no more instructions being processed in the program and as such there is no while loop to wait for receiving the continuation.
If you check man 7 signal you can see that only one signal currently (in Linux) causes continuation of a process: SIGCONT, hence its not technically necessary to process a while loop check if you didn't get a continuation -- UNLESS you've got a situation where a number of signals are pending and you're trying to determine that.
You can rewrite your code implicitly to be:
int pid = getpid();
printf("PID %d has been stopped\n", pid);
kill(pid, SIGSTOP);
/* Process implicitly continues here, no while needed */
There are multiple vectors in Linux to manage signal handling which may not necessarily be portable.
There is the traditional signal/sigaction method of catching signals and invoking function calls on receipt of the signal. This can come with some unexpected caveats if you aren't careful.
Another way you can manage signals is the use of sigwait, you block the signal with sigprocmask and can consume signals in a safe fashion using sigwait to consume the signal at some controlled point in your process.
Finally you can do similar to sigwait with a signalfd. The main difference between it and sigwait being you can poll the FD to determine its readiness (a signal is received) then read the FD to consume the signals. This makes it a very nice way to manage signals in event driven programs.

Kill -SIGTERM and KILLSIG: Safely terminating applications

On a Linux system, the signal -KILLTERM sends a signal that allows applications to safely shut down. These questions might be a little theoretical, but I want to understand them.
When a system sends a terminate signal, where is it sent?
What allows time for the process or, application, to 'safely' terminate?
Is there a child process, or something similar, that runs in the background of an application that looks for this signal?
These questions stem from the Linux watchdog, in reading the man page I saw that the process of the watchdog is to first send a terminate signal to a given PID, and then a KILL -9 signal to force it. I want to be able to utilize the safety built in to the watchdog.
See this code,
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
void cleanUp(){ // Do whatever you want here
printf("Safely terminating \n");
}
void hand(int sig){ // called when you are sent SIGTERM
/*
Here you can safely terminate..
*/
atexit(cleanUp); // call cleanUp at exit.
exit(0);
}
int main(){
signal(SIGTERM, hand); //Assign function to be called on SIGTERM
/*
Your code goes here.
I have put an infinite loop for demonstration.
*/
printf("Started execution..\n");
for(;;);
}
This shows how a function can be assigned to be called when a signal is delivered to your application.
To deliver the signal SIGTERM to this code, do this,
kill -SIGTERM <pid>
Here, <pid> id the process id of your running program.

Is there a version of the wait() system call that sets a timeout?

Is there any way to use the wait() system call with a timeout, besides using a busy-waiting or busy-sleeping loop?
I've got a parent process that forks itself and execs a child executable. It then waits for the child to finish, grabs its output by whatever means appropriate, and and performs further processing. If the process does not finish within a certain period of time, it assumes that its execution timed out, and does something else. Unfortunately, this timeout detection is necessary given the nature of the problem.
There's not a wait call that takes a timeout.
What you can do instead is install a signal handler that sets a flag for SIGCHLD, and use select() to implement a timeout. select() will be interrupted by a signal.
static volatile int punt;
static void sig_handler(int sig)
{
punt = 1;
}
...
struct timeval timeout = {10,0};
int rc;
signal(SIGCHLD, sig_handler);
fork/exec stuff
//select will get interrupted by a signal
rc = select(0, NULL,NULL,NULL, &timeout );
if (rc == 0) {
// timed out
} else if (punt) {
//child terminated
}
More logic is needed if you have other signal you need to handle as well though
You can use waitpid together with the WNOHANG option and a sleep.
while(waitpid(pid, &status, WNOHANG) == 0) {
sleep(1);
}
But this will be an active sleeping. However I see no other way using the wait type of functions.
On linux, you can also solve this problem using signalfd. signalfd essentially takes a set of signals and creates an fd which you can read; each block you read corresponds to a signal which has fired. (You should block these signals with sigprocmask so that they are not actually sent.)
The advantage of signalfd is that you can use the fd with select, poll, or epoll, all of which allow for timeouts, and all of which allow you to wait for other things as well.
One note: If the same signal fires twice before the corresponding struct signalfd_siginfo is read, you'll only receive a single indication. So when you get a SIGCHLD indication, you need to waitpid(-1, &status, &WNOHANG) repeatedly until it returns -1.
On FreeBSD, you can achieve the same effect rather more directly using kqueue and a kevent of type EVFILT_PROC. (You can also kqueue a SIGCHLD event, but EVFILT_PROC lets you specify the events by child pid instead of globally for all children.) This should also work on Mac OS X, but I've never tried it.

IPC using Signals on linux

It is possible to do IPC (inter process communication) using signal catch and signal raise?
I made two programs. In the first program I did handling of signals, and in the other program I just raised signal which I want to handle in another program. I'ts working fine for me but I want to do communication between these two programs using signals and also want to send some bytes of data with this raise signal. How can I do this?
I want to pass messages with this signal also. Can i do it? It is possible?
And also, what are the disadvantages and advantages of IPC mechanisms using signals?
The following is working code of my two programs. Ising this, I am able to just raise signals and catch signals, but I want to pass data from one program to another.
In the second program, I used the first program's process ID. How can I make it dynamic.?
first program :
/* Example of using sigaction() to setup a signal handler with 3 arguments
* including siginfo_t.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
static void hdl (int sig, siginfo_t *siginfo, void *context)
{
printf("sig no = %d \n", sig);
if(sig == SIGINT)
exit(0);
printf ("Sending PID: %ld, UID: %ld\n",
(long)siginfo->si_pid, (long)siginfo->si_uid);
}
int main (int argc, char *argv[])
{
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_sigaction = &hdl;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGUSR1, &act, NULL) < 0) {
perror ("sigaction SIGUSR1");
return 1;
}
if (sigaction(SIGINT, &act, NULL) < 0) {
perror ("sigaction SIGINT");
return 1;
}
while (1)
{
sleep(1);
}
return 0;
}
second program
#include <stdio.h>
#include <signal.h>
void main(void)
{
while (1)
{
sleep(1);
kill(11558, SIGUSR1);
}
}
Signals are intended to provide a rudimentary form of control over a process, not as an IPC mechanism. Signals have several issues when used as anything else:
A lot of system calls will be interrupted by a signal and need special handling.
Accordingly, a lot of code in the wild is not signal-safe.
Signals do not have any kind of data content, except for themselves. This makes them mostly useless as a message passing method.
There is only so much you can do in a signal handler.
Most importantly, subsequent signals of the same type are not queued - they are merged into one instance.
Even more important, there is no guarantee that signals are delivered in the same order as they were generated. From the manual page:
By contrast, if multiple standard signals are pending for a process, the order in which
they are delivered is unspecified.
You might theoretically be able set up some kind of channel using several signals going back and forth, with some acting like some sort of acknowledgement, but no sane person would want to attempt something like that. You might as well use smoke signals instead...
No, don't try and use signals for this. You cannot attach extra data with signals other than the siginfo struct. The main problem with using signals though is that so little is signal safe. You have to avoid just about all the C runtime routines, and make sure the recieving program does EINTR checks on all its kernel calls. The only thing you can say about when a signal occurs is that it won't be when you expect it (a bit like the Spanish Inquisition).
I suggest you look into the other IPC mechanisms, such as shared memory, message queues, fifos (named pipes), and sockets.
It is possible to do IPC (inter process communication) using signal catch and signal raise?
Yes and no. Considering signals only, you can send a signal to another process, but you can't send anything other than just a signal.
I want to pass messages with this signal also. Can i do it? It is possible?
No, not the way you're trying to. You can use sockets, files, pipes, or named pipes to do this. If you want to learn more about UNIX IPC, read Advanced Programming in the UNIX Environment.
Except in one specific case that I've encountered signals aren't generally useful as IPC mechanism.
The only time I've used signals was as part of an IPC mechanism when you need to interrupt the normal flow of operation of the signalled process to handle something, for example a timer interrupt. The signal ( have used signals together with boost shared memory to implement interprocess event management. The shared memory contains a list of events that need processing and the signal is used to get the process to process these events. These events are out-of-band and unpredictable so using a signal was ideal. I performed considerable testing to verify the implementation (and it was hard to get it all stable).
This used sigqueue together with signal SIGRTMIN+1 in a Linux environment using glibc and using SA_RESTART on the sigaction will avoid the need to directly handle EINTR see glibc: Primitives Interrupted by Signals. BSD has a similar scheme so EINTR handling wasn't required in my system. All of the points made by the other answers were considered and handled (and tested).
However if you just want to pass values back and forwards within the normal operation of the process then another IPC such as sockets, files, pipes or named pipes are better. If you can use ZeroMQ then even better as that does a lot of the hard work for you in a very elegant way.
I'm currently reading man 7 signal:
Real-time signals are distinguished by the following:
If the signal is sent using sigqueue(3), an accompanying value (either an integer or a pointer) can be sent with the signal. ...
Note: Real-time signals start from SIGRTMIN to SIGRTMAX.

How to implement alarm() method correctly to kill all worker processes created by fork()?

If I have a parent coordinator program and a worker program, but the coordinator program is creating all of the needed worker processes. If I want to implement the alarm() method correctly to kill all of the processes and terminate the program after a certain amount of time.
Is this the correct way to implement it? The current way I have it, it does now print out the message corresponding printf() message for the worker processes being killed.
Note: I implemented the ignoring of interrupt signals so more worker processes could proceed without worry.
int main(int argc, char** argv)
{
signal(SIGINT, sig_ctrl);
signal(SIGALRM, sig_alarm);
alarm(5);
sleep(10);
//rest of program which creates the needed processes
}
void sig_ctrl(int sig)
{
printf("Hold on buddy, you're not terminating this program with CTRL^C.\n");
}
void sig_alarm(int sig)
{
sleep(0);
fflush(stdout);
printf("The alarm is sounding, all worker procceses will be...TERMINATED!");
raise(SIGTERM);
}
There's the easy way, which is arguably the sloppy way, and the hard way.
The easy way involves ensuring that the initial process is the process group leader, that it ignores an appropriate signal (but that its children do not ignore the signal), and then sending the signal to the process group.
The harder way requires a list somewhere of all the child processes, and the parent can then duly send a signal to each of the processes, removing the dead ones from its list.
Your program's problem is that sleep() is usually implemented using the SIGALRM timer, so calling it probably overrides your signal() setting for SIGALRM
$ man 3 sleep
BUGS
sleep() may be implemented using SIGALRM; mixing calls to alarm(2) and
sleep() is a bad idea.
(BTW, The sleep(0) is nonsense too. What are you trying to achieve with that?)
I had the same type of problem in some homework for a unix unit. That is pretty much the solution most people came up with :P

Resources