|
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