1

I am trying to communicate between 2 processes ( parent and child process in linux ) using signals in C programming language.

The first process does some calculation and provides a data. Then, it sends a signal to the second, which is in a suspended state, waiting for a signal to wake up and collect that data shared by the first process using a shared memory.

How to make the second process wait for a certain time or let's say a period of time ?

Within that period, if the first process provides data and sends a signal to the second, everything is OK. Otherwise, if it doesn't receive any signal from the first within that period, it will do another thing.

How can I make the second process respond to that need ?

Which algorithms and signals should I use to implement this ?

user3666197
  • 1
  • 6
  • 50
  • 92
Gismail
  • 89
  • 10
  • without any information on the target Plattform, this question can not be satisfyingly answered – Markus Spöri Feb 25 '20 at 18:01
  • It may be simpler to use threads and a semaphore. – Jim Rogers Feb 25 '20 at 18:02
  • For processes, i have already implented them , i still have problem with time , how to make a child process wait for signal within certain period of time knowing that it is in suspended state . – Gismail Feb 25 '20 at 18:06
  • 1
    [`sigtimedwait()`](http://man7.org/linux/man-pages/man2/sigwaitinfo.2.html) is one possible approach. – Shawn Feb 25 '20 at 18:06
  • 3
    Use `select` to do this. – stark Feb 25 '20 at 18:07
  • @Shawn , Yes may be it is a solution , i will try to follow that lead and see what i can do. Thanks – Gismail Feb 25 '20 at 18:09
  • @stark, I don't really understand what you are referring to ? could you please be more specific ? – Gismail Feb 25 '20 at 18:17
  • 1
    Select with no file descriptor waits for either a timeout or a signal https://stackoverflow.com/a/52310127/1216776 – stark Feb 25 '20 at 18:17
  • 2
    Why are you using signals for this? That is unnecessarily complicated. `select` has a timeout option. Easiest would be to send the data over a pipe rather than with shared memory. If you do want to use shared memory, just send a single byte over the pipe instead of sending a signal. If you really want to use a signal, use something like `signalfd`. In either case, still use `select` for the timeout. – William Pursell Feb 25 '20 at 18:22
  • @stark, I tried to use select but i dont know how to initialize it . What should i put as parameters in order to wait for signal lest's say SIGUSER1 for 10 seconds . what are the parameters should I enter to initialize it ? – Gismail Feb 25 '20 at 19:08
  • See answer below for an example. – stark Feb 25 '20 at 19:17

2 Answers2

3

POSIX defines a function for exactly your purpose: sigtimedwait(). It will suspend execution of the calling process until either one of the signals in a specified set becomes pending, or a specified timeout expires. Its return value indicates which of those occurred.

Within that period, if the first process provides data and sends a signal to the second, everything is OK. Otherwise, if it doesn't receive any signal from the first within that period, it will do another thing.

How can I make the second process respond to that need ?

The second process sets up the arguments for sigtimedwait. It then blocks the expected signal (via sigprocmask), so that the default disposition does not occur when that signal is received, and afterward calls sigtimedwait. The return value of the latter indicates whether one of the specified signals was received (and if so, which), or whether the function returned for some other reason -- typically, because the timeout expired. In the latter case, the errno variable can be examined to determine whether indeed it was a timeout. The manual page linked above provides some additional usage notes.

Specifically, you need two main arguments:

  • a sigset_t defining the signals to block and to wait upon. The "See also" section at the end of the manual page refers you to the documentation for related and similar functions, including sigsetops(3), which tells you about how to manipulate such objects. For example,

    #include <signal.h>
    
    // ...
    
    sigset_t sigs;
    sigemptyset(&sigs);
    sigaddset(&sigs, SIGUSER2);
    
  • a struct timespec, whose definition is provided inline in the manual page. That definition should be sufficient for you to come up with something like

    struct timespec timeout = { .tv_sec = 10 };
    

Per the docs, you may specify the second argument of sigtimedwait as NULL if you do not need the information that otherwise could be conveyed back to you by that means, which you don't.

You can use the signal set already prepared as described above for setting up signal blocking, for example:

sigprocmask(SIG_BLOCK, &sigs, NULL);

This may seem a bit counterintuitive, since you do want to receive the signal, but the effect is to block whatever disposition has been established for the signal from occurring, which is a different path from handling it via sigtimedwait.

At this point, then, you are ready to make the call to sigtimedwait():

int sig_num = sigtimedwait(&sigs, NULL, &timeout);

The result will be a signal number if one of the specified signals (only SIGUSER2 in this example) is received within the specified time, or -1 otherwise. Therefore,

if (sig_num == SIGUSER2) {
    // I received the signal
    // do something ...
} else {
    // assert(sig_num == -1);
    // I did not receive the signal within the alotted time
    // do something else ...
}

You might choose to assume that a timeout occurred in the case where the signal is not received, but the most robust code would check errno to verify that:

    if (errno == EAGAIN) {
        // it was a timeout
    } else if (errno = EINTR) {
        // a signal outside the set was received
        // ... might want to calculate how much wait time is left and try again
        //     (left as an exercise)
    } else {
        // some other error occurred
        // ... aborting with an error might be best:
        perror("signal wait failed unexpectedly");
        exit(1);
    }
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • I tried to follow the explanation on manual page , but it's defficult for me to follow the instructions,All what i need is the second wait a signal SIGUSER2 from first within 10 seconds .I don't know how to implement that . – Gismail Feb 25 '20 at 19:49
  • @Gismail, reading documentation such as the manual page I linked is an important skill that you will absolutely need to learn if you want to be an effective programmer. But it can be a bit daunting at first, especially if you're not well versed in the language to begin with. I have added substantial commentary and example code that I hope will help in this case. – John Bollinger Feb 25 '20 at 20:13
  • I'd mention also that the awaited signals should be blocked before calling `sigtimedwait`. That may be what you meant by referencing "some additional usage notes" in the manpage, but I'd suggest its important enough to call out here. – pilcrow Feb 27 '20 at 16:37
  • 1
    Fair enough, @pilcrow, I have extended my comments and example code to explicitly address the needed signal-blocking. – John Bollinger Feb 27 '20 at 17:43
1

Call to sleep until 10 seconds or signal would be:

struct timeval t = {10, 0};
int rc = select(0, NULL, NULL, NULL, &t);
if (rc == 0) {
    // timeout
} else if (errno == EINTR) {
    // signal
} else {
    // some error
stark
  • 12,615
  • 3
  • 33
  • 50
  • I have got this : error: expected expression before ‘{’ token int rc = select(0, NULL, NULL, NULL, {5, 0}); – Gismail Feb 25 '20 at 19:34
  • Did you fix warnings? Add `#include ` and `#include ` – stark Feb 25 '20 at 19:37
  • What happens if the signal arrives before the call to `select`? Is missing a signal and fully timing out acceptable to the OP? – pilcrow Feb 25 '20 at 19:37
  • @stark, I still have the same problem even after including 2 libraries – Gismail Feb 25 '20 at 19:43
  • @pilcrow, I didn't really understand what have said , sorry . – Gismail Feb 25 '20 at 19:44
  • @Gismail, it’s like the problem of [using `pause` to await a signal](https://www.gnu.org/software/libc/manual/html_node/Pause-Problems.html). If the signal arrives before your code enters the `select`, then your code will time out, never aware that it was instructed to do something. – pilcrow Feb 25 '20 at 19:55
  • @stark what is : (errno == EINTR), because they are undefined ? – Gismail Feb 25 '20 at 20:10
  • All of the system library has documentation which tells you what system header files you need to include to define them. Please learn how to look this up on your own as it is a necessary skill. – stark Feb 25 '20 at 20:14