Skip to content

Commit 26fba39

Browse files
committed
Merge bitcoin/bitcoin#32466: threading: drop CSemaphore in favor of c++20 std::counting_semaphore
6f7052a threading: semaphore: move CountingSemaphoreGrant to its own header (Cory Fields) fd15469 threading: semaphore: remove temporary convenience types (Cory Fields) 1f89e2a scripted-diff: threading: semaphore: use direct types rather than the temporary convenience ones (Cory Fields) f21365c threading: replace CountingSemaphore with std::counting_semaphore (Cory Fields) 1acacfb threading: make CountingSemaphore/CountingSemaphoreGrant template types (Cory Fields) e6ce5f9 scripted-diff: rename CSemaphore and CSemaphoreGrant (Cory Fields) 793166d wallet: change the write semaphore to a BinarySemaphore (Cory Fields) 6790ad2 scripted-diff: rename CSemaphoreGrant and CSemaphore for net (Cory Fields) d870bc9 threading: add temporary semaphore aliases (Cory Fields) 7b816c4 threading: rename CSemaphore methods to match std::semaphore (Cory Fields) Pull request description: This is relatively simple, but done in a bunch of commits to enable scripted diffs. I wanted to add a semaphore in a branch I've been working on, but it was unclear if I should use `std::counting_semaphore` or stick with our old `CSemaphore`. I couldn't decide, so I just decided to remove all doubt and get rid of ours :) This replaces our old `CSemaphore` with `std::counting_semaphore` everywhere we used it. `CSemaphoreGrant` is still there as an RAII wrapper, but is now called `CountingSemaphoreGrant` and `BinarySemaphoreGrant` to match. Those have been moved out of `sync.h` to their own file. ACKs for top commit: purpleKarrot: ACK 6f7052a achow101: ACK 6f7052a TheCharlatan: ACK 6f7052a hebasto: ACK 6f7052a, I have reviewed the code and it looks OK. Tree-SHA512: 5975d13aa21739174e3a22c544620ae3f36345f172b51612346d3b7baf0a07c39ef6fd54f647c87878c21a67951b347a5d4a5f90e897f3f6c0db360a3779d0df
2 parents 8785569 + 6f7052a commit 26fba39

File tree

6 files changed

+121
-152
lines changed

6 files changed

+121
-152
lines changed

src/net.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1886,7 +1886,7 @@ bool CConnman::AddConnection(const std::string& address, ConnectionType conn_typ
18861886
if (max_connections != std::nullopt && existing_connections >= max_connections) return false;
18871887

18881888
// Max total outbound connections already exist
1889-
CSemaphoreGrant grant(*semOutbound, true);
1889+
CountingSemaphoreGrant<> grant(*semOutbound, true);
18901890
if (!grant) return false;
18911891

18921892
OpenNetworkConnection(CAddress(), false, std::move(grant), address.c_str(), conn_type, /*use_v2transport=*/use_v2transport);
@@ -2402,7 +2402,7 @@ void CConnman::ProcessAddrFetch()
24022402
// peer doesn't support it or immediately disconnects us for another reason.
24032403
const bool use_v2transport(GetLocalServices() & NODE_P2P_V2);
24042404
CAddress addr;
2405-
CSemaphoreGrant grant(*semOutbound, /*fTry=*/true);
2405+
CountingSemaphoreGrant<> grant(*semOutbound, /*fTry=*/true);
24062406
if (grant) {
24072407
OpenNetworkConnection(addr, false, std::move(grant), strDest.c_str(), ConnectionType::ADDR_FETCH, use_v2transport);
24082408
}
@@ -2576,7 +2576,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
25762576

25772577
PerformReconnections();
25782578

2579-
CSemaphoreGrant grant(*semOutbound);
2579+
CountingSemaphoreGrant<> grant(*semOutbound);
25802580
if (interruptNet)
25812581
return;
25822582

@@ -2954,7 +2954,7 @@ void CConnman::ThreadOpenAddedConnections()
29542954
AssertLockNotHeld(m_reconnections_mutex);
29552955
while (true)
29562956
{
2957-
CSemaphoreGrant grant(*semAddnode);
2957+
CountingSemaphoreGrant<> grant(*semAddnode);
29582958
std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo(/*include_connected=*/false);
29592959
bool tried = false;
29602960
for (const AddedNodeInfo& info : vInfo) {
@@ -2967,7 +2967,7 @@ void CConnman::ThreadOpenAddedConnections()
29672967
CAddress addr(CService(), NODE_NONE);
29682968
OpenNetworkConnection(addr, false, std::move(grant), info.m_params.m_added_node.c_str(), ConnectionType::MANUAL, info.m_params.m_use_v2transport);
29692969
if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) return;
2970-
grant = CSemaphoreGrant(*semAddnode, /*fTry=*/true);
2970+
grant = CountingSemaphoreGrant<>(*semAddnode, /*fTry=*/true);
29712971
}
29722972
// See if any reconnections are desired.
29732973
PerformReconnections();
@@ -2978,7 +2978,7 @@ void CConnman::ThreadOpenAddedConnections()
29782978
}
29792979

