diff options
Diffstat (limited to 'absl/base/internal')
-rw-r--r-- | absl/base/internal/errno_saver.h | 43 | ||||
-rw-r--r-- | absl/base/internal/errno_saver_test.cc | 44 | ||||
-rw-r--r-- | absl/base/internal/spinlock_linux.inc | 5 | ||||
-rw-r--r-- | absl/base/internal/spinlock_posix.inc | 6 |
4 files changed, 92 insertions, 6 deletions
diff --git a/absl/base/internal/errno_saver.h b/absl/base/internal/errno_saver.h new file mode 100644 index 00000000..251de510 --- /dev/null +++ b/absl/base/internal/errno_saver.h @@ -0,0 +1,43 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed 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 +// +// https://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. + +#ifndef ABSL_BASE_INTERNAL_ERRNO_SAVER_H_ +#define ABSL_BASE_INTERNAL_ERRNO_SAVER_H_ + +#include <cerrno> + +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace base_internal { + +// `ErrnoSaver` captures the value of `errno` upon construction and restores it +// upon deletion. It is used in low-level code and must be super fast. Do not +// add instrumentation, even in debug modes. +class ErrnoSaver { + public: + ErrnoSaver() : saved_errno_(errno) {} + ~ErrnoSaver() { errno = saved_errno_; } + int operator()() const { return saved_errno_; } + + private: + const int saved_errno_; +}; + +} // namespace base_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_BASE_INTERNAL_ERRNO_SAVER_H_ diff --git a/absl/base/internal/errno_saver_test.cc b/absl/base/internal/errno_saver_test.cc new file mode 100644 index 00000000..b845e2dd --- /dev/null +++ b/absl/base/internal/errno_saver_test.cc @@ -0,0 +1,44 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed 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 +// +// https://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. + +#include "absl/base/internal/errno_saver.h" + +#include <cerrno> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace { +using ::testing::Eq; + +struct ErrnoPrinter { + int no; +}; +std::ostream &operator<<(std::ostream &os, ErrnoPrinter ep) { + return os << strerror(ep.no) << " [" << ep.no << "]"; +} +bool operator==(ErrnoPrinter one, ErrnoPrinter two) { return one.no == two.no; } + +TEST(ErrnoSaverTest, Works) { + errno = EDOM; + { + absl::base_internal::ErrnoSaver errno_saver; + EXPECT_THAT(ErrnoPrinter{errno}, Eq(ErrnoPrinter{EDOM})); + errno = ERANGE; + EXPECT_THAT(ErrnoPrinter{errno}, Eq(ErrnoPrinter{ERANGE})); + EXPECT_THAT(ErrnoPrinter{errno_saver()}, Eq(ErrnoPrinter{EDOM})); + } + EXPECT_THAT(ErrnoPrinter{errno}, Eq(ErrnoPrinter{EDOM})); +} +} // namespace diff --git a/absl/base/internal/spinlock_linux.inc b/absl/base/internal/spinlock_linux.inc index 28e29d19..323edd62 100644 --- a/absl/base/internal/spinlock_linux.inc +++ b/absl/base/internal/spinlock_linux.inc @@ -19,12 +19,12 @@ #include <unistd.h> #include <atomic> -#include <cerrno> #include <climits> #include <cstdint> #include <ctime> #include "absl/base/attributes.h" +#include "absl/base/internal/errno_saver.h" // The SpinLock lockword is `std::atomic<uint32_t>`. Here we assert that // `std::atomic<uint32_t>` is bitwise equivalent of the `int` expected @@ -51,12 +51,11 @@ extern "C" { ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( std::atomic<uint32_t> *w, uint32_t value, int loop, absl::base_internal::SchedulingMode) { - int save_errno = errno; + absl::base_internal::ErrnoSaver errno_saver; struct timespec tm; tm.tv_sec = 0; tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop); syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm); - errno = save_errno; } ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic<uint32_t> *w, diff --git a/absl/base/internal/spinlock_posix.inc b/absl/base/internal/spinlock_posix.inc index f025b5f8..fcd21b15 100644 --- a/absl/base/internal/spinlock_posix.inc +++ b/absl/base/internal/spinlock_posix.inc @@ -15,10 +15,11 @@ // This file is a Posix-specific part of spinlock_wait.cc #include <sched.h> + #include <atomic> #include <ctime> -#include <cerrno> +#include "absl/base/internal/errno_saver.h" #include "absl/base/internal/scheduling_mode.h" #include "absl/base/port.h" @@ -27,7 +28,7 @@ extern "C" { ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop, absl::base_internal::SchedulingMode /* mode */) { - int save_errno = errno; + absl::base_internal::ErrnoSaver errno_saver; if (loop == 0) { } else if (loop == 1) { sched_yield(); @@ -37,7 +38,6 @@ ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop); nanosleep(&tm, nullptr); } - errno = save_errno; } ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake( |