From d9c0bf9f2dde3955ef6feef7102f255a9aa610b5 Mon Sep 17 00:00:00 2001 From: Ludovic Rousseau Date: Sat, 19 Oct 2024 13:07:12 +0200 Subject: [PATCH] PCSCCardRequest: use a local PC/SC context to avoid locks SCardGetStatusChange() should not be called from the same PC/SC context used by all the other PC/SC functions. Because of a mutex in pcsc-lite the calls using the same context are exclusive. So the performances were bad. The problem was discovered by the framework testsuite that was running very slow on GNU/Linux (but not on Windows or macOS). --- src/smartcard/pcsc/PCSCCardRequest.py | 29 ++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/smartcard/pcsc/PCSCCardRequest.py b/src/smartcard/pcsc/PCSCCardRequest.py index 5b0f18f9..45c73221 100644 --- a/src/smartcard/pcsc/PCSCCardRequest.py +++ b/src/smartcard/pcsc/PCSCCardRequest.py @@ -32,7 +32,10 @@ CardRequestTimeoutException, ListReadersException, ) -from smartcard.pcsc.PCSCContext import PCSCContext +from smartcard.pcsc.PCSCExceptions import ( + EstablishContextException, + ReleaseContextException, +) from smartcard.pcsc.PCSCReader import PCSCReader from smartcard.scard import * @@ -79,24 +82,36 @@ def __init__( else: self.timeout = int(self.timeout * 1000) - self.hcontext = PCSCContext().getContext() + hresult, self.hcontext = SCardEstablishContext(SCARD_SCOPE_USER) + if hresult != SCARD_S_SUCCESS: + raise EstablishContextException(hresult) self.evt = threading.Event() self.hresult = SCARD_S_SUCCESS self.readerstates = {} self.newstates = [] self.timeout_init = self.timeout + def __del__(self): + hresult = SCardReleaseContext(self.hcontext) + if hresult != SCARD_S_SUCCESS: + raise ReleaseContextException(hresult) + self.hcontext = -1 + def getReaderNames(self): """Returns the list of PCSC readers on which to wait for cards.""" - # renew the context in case PC/SC was stopped - # this happens on Windows when the last reader is disconnected - self.hcontext = PCSCContext().getContext() - # get inserted readers hresult, pcscreaders = SCardListReaders(self.hcontext, []) + + # renew the context in case PC/SC was stopped + # this happens on Windows when the last reader is disconnected if hresult in (SCARD_E_SERVICE_STOPPED, SCARD_E_NO_SERVICE): - self.hcontext = PCSCContext().renewContext() + hresult = SCardReleaseContext(self.hcontext) + if hresult != SCARD_S_SUCCESS: + raise ReleaseContextException(hresult) + hresult, self.hcontext = SCardEstablishContext(SCARD_SCOPE_USER) + if hresult != SCARD_S_SUCCESS: + raise EstablishContextException(hresult) hresult, pcscreaders = SCardListReaders(self.hcontext, []) if SCARD_E_NO_READERS_AVAILABLE == hresult: return []