Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

POSIX specifics

Self-pipe

Boost.Application have some specifics on each side, here the user that uses POSIX system need be aware.

The Self-pipe aspect can be used if user need more control of application.

In default form a SIGNAL can interrupt your program at any time. E.g.: while any of your code is executing, a signal can arrive and interrupt it. While one signal is being handled, another signal (or the same signal), can arrive a second time and interrupt the first handler and so on.

The problem is that the default signal handler is not re-entrant, and if you need that your signal handlers to be re-entrant, you can use Self-pipe aspect.

In Self-pipe a 'pipe' is used as queue (you just write some bytes to one end and read some bytes from the other end), and this queue is used to notify the other side that an 'event', or a SIGNAL has arrived.

User can use 'select' system call to monitors the reading end of this pipe, to know when SIGNAL arrives.

class selfpipe_state
{
   boost::mutex mutex_;
   boost::logic::tribool state_;

public:

   selfpipe_state()
      : state_(false) {}

   void signal()
   {
      boost::lock_guard<boost::mutex> lock(mutex_);
      state_ = true;
   }

   void error()
   {
      boost::lock_guard<boost::mutex> lock(mutex_);
      state_ = boost::logic::indeterminate;
   }

   boost::logic::tribool state()
   {
      boost::lock_guard<boost::mutex> lock(mutex_);
      return state_;
   }

};

class myapp
{
public:

   int operator()()
   {
      boost::shared_ptr<application::selfpipe> selfpipe
         = this_application()->find<application::selfpipe>();

      fd_set readfds;
      FD_ZERO(&readfds);
      FD_SET(selfpipe->read_fd(), &readfds);

      1boost::thread thread(&myapp::worker, this);

      int retval = 0;

      2while((retval = select(selfpipe->read_fd() + 1, &readfds, 0, 0, 0)) == -1 && errno == EINTR) // block and wait
      {
         // nothing here, restart when signal is catch
         std::cout << "signal is catch" << std::endl;
      }
      // we are poked

      if(retval == -1)
      {
         selfpipe_state_.error();
      }
      else
      {
         3selfpipe_state_.signal();
      }

      4thread.join();

      return 0;
   }

protected:

   void worker()
   {
      while(selfpipe_state_.state() == false)
      {
         boost::this_thread::sleep(boost::posix_time::seconds(1));
         std::cout << "working..." << std::endl;
      }

      // select fail
      if(selfpipe_state_.state() == boost::logic::indeterminate) {
         std::cout << "other end work when we have an error..." << std::endl;
      }

      boost::this_thread::sleep(boost::posix_time::seconds(1));
      std::cout << "other end work..." << std::endl;
   }

private:

   selfpipe_state selfpipe_state_;

};

5class signal_usr2 : public application::signal_manager
{
public:

   6signal_usr2(application::global_context_ptr cxt)
      : application::signal_manager(cxt)
   {
      application::handler<>::parameter_callback callback1
         = boost::bind<bool>(&signal_usr2::signal_usr1_handler, this);

      application::handler<>::parameter_callback callback2
         = boost::bind<bool>(&signal_usr2::signal_usr2_handler, this);

      7bind(SIGUSR1, callback1);
      bind(SIGUSR2, callback2);
   }

   bool signal_usr1_handler()
   {
      std::cout << "signal_usr1_handler" << std::endl;

      return false;
   }

   8bool signal_usr2_handler()
   {
      std::cout << "signal_usr2_handler" << std::endl;

      boost::shared_ptr<application::selfpipe> selfpipe
         = this_application()->find<application::selfpipe>();

      9selfpipe->poke();

      return false;
   }
};

// main

int main(int argc, char *argv[])
{
   myapp app;

   application::global_context_ptr ctx = application::global_context::create();

   10this_application()->insert<application::posix::selfpipe>(
      boost::make_shared<application::posix::selfpipe>());
	
   signal_usr2 sm(ctx);
   int ret = application::launch<application::common>(app, sm, ctx);

   return ret;
}

1

Launch a work thread

2

Use select posix system call to wait for SIGUSR2 signal, using our self-pipe

3

Was poked, notify work thread using selfpipe_state_

4

Wait for the end of the work

5

Define a new signal_manager to act on SIGUSR2

6

Customize SIGNALS bind

7

Define signal bind

8

Define signal callback

9

Notify application in case of reception of SIGUSR2 signal, unsing self-pipe

10

Add selfpipe to application context

[Note] Note

Note that Self-pipe is only available on POSIX platform. This aspect is platform dependent, and the use of it implies in use of some POSIX API, like select().


PrevUpHomeNext