Author: Amaury Forgeot d'Arc <amaur...@gmail.com> Branch: Changeset: r44092:007178224553 Date: 2011-05-12 08:06 +0200 http://bitbucket.org/pypy/pypy/changeset/007178224553/
Log: Some openssl functions update global state, add the necessary locks to make them thread-safe. diff --git a/lib-python/modified-2.7/test/test_ssl.py b/lib-python/modified-2.7/test/test_ssl.py --- a/lib-python/modified-2.7/test/test_ssl.py +++ b/lib-python/modified-2.7/test/test_ssl.py @@ -839,6 +839,8 @@ c = socket.socket() c.connect((HOST, port)) listener_gone.wait() + # XXX why is it necessary? + test_support.gc_collect() try: ssl_sock = ssl.wrap_socket(c) except IOError: diff --git a/pypy/module/_ssl/__init__.py b/pypy/module/_ssl/__init__.py --- a/pypy/module/_ssl/__init__.py +++ b/pypy/module/_ssl/__init__.py @@ -31,3 +31,5 @@ def startup(self, space): from pypy.rlib.ropenssl import init_ssl init_ssl() + from pypy.module._ssl.interp_ssl import setup_ssl_threads + setup_ssl_threads() diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -873,3 +873,37 @@ finally: libssl_BIO_free(cert) +# this function is needed to perform locking on shared data +# structures. (Note that OpenSSL uses a number of global data +# structures that will be implicitly shared whenever multiple threads +# use OpenSSL.) Multi-threaded applications will crash at random if +# it is not set. +# +# locking_function() must be able to handle up to CRYPTO_num_locks() +# different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and +# releases it otherwise. +# +# filename and line are the file number of the function setting the +# lock. They can be useful for debugging. +_ssl_locks = [] + +def _ssl_thread_locking_function(mode, n, filename, line): + n = intmask(n) + if n < 0 or n >= len(_ssl_locks): + return + + if intmask(mode) & CRYPTO_LOCK: + _ssl_locks[n].acquire(True) + else: + _ssl_locks[n].release() + +def _ssl_thread_id_function(): + from pypy.module.thread import ll_thread + return ll_thread.get_ident() + +def setup_ssl_threads(): + from pypy.module.thread import ll_thread + for i in range(libssl_CRYPTO_num_locks()): + _ssl_locks.append(ll_thread.allocate_lock()) + libssl_CRYPTO_set_locking_callback(_ssl_thread_locking_function) + libssl_CRYPTO_set_id_callback(_ssl_thread_id_function) diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -86,6 +86,8 @@ NID_subject_alt_name = rffi_platform.ConstantInteger("NID_subject_alt_name") GEN_DIRNAME = rffi_platform.ConstantInteger("GEN_DIRNAME") + CRYPTO_LOCK = rffi_platform.ConstantInteger("CRYPTO_LOCK") + # Some structures, with only the fields used in the _ssl module X509_name_entry_st = rffi_platform.Struct('struct X509_name_entry_st', [('set', rffi.INT)]) @@ -142,6 +144,15 @@ ssl_external('SSL_load_error_strings', [], lltype.Void) ssl_external('SSL_library_init', [], rffi.INT) +ssl_external('CRYPTO_num_locks', [], rffi.INT) +ssl_external('CRYPTO_set_locking_callback', + [lltype.Ptr(lltype.FuncType( + [rffi.INT, rffi.INT, rffi.CCHARP, rffi.INT], lltype.Void))], + lltype.Void) +ssl_external('CRYPTO_set_id_callback', + [lltype.Ptr(lltype.FuncType([], rffi.INT))], + lltype.Void) + if HAVE_OPENSSL_RAND: ssl_external('RAND_add', [rffi.CCHARP, rffi.INT, rffi.DOUBLE], lltype.Void) ssl_external('RAND_status', [], rffi.INT) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit