summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSpencer Jackson <spencer.jackson@mongodb.com>2019-02-07 14:24:58 -0500
committerSpencer Jackson <spencer.jackson@mongodb.com>2019-04-01 15:23:53 -0400
commitbfec2c3a4398477688a0fcffca35b838e1483a3b (patch)
treecf4e171f45be3bbb0a98d134daaa3b8ad50fc575
parent029336d07dd89eee17cfa090ca0b63f44883b485 (diff)
downloadmongo-bfec2c3a4398477688a0fcffca35b838e1483a3b.tar.gz
SERVER-38945: Cache OpenSSL error states to elide error clearing
(cherry picked from commit 9245a51842f1f8b9da42cadf27627642c4d94fd4)
-rw-r--r--src/mongo/util/net/ssl/detail/engine_openssl.hpp2
-rw-r--r--src/mongo/util/net/ssl/detail/impl/engine_openssl.ipp20
2 files changed, 21 insertions, 1 deletions
diff --git a/src/mongo/util/net/ssl/detail/engine_openssl.hpp b/src/mongo/util/net/ssl/detail/engine_openssl.hpp
index 5a98fe6c7a7..6f0f4afc54b 100644
--- a/src/mongo/util/net/ssl/detail/engine_openssl.hpp
+++ b/src/mongo/util/net/ssl/detail/engine_openssl.hpp
@@ -99,6 +99,8 @@ private:
ASIO_DECL static asio::detail::static_mutex& accept_mutex();
#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
+ ASIO_DECL void purge_error_state();
+
// Perform one operation. Returns >= 0 on success or error, want_read if the
// operation needs more input, or want_write if it needs to write some output
// before the operation can complete.
diff --git a/src/mongo/util/net/ssl/detail/impl/engine_openssl.ipp b/src/mongo/util/net/ssl/detail/impl/engine_openssl.ipp
index 92594883d75..01de79294b2 100644
--- a/src/mongo/util/net/ssl/detail/impl/engine_openssl.ipp
+++ b/src/mongo/util/net/ssl/detail/impl/engine_openssl.ipp
@@ -144,13 +144,31 @@ asio::detail::static_mutex& engine::accept_mutex() {
}
#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
+
+void engine::purge_error_state() {
+#if (OPENSSL_VERSION_NUMBER < 0x1010000fL)
+ // OpenSSL 1.1.0 introduced a thread local state storage mechanism.
+ // Versions prior sometimes had contention issues on global mutexes
+ // which protected thread local state.
+ // If we are compiled against a version without native thread local
+ // support, cache a pointer to this thread's error state, which we can
+ // access without contention. If that state requires no cleanup,
+ // we can avoid invoking OpenSSL's more expensive machinery.
+ const static thread_local ERR_STATE* es = ERR_get_state();
+ if (es->bottom == es->top) {
+ return;
+ }
+#endif // (OPENSSL_VERSION_NUMBER < 0x1010000fL)
+ ::ERR_clear_error();
+}
+
engine::want engine::perform(int (engine::*op)(void*, std::size_t),
void* data,
std::size_t length,
asio::error_code& ec,
std::size_t* bytes_transferred) {
std::size_t pending_output_before = ::BIO_ctrl_pending(ext_bio_);
- ::ERR_clear_error();
+ purge_error_state();
int result = (this->*op)(data, length);
int ssl_error = ::SSL_get_error(ssl_, result);
int sys_error = static_cast<int>(::ERR_get_error());