@@ -31,9 +31,11 @@ namespace server {
3131using boost::format;
3232using namespace std ::placeholders;
3333
34- std::atomic_bool executor::cancel_{};
34+ // static initializers.
3535std::thread executor::stop_poller_{};
3636std::promise<bool > executor::stopping_{};
37+ std::atomic<bool > executor::initialized_{};
38+ std::atomic<int > executor::signal_{ unsignalled };
3739
3840executor::executor (parser& metadata, std::istream& input, std::ostream& output,
3941 std::ostream&)
@@ -56,45 +58,35 @@ executor::executor(parser& metadata, std::istream& input, std::ostream& output,
5658 metadata.configured .log .verbose
5759 }
5860{
59- initialize_stop ( );
60- }
61+ BC_ASSERT (!initialized_ );
62+ initialized_ = true ;
6163
62- // Stop signal.
63- // ----------------------------------------------------------------------------
64+ initialize_stop ();
6465
6566#if defined(HAVE_MSC)
66- BOOL WINAPI executor::win32_handler (DWORD signal)
67+ create_hidden_window ();
68+ #endif
69+ }
70+
71+ executor::~executor ()
6772{
68- // //if (auto* log = fopen("shutdown.log", "a"))
69- // //{
70- // // fprintf(log, "Signal %lu at %llu\n", signal, GetTickCount64());
71- // // fflush(log);
72- // // fclose(log);
73- // //}
73+ initialized_ = false ;
7474
75- switch (signal)
76- {
77- case CTRL_C_EVENT:
78- case CTRL_BREAK_EVENT:
79- case CTRL_CLOSE_EVENT:
80- case CTRL_LOGOFF_EVENT:
81- case CTRL_SHUTDOWN_EVENT:
82- executor::handle_stop ({});
83- return TRUE ;
84- default :
85- return FALSE ;
86- }
87- }
75+ #if defined(HAVE_MSC)
76+ destroy_hidden_window ();
8877#endif
78+ }
79+
80+ // Stop signal.
81+ // ----------------------------------------------------------------------------
82+ // static
8983
90- // Call only once.
9184void executor::initialize_stop ()
9285{
9386 poll_for_stopping ();
9487
9588#if defined(HAVE_MSC)
96- // TODO: use RegisterServiceCtrlHandlerEx for service registration.
97- ::SetConsoleCtrlHandler (&executor::win32_handler, TRUE );
89+ ::SetConsoleCtrlHandler (&executor::control_handler, TRUE );
9890#else
9991 // Restart interrupted system calls.
10092 struct sigaction action
@@ -123,34 +115,72 @@ void executor::initialize_stop()
123115#endif
124116}
125117
118+ // Handle the stop signal and invoke stop method (requries signal safe code).
119+ void executor::handle_stop (int signal)
120+ {
121+ stop (signal);
122+ }
123+
124+ // Manage race between console stop and server stop.
125+ void executor::stop (int signal)
126+ {
127+ // //if (auto* log = fopen("shutdown.log", "a"))
128+ // //{
129+ // // fprintf(log, "stop %lu at %llu\n", signal, GetTickCount64());
130+ // // fflush(log);
131+ // // fclose(log);
132+ // //}
133+
134+ // Implementation is limited to signal safe code.
135+ static_assert (std::atomic<int >::is_always_lock_free);
136+
137+ // Capture first handled signal value.
138+ auto unset = unsignalled;
139+ signal_.compare_exchange_strong (unset, signal, std::memory_order_acq_rel);
140+ }
141+
142+ // Any thread can monitor this for stopping.
143+ bool executor::canceled ()
144+ {
145+ return signal_.load (std::memory_order_acquire) != unsignalled;
146+ }
147+
148+ // Spinning must be used in signal handler, cannot wait on a promise.
126149void executor::poll_for_stopping ()
127150{
151+ using namespace std ::this_thread;
152+
128153 stop_poller_ = std::thread ([]()
129154 {
130- while (!cancel_. load (std::memory_order_acquire ))
131- std::this_thread:: sleep_for (std::chrono::milliseconds (10 ));
155+ while (!canceled ( ))
156+ sleep_for (std::chrono::milliseconds (10 ));
132157
133158 stopping_.set_value (true );
134159 });
135160}
136161
162+ // Blocks until stopping is signalled by poller.
137163void executor::wait_for_stopping ()
138164{
139165 stopping_.get_future ().wait ();
140166 if (stop_poller_.joinable ())
141167 stop_poller_.join ();
142168}
143169
144- // Implementation is limited to signal safe code .
145- void executor::handle_stop ( int )
170+ // Suspend verbose logging and log the stop signal .
171+ void executor::log_stopping ( )
146172{
147- stop ();
148- }
173+ const auto signal = signal_.load ();
174+ if (signal == signal_none)
175+ return ;
149176
150- // Manage the race between console stop and server stop.
151- void executor::stop ()
152- {
153- cancel_.store (true , std::memory_order_release);
177+ // A high level of consolve logging can obscure and delay stop.
178+ toggle_.at (network::levels::protocol) = false ;
179+ toggle_.at (network::levels::verbose) = false ;
180+ toggle_.at (network::levels::proxy) = false ;
181+
182+ logger (format (BS_NODE_INTERRUPTED) % signal);
183+ logger (BS_NETWORK_STOPPING);
154184}
155185
156186// Event handlers.
0 commit comments