Skip to content

Commit b77bb95

Browse files
committed
Merge #8421: httpserver: drop boost (#8023 dependency)
7e87033 httpserver: replace boost threads with std (Cory Fields) d3773ca httpserver: explicitly detach worker threads (Cory Fields) 755aa05 httpserver: use a future rather than relying on boost's try_join_for (Cory Fields)
2 parents 842bf8d + 7e87033 commit b77bb95

File tree

2 files changed

+33
-35
lines changed

2 files changed

+33
-35
lines changed

src/httpserver.cpp

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <sys/types.h>
2020
#include <sys/stat.h>
2121
#include <signal.h>
22+
#include <future>
2223

2324
#include <event2/event.h>
2425
#include <event2/http.h>
@@ -34,9 +35,6 @@
3435
#endif
3536
#endif
3637

37-
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
38-
#include <boost/foreach.hpp>
39-
4038
/** Maximum size of http request (request line + headers) */
4139
static const size_t MAX_HEADERS_SIZE = 8192;
4240

@@ -68,8 +66,8 @@ class WorkQueue
6866
{
6967
private:
7068
/** Mutex protects entire object */
71-
CWaitableCriticalSection cs;
72-
CConditionVariable cond;
69+
std::mutex cs;
70+
std::condition_variable cond;
7371
std::deque<std::unique_ptr<WorkItem>> queue;
7472
bool running;
7573
size_t maxDepth;
@@ -82,12 +80,12 @@ class WorkQueue
8280
WorkQueue &wq;
8381
ThreadCounter(WorkQueue &w): wq(w)
8482
{
85-
boost::lock_guard<boost::mutex> lock(wq.cs);
83+
std::lock_guard<std::mutex> lock(wq.cs);
8684
wq.numThreads += 1;
8785
}
8886
~ThreadCounter()
8987
{
90-
boost::lock_guard<boost::mutex> lock(wq.cs);
88+
std::lock_guard<std::mutex> lock(wq.cs);
9189
wq.numThreads -= 1;
9290
wq.cond.notify_all();
9391
}
@@ -108,7 +106,7 @@ class WorkQueue
108106
/** Enqueue a work item */
109107
bool Enqueue(WorkItem* item)
110108
{
111-
boost::unique_lock<boost::mutex> lock(cs);
109+
std::unique_lock<std::mutex> lock(cs);
112110
if (queue.size() >= maxDepth) {
113111
return false;
114112
}
@@ -123,7 +121,7 @@ class WorkQueue
123121
while (running) {
124122
std::unique_ptr<WorkItem> i;
125123
{
126-
boost::unique_lock<boost::mutex> lock(cs);
124+
std::unique_lock<std::mutex> lock(cs);
127125
while (running && queue.empty())
128126
cond.wait(lock);
129127
if (!running)
@@ -137,22 +135,22 @@ class WorkQueue
137135
/** Interrupt and exit loops */
138136
void Interrupt()
139137
{
140-
boost::unique_lock<boost::mutex> lock(cs);
138+
std::unique_lock<std::mutex> lock(cs);
141139
running = false;
142140
cond.notify_all();
143141
}
144142
/** Wait for worker threads to exit */
145143
void WaitExit()
146144
{
147-
boost::unique_lock<boost::mutex> lock(cs);
145+
std::unique_lock<std::mutex> lock(cs);
148146
while (numThreads > 0)
149147
cond.wait(lock);
150148
}
151149

152150
/** Return current depth of queue */
153151
size_t Depth()
154152
{
155-
boost::unique_lock<boost::mutex> lock(cs);
153+
std::unique_lock<std::mutex> lock(cs);
156154
return queue.size();
157155
}
158156
};
@@ -189,7 +187,7 @@ static bool ClientAllowed(const CNetAddr& netaddr)
189187
{
190188
if (!netaddr.IsValid())
191189
return false;
192-
BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets)
190+
for(const CSubNet& subnet : rpc_allow_subnets)
193191
if (subnet.Match(netaddr))
194192
return true;
195193
return false;
@@ -203,7 +201,7 @@ static bool InitHTTPAllowList()
203201
rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost
204202
if (mapMultiArgs.count("-rpcallowip")) {
205203
const std::vector<std::string>& vAllow = mapMultiArgs["-rpcallowip"];
206-
BOOST_FOREACH (std::string strAllow, vAllow) {
204+
for (std::string strAllow : vAllow) {
207205
CSubNet subnet(strAllow);
208206
if (!subnet.IsValid()) {
209207
uiInterface.ThreadSafeMessageBox(
@@ -215,7 +213,7 @@ static bool InitHTTPAllowList()
215213
}
216214
}
217215
std::string strAllowed;
218-
BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets)
216+
for (const CSubNet& subnet : rpc_allow_subnets)
219217
strAllowed += subnet.ToString() + " ";
220218
LogPrint("http", "Allowing HTTP connections from: %s\n", strAllowed);
221219
return true;
@@ -302,13 +300,14 @@ static void http_reject_request_cb(struct evhttp_request* req, void*)
302300
}
303301

304302
/** Event dispatcher thread */
305-
static void ThreadHTTP(struct event_base* base, struct evhttp* http)
303+
static bool ThreadHTTP(struct event_base* base, struct evhttp* http)
306304
{
307305
RenameThread("bitcoin-http");
308306
LogPrint("http", "Entering http event loop\n");
309307
event_base_dispatch(base);
310308
// Event loop will be interrupted by InterruptHTTPServer()
311309
LogPrint("http", "Exited http event loop\n");
310+
return event_base_got_break(base) == 0;
312311
}
313312

314313
/** Bind HTTP server to specified addresses */
@@ -437,17 +436,22 @@ bool InitHTTPServer()
437436
return true;
438437
}
439438

440-
boost::thread threadHTTP;
439+
std::thread threadHTTP;
440+
std::future<bool> threadResult;
441441

442442
bool StartHTTPServer()
443443
{
444444
LogPrint("http", "Starting HTTP server\n");
445445
int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
446446
LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
447-
threadHTTP = boost::thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP));
447+
std::packaged_task<bool(event_base*, evhttp*)> task(ThreadHTTP);
448+
threadResult = task.get_future();
449+
threadHTTP = std::thread(std::move(task), eventBase, eventHTTP);
448450

449-
for (int i = 0; i < rpcThreads; i++)
450-
boost::thread(boost::bind(&HTTPWorkQueueRun, workQueue));
451+
for (int i = 0; i < rpcThreads; i++) {
452+
std::thread rpc_worker(HTTPWorkQueueRun, workQueue);
453+
rpc_worker.detach();
454+
}
451455
return true;
452456
}
453457

@@ -456,7 +460,7 @@ void InterruptHTTPServer()
456460
LogPrint("http", "Interrupting HTTP server\n");
457461
if (eventHTTP) {
458462
// Unlisten sockets
459-
BOOST_FOREACH (evhttp_bound_socket *socket, boundSockets) {
463+
for (evhttp_bound_socket *socket : boundSockets) {
460464
evhttp_del_accept_socket(eventHTTP, socket);
461465
}
462466
// Reject requests on current connections
@@ -482,15 +486,11 @@ void StopHTTPServer()
482486
// master that appears to be solved, so in the future that solution
483487
// could be used again (if desirable).
484488
// (see discussion in https://github.com/bitcoin/bitcoin/pull/6990)
485-
#if BOOST_VERSION >= 105000
486-
if (!threadHTTP.try_join_for(boost::chrono::milliseconds(2000))) {
487-
#else
488-
if (!threadHTTP.timed_join(boost::posix_time::milliseconds(2000))) {
489-
#endif
489+
if (threadResult.valid() && threadResult.wait_for(std::chrono::milliseconds(2000)) == std::future_status::timeout) {
490490
LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n");
491491
event_base_loopbreak(eventBase);
492-
threadHTTP.join();
493492
}
493+
threadHTTP.join();
494494
}
495495
if (eventHTTP) {
496496
evhttp_free(eventHTTP);
@@ -517,7 +517,7 @@ static void httpevent_callback_fn(evutil_socket_t, short, void* data)
517517
delete self;
518518
}
519519

520-
HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler):
520+
HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function<void(void)>& handler):
521521
deleteWhenTriggered(deleteWhenTriggered), handler(handler)
522522
{
523523
ev = event_new(base, -1, 0, httpevent_callback_fn, this);
@@ -599,7 +599,7 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
599599
assert(evb);
600600
evbuffer_add(evb, strReply.data(), strReply.size());
601601
HTTPEvent* ev = new HTTPEvent(eventBase, true,
602-
boost::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
602+
std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
603603
ev->trigger(0);
604604
replySent = true;
605605
req = 0; // transferred back to main thread

src/httpserver.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77

88
#include <string>
99
#include <stdint.h>
10-
#include <boost/thread.hpp>
11-
#include <boost/scoped_ptr.hpp>
12-
#include <boost/function.hpp>
10+
#include <functional>
1311

1412
static const int DEFAULT_HTTP_THREADS=4;
1513
static const int DEFAULT_HTTP_WORKQUEUE=16;
@@ -35,7 +33,7 @@ void InterruptHTTPServer();
3533
void StopHTTPServer();
3634

3735
/** Handler for requests to a certain HTTP path */
38-
typedef boost::function<void(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
36+
typedef std::function<void(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
3937
/** Register handler for prefix.
4038
* If multiple handlers match a prefix, the first-registered one will
4139
* be invoked.
@@ -132,7 +130,7 @@ class HTTPEvent
132130
* deleteWhenTriggered deletes this event object after the event is triggered (and the handler called)
133131
* handler is the handler to call when the event is triggered.
134132
*/
135-
HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler);
133+
HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function<void(void)>& handler);
136134
~HTTPEvent();
137135

138136
/** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after
@@ -141,7 +139,7 @@ class HTTPEvent
141139
void trigger(struct timeval* tv);
142140

143141
bool deleteWhenTriggered;
144-
boost::function<void(void)> handler;
142+
std::function<void(void)> handler;
145143
private:
146144
struct event* ev;
147145
};

0 commit comments

Comments
 (0)