1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Use of this source code is governed by a BSD-style license that can be
3731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// found in the LICENSE file.
4731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
53f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#ifndef BASE_THREADING_THREAD_RESTRICTIONS_H_
63f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#define BASE_THREADING_THREAD_RESTRICTIONS_H_
7731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/base_api.h"
9513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/basictypes.h"
10513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
11731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace base {
12731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
13201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// Certain behavior is disallowed on certain threads.  ThreadRestrictions helps
14201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// enforce these rules.  Examples of such rules:
15201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch//
16201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// * Do not do blocking IO (makes the thread janky)
17201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// * Do not access Singleton/LazyInstance (may lead to shutdown crashes)
18201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch//
19201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// Here's more about how the protection works:
20731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick//
21731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// 1) If a thread should not be allowed to make IO calls, mark it:
22731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick//      base::ThreadRestrictions::SetIOAllowed(false);
23731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick//    By default, threads *are* allowed to make IO calls.
24731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick//    In Chrome browser code, IO calls should be proxied to the File thread.
25731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick//
26731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// 2) If a function makes a call that will go out to disk, check whether the
27731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick//    current thread is allowed:
28731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick//      base::ThreadRestrictions::AssertIOAllowed();
29731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick//
30731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// ThreadRestrictions does nothing in release builds; it is debug-only.
31731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick//
32513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Style tip: where should you put AssertIOAllowed checks?  It's best
33513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// if you put them as close to the disk access as possible, at the
34513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// lowest level.  This rule is simple to follow and helps catch all
35513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// callers.  For example, if your function GoDoSomeBlockingDiskCall()
36513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// only calls other functions in Chrome and not fopen(), you should go
37513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// add the AssertIOAllowed checks in the helper functions.
38513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass BASE_API ThreadRestrictions {
40731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick public:
41513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Constructing a ScopedAllowIO temporarily allows IO for the current
42513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // thread.  Doing this is almost certainly always incorrect.
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  class BASE_API ScopedAllowIO {
44513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch   public:
45513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    ScopedAllowIO() { previous_value_ = SetIOAllowed(true); }
46513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    ~ScopedAllowIO() { SetIOAllowed(previous_value_); }
47513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch   private:
48513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // Whether IO is allowed when the ScopedAllowIO was constructed.
49513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    bool previous_value_;
50513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
51513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO);
52513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  };
53513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
54201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Constructing a ScopedAllowSingleton temporarily allows accessing for the
55201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // current thread.  Doing this is almost always incorrect.
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  class BASE_API ScopedAllowSingleton {
57201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch   public:
58201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    ScopedAllowSingleton() { previous_value_ = SetSingletonAllowed(true); }
59201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    ~ScopedAllowSingleton() { SetSingletonAllowed(previous_value_); }
60201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch   private:
61201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // Whether singleton use is allowed when the ScopedAllowSingleton was
62201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // constructed.
63201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    bool previous_value_;
64201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
65201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    DISALLOW_COPY_AND_ASSIGN(ScopedAllowSingleton);
66201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  };
67201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
68513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#ifndef NDEBUG
69731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Set whether the current thread to make IO calls.
70731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Threads start out in the *allowed* state.
71513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Returns the previous value.
72513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  static bool SetIOAllowed(bool allowed);
73731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
74731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Check whether the current thread is allowed to make IO calls,
75513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // and DCHECK if not.  See the block comment above the class for
76513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // a discussion of where to add these checks.
77731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  static void AssertIOAllowed();
78201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
79201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Set whether the current thread can use singletons.  Returns the previous
80201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // value.
81201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  static bool SetSingletonAllowed(bool allowed);
82201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
83201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Check whether the current thread is allowed to use singletons (Singleton /
84201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // LazyInstance).  DCHECKs if not.
85201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  static void AssertSingletonAllowed();
86513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#else
87513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // In Release builds, inline the empty definitions of these functions so
88513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // that they can be compiled out.
89513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  static bool SetIOAllowed(bool allowed) { return true; }
90513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  static void AssertIOAllowed() {}
91201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  static bool SetSingletonAllowed(bool allowed) { return true; }
92201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  static void AssertSingletonAllowed() {}
93513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#endif
94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick private:
96201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions);
97731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick};
98731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
99731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}  // namespace base
100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1013f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#endif  // BASE_THREADING_THREAD_RESTRICTIONS_H_
102