29802980
// if successful, this moves the passed grant to the constructed node
2981-
void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant&& grant_outbound, const char *pszDest, ConnectionType conn_type, bool use_v2transport)
2981+
void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CountingSemaphoreGrant<>&& grant_outbound, const char *pszDest, ConnectionType conn_type, bool use_v2transport)
29822982
{
29832983
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
29842984
assert(conn_type != ConnectionType::INBOUND);
@@ -3329,11 +3329,11 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
33293329

33303330
if (semOutbound == nullptr) {
33313331
// initialize semaphore
3332-
semOutbound = std::make_unique<CSemaphore>(std::min(m_max_automatic_outbound, m_max_automatic_connections));
3332+
semOutbound = std::make_unique<std::counting_semaphore<>>(std::min(m_max_automatic_outbound, m_max_automatic_connections));
33333333
}
33343334
if (semAddnode == nullptr) {
33353335
// initialize semaphore
3336-
semAddnode = std::make_unique<CSemaphore>(m_max_addnode);
3336+
semAddnode = std::make_unique<std::counting_semaphore<>>(m_max_addnode);
33373337
}
33383338

33393339
//
@@ -3421,13 +3421,13 @@ void CConnman::Interrupt()
34213421

34223422
if (semOutbound) {
34233423
for (int i=0; i<m_max_automatic_outbound; i++) {
3424-
semOutbound->post();
3424+
semOutbound->release();
34253425
}
34263426
}
34273427

34283428
if (semAddnode) {
34293429
for (int i=0; i<m_max_addnode; i++) {
3430-
semAddnode->post();
3430+
semAddnode->release();
34313431
}
34323432
}
34333433
}

src/net.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <policy/feerate.h>
2525
#include <protocol.h>
2626
#include <random.h>
27+
#include <semaphore_grant.h>
2728
#include <span.h>
2829
#include <streams.h>
2930
#include <sync.h>
@@ -729,7 +730,7 @@ class CNode
729730
// Setting fDisconnect to true will cause the node to be disconnected the
730731
// next time DisconnectNodes() runs
731732
std::atomic_bool fDisconnect{false};
732-
CSemaphoreGrant grantOutbound;
733+
CountingSemaphoreGrant<> grantOutbound;
733734
std::atomic<int> nRefCount{0};
734735

735736
const uint64_t nKeyedNetGroup;
@@ -1136,7 +1137,7 @@ class CConnman
11361137
bool GetNetworkActive() const { return fNetworkActive; };
11371138
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
11381139
void SetNetworkActive(bool active);
1139-
void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant&& grant_outbound, const char* strDest, ConnectionType conn_type, bool use_v2transport) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
1140+
void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CountingSemaphoreGrant<>&& grant_outbound, const char* strDest, ConnectionType conn_type, bool use_v2transport) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
11401141
bool CheckIncomingNonce(uint64_t nonce);
11411142
void ASMapHealthCheck();
11421143

