about summary refs log tree commit diff
path: root/absl/base
diff options
context:
space:
mode:
Diffstat (limited to 'absl/base')
-rw-r--r--absl/base/BUILD.bazel24
-rw-r--r--absl/base/CMakeLists.txt25
-rw-r--r--absl/base/attributes.h2
-rw-r--r--absl/base/internal/errno_saver.h43
-rw-r--r--absl/base/internal/errno_saver_test.cc44
-rw-r--r--absl/base/internal/spinlock_linux.inc5
-rw-r--r--absl/base/internal/spinlock_posix.inc6
7 files changed, 142 insertions, 7 deletions
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index c6948a272f35..bae79427ac4e 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -41,6 +41,17 @@ cc_library(
 )
 
 cc_library(
+    name = "errno_saver",
+    hdrs = ["internal/errno_saver.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [":config"],
+)
+
+cc_library(
     name = "log_severity",
     srcs = ["log_severity.cc"],
     hdrs = ["log_severity.h"],
@@ -87,6 +98,7 @@ cc_library(
     deps = [
         ":base_internal",
         ":core_headers",
+        ":errno_saver",
     ],
 )
 
@@ -287,6 +299,18 @@ cc_test(
     ],
 )
 
+cc_test(
+    name = "errno_saver_test",
+    size = "small",
+    srcs = ["internal/errno_saver_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":errno_saver",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
 cc_library(
     name = "exception_testing",
     testonly = 1,
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index c21571be9b8c..14c52eabdfb3 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -30,6 +30,17 @@ absl_cc_library(
 
 absl_cc_library(
   NAME
+    errno_saver
+  HDRS
+    "internal/errno_saver.h"
+  DEPS
+    absl::config
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+)
+
+absl_cc_library(
+  NAME
     log_severity
   HDRS
     "log_severity.h"
@@ -73,6 +84,7 @@ absl_cc_library(
   DEPS
     absl::base_internal
     absl::core_headers
+    absl::errno_saver
 )
 
 absl_cc_library(
@@ -307,6 +319,19 @@ absl_cc_test(
 
 absl_cc_test(
   NAME
+    errno_saver_test
+  SRCS
+    "internal/errno_saver_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::errno_saver
+    gmock
+    gtest_main
+)
+
+absl_cc_test(
+  NAME
     throw_delegate_test
   SRCS
     "throw_delegate_test.cc"
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index 8f77db77d23a..ff138629d1f1 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -575,7 +575,7 @@
 // When applying ABSL_ATTRIBUTE_PACKED only to specific structure members the
 // natural alignment of structure members not annotated is preserved. Aligned
 // member accesses are faster than non-aligned member accesses even if the
-// targeted microprosessor supports non-aligned accesses.
+// targeted microprocessor supports non-aligned accesses.
 #if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
 #define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__))
 #else
diff --git a/absl/base/internal/errno_saver.h b/absl/base/internal/errno_saver.h
new file mode 100644
index 000000000000..251de510fc93
--- /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 000000000000..b845e2dd1a0f
--- /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 28e29d191909..323edd62f464 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 f025b5f8a373..fcd21b151b6e 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(