Boost logo

Boost :

Subject: Re: [boost] New Version (0.4) of Boost.Application (Aspect Based) available to comments (RFC).
From: Stanislav Ivochkin (isn_at_[hidden])
Date: 2013-11-07 16:45:51


2013/11/7 Renato Forti <re.tf_at_[hidden]>

> >> What do you think about self pipe built-in functionality? It is a widely
> used trick. I think it can be implemented as an aspect in a quite
> straightforward way.
>
> Can you give more details about what you're proposing here? Elegant signal
> handler is my main problem in this lib! I want ideas to get it correctly
> designed!
>

The problem is to transfer interruption signal to the thread performing I/O
multiplexing, for instance, waiting for new data during select(2) call.
Default signal handler will force select(..) to return, but as far as we
want to have a custom one, we need to abort select(..) manually.

One can set a reasonable timeout for I/O operation, and check whether
interruption signal have been delivered or not after timeout expires. For
example,

while (1) {
  if (termination_signal_received) {
    break;
  }
  // imagine signal received here, termination_signal_received set to true.
  // nevertheless, to get out of the loop we have to wait until timeout
expires
  select(...);
}

This is a feasible solution, but it yields delayed termination and can not
be accepted for some particular cases.

The tricky solution is to set up an non-blocking pipe and add its read end
to select(2)'s readfds array. Hence select(..) will return immediately when
any data will be written to the pipe's write end. Therefore,
write(selfpipe_write_fd, "", 1); must be called in signal handler after the
termination_signal_received is set to true.

The same effect can be achieved with signalfd(2). Unfortunately, this
syscall is linux-specific.

Here is a draft of the proposed aspect:

class selfpipe : noncopyable
{
protected:
    void setup() {
        pipe(fd_);
        fcntl(fd_[READ_FD], F_SETFL, fcntl(fd_[READ_FD], F_GETFL) |
O_NONBLOCK);
        fcntl(fd_[WRITE_FD], F_SETFL, fcntl(fd_[WRITE_FD], F_GETFL) |
O_NONBLOCK);
    }

    void teardown() {
        close(fd_[READ_FD];
        close(fd_[WRITE_FD];
    }

public:
    int readfd() const { return fd_[READ_FD]; }
    void poke() { write(fd_[WRITE_FD], "", 1); }

private:
    enum { READ_FD = 0, WRITE_FD = 1 };
    int fd_[2];
};

If an application has selfpipe aspect, the selfpipe::setup() method must be
called during application's initialization, and selfpipe::teardown() during
termination.

-- 
Regards,
Stas.

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk