blob: 23f0cd52a111a7821ced0d7112f40d4e1c3f277a [file] [log] [blame]
// 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 */