summaryrefslogtreecommitdiff
path: root/chromium/base/threading/scoped_blocking_call.h
blob: 1681fe9cdcc42d96f6cb0a2d62d2ce51da368dc5 (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
// 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/location.h"
#include "base/threading/scoped_blocking_call_internal.h"

namespace base {

// A "blocking call" refers to any call that causes the calling thread to wait
// off-CPU. It includes but is not limited to calls that wait on synchronous
// file I/O operations: read or write a file from disk, interact with a pipe or
// a socket, rename or delete a file, enumerate files in a directory, etc.
// Acquiring a low contention lock is not considered a blocking call.

// 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
};

// This class must be instantiated in every scope where a blocking call is made
// and serves as a precise annotation of the scope that may/will block for the
// scheduler. When a ScopedBlockingCall is instantiated, it asserts that
// blocking calls are allowed in its scope with a call to
// base::AssertBlockingAllowed(). 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. Nested ScopedBlockingCalls are supported (mostly a no-op
// except for WILL_BLOCK nested within MAY_BLOCK which will result in immediate
// WILL_BLOCK semantics).
//
// Good:
//   Data data;
//   {
//     ScopedBlockingCall scoped_blocking_call(
//         FROM_HERE, BlockingType::WILL_BLOCK);
//     data = GetDataFromNetwork();
//   }
//   CPUIntensiveProcessing(data);
//
// Bad:
//   ScopedBlockingCall scoped_blocking_call(FROM_HERE,
//       BlockingType::WILL_BLOCK);
//   Data data = GetDataFromNetwork();
//   CPUIntensiveProcessing(data);  // CPU usage within a ScopedBlockingCall.
//
// Good:
//   Data a;
//   Data b;
//   {
//     ScopedBlockingCall scoped_blocking_call(
//         FROM_HERE, BlockingType::MAY_BLOCK);
//     a = GetDataFromMemoryCacheOrNetwork();
//     b = GetDataFromMemoryCacheOrNetwork();
//   }
//   CPUIntensiveProcessing(a);
//   CPUIntensiveProcessing(b);
//
// Bad:
//   ScopedBlockingCall scoped_blocking_call(
//       FROM_HERE, 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(
//      FROM_HERE, BlockingType::WILL_BLOCK);
//  waitable_event.Wait();  // Wait() instantiates its own ScopedBlockingCall.
//
// When a ScopedBlockingCall is instantiated from a ThreadPool 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 internal::UncheckedScopedBlockingCall {
 public:
  ScopedBlockingCall(const Location& from_here, BlockingType blocking_type);
  ~ScopedBlockingCall();
};

// Usage reserved for //base callers.
namespace internal {

// This class must be instantiated in every scope where a sync primitive is
// used. When a ScopedBlockingCallWithBaseSyncPrimitives is instantiated, it
// asserts that sync primitives are allowed in its scope with a call to
// internal::AssertBaseSyncPrimitivesAllowed(). The same guidelines as for
// ScopedBlockingCall should be followed.
class BASE_EXPORT ScopedBlockingCallWithBaseSyncPrimitives
    : public UncheckedScopedBlockingCall {
 public:
  ScopedBlockingCallWithBaseSyncPrimitives(const Location& from_here,
                                           BlockingType blocking_type);
  ~ScopedBlockingCallWithBaseSyncPrimitives();
};

}  // namespace internal

}  // namespace base

#endif  // BASE_THREADING_SCOPED_BLOCKING_CALL_H