forked from ravinet/mahimahi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathevent_loop.cc
99 lines (83 loc) · 3.11 KB
/
event_loop.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/* -*-mode:c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "event_loop.hh"
using namespace std;
using namespace PollerShortNames;
EventLoop::EventLoop()
: signals_( { SIGCHLD, SIGCONT, SIGHUP, SIGTERM, SIGQUIT, SIGINT } ),
poller_(),
child_processes_()
{
signals_.set_as_mask(); /* block signals so we can later use signalfd to read them */
}
void EventLoop::add_simple_input_handler( FileDescriptor & fd,
const Poller::Action::CallbackType & callback )
{
poller_.add_action( Poller::Action( fd, Direction::In, callback ) );
}
Result EventLoop::handle_signal( const signalfd_siginfo & sig )
{
switch ( sig.ssi_signo ) {
case SIGCONT:
/* resume child processes too */
for ( auto & x : child_processes_ ) {
x.first.resume();
}
break;
case SIGCHLD:
{
/* find which children are waitable */
/* we can't count on getting exactly one SIGCHLD per waitable event, so search */
list<pair<ChildProcess, bool>>::iterator x = child_processes_.begin();
while ( x != child_processes_.end() ) {
if ( x->first.waitable() ) {
x->first.wait( true ); /* nonblocking */
if ( x->first.terminated() ) {
if ( x->first.exit_status() != 0 ) {
x->first.throw_exception();
} else { /* exit event loop */
if ( x->second ) {
return ResultType::Exit;
} else { /* remove child process but don't exit eventloop */
x = child_processes_.erase( x );
return ResultType::Continue;
}
}
} else if ( !x->first.running() ) {
/* suspend parent too */
SystemCall( "raise", raise( SIGSTOP ) );
}
break;
}
x++;
}
}
break;
case SIGHUP:
case SIGTERM:
case SIGQUIT:
case SIGINT:
return ResultType::Exit;
default:
throw Exception( "EventLoop", "unknown signal" );
}
return ResultType::Continue;
}
int EventLoop::internal_loop( const std::function<int(void)> & wait_time )
{
TemporarilyUnprivileged tu;
/* verify that signal mask is intact */
SignalMask current_mask = SignalMask::current_mask();
if ( !( signals_ == current_mask ) ) {
throw Exception( "EventLoop", "signal mask has been altered" );
}
SignalFD signal_fd( signals_ );
/* we get signal -> main screen turn on */
add_simple_input_handler( signal_fd.fd(),
[&] () { return handle_signal( signal_fd.read_signal() ); } );
while ( true ) {
const auto poll_result = poller_.poll( wait_time() );
if ( poll_result.result == Poller::Result::Type::Exit ) {
return poll_result.exit_status;
}
}
}