Author: Amaury Forgeot d'Arc <[email protected]>
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
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit