forked from pool/openssl
86 lines
2.5 KiB
Diff
86 lines
2.5 KiB
Diff
|
From d8afda60a991791f27cfac79186b1f8a4f4e30a0 Mon Sep 17 00:00:00 2001
|
||
|
From: Geoff Thorpe <geoff@openssl.org>
|
||
|
Date: Sun, 4 May 2014 16:19:22 -0400
|
||
|
Subject: [PATCH 22/23] bignum: allow concurrent BN_MONT_CTX_set_locked()
|
||
|
|
||
|
The lazy-initialisation of BN_MONT_CTX was serialising all threads, as
|
||
|
noted by Daniel Sands and co at Sandia. This was to handle the case that
|
||
|
2 or more threads race to lazy-init the same context, but stunted all
|
||
|
scalability in the case where 2 or more threads are doing unrelated
|
||
|
things! We favour the latter case by punishing the former. The init work
|
||
|
gets done by each thread that finds the context to be uninitialised, and
|
||
|
we then lock the "set" logic after that work is done - the winning
|
||
|
thread's work gets used, the losing threads throw away what they've done.
|
||
|
|
||
|
Signed-off-by: Geoff Thorpe <geoff@openssl.org>
|
||
|
---
|
||
|
crypto/bn/bn_mont.c | 46 ++++++++++++++++++++++++++--------------------
|
||
|
1 file changed, 26 insertions(+), 20 deletions(-)
|
||
|
|
||
|
diff --git a/crypto/bn/bn_mont.c b/crypto/bn/bn_mont.c
|
||
|
index 427b5cf..ee8532c 100644
|
||
|
--- a/crypto/bn/bn_mont.c
|
||
|
+++ b/crypto/bn/bn_mont.c
|
||
|
@@ -478,32 +478,38 @@ BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from)
|
||
|
BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, int lock,
|
||
|
const BIGNUM *mod, BN_CTX *ctx)
|
||
|
{
|
||
|
- int got_write_lock = 0;
|
||
|
BN_MONT_CTX *ret;
|
||
|
|
||
|
CRYPTO_r_lock(lock);
|
||
|
- if (!*pmont)
|
||
|
+ ret = *pmont;
|
||
|
+ CRYPTO_r_unlock(lock);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ /* We don't want to serialise globally while doing our lazy-init math in
|
||
|
+ * BN_MONT_CTX_set. That punishes threads that are doing independent
|
||
|
+ * things. Instead, punish the case where more than one thread tries to
|
||
|
+ * lazy-init the same 'pmont', by having each do the lazy-init math work
|
||
|
+ * independently and only use the one from the thread that wins the race
|
||
|
+ * (the losers throw away the work they've done). */
|
||
|
+ ret = BN_MONT_CTX_new();
|
||
|
+ if (!ret)
|
||
|
+ return NULL;
|
||
|
+ if (!BN_MONT_CTX_set(ret, mod, ctx))
|
||
|
{
|
||
|
- CRYPTO_r_unlock(lock);
|
||
|
- CRYPTO_w_lock(lock);
|
||
|
- got_write_lock = 1;
|
||
|
+ BN_MONT_CTX_free(ret);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
|
||
|
- if (!*pmont)
|
||
|
- {
|
||
|
- ret = BN_MONT_CTX_new();
|
||
|
- if (ret && !BN_MONT_CTX_set(ret, mod, ctx))
|
||
|
- BN_MONT_CTX_free(ret);
|
||
|
- else
|
||
|
- *pmont = ret;
|
||
|
- }
|
||
|
+ /* The locked compare-and-set, after the local work is done. */
|
||
|
+ CRYPTO_w_lock(lock);
|
||
|
+ if (*pmont)
|
||
|
+ {
|
||
|
+ BN_MONT_CTX_free(ret);
|
||
|
+ ret = *pmont;
|
||
|
}
|
||
|
-
|
||
|
- ret = *pmont;
|
||
|
-
|
||
|
- if (got_write_lock)
|
||
|
- CRYPTO_w_unlock(lock);
|
||
|
else
|
||
|
- CRYPTO_r_unlock(lock);
|
||
|
-
|
||
|
+ *pmont = ret;
|
||
|
+ CRYPTO_w_unlock(lock);
|
||
|
return ret;
|
||
|
}
|
||
|
--
|
||
|
1.8.4.5
|
||
|
|