@@ -1491,8 +1492,8 @@ class CConnman
14911492
*/
14921493
std::atomic<ServiceFlags> m_local_services;
14931494

1494-
std::unique_ptr<CSemaphore> semOutbound;
1495-
std::unique_ptr<CSemaphore> semAddnode;
1495+
std::unique_ptr<std::counting_semaphore<>> semOutbound;
1496+
std::unique_ptr<std::counting_semaphore<>> semAddnode;
14961497

14971498
/**
14981499
* Maximum number of automatic connections permitted, excluding manual
@@ -1614,7 +1615,7 @@ class CConnman
16141615
struct ReconnectionInfo
16151616
{
16161617
CAddress addr_connect;
1617-
CSemaphoreGrant grant;
1618+
CountingSemaphoreGrant<> grant;
16181619
std::string destination;
16191620
ConnectionType conn_type;
16201621
bool use_v2transport;

src/semaphore_grant.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright (c) 2009-2010 Satoshi Nakamoto
2+
// Copyright (c) 2009-present The Bitcoin Core developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#ifndef BITCOIN_SEMAPHORE_GRANT_H
7+
#define BITCOIN_SEMAPHORE_GRANT_H
8+
9+
#include <semaphore>
10+
11+
/** RAII-style semaphore lock */
12+
template <std::ptrdiff_t LeastMaxValue = std::counting_semaphore<>::max()>
13+
class CountingSemaphoreGrant
14+
{
15+
private:
16+
std::counting_semaphore<LeastMaxValue>* sem;
17+
bool fHaveGrant;
18+
19+
public:
20+
void Acquire() noexcept
21+
{
22+
if (fHaveGrant) {
23+
return;
24+
}
25+
sem->acquire();
26+
fHaveGrant = true;
27+
}
28+
29+
void Release() noexcept
30+
{
31+
if (!fHaveGrant) {
32+
return;
33+
}
34+
sem->release();
35+
fHaveGrant = false;
36+
}
37+
38+
bool TryAcquire() noexcept
39+
{
40+
if (!fHaveGrant && sem->try_acquire()) {
41+
fHaveGrant = true;
42+
}
43+
return fHaveGrant;
44+
}
45+
46+
// Disallow copy.
47+
CountingSemaphoreGrant(const CountingSemaphoreGrant&) = delete;
48+
CountingSemaphoreGrant& operator=(const CountingSemaphoreGrant&) = delete;
49+
50+
// Allow move.
51+
CountingSemaphoreGrant(CountingSemaphoreGrant&& other) noexcept
52+
{
53+
sem = other.sem;
54+
fHaveGrant = other.fHaveGrant;
55+
other.fHaveGrant = false;
56+
other.sem = nullptr;
57+
}
58+
59+
CountingSemaphoreGrant& operator=(CountingSemaphoreGrant&& other) noexcept
60+
{
61+
Release();
62+
sem = other.sem;
63+
fHaveGrant = other.fHaveGrant;
64+
other.fHaveGrant = false;
65+
other.sem = nullptr;
66+
return *this;
67+
}
68+
69+
CountingSemaphoreGrant() noexcept : sem(nullptr), fHaveGrant(false) {}
70+
71+
explicit CountingSemaphoreGrant(std::counting_semaphore<LeastMaxValue>& sema, bool fTry = false) noexcept : sem(&sema), fHaveGrant(false)
72+
{
73+
if (fTry) {
74+
TryAcquire();
75+
} else {
76+
Acquire();
77+
}
78+
}
79+
80+
~CountingSemaphoreGrant()
81+
{
82+
Release();
83+
}
84+
85+
explicit operator bool() const noexcept
86+
{
87+
return fHaveGrant;
88+
}
89+
};
90+
91+
using BinarySemaphoreGrant = CountingSemaphoreGrant<1>;
92+
93+
#endif // BITCOIN_SEMAPHORE_GRANT_H

