| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| // Some portions: Copyright (c) 2012, The Chromium Authors. |
| #ifndef KUDU_UTIL_THREAD_RESTRICTIONS_H |
| #define KUDU_UTIL_THREAD_RESTRICTIONS_H |
| |
| #include "kudu/gutil/macros.h" |
| |
| #ifndef NDEBUG |
| #define ENABLE_THREAD_RESTRICTIONS 1 |
| #endif |
| |
| namespace kudu { |
| |
| // Certain behavior is disallowed on certain threads. ThreadRestrictions helps |
| // enforce these rules. Examples of such rules: |
| // |
| // * Do not do blocking IO |
| // * Do not wait on synchronization variables or sleep |
| // |
| // Here's more about how the protection works: |
| // |
| // 1) If a thread should not be allowed to make IO calls, mark it: |
| // ThreadRestrictions::SetIOAllowed(false); |
| // By default, threads *are* allowed to make IO calls. |
| // In particular, threads like RPC reactors should never do blocking IO |
| // because it may stall other unrelated requests. |
| // |
| // 2) If a function makes a call that will go out to disk, check whether the |
| // current thread is allowed: |
| // ThreadRestrictions::AssertIOAllowed(); |
| // |
| // |
| // Style tip: where should you put AssertIOAllowed checks? It's best |
| // if you put them as close to the disk access as possible, at the |
| // lowest level. This rule is simple to follow and helps catch all |
| // callers. For example, if your function GoDoSomeBlockingDiskCall() |
| // only calls other functions in Kudu and doesn't access the underlying |
| // disk, you should go add the AssertIOAllowed checks in the helper functions. |
| class ThreadRestrictions { |
| public: |
| // Constructing a ScopedAllowIO temporarily allows IO for the current |
| // thread. Doing this is almost certainly always incorrect, but sometimes |
| // it makes more sense to allow an exception and file a bug in the backlog |
| // to improve it later. |
| class ScopedAllowIO { |
| public: |
| ScopedAllowIO() { previous_value_ = SetIOAllowed(true); } |
| ~ScopedAllowIO() { SetIOAllowed(previous_value_); } |
| private: |
| // Whether IO is allowed when the ScopedAllowIO was constructed. |
| bool previous_value_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO); |
| }; |
| |
| // Constructing a ScopedAllowWait temporarily allows waiting on the current |
| // thread. Doing this is almost always incorrect: consider carefully whether |
| // you should instead be deferring work to a different thread. |
| class ScopedAllowWait { |
| public: |
| ScopedAllowWait() { previous_value_ = SetWaitAllowed(true); } |
| ~ScopedAllowWait() { SetWaitAllowed(previous_value_); } |
| private: |
| // Whether singleton use is allowed when the ScopedAllowWait was |
| // constructed. |
| bool previous_value_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedAllowWait); |
| }; |
| |
| |
| #if ENABLE_THREAD_RESTRICTIONS |
| // Set whether the current thread to make IO calls. |
| // Threads start out in the *allowed* state. |
| // Returns the previous value. |
| static bool SetIOAllowed(bool allowed); |
| |
| // Check whether the current thread is allowed to make IO calls, |
| // and FATALs if not. See the block comment above the class for |
| // a discussion of where to add these checks. |
| static void AssertIOAllowed(); |
| |
| // Set whether the current thread may wait/block. Returns the previous |
| // value. |
| static bool SetWaitAllowed(bool allowed); |
| |
| // Check whether the current thread is allowed to wait/block. |
| // FATALs if not. |
| static void AssertWaitAllowed(); |
| #else |
| // Inline the empty definitions of these functions so that they can be |
| // compiled out. |
| static bool SetIOAllowed(bool allowed) { return true; } |
| static void AssertIOAllowed() {} |
| static bool SetWaitAllowed(bool allowed) { return true; } |
| static void AssertWaitAllowed() {} |
| #endif |
| |
| private: |
| DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions); |
| }; |
| |
| } // namespace kudu |
| |
| #endif /* KUDU_UTIL_THREAD_RESTRICTIONS_H */ |