# HG changeset patch # User Daiki Ueno # Date 1521731296 -3600 # Thu Mar 22 16:08:16 2018 +0100 # Node ID 6ae3ab8a1e7b4161f3f8eee90db7a745acced408 # Parent dedf5290c679153e5b3555ba9c711fe62323c156 Bug 1447628, devslot: avoid deadlock when re-inserting a token, r=rrelyea diff --git a/lib/dev/devslot.c b/lib/dev/devslot.c --- a/lib/dev/devslot.c +++ b/lib/dev/devslot.c @@ -96,10 +96,16 @@ nssSlot_ResetDelay( } static PRBool -within_token_delay_period(const NSSSlot *slot) +token_status_checked(const NSSSlot *slot) { PRIntervalTime time; int lastPingState = slot->lastTokenPingState; + /* When called from the same thread, that means + * nssSlot_IsTokenPresent() is called recursively through + * nssSlot_Refresh(). Return immediately in that case. */ + if (slot->isPresentThread == PR_GetCurrentThread()) { + return PR_TRUE; + } /* Set the delay time for checking the token presence */ if (s_token_delay_time == 0) { s_token_delay_time = PR_SecondsToInterval(NSSSLOT_TOKEN_DELAY_TIME); @@ -130,7 +136,7 @@ nssSlot_IsTokenPresent( /* avoid repeated calls to check token status within set interval */ PZ_Lock(slot->isPresentLock); - if (within_token_delay_period(slot)) { + if (token_status_checked(slot)) { CK_FLAGS ckFlags = slot->ckFlags; PZ_Unlock(slot->isPresentLock); return ((ckFlags & CKF_TOKEN_PRESENT) != 0); @@ -146,12 +152,12 @@ nssSlot_IsTokenPresent( /* set up condition so only one thread is active in this part of the code at a time */ PZ_Lock(slot->isPresentLock); - while (slot->inIsPresent) { + while (slot->isPresentThread) { PR_WaitCondVar(slot->isPresentCondition, 0); } /* if we were one of multiple threads here, the first thread will have * given us the answer, no need to make more queries of the token. */ - if (within_token_delay_period(slot)) { + if (token_status_checked(slot)) { CK_FLAGS ckFlags = slot->ckFlags; PZ_Unlock(slot->isPresentLock); return ((ckFlags & CKF_TOKEN_PRESENT) != 0); @@ -159,7 +165,7 @@ nssSlot_IsTokenPresent( /* this is the winning thread, block all others until we've determined * if the token is present and that it needs initialization. */ slot->lastTokenPingState = nssSlotLastPingState_Update; - slot->inIsPresent = PR_TRUE; + slot->isPresentThread = PR_GetCurrentThread(); PZ_Unlock(slot->isPresentLock); @@ -257,7 +263,7 @@ done: slot->lastTokenPingTime = PR_IntervalNow(); slot->lastTokenPingState = nssSlotLastPingState_Valid; } - slot->inIsPresent = PR_FALSE; + slot->isPresentThread = NULL; PR_NotifyAllCondVar(slot->isPresentCondition); PZ_Unlock(slot->isPresentLock); return isPresent; diff --git a/lib/dev/devt.h b/lib/dev/devt.h --- a/lib/dev/devt.h +++ b/lib/dev/devt.h @@ -92,7 +92,7 @@ struct NSSSlotStr { PK11SlotInfo *pk11slot; PZLock *isPresentLock; PRCondVar *isPresentCondition; - PRBool inIsPresent; + PRThread *isPresentThread; }; struct nssSessionStr { diff --git a/lib/pk11wrap/dev3hack.c b/lib/pk11wrap/dev3hack.c --- a/lib/pk11wrap/dev3hack.c +++ b/lib/pk11wrap/dev3hack.c @@ -122,7 +122,7 @@ nssSlot_CreateFromPK11SlotInfo(NSSTrustD rvSlot->lock = (nss3slot->isThreadSafe) ? NULL : nss3slot->sessionLock; rvSlot->isPresentLock = PZ_NewLock(nssiLockOther); rvSlot->isPresentCondition = PR_NewCondVar(rvSlot->isPresentLock); - rvSlot->inIsPresent = PR_FALSE; + rvSlot->isPresentThread = NULL; rvSlot->lastTokenPingState = nssSlotLastPingState_Reset; return rvSlot; }