Coverage Report

Created: 2026-07-03 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/brpc/src/bthread/parking_lot.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
// bthread - An M:N threading library to make applications more concurrent.
19
20
// Date: 2017/07/27 23:07:06
21
22
#ifndef BTHREAD_PARKING_LOT_H
23
#define BTHREAD_PARKING_LOT_H
24
25
#include <gflags/gflags.h>
26
#include "butil/atomicops.h"
27
#include "bthread/sys_futex.h"
28
29
namespace bthread {
30
31
DECLARE_bool(parking_lot_no_signal_when_no_waiter);
32
33
// Park idle workers.
34
class BAIDU_CACHELINE_ALIGNMENT ParkingLot {
35
public:
36
    class State {
37
    public:
38
0
        State(): val(0) {}
39
0
        bool stopped() const { return val & 1; }
40
    private:
41
    friend class ParkingLot;
42
0
        State(int val) : val(val) {}
43
        int val;
44
    };
45
46
    ParkingLot()
47
0
        : _pending_signal(0), _waiter_num(0)
48
0
        , _no_signal_when_no_waiter(FLAGS_parking_lot_no_signal_when_no_waiter) {}
49
50
    // Wake up at most `num_task' workers.
51
    // Returns #workers woken up.
52
0
    int signal(int num_task) {
53
0
        _pending_signal.fetch_add((num_task << 1), butil::memory_order_release);
54
0
        if (_no_signal_when_no_waiter && _waiter_num.load(butil::memory_order_relaxed) == 0) {
55
0
            return 0;
56
0
        }
57
0
        return futex_wake_private(&_pending_signal, num_task);
58
0
    }
59
60
    // Get a state for later wait().
61
0
    State get_state() {
62
0
        return _pending_signal.load(butil::memory_order_acquire);
63
0
    }
64
65
    // Wait for tasks.
66
    // If the `expected_state' does not match, wait() may finish directly.
67
0
    void wait(const State& expected_state) {
68
0
        if (get_state().val != expected_state.val) {
69
            // Fast path, no need to futex_wait.
70
0
            return;
71
0
        }
72
0
        if (_no_signal_when_no_waiter) {
73
0
            _waiter_num.fetch_add(1, butil::memory_order_relaxed);
74
0
        }
75
0
        futex_wait_private(&_pending_signal, expected_state.val, NULL);
76
0
        if (_no_signal_when_no_waiter) {
77
0
            _waiter_num.fetch_sub(1, butil::memory_order_relaxed);
78
0
        }
79
0
    }
80
81
    // Wakeup suspended wait() and make them unwaitable ever. 
82
0
    void stop() {
83
0
        _pending_signal.fetch_or(1);
84
0
        futex_wake_private(&_pending_signal, 10000);
85
0
    }
86
87
private:
88
    // higher 31 bits for signalling, LSB for stopping.
89
    butil::atomic<int> _pending_signal;
90
    butil::atomic<int> _waiter_num;
91
    // Whether to signal when there is no waiter.
92
    // In busy worker scenarios, signal overhead
93
    // can be reduced.
94
    bool _no_signal_when_no_waiter;
95
};
96
97
}  // namespace bthread
98
99
#endif  // BTHREAD_PARKING_LOT_H