File: 823.diff

package info (click to toggle)
python-eventlet 0.40.1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 3,200 kB
  • sloc: python: 25,101; sh: 78; makefile: 31
file content (238 lines) | stat: -rw-r--r-- 8,463 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
Index: python-eventlet/eventlet/greenio/base.py
===================================================================
--- python-eventlet.orig/eventlet/greenio/base.py
+++ python-eventlet/eventlet/greenio/base.py
@@ -496,9 +496,16 @@ def shutdown_safe(sock):
 
     Regular sockets don't need a shutdown before close, but it doesn't hurt.
     """
+    from eventlet.green.ssl import GreenSSLSocket
+    if sys.version_info[:2] < (3, 8) and isinstance(sock, GreenSSLSocket):
+        try:
+            sock.unwrap()
+        except:
+            pass
+        return
     try:
         try:
-            # socket, ssl.SSLSocket
+            # socket, SSLSocket on Python 3.8+
             return sock.shutdown(socket.SHUT_RDWR)
         except TypeError:
             # SSL.Connection
Index: python-eventlet/eventlet/patcher.py
===================================================================
--- python-eventlet.orig/eventlet/patcher.py
+++ python-eventlet/eventlet/patcher.py
@@ -423,10 +423,143 @@ def _fix_py2_rlock(rlock, tid):
         rlock._RLock__owner = tid
 
 
+class _PyRLock:
+    """This class implements reentrant lock objects.
+
+    A reentrant lock must be released by the thread that acquired it.  Once a
+    thread has acquired a reentrant lock, the same thread may acquire it again
+    without blocking; the thread must release it once for each time it has
+    acquired it.
+
+    Copied from Python 3.11 and tweaked to work with eventlet, this code is
+    licensed under the PSF license.
+    """
+
+    import threading as _threading
+
+    def __init__(self):
+        from eventlet.green.threading import _allocate_lock
+        self._block = _allocate_lock()
+        self._owner = None
+        self._count = 0
+
+    def __repr__(self):
+        owner = self._owner
+        try:
+            owner = self._threading._active[owner].name
+        except KeyError:
+            pass
+        return "<%s %s.%s object owner=%r count=%d at %s>" % (
+            "locked" if self._block.locked() else "unlocked",
+            self.__class__.__module__,
+            self.__class__.__qualname__,
+            owner,
+            self._count,
+            hex(id(self))
+        )
+
+    def _at_fork_reinit(self):
+        self._block._at_fork_reinit()
+        self._owner = None
+        self._count = 0
+
+    def acquire(self, blocking=True, timeout=-1):
+        """Acquire a lock, blocking or non-blocking.
+
+        When invoked without arguments: if this thread already owns the lock,
+        increment the recursion level by one, and return immediately. Otherwise,
+        if another thread owns the lock, block until the lock is unlocked. Once
+        the lock is unlocked (not owned by any thread), then grab ownership, set
+        the recursion level to one, and return. If more than one thread is
+        blocked waiting until the lock is unlocked, only one at a time will be
+        able to grab ownership of the lock. There is no return value in this
+        case.
+
+        When invoked with the blocking argument set to true, do the same thing
+        as when called without arguments, and return true.
+
+        When invoked with the blocking argument set to false, do not block. If a
+        call without an argument would block, return false immediately;
+        otherwise, do the same thing as when called without arguments, and
+        return true.
+
+        When invoked with the floating-point timeout argument set to a positive
+        value, block for at most the number of seconds specified by timeout
+        and as long as the lock cannot be acquired.  Return true if the lock has
+        been acquired, false if the timeout has elapsed.
+
+        """
+        me = self._threading.get_ident()
+        if self._owner == me:
+            self._count += 1
+            return 1
+        rc = self._block.acquire(blocking, timeout)
+        if rc:
+            self._owner = me
+            self._count = 1
+        return rc
+
+    __enter__ = acquire
+
+    def release(self):
+        """Release a lock, decrementing the recursion level.
+
+        If after the decrement it is zero, reset the lock to unlocked (not owned
+        by any thread), and if any other threads are blocked waiting for the
+        lock to become unlocked, allow exactly one of them to proceed. If after
+        the decrement the recursion level is still nonzero, the lock remains
+        locked and owned by the calling thread.
+
+        Only call this method when the calling thread owns the lock. A
+        RuntimeError is raised if this method is called when the lock is
+        unlocked.
+
+        There is no return value.
+
+        """
+        # This breaks locks created by _fix_py3_rlock, so we comment it out:
+        #if self._owner != get_ident():
+        #    raise RuntimeError("cannot release un-acquired lock")
+        self._count = count = self._count - 1
+        if not count:
+            self._owner = None
+            self._block.release()
+
+    def __exit__(self, t, v, tb):
+        self.release()
+
+    # Internal methods used by condition variables
+
+    def _acquire_restore(self, state):
+        self._block.acquire()
+        self._count, self._owner = state
+
+    def _release_save(self):
+        if self._count == 0:
+            raise RuntimeError("cannot release un-acquired lock")
+        count = self._count
+        self._count = 0
+        owner = self._owner
+        self._owner = None
+        self._block.release()
+        return (count, owner)
+
+    def _is_owned(self):
+        return self._owner == self._threading.get_ident()
+
+    # Internal method used for reentrancy checks
+
+    def _recursion_count(self):
+        if self._owner != self._threading.get_ident():
+            return 0
+        return self._count
+
+
 def _fix_py3_rlock(old):
     import gc
-    import threading
-    new = threading._PyRLock()
+    # On 3.11 and presumably later the _PyRLock class is no longer compatible
+    # with eventlet, so use a patched copy.
+    new = _PyRLock()
     while old._is_owned():
         old.release()
         new.acquire()
@@ -434,6 +567,16 @@ def _fix_py3_rlock(old):
         new.acquire()
     gc.collect()
     for ref in gc.get_referrers(old):
+        if isinstance(ref, dict):
+            for k, v in list(ref.items()):
+                if v is old:
+                    ref[k] = new
+            continue
+        if isinstance(ref, list):
+            for i, v in enumerate(ref):
+                if v is old:
+                    ref[i] = new
+            continue
         try:
             ref_vars = vars(ref)
         except TypeError:
Index: python-eventlet/tests/api_test.py
===================================================================
--- python-eventlet.orig/tests/api_test.py
+++ python-eventlet/tests/api_test.py
@@ -1,3 +1,5 @@
+import sys
+
 import eventlet
 from eventlet import greenio, hubs, greenthread
 from eventlet.green import ssl
Index: python-eventlet/tests/ssl_test.py
===================================================================
--- python-eventlet.orig/tests/ssl_test.py
+++ python-eventlet/tests/ssl_test.py
@@ -2,6 +2,7 @@ import contextlib
 import random
 import socket
 import sys
+from unittest import SkipTest
 import warnings
 
 import eventlet
@@ -208,6 +209,12 @@ class SSLTest(tests.LimitedTestCase):
         server_coro.kill()
 
     def test_greensslobject(self):
+        if sys.version_info[:2] < (3, 8):
+            raise SkipTest(
+                "This only passes on Python 3.8 and later "
+                "but since 3.7 is end-of-life it doesn't seem worth fixing..."
+            )
+
         def serve(listener):
             sock, addr = listener.accept()
             sock.sendall(b'content')
Index: python-eventlet/tests/wsgi_test.py
===================================================================
--- python-eventlet.orig/tests/wsgi_test.py
+++ python-eventlet/tests/wsgi_test.py
@@ -565,6 +565,9 @@ class TestHttpd(_TestBase):
                 client_socket, addr = sock.accept()
                 serv.process_request([addr, client_socket, wsgi.STATE_IDLE])
                 return True
+            except (ssl.SSLZeroReturnError, ssl.SSLEOFError):
+                # Can't write a response to a closed TLS session
+                return True
             except Exception:
                 traceback.print_exc()
                 return False