Coverage Report

Created: 2024-10-21 15:10

/root/bitcoin/src/util/signalinterrupt.cpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2022 The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#include <util/signalinterrupt.h>
6
7
#ifdef WIN32
8
#include <mutex>
9
#else
10
#include <util/tokenpipe.h>
11
#endif
12
13
#include <ios>
14
#include <optional>
15
16
namespace util {
17
18
0
SignalInterrupt::SignalInterrupt() : m_flag{false}
19
0
{
20
0
#ifndef WIN32
21
0
    std::optional<TokenPipe> pipe = TokenPipe::Make();
22
0
    if (!pipe) throw std::ios_base::failure("Could not create TokenPipe");
23
0
    m_pipe_r = pipe->TakeReadEnd();
24
0
    m_pipe_w = pipe->TakeWriteEnd();
25
0
#endif
26
0
}
27
28
SignalInterrupt::operator bool() const
29
0
{
30
0
    return m_flag;
31
0
}
32
33
bool SignalInterrupt::reset()
34
0
{
35
    // Cancel existing interrupt by waiting for it, this will reset condition flags and remove
36
    // the token from the pipe.
37
0
    if (*this && !wait()) return false;
38
0
    m_flag = false;
39
0
    return true;
40
0
}
41
42
bool SignalInterrupt::operator()()
43
0
{
44
#ifdef WIN32
45
    std::unique_lock<std::mutex> lk(m_mutex);
46
    m_flag = true;
47
    m_cv.notify_one();
48
#else
49
    // This must be reentrant and safe for calling in a signal handler, so using a condition variable is not safe.
50
    // Make sure that the token is only written once even if multiple threads call this concurrently or in
51
    // case of a reentrant signal.
52
0
    if (!m_flag.exchange(true)) {
53
        // Write an arbitrary byte to the write end of the pipe.
54
0
        int res = m_pipe_w.TokenWrite('x');
55
0
        if (res != 0) {
56
0
            return false;
57
0
        }
58
0
    }
59
0
#endif
60
0
    return true;
61
0
}
62
63
bool SignalInterrupt::wait()
64
0
{
65
#ifdef WIN32
66
    std::unique_lock<std::mutex> lk(m_mutex);
67
    m_cv.wait(lk, [this] { return m_flag.load(); });
68
#else
69
0
    int res = m_pipe_r.TokenRead();
70
0
    if (res != 'x') {
71
0
        return false;
72
0
    }
73
0
#endif
74
0
    return true;
75
0
}
76
77
} // namespace util