| 92 | }}} |
| 93 | |
| 94 | == Lock handling == |
| 95 | |
| 96 | Locks should always be acquired in exception-safe manner, otherwise the system will deadlock when an exception is raised while a lock is held. |
| 97 | |
| 98 | Consider the following example (#11193): |
| 99 | |
| 100 | '''WRONG''' |
| 101 | {{{ |
| 102 | if self._request_middleware is None: |
| 103 | self.initLock.acquire() |
| 104 | # Check that middleware is still uninitialised. |
| 105 | if self._request_middleware is None: |
| 106 | self.load_middleware() |
| 107 | self.initLock.release() |
| 108 | }}} |
| 109 | |
| 110 | This will deadlock when `self.load_middleware()` raises an exception (the lock will never be released). |
| 111 | |
| 112 | '''RIGHT''' |
| 113 | {{{ |
| 114 | if self._request_middleware is None: |
| 115 | self.initLock.acquire() |
| 116 | try: |
| 117 | # Check that middleware is still uninitialised. |
| 118 | if self._request_middleware is None: |
| 119 | self.load_middleware() |
| 120 | except: |
| 121 | # possibly unload whatever middleware didn't fail here |
| 122 | # set the guard back to uninitialized state |
| 123 | self._request_middleware = None |
| 124 | raise |
| 125 | finally: |
| 126 | self.initLock.release() |