| 642 | return bool(self.capi.fdb_future_is_ready(self.fpointer)) |
| 643 | |
| 644 | def block_until_ready(self): |
| 645 | # Checking readiness is faster than using the callback, so it saves us time if we are already |
| 646 | # ready. It also doesn't add much to the cost of this function |
| 647 | if not self.is_ready(): |
| 648 | # Blocking in the native client from the main thread prevents Python from handling signals. |
| 649 | # To avoid that behavior, we implement the blocking in Python using semaphores and on_ready. |
| 650 | # Using a Semaphore is faster than an Event, and we create only one per thread to avoid the |
| 651 | # cost of creating one every time. |
| 652 | semaphore = getattr(_thread_local_storage, 'future_block_semaphore', None) |
| 653 | if semaphore is None: |
| 654 | semaphore = multiprocessing.Semaphore(0) |
| 655 | _thread_local_storage.future_block_semaphore = semaphore |
| 656 | |
| 657 | self.on_ready(lambda self: semaphore.release()) |
| 658 | |
| 659 | try: |
| 660 | semaphore.acquire() |
| 661 | except: |
| 662 | # If this semaphore didn't actually get released, then we need to replace our thread-local |
| 663 | # copy so that later callers still function correctly |
| 664 | _thread_local_storage.future_block_semaphore = multiprocessing.Semaphore(0) |
| 665 | raise |
| 666 | |
| 667 | def on_ready(self, callback): |
| 668 | def cb_and_delref(ignore): |