mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #14533 -- Make django signals more thread-safe. Thanks milosu for the patch!
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14662 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		| @@ -1,4 +1,5 @@ | |||||||
| import weakref | import weakref | ||||||
|  | import threading | ||||||
|  |  | ||||||
| from django.dispatch import saferef | from django.dispatch import saferef | ||||||
|  |  | ||||||
| @@ -30,6 +31,7 @@ class Signal(object): | |||||||
|         if providing_args is None: |         if providing_args is None: | ||||||
|             providing_args = [] |             providing_args = [] | ||||||
|         self.providing_args = set(providing_args) |         self.providing_args = set(providing_args) | ||||||
|  |         self.lock = threading.Lock() | ||||||
|  |  | ||||||
|     def connect(self, receiver, sender=None, weak=True, dispatch_uid=None): |     def connect(self, receiver, sender=None, weak=True, dispatch_uid=None): | ||||||
|         """ |         """ | ||||||
| @@ -97,11 +99,15 @@ class Signal(object): | |||||||
|         if weak: |         if weak: | ||||||
|             receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver) |             receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver) | ||||||
|  |  | ||||||
|         for r_key, _ in self.receivers: |         try: | ||||||
|             if r_key == lookup_key: |             self.lock.acquire() | ||||||
|                 break |             for r_key, _ in self.receivers: | ||||||
|         else: |                 if r_key == lookup_key: | ||||||
|             self.receivers.append((lookup_key, receiver)) |                     break | ||||||
|  |             else: | ||||||
|  |                 self.receivers.append((lookup_key, receiver)) | ||||||
|  |         finally: | ||||||
|  |             self.lock.release() | ||||||
|  |  | ||||||
|     def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None): |     def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None): | ||||||
|         """ |         """ | ||||||
| @@ -130,11 +136,15 @@ class Signal(object): | |||||||
|         else: |         else: | ||||||
|             lookup_key = (_make_id(receiver), _make_id(sender)) |             lookup_key = (_make_id(receiver), _make_id(sender)) | ||||||
|          |          | ||||||
|         for index in xrange(len(self.receivers)): |         try: | ||||||
|             (r_key, _) = self.receivers[index] |             self.lock.acquire() | ||||||
|             if r_key == lookup_key: |             for index in xrange(len(self.receivers)): | ||||||
|                 del self.receivers[index] |                 (r_key, _) = self.receivers[index] | ||||||
|                 break |                 if r_key == lookup_key: | ||||||
|  |                     del self.receivers[index] | ||||||
|  |                     break | ||||||
|  |         finally: | ||||||
|  |             self.lock.release() | ||||||
|  |  | ||||||
|     def send(self, sender, **named): |     def send(self, sender, **named): | ||||||
|         """ |         """ | ||||||
| @@ -227,14 +237,21 @@ class Signal(object): | |||||||
|         Remove dead receivers from connections. |         Remove dead receivers from connections. | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         to_remove = [] |         try: | ||||||
|         for key, connected_receiver in self.receivers: |             self.lock.acquire() | ||||||
|             if connected_receiver == receiver: |             to_remove = [] | ||||||
|                 to_remove.append(key) |             for key, connected_receiver in self.receivers: | ||||||
|         for key in to_remove: |                 if connected_receiver == receiver: | ||||||
|             for idx, (r_key, _) in enumerate(self.receivers): |                     to_remove.append(key) | ||||||
|                 if r_key == key: |             for key in to_remove: | ||||||
|                     del self.receivers[idx] |                 last_idx = len(self.receivers) - 1 | ||||||
|  |                 # enumerate in reverse order so that indexes are valid even | ||||||
|  |                 # after we delete some items | ||||||
|  |                 for idx, (r_key, _) in enumerate(reversed(self.receivers)): | ||||||
|  |                     if r_key == key: | ||||||
|  |                         del self.receivers[last_idx-idx] | ||||||
|  |         finally: | ||||||
|  |             self.lock.release() | ||||||
|  |  | ||||||
|  |  | ||||||
| def receiver(signal, **kwargs): | def receiver(signal, **kwargs): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user