summaryrefslogtreecommitdiffstats
path: root/crypto/init.c
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2020-12-22 17:44:07 +0000
committerDmitry Belyavskiy <beldmit@gmail.com>2020-12-31 13:14:38 +0100
commitdb6bcc81ab86fca74730566f0b471a7c3757c95c (patch)
treea6c795f78a9c49dd99cd838ae3c6f76a9daa0b6c /crypto/init.c
parentd5e742de653954bfae88f0e5f6c8f0a7a5f6c437 (diff)
Optimise OPENSSL_init_crypto
If everything has already been initialised we can check this with a single test at the beginning of OPENSSL_init_crypto() and therefore reduce the amount of time spent in this function. Since this is called via very many codepaths this should have significant performance benefits. Partially fixes #13725 and #13578 Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com> (Merged from https://github.com/openssl/openssl/pull/13733)
Diffstat (limited to 'crypto/init.c')
-rw-r--r--crypto/init.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/crypto/init.c b/crypto/init.c
index f1100df169..50aec32c3d 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -34,6 +34,7 @@
#include <openssl/trace.h>
static int stopped = 0;
+static uint64_t optsdone = 0;
typedef struct ossl_init_stop_st OPENSSL_INIT_STOP;
struct ossl_init_stop_st {
@@ -464,6 +465,28 @@ void OPENSSL_cleanup(void)
*/
int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
{
+ uint64_t tmp;
+ int aloaddone = 0;
+
+ /*
+ * We ignore failures from this function. It is probably because we are
+ * on a platform that doesn't support lockless atomic loads (we may not
+ * have created init_lock yet so we can't use it). This is just an
+ * optimisation to skip the full checks in this function if we don't need
+ * to, so we carry on regardless in the event of failure.
+ *
+ * There could be a race here with other threads, so that optsdone has not
+ * been updated yet, even though the options have in fact been initialised.
+ * This doesn't matter - it just means we will run the full function
+ * unnecessarily - but all the critical code is contained in RUN_ONCE
+ * functions anyway so we are safe.
+ */
+ if (CRYPTO_atomic_load(&optsdone, &tmp, NULL)) {
+ if ((tmp & opts) == opts)
+ return 1;
+ aloaddone = 1;
+ }
+
/*
* TODO(3.0): This function needs looking at with a view to moving most/all
* of this into OSSL_LIB_CTX.
@@ -493,6 +516,18 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
return 1;
/*
+ * init_lock should definitely be set up now, so we can now repeat the
+ * same check from above but be sure that it will work even on platforms
+ * without lockless CRYPTO_atomic_load
+ */
+ if (!aloaddone) {
+ if (!CRYPTO_atomic_load(&optsdone, &tmp, init_lock))
+ return 0;
+ if ((tmp & opts) == opts)
+ return 1;
+ }
+
+ /*
* Now we don't always set up exit handlers, the INIT_BASE_ONLY calls
* should not have the side-effect of setting up exit handlers, and
* therefore, this code block is below the INIT_BASE_ONLY-conditioned early
@@ -614,6 +649,9 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
return 0;
#endif
+ if (!CRYPTO_atomic_or(&optsdone, opts, &tmp, init_lock))
+ return 0;
+
return 1;
}