Wednesday, June 5, 2013

Linux IPC

I needed a way for my raspi program to communicate with with some events from the GPIO. Some options that quickly come to mind are sockets, shared memory, files, and signals. I wanted to briefly share an example in c++ using signals. For this example, we will use the SIGUSR1 signal, which by default, will terminate your application if not caught.

Lets create the signal handler. Pretty straight forward... If we get the SIGUSR1 signal, print out a message to stdout
// signal handler function
void sig_handler (int signo)
{
   if (signo == SIGUSR1)
      cout << "got SIGUSR1" << endl;
}

Next, we need to tell our application to listen for the signal. We do that by calling signal(). If we try to register our listener and something fails or a that signal can't be listened to, we will see an error message printed out to stdout. Note, not all message can be trapped and acted upon. For example, SIGKILL can't be caught. If you were to try and register a listener for it (I encourage you to do so), you will see it will fail.
if (signal(SIGUSR1, sig_handler) == SIG_ERR)
      cout << "Unable to catch SIGUSR1" << endl;

Now, if we put this all together and run our program, we can try to send the SIGUSR1 signal and see if we trap it in our application. Here is a complete example (signal-receiver.cpp).
#include <iostream>
#include <signal.h>
#include <stdio.h>

using namespace std;

// signal handler function
void sig_handler (int signo)
{
   if (signo == SIGUSR1)
      cout << "got SIGUSR1" << endl;
}

int main()
{
   if (signal(SIGUSR1, sig_handler) == SIG_ERR)
      cout << "Unable to catch SIGUSR1" << endl;

   // simulate a long process - calling sleep() so CPU doesn't go to 100%
   while (1)
      sleep(1);

   return 0;
}

To compile, nothing special.
g++ -Wall signal-receiver.cpp -o signal-receiver 

Run and send the SIGUSR1 signal. Notice the program does not terminate upon receiving the signal. You can send it over and over and it will not terminate. Try commenting out the adding of the listener in the program above, re-compile, and run. When you send the SIGUSR1 signal, it will terminate your application.
$ ./signal-receiver 
got SIGUSR1
got SIGUSR1
got SIGUSR1

To send the signal from the command line
$ kill -USR1 <PID>

Lastly, if you are curious if you can send a signal from another c++ program, the answer is yes! Here is a simple example.
#include <iostream>
#include <signal.h>

using namespace std;

int main (int argc, char* argv[])
{
   if (argc != 2)
   {
      cout << "Usage: " << argv[0] << " <PID>" << endl;
      return 1;
   }
   int ret;
   ret = kill(atof(argv[1]), SIGUSR1);
   if (!ret)
      cout << "Successfully sent signal";
   else
      cout << "Error sending signal";
   cout << endl;
   return 0;
}

No comments :

Post a Comment