src/sync.h

Lines changed: 0 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -300,131 +300,4 @@ inline MutexType* MaybeCheckNotHeld(MutexType* m) LOCKS_EXCLUDED(m) LOCK_RETURNE
300300
//! gcc and the -Wreturn-stack-address flag in clang, both enabled by default.
301301
#define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }())
302302

303-
/** An implementation of a semaphore.
304-
*
305-
* See https://en.wikipedia.org/wiki/Semaphore_(programming)
306-
*/
307-
class CSemaphore
308-
{
309-
private:
310-
std::condition_variable condition;
311-
std::mutex mutex;
312-
int value;
313-
314-
public:
315-
explicit CSemaphore(int init) noexcept : value(init) {}
316-
317-
// Disallow default construct, copy, move.
318-
CSemaphore() = delete;
319-
CSemaphore(const CSemaphore&) = delete;
320-
CSemaphore(CSemaphore&&) = delete;
321-
CSemaphore& operator=(const CSemaphore&) = delete;
322-
CSemaphore& operator=(CSemaphore&&) = delete;
323-
324-
void wait() noexcept
325-
{
326-
std::unique_lock<std::mutex> lock(mutex);
327-
condition.wait(lock, [&]() { return value >= 1; });
328-
value--;
329-
}
330-
331-
bool try_wait() noexcept
332-
{
333-
std::lock_guard<std::mutex> lock(mutex);
334-
if (value < 1) {
335-
return false;
336-
}
337-
value--;
338-
return true;
339-
}
340-
341-
void post() noexcept
342-
{
343-
{
344-
std::lock_guard<std::mutex> lock(mutex);
345-
value++;
346-
}
347-
condition.notify_one();
348-
}
349-
};
350-
351-
/** RAII-style semaphore lock */
352-
class CSemaphoreGrant
353-
{
354-
private:
355-
CSemaphore* sem;
356-
bool fHaveGrant;
357-
358-
public:
359-
void Acquire() noexcept
360-
{
361-
if (fHaveGrant) {
362-
return;
363-
}
364-
sem->wait();
365-
fHaveGrant = true;
366-
}
367-
368-
void Release() noexcept
369-
{
370-
if (!fHaveGrant) {
371-
return;
372-
}
373-
sem->post();
374-
fHaveGrant = false;
375-
}
376-
377-
bool TryAcquire() noexcept
378-
{
379-
if (!fHaveGrant && sem->try_wait()) {
380-
fHaveGrant = true;
381-
}
382-
return fHaveGrant;
383-
}
384-
385-
// Disallow copy.
386-
CSemaphoreGrant(const CSemaphoreGrant&) = delete;
387-
CSemaphoreGrant& operator=(const CSemaphoreGrant&) = delete;
388-
389-
// Allow move.
390-
CSemaphoreGrant(CSemaphoreGrant&& other) noexcept
391-
{
392-
sem = other.sem;
393-
fHaveGrant = other.fHaveGrant;
394-
other.fHaveGrant = false;
395-
other.sem = nullptr;
396-
}
397-
398-
CSemaphoreGrant& operator=(CSemaphoreGrant&& other) noexcept
399-
{
400-
Release();
401-
sem = other.sem;
402-
fHaveGrant = other.fHaveGrant;
403-
other.fHaveGrant = false;
404-
other.sem = nullptr;
405-
return *this;
406-
}
407-
408-
CSemaphoreGrant() noexcept : sem(nullptr), fHaveGrant(false) {}
409-
410-
explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) noexcept : sem(&sema), fHaveGrant(false)
411-
{
412-
if (fTry) {
413-
TryAcquire();
414-
} else {
415-
Acquire();
416-
}
417-
}
418-
419-
~CSemaphoreGrant()
420-
{
421-
Release();
422-
}
423-
424-
explicit operator bool() const noexcept
425-
{
426-
return fHaveGrant;
427-
}
428-
};
429-
430303
#endif // BITCOIN_SYNC_H

0 commit comments

Comments
 (0)