Add a compatibility shim for working with libevent on MSVC
[folly.git] / folly / io / async / AsyncSignalHandler.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <folly/io/async/AsyncSignalHandler.h>
17
18 #include <folly/io/async/EventBase.h>
19
20 #include <folly/Conv.h>
21
22 using std::make_pair;
23 using std::pair;
24 using std::string;
25
26 namespace folly {
27
28 AsyncSignalHandler::AsyncSignalHandler(EventBase* eventBase)
29   : eventBase_(eventBase) {
30 }
31
32 AsyncSignalHandler::~AsyncSignalHandler() {
33   // Unregister any outstanding events
34   for (SignalEventMap::iterator it = signalEvents_.begin();
35        it != signalEvents_.end();
36        ++it) {
37     event_del(&it->second);
38   }
39 }
40
41 void AsyncSignalHandler::registerSignalHandler(int signum) {
42   pair<SignalEventMap::iterator, bool> ret =
43     signalEvents_.insert(make_pair(signum, event()));
44   if (!ret.second) {
45     // This signal has already been registered
46     throw std::runtime_error(folly::to<string>(
47                                "handler already registered for signal ",
48                                signum));
49   }
50
51   struct event* ev = &(ret.first->second);
52   try {
53     signal_set(ev, signum, libeventCallback, this);
54     if (event_base_set(eventBase_->getLibeventBase(), ev) != 0 ) {
55       throw std::runtime_error(folly::to<string>(
56                                  "error initializing event handler for signal ",
57                                  signum));
58     }
59
60     if (event_add(ev, nullptr) != 0) {
61       throw std::runtime_error(folly::to<string>(
62                                  "error adding event handler for signal ",
63                                  signum));
64     }
65   } catch (...) {
66     signalEvents_.erase(ret.first);
67     throw;
68   }
69 }
70
71 void AsyncSignalHandler::unregisterSignalHandler(int signum) {
72   SignalEventMap::iterator it = signalEvents_.find(signum);
73   if (it == signalEvents_.end()) {
74     throw std::runtime_error(folly::to<string>(
75                                "unable to unregister handler for signal ",
76                                signum, ": signal not registered"));
77   }
78
79   event_del(&it->second);
80   signalEvents_.erase(it);
81 }
82
83 void AsyncSignalHandler::libeventCallback(libevent_fd_t signum,
84                                           short /* events */,
85                                           void* arg) {
86   AsyncSignalHandler* handler = static_cast<AsyncSignalHandler*>(arg);
87   handler->signalReceived(signum);
88 }
89
90 } // folly