blob: e376c308c561df152fd2744d6979a47c775683a7 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_THREADING_SCOPED_BLOCKING_CALL_H
#define BASE_THREADING_SCOPED_BLOCKING_CALL_H
#include "base/base_export.h"
#include "base/logging.h"
namespace base {
// BlockingType indicates the likelihood that a blocking call will actually
// block.
enum class BlockingType {
// The call might block (e.g. file I/O that might hit in memory cache).
MAY_BLOCK,
// The call will definitely block (e.g. cache already checked and now pinging
// server synchronously).
WILL_BLOCK
};
namespace internal {
class BlockingObserver;
}
// This class must be instantiated in every scope where a blocking call is made.
// CPU usage should be minimal within that scope. //base APIs that block
// instantiate their own ScopedBlockingCall; it is not necessary to instantiate
// another ScopedBlockingCall in the scope where these APIs are used.
//
// Good:
// Data data;
// {
// ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
// data = GetDataFromNetwork();
// }
// CPUIntensiveProcessing(data);
//
// Bad:
// ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
// Data data = GetDataFromNetwork();
// CPUIntensiveProcessing(data); // CPU usage within a ScopedBlockingCall.
//
// Good:
// Data a;
// Data b;
// {
// ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK);
// a = GetDataFromMemoryCacheOrNetwork();
// b = GetDataFromMemoryCacheOrNetwork();
// }
// CPUIntensiveProcessing(a);
// CPUIntensiveProcessing(b);
//
// Bad:
// ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK);
// Data a = GetDataFromMemoryCacheOrNetwork();
// Data b = GetDataFromMemoryCacheOrNetwork();
// CPUIntensiveProcessing(a); // CPU usage within a ScopedBlockingCall.
// CPUIntensiveProcessing(b); // CPU usage within a ScopedBlockingCall.
//
// Good:
// base::WaitableEvent waitable_event(...);
// waitable_event.Wait();
//
// Bad:
// base::WaitableEvent waitable_event(...);
// ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
// waitable_event.Wait(); // Wait() instantiates its own ScopedBlockingCall.
//
// When a ScopedBlockingCall is instantiated from a TaskScheduler parallel or
// sequenced task, the thread pool size is incremented to compensate for the
// blocked thread (more or less aggressively depending on BlockingType).
class BASE_EXPORT ScopedBlockingCall {
public:
ScopedBlockingCall(BlockingType blocking_type);
~ScopedBlockingCall();
private:
internal::BlockingObserver* const blocking_observer_;
// Previous ScopedBlockingCall instantiated on this thread.
ScopedBlockingCall* const previous_scoped_blocking_call_;
// Whether the BlockingType of the current thread was WILL_BLOCK after this
// ScopedBlockingCall was instantiated.
const bool is_will_block_;
DISALLOW_COPY_AND_ASSIGN(ScopedBlockingCall);
};
namespace internal {
// Interface for an observer to be informed when a thread enters or exits
// the scope of ScopedBlockingCall objects.
class BASE_EXPORT BlockingObserver {
public:
virtual ~BlockingObserver() = default;
// Invoked when a ScopedBlockingCall is instantiated on the observed thread
// where there wasn't an existing ScopedBlockingCall.
virtual void BlockingStarted(BlockingType blocking_type) = 0;
// Invoked when a WILL_BLOCK ScopedBlockingCall is instantiated on the
// observed thread where there was a MAY_BLOCK ScopedBlockingCall but not a
// WILL_BLOCK ScopedBlockingCall.
virtual void BlockingTypeUpgraded() = 0;
// Invoked when the last ScopedBlockingCall on the observed thread is
// destroyed.
virtual void BlockingEnded() = 0;
};
// Registers |blocking_observer| on the current thread. It is invalid to call
// this on a thread where there is an active ScopedBlockingCall.
BASE_EXPORT void SetBlockingObserverForCurrentThread(
BlockingObserver* blocking_observer);
BASE_EXPORT void ClearBlockingObserverForTesting();
// Unregisters the |blocking_observer| on the current thread within its scope.
// Used in TaskScheduler tests to prevent calls to //base sync primitives from
// affecting the thread pool capacity.
class BASE_EXPORT ScopedClearBlockingObserverForTesting {
public:
ScopedClearBlockingObserverForTesting();
~ScopedClearBlockingObserverForTesting();
private:
BlockingObserver* const blocking_observer_;
DISALLOW_COPY_AND_ASSIGN(ScopedClearBlockingObserverForTesting);
};
} // namespace internal
} // namespace base
#endif // BASE_THREADING_SCOPED_BLOCKING_CALL_H
|