rwlocker 3.1__tar.gz → 3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rwlocker-3.1/rwlocker.egg-info → rwlocker-3.2}/PKG-INFO +1 -11
- {rwlocker-3.1 → rwlocker-3.2}/README-pypi.md +0 -10
- {rwlocker-3.1 → rwlocker-3.2}/pyproject.toml +1 -1
- {rwlocker-3.1 → rwlocker-3.2}/rwlocker/__init__.py +1 -1
- {rwlocker-3.1 → rwlocker-3.2}/rwlocker/async_rwlock.py +285 -13
- {rwlocker-3.1 → rwlocker-3.2}/rwlocker/thread_rwlock.py +290 -22
- {rwlocker-3.1 → rwlocker-3.2/rwlocker.egg-info}/PKG-INFO +1 -11
- {rwlocker-3.1 → rwlocker-3.2}/rwlocker.egg-info/SOURCES.txt +0 -1
- rwlocker-3.1/rwlocker/mixins.py +0 -305
- {rwlocker-3.1 → rwlocker-3.2}/LICENSE +0 -0
- {rwlocker-3.1 → rwlocker-3.2}/MANIFEST.in +0 -0
- {rwlocker-3.1 → rwlocker-3.2}/rwlocker.egg-info/dependency_links.txt +0 -0
- {rwlocker-3.1 → rwlocker-3.2}/rwlocker.egg-info/top_level.txt +0 -0
- {rwlocker-3.1 → rwlocker-3.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rwlocker
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2
|
|
4
4
|
Summary: Advanced, High-Performance, and State-Machine Based Synchronous/Asynchronous Read-Write Locks.
|
|
5
5
|
Author-email: TahsinCr <TahsinCrs@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -486,13 +486,3 @@ Email: TahsinCrs@gmail.com
|
|
|
486
486
|
[linkedin-url]: https://linkedin.com/in/TahsinCr
|
|
487
487
|
|
|
488
488
|
[x-url]: https://twitter.com/TahsinCrs
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
<!-- File URL -->
|
|
493
|
-
|
|
494
|
-
[lang-tr-url]: https://github.com/TahsinCr/python-rwlocker/blob/main/README_tr.md
|
|
495
|
-
|
|
496
|
-
[lang-en-url]: https://github.com/TahsinCr/python-rwlocker/blob/main/README.md
|
|
497
|
-
|
|
498
|
-
[lang-ru-url]: https://github.com/TahsinCr/python-rwlocker/blob/main/README_ru.md
|
|
@@ -457,13 +457,3 @@ Email: TahsinCrs@gmail.com
|
|
|
457
457
|
[linkedin-url]: https://linkedin.com/in/TahsinCr
|
|
458
458
|
|
|
459
459
|
[x-url]: https://twitter.com/TahsinCrs
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
<!-- File URL -->
|
|
464
|
-
|
|
465
|
-
[lang-tr-url]: https://github.com/TahsinCr/python-rwlocker/blob/main/README_tr.md
|
|
466
|
-
|
|
467
|
-
[lang-en-url]: https://github.com/TahsinCr/python-rwlocker/blob/main/README.md
|
|
468
|
-
|
|
469
|
-
[lang-ru-url]: https://github.com/TahsinCr/python-rwlocker/blob/main/README_ru.md
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rwlocker"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.2"
|
|
8
8
|
description = "Advanced, High-Performance, and State-Machine Based Synchronous/Asynchronous Read-Write Locks."
|
|
9
9
|
readme = {file = "README-pypi.md", content-type = "text/markdown"}
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -37,10 +37,9 @@ from collections import deque
|
|
|
37
37
|
from abc import ABC, abstractmethod
|
|
38
38
|
from typing import Callable, Protocol, Optional
|
|
39
39
|
from types import TracebackType
|
|
40
|
+
import weakref
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
__version__ = '3.1'
|
|
42
|
+
__version__ = '3.2'
|
|
44
43
|
__all__ = (
|
|
45
44
|
'AsyncLockable', 'AsyncLockDowngradable', 'AsyncRWLockBase', 'AsyncRWLockWithProxyBase',
|
|
46
45
|
'AsyncRWLockProxy', 'AsyncRWLockReaderProxy', 'AsyncRWLockWriterProxy',
|
|
@@ -280,7 +279,7 @@ class AsyncRWLockWriterProxy(AsyncRWLockProxy):
|
|
|
280
279
|
)
|
|
281
280
|
self._read_lock = rwlock.read
|
|
282
281
|
self._downgrade_core = rwlock._downgrade_core
|
|
283
|
-
self._downgraded_tasks:
|
|
282
|
+
self._downgraded_tasks:weakref.WeakSet[asyncio.Task] = weakref.WeakSet()
|
|
284
283
|
|
|
285
284
|
def downgrade(self):
|
|
286
285
|
"""
|
|
@@ -311,7 +310,7 @@ class AsyncRWLockWriterProxy(AsyncRWLockProxy):
|
|
|
311
310
|
self._release_core()
|
|
312
311
|
|
|
313
312
|
# Read and Write Lock
|
|
314
|
-
class AsyncRWLockWrite(
|
|
313
|
+
class AsyncRWLockWrite(AsyncRWLockWithProxyBase):
|
|
315
314
|
"""
|
|
316
315
|
Write-preferring Asynchronous Read-Write Lock.
|
|
317
316
|
|
|
@@ -347,8 +346,55 @@ class AsyncRWLockWrite(mixins._RWLockWriteMixin, AsyncRWLockWithProxyBase):
|
|
|
347
346
|
super().__init__()
|
|
348
347
|
self._writer_active = False
|
|
349
348
|
self._readers_active = 0
|
|
349
|
+
|
|
350
|
+
def _can_read(self) -> bool:
|
|
351
|
+
return not self._writer_active and self.write.those_waiting == 0
|
|
352
|
+
|
|
353
|
+
def _acquire_read_core(self):
|
|
354
|
+
self._readers_active += 1
|
|
355
|
+
|
|
356
|
+
def _release_read_core(self):
|
|
357
|
+
if self._readers_active == 0:
|
|
358
|
+
raise RuntimeError("Unacquired read lock")
|
|
359
|
+
self._readers_active -= 1
|
|
360
|
+
if self._readers_active == 0:
|
|
361
|
+
self.write.condition.notify()
|
|
362
|
+
|
|
363
|
+
def _on_reader_abort(self):
|
|
364
|
+
pass
|
|
365
|
+
|
|
366
|
+
def _can_write(self) -> bool:
|
|
367
|
+
return not self._writer_active and self._readers_active == 0
|
|
368
|
+
|
|
369
|
+
def _acquire_write_core(self):
|
|
370
|
+
self._writer_active = True
|
|
371
|
+
|
|
372
|
+
def _release_write_core(self):
|
|
373
|
+
if not self._writer_active:
|
|
374
|
+
raise RuntimeError("Unacquired write lock")
|
|
375
|
+
self._writer_active = False
|
|
376
|
+
self._on_writer_abort()
|
|
377
|
+
|
|
378
|
+
def _downgrade_core(self):
|
|
379
|
+
if not self._writer_active:
|
|
380
|
+
raise RuntimeError("Cannot downgrade unlocked lock")
|
|
381
|
+
self._writer_active = False
|
|
382
|
+
self._readers_active += 1
|
|
383
|
+
self.read.condition.notify_all()
|
|
384
|
+
|
|
385
|
+
def _on_writer_abort(self):
|
|
386
|
+
if self.write.those_waiting > 0:
|
|
387
|
+
self.write.condition.notify()
|
|
388
|
+
else:
|
|
389
|
+
self.read.condition.notify_all()
|
|
390
|
+
|
|
391
|
+
def _is_write_locked(self) -> bool:
|
|
392
|
+
return self._writer_active
|
|
393
|
+
|
|
394
|
+
def _is_read_locked(self) -> bool:
|
|
395
|
+
return self._readers_active > 0
|
|
350
396
|
|
|
351
|
-
class AsyncRWLockWriteReentrantWriter(
|
|
397
|
+
class AsyncRWLockWriteReentrantWriter(AsyncRWLockWrite):
|
|
352
398
|
"""
|
|
353
399
|
Write-preferring Asynchronous Read-Write Lock with Task-Reentrancy.
|
|
354
400
|
|
|
@@ -400,7 +446,42 @@ class AsyncRWLockWriteReentrantWriter(mixins._RWLockWriteReentrantMixin, AsyncRW
|
|
|
400
446
|
def _clear_current_writer(self) -> None:
|
|
401
447
|
self._writer_id = None
|
|
402
448
|
|
|
403
|
-
|
|
449
|
+
def _can_read(self) -> bool:
|
|
450
|
+
if self._writer_id is not None:
|
|
451
|
+
return self._is_current_writer()
|
|
452
|
+
return self.write.those_waiting == 0
|
|
453
|
+
|
|
454
|
+
def _can_write(self) -> bool:
|
|
455
|
+
if self._writer_id is not None:
|
|
456
|
+
return self._is_current_writer()
|
|
457
|
+
return self._readers_active == 0
|
|
458
|
+
|
|
459
|
+
def _acquire_write_core(self):
|
|
460
|
+
self._set_current_writer()
|
|
461
|
+
self._write_count += 1
|
|
462
|
+
|
|
463
|
+
def _release_write_core(self):
|
|
464
|
+
if not self._is_current_writer():
|
|
465
|
+
raise RuntimeError("Permission denied")
|
|
466
|
+
self._write_count -= 1
|
|
467
|
+
if self._write_count == 0:
|
|
468
|
+
self._clear_current_writer()
|
|
469
|
+
self._on_writer_abort()
|
|
470
|
+
|
|
471
|
+
def _downgrade_core(self):
|
|
472
|
+
if not self._is_current_writer():
|
|
473
|
+
raise RuntimeError("Permission denied")
|
|
474
|
+
if self._write_count > 1:
|
|
475
|
+
raise RuntimeError("Cannot downgrade a nested write lock. Release inner locks first.")
|
|
476
|
+
self._clear_current_writer()
|
|
477
|
+
self._write_count = 0
|
|
478
|
+
self._readers_active += 1
|
|
479
|
+
self.read.condition.notify_all()
|
|
480
|
+
|
|
481
|
+
def _is_write_locked(self) -> bool:
|
|
482
|
+
return self._writer_id is not None
|
|
483
|
+
|
|
484
|
+
class AsyncRWLockRead(AsyncRWLockWithProxyBase):
|
|
404
485
|
"""
|
|
405
486
|
Read-preferring Asynchronous Read-Write Lock.
|
|
406
487
|
|
|
@@ -436,8 +517,56 @@ class AsyncRWLockRead(mixins._RWLockReadMixin, AsyncRWLockWithProxyBase):
|
|
|
436
517
|
super().__init__()
|
|
437
518
|
self._writer_active = False
|
|
438
519
|
self._readers_active = 0
|
|
520
|
+
|
|
521
|
+
def _can_read(self) -> bool:
|
|
522
|
+
return not self._writer_active
|
|
523
|
+
|
|
524
|
+
def _acquire_read_core(self):
|
|
525
|
+
self._readers_active += 1
|
|
526
|
+
|
|
527
|
+
def _release_read_core(self):
|
|
528
|
+
if self._readers_active == 0:
|
|
529
|
+
raise RuntimeError("Unacquired read lock")
|
|
530
|
+
self._readers_active -= 1
|
|
531
|
+
if self._readers_active == 0:
|
|
532
|
+
self.write.condition.notify()
|
|
533
|
+
|
|
534
|
+
def _on_reader_abort(self):
|
|
535
|
+
if self.read.those_waiting == 0 and self._readers_active == 0:
|
|
536
|
+
self.write.condition.notify()
|
|
537
|
+
|
|
538
|
+
def _can_write(self) -> bool:
|
|
539
|
+
return not self._writer_active and self._readers_active == 0 and self.read.those_waiting == 0
|
|
540
|
+
|
|
541
|
+
def _acquire_write_core(self):
|
|
542
|
+
self._writer_active = True
|
|
543
|
+
|
|
544
|
+
def _release_write_core(self):
|
|
545
|
+
if not self._writer_active:
|
|
546
|
+
raise RuntimeError("Unacquired write lock")
|
|
547
|
+
self._writer_active = False
|
|
548
|
+
self._on_writer_abort()
|
|
549
|
+
|
|
550
|
+
def _downgrade_core(self):
|
|
551
|
+
if not self._writer_active:
|
|
552
|
+
raise RuntimeError("Cannot downgrade unlocked lock")
|
|
553
|
+
self._writer_active = False
|
|
554
|
+
self._readers_active += 1
|
|
555
|
+
self.read.condition.notify_all()
|
|
556
|
+
|
|
557
|
+
def _on_writer_abort(self):
|
|
558
|
+
if self.read.those_waiting > 0:
|
|
559
|
+
self.read.condition.notify_all()
|
|
560
|
+
else:
|
|
561
|
+
self.write.condition.notify()
|
|
562
|
+
|
|
563
|
+
def _is_write_locked(self) -> bool:
|
|
564
|
+
return self._writer_active
|
|
565
|
+
|
|
566
|
+
def _is_read_locked(self) -> bool:
|
|
567
|
+
return self._readers_active > 0
|
|
439
568
|
|
|
440
|
-
class AsyncRWLockReadReentrantWriter(
|
|
569
|
+
class AsyncRWLockReadReentrantWriter(AsyncRWLockRead):
|
|
441
570
|
"""
|
|
442
571
|
Read-preferring Asynchronous Read-Write Lock with Task-Reentrancy.
|
|
443
572
|
|
|
@@ -487,7 +616,42 @@ class AsyncRWLockReadReentrantWriter(mixins._RWLockReadReentrantMixin, AsyncRWLo
|
|
|
487
616
|
def _clear_current_writer(self) -> None:
|
|
488
617
|
self._writer_id = None
|
|
489
618
|
|
|
490
|
-
|
|
619
|
+
def _can_read(self) -> bool:
|
|
620
|
+
if self._writer_id is not None:
|
|
621
|
+
return self._is_current_writer()
|
|
622
|
+
return True
|
|
623
|
+
|
|
624
|
+
def _can_write(self) -> bool:
|
|
625
|
+
if self._writer_id is not None:
|
|
626
|
+
return self._is_current_writer()
|
|
627
|
+
return self._readers_active == 0 and self.read.those_waiting == 0
|
|
628
|
+
|
|
629
|
+
def _acquire_write_core(self):
|
|
630
|
+
self._set_current_writer()
|
|
631
|
+
self._write_count += 1
|
|
632
|
+
|
|
633
|
+
def _release_write_core(self):
|
|
634
|
+
if not self._is_current_writer():
|
|
635
|
+
raise RuntimeError("Permission denied")
|
|
636
|
+
self._write_count -= 1
|
|
637
|
+
if self._write_count == 0:
|
|
638
|
+
self._clear_current_writer()
|
|
639
|
+
self._on_writer_abort()
|
|
640
|
+
|
|
641
|
+
def _downgrade_core(self):
|
|
642
|
+
if not self._is_current_writer():
|
|
643
|
+
raise RuntimeError("Permission denied")
|
|
644
|
+
if self._write_count > 1:
|
|
645
|
+
raise RuntimeError("Cannot downgrade a nested write lock. Release inner locks first.")
|
|
646
|
+
self._clear_current_writer()
|
|
647
|
+
self._write_count = 0
|
|
648
|
+
self._readers_active += 1
|
|
649
|
+
self.read.condition.notify_all()
|
|
650
|
+
|
|
651
|
+
def _is_write_locked(self) -> bool:
|
|
652
|
+
return self._writer_id is not None
|
|
653
|
+
|
|
654
|
+
class AsyncRWLockFair(AsyncRWLockWithProxyBase):
|
|
491
655
|
"""
|
|
492
656
|
Fair (First-In-First-Out) Asynchronous Read-Write Lock.
|
|
493
657
|
|
|
@@ -524,8 +688,66 @@ class AsyncRWLockFair(mixins._RWLockFairMixin, AsyncRWLockWithProxyBase):
|
|
|
524
688
|
self._writer_active = False
|
|
525
689
|
self._readers_turn = False
|
|
526
690
|
self._readers_active = 0
|
|
691
|
+
|
|
692
|
+
def _can_read(self) -> bool:
|
|
693
|
+
if self._writer_active:
|
|
694
|
+
return False
|
|
695
|
+
return self._readers_turn or self.write.those_waiting == 0
|
|
696
|
+
|
|
697
|
+
def _acquire_read_core(self):
|
|
698
|
+
self._readers_active += 1
|
|
699
|
+
|
|
700
|
+
def _release_read_core(self):
|
|
701
|
+
if self._readers_active == 0:
|
|
702
|
+
raise RuntimeError("Unacquired read lock")
|
|
703
|
+
self._readers_active -= 1
|
|
704
|
+
if self._readers_active == 0:
|
|
705
|
+
self._readers_turn = False
|
|
706
|
+
self.write.condition.notify()
|
|
707
|
+
|
|
708
|
+
def _on_reader_abort(self):
|
|
709
|
+
if self._readers_turn and self.read.those_waiting == 0 and self._readers_active == 0:
|
|
710
|
+
self._readers_turn = False
|
|
711
|
+
self.write.condition.notify()
|
|
712
|
+
|
|
713
|
+
def _can_write(self) -> bool:
|
|
714
|
+
if self._writer_active or self._readers_active > 0:
|
|
715
|
+
return False
|
|
716
|
+
if self._readers_turn and self.read.those_waiting > 0:
|
|
717
|
+
return False
|
|
718
|
+
return True
|
|
719
|
+
|
|
720
|
+
def _acquire_write_core(self):
|
|
721
|
+
self._writer_active = True
|
|
722
|
+
|
|
723
|
+
def _release_write_core(self):
|
|
724
|
+
if not self._writer_active:
|
|
725
|
+
raise RuntimeError("Unacquired write lock")
|
|
726
|
+
self._writer_active = False
|
|
727
|
+
self._on_writer_abort()
|
|
728
|
+
|
|
729
|
+
def _downgrade_core(self):
|
|
730
|
+
if not self._writer_active:
|
|
731
|
+
raise RuntimeError("Cannot downgrade unlocked lock")
|
|
732
|
+
self._writer_active = False
|
|
733
|
+
self._readers_active += 1
|
|
734
|
+
self._readers_turn = True
|
|
735
|
+
self.read.condition.notify_all()
|
|
736
|
+
|
|
737
|
+
def _on_writer_abort(self):
|
|
738
|
+
if self.read.those_waiting > 0:
|
|
739
|
+
self._readers_turn = True
|
|
740
|
+
self.read.condition.notify_all()
|
|
741
|
+
else:
|
|
742
|
+
self.write.condition.notify()
|
|
743
|
+
|
|
744
|
+
def _is_write_locked(self) -> bool:
|
|
745
|
+
return self._writer_active
|
|
746
|
+
|
|
747
|
+
def _is_read_locked(self) -> bool:
|
|
748
|
+
return self._readers_active > 0
|
|
527
749
|
|
|
528
|
-
class AsyncRWLockFairReentrantWriter(
|
|
750
|
+
class AsyncRWLockFairReentrantWriter(AsyncRWLockFair):
|
|
529
751
|
"""
|
|
530
752
|
Fair (First-In-First-Out) Asynchronous Read-Write Lock with Task-Reentrancy.
|
|
531
753
|
|
|
@@ -575,6 +797,50 @@ class AsyncRWLockFairReentrantWriter(mixins._RWLockFairReentrantMixin, AsyncRWLo
|
|
|
575
797
|
def _clear_current_writer(self) -> None:
|
|
576
798
|
self._writer_id = None
|
|
577
799
|
|
|
800
|
+
def _can_read(self) -> bool:
|
|
801
|
+
if self._writer_id is not None:
|
|
802
|
+
if self._is_current_writer():
|
|
803
|
+
return True
|
|
804
|
+
return False
|
|
805
|
+
return self._readers_turn or self.write.those_waiting == 0
|
|
806
|
+
|
|
807
|
+
def _can_write(self) -> bool:
|
|
808
|
+
if self._writer_id is not None:
|
|
809
|
+
if self._is_current_writer():
|
|
810
|
+
return True
|
|
811
|
+
return False
|
|
812
|
+
if self._readers_active > 0:
|
|
813
|
+
return False
|
|
814
|
+
if self._readers_turn and self.read.those_waiting > 0:
|
|
815
|
+
return False
|
|
816
|
+
return True
|
|
817
|
+
|
|
818
|
+
def _acquire_write_core(self):
|
|
819
|
+
self._set_current_writer()
|
|
820
|
+
self._write_count += 1
|
|
821
|
+
|
|
822
|
+
def _release_write_core(self):
|
|
823
|
+
if not self._is_current_writer():
|
|
824
|
+
raise RuntimeError("Permission denied")
|
|
825
|
+
self._write_count -= 1
|
|
826
|
+
if self._write_count == 0:
|
|
827
|
+
self._clear_current_writer()
|
|
828
|
+
self._on_writer_abort()
|
|
829
|
+
|
|
830
|
+
def _downgrade_core(self):
|
|
831
|
+
if not self._is_current_writer():
|
|
832
|
+
raise RuntimeError("Permission denied")
|
|
833
|
+
if self._write_count > 1:
|
|
834
|
+
raise RuntimeError("Cannot downgrade a nested write lock. Release inner locks first.")
|
|
835
|
+
self._clear_current_writer()
|
|
836
|
+
self._write_count = 0
|
|
837
|
+
self._readers_active += 1
|
|
838
|
+
self._readers_turn = True
|
|
839
|
+
self.read.condition.notify_all()
|
|
840
|
+
|
|
841
|
+
def _is_write_locked(self) -> bool:
|
|
842
|
+
return self._writer_id is not None
|
|
843
|
+
|
|
578
844
|
# Standart Lock Adapter
|
|
579
845
|
class AsyncLock(AsyncRWLockBase):
|
|
580
846
|
"""
|
|
@@ -632,7 +898,7 @@ class AsyncRWConditionBase(ABC):
|
|
|
632
898
|
"""
|
|
633
899
|
__slots__ = ('_lock', 'read', 'write')
|
|
634
900
|
|
|
635
|
-
def __init__(self, lock: Optional[
|
|
901
|
+
def __init__(self, lock: Optional[AsyncLockable] = None):
|
|
636
902
|
self._lock = AsyncLock() if lock is None else lock
|
|
637
903
|
self.write: AsyncConditionLockable = asyncio.Condition(self._lock)
|
|
638
904
|
self.read: AsyncConditionLockable = self.write
|
|
@@ -934,7 +1200,7 @@ class AsyncRWConditionWriterProxy(AsyncRWConditionProxy):
|
|
|
934
1200
|
self._lock_proxy.downgrade()
|
|
935
1201
|
|
|
936
1202
|
# Read Write Lock For Condition
|
|
937
|
-
class AsyncRWCondition(
|
|
1203
|
+
class AsyncRWCondition(AsyncRWConditionWithProxyBase):
|
|
938
1204
|
"""
|
|
939
1205
|
Standard implementation of an Asynchronous Read-Write Condition variable.
|
|
940
1206
|
|
|
@@ -977,6 +1243,12 @@ class AsyncRWCondition(mixins._RWConditionMixin, AsyncRWConditionWithProxyBase):
|
|
|
977
1243
|
self._waiters: deque[asyncio.Future] = deque()
|
|
978
1244
|
super().__init__(lock)
|
|
979
1245
|
|
|
1246
|
+
def _is_owned_read(self) -> bool:
|
|
1247
|
+
return self._lock._is_read_locked()
|
|
1248
|
+
|
|
1249
|
+
def _is_owned_write(self) -> bool:
|
|
1250
|
+
return self._lock._is_write_locked()
|
|
1251
|
+
|
|
980
1252
|
def _add_waiter(self) -> asyncio.Future:
|
|
981
1253
|
loop = asyncio.get_running_loop()
|
|
982
1254
|
waiter = loop.create_future()
|
|
@@ -1039,7 +1311,7 @@ class AsyncCondition(AsyncRWConditionBase):
|
|
|
1039
1311
|
```
|
|
1040
1312
|
"""
|
|
1041
1313
|
__slots__ = ()
|
|
1042
|
-
def __init__(self, lock: Optional[
|
|
1314
|
+
def __init__(self, lock: Optional[AsyncLockable] = None):
|
|
1043
1315
|
if lock is not None and isinstance(lock, AsyncRWLockWithProxyBase):
|
|
1044
1316
|
raise TypeError("Standard 'AsyncCondition' adapters cannot be used with proxy-based RWLocks. Use 'AsyncRWCondition' instead.")
|
|
1045
1317
|
super().__init__(lock)
|
|
@@ -37,9 +37,7 @@ from abc import ABC, abstractmethod
|
|
|
37
37
|
from typing import Callable, Protocol, Optional
|
|
38
38
|
from types import TracebackType
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
__version__ = '3.1'
|
|
40
|
+
__version__ = '3.2'
|
|
43
41
|
__all__ = (
|
|
44
42
|
'Lockable', 'LockDowngradable', 'RWLockBase', 'RWLockWithProxyBase',
|
|
45
43
|
'RWLockProxy', 'RWLockReaderProxy', 'RWLockWriterProxy',
|
|
@@ -306,7 +304,7 @@ class RWLockWriterProxy(RWLockProxy):
|
|
|
306
304
|
Proxy specifically handling Writer logic, extending capabilities with
|
|
307
305
|
atomic state degradation (downgrading).
|
|
308
306
|
"""
|
|
309
|
-
__slots__ = ('_read_lock', '_downgrade_core', '
|
|
307
|
+
__slots__ = ('_read_lock', '_downgrade_core', '_downgraded_thread_id')
|
|
310
308
|
def __init__(self, rwlock: RWLockWithProxyBase):
|
|
311
309
|
super().__init__(
|
|
312
310
|
lock=rwlock._lock,
|
|
@@ -318,7 +316,7 @@ class RWLockWriterProxy(RWLockProxy):
|
|
|
318
316
|
)
|
|
319
317
|
self._read_lock = rwlock.read
|
|
320
318
|
self._downgrade_core = rwlock._downgrade_core
|
|
321
|
-
self.
|
|
319
|
+
self._downgraded_thread_id: Optional[int] = None
|
|
322
320
|
|
|
323
321
|
def downgrade(self):
|
|
324
322
|
"""
|
|
@@ -332,7 +330,7 @@ class RWLockWriterProxy(RWLockProxy):
|
|
|
332
330
|
"""
|
|
333
331
|
with self._lock:
|
|
334
332
|
self._downgrade_core()
|
|
335
|
-
self.
|
|
333
|
+
self._downgraded_thread_id = threading.get_ident()
|
|
336
334
|
|
|
337
335
|
def release(self):
|
|
338
336
|
"""
|
|
@@ -341,17 +339,14 @@ class RWLockWriterProxy(RWLockProxy):
|
|
|
341
339
|
and routes the release to the reader core to prevent deadlocks.
|
|
342
340
|
"""
|
|
343
341
|
with self._lock:
|
|
344
|
-
if self.
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
return
|
|
349
|
-
except KeyError:
|
|
350
|
-
pass
|
|
342
|
+
if self._downgraded_thread_id == threading.get_ident():
|
|
343
|
+
self._downgraded_thread_id = None
|
|
344
|
+
self._read_lock._release_core()
|
|
345
|
+
return
|
|
351
346
|
self._release_core()
|
|
352
347
|
|
|
353
348
|
# Read and Write Lock
|
|
354
|
-
class RWLockWrite(
|
|
349
|
+
class RWLockWrite(RWLockWithProxyBase):
|
|
355
350
|
"""
|
|
356
351
|
Write-preferring Read-Write Lock.
|
|
357
352
|
|
|
@@ -387,8 +382,55 @@ class RWLockWrite(mixins._RWLockWriteMixin, RWLockWithProxyBase):
|
|
|
387
382
|
super().__init__(lock)
|
|
388
383
|
self._writer_active = False
|
|
389
384
|
self._readers_active = 0
|
|
385
|
+
|
|
386
|
+
def _can_read(self) -> bool:
|
|
387
|
+
return not self._writer_active and self.write.those_waiting == 0
|
|
388
|
+
|
|
389
|
+
def _acquire_read_core(self):
|
|
390
|
+
self._readers_active += 1
|
|
391
|
+
|
|
392
|
+
def _release_read_core(self):
|
|
393
|
+
if self._readers_active == 0:
|
|
394
|
+
raise RuntimeError("Unacquired read lock")
|
|
395
|
+
self._readers_active -= 1
|
|
396
|
+
if self._readers_active == 0:
|
|
397
|
+
self.write.condition.notify()
|
|
398
|
+
|
|
399
|
+
def _on_reader_abort(self):
|
|
400
|
+
pass
|
|
401
|
+
|
|
402
|
+
def _can_write(self) -> bool:
|
|
403
|
+
return not self._writer_active and self._readers_active == 0
|
|
390
404
|
|
|
391
|
-
|
|
405
|
+
def _acquire_write_core(self):
|
|
406
|
+
self._writer_active = True
|
|
407
|
+
|
|
408
|
+
def _release_write_core(self):
|
|
409
|
+
if not self._writer_active:
|
|
410
|
+
raise RuntimeError("Unacquired write lock")
|
|
411
|
+
self._writer_active = False
|
|
412
|
+
self._on_writer_abort()
|
|
413
|
+
|
|
414
|
+
def _downgrade_core(self):
|
|
415
|
+
if not self._writer_active:
|
|
416
|
+
raise RuntimeError("Cannot downgrade unlocked lock")
|
|
417
|
+
self._writer_active = False
|
|
418
|
+
self._readers_active += 1
|
|
419
|
+
self.read.condition.notify_all()
|
|
420
|
+
|
|
421
|
+
def _on_writer_abort(self):
|
|
422
|
+
if self.write.those_waiting > 0:
|
|
423
|
+
self.write.condition.notify()
|
|
424
|
+
else:
|
|
425
|
+
self.read.condition.notify_all()
|
|
426
|
+
|
|
427
|
+
def _is_write_locked(self) -> bool:
|
|
428
|
+
return self._writer_active
|
|
429
|
+
|
|
430
|
+
def _is_read_locked(self) -> bool:
|
|
431
|
+
return self._readers_active > 0
|
|
432
|
+
|
|
433
|
+
class RWLockWriteReentrantWriter(RWLockWrite):
|
|
392
434
|
"""
|
|
393
435
|
Write-preferring Read-Write Lock with Write-Reentrancy support.
|
|
394
436
|
|
|
@@ -440,7 +482,42 @@ class RWLockWriteReentrantWriter(mixins._RWLockWriteReentrantMixin, RWLockWrite)
|
|
|
440
482
|
def _clear_current_writer(self) -> None:
|
|
441
483
|
self._writer_id = None
|
|
442
484
|
|
|
443
|
-
|
|
485
|
+
def _can_read(self) -> bool:
|
|
486
|
+
if self._writer_id is not None:
|
|
487
|
+
return self._is_current_writer()
|
|
488
|
+
return self.write.those_waiting == 0
|
|
489
|
+
|
|
490
|
+
def _can_write(self) -> bool:
|
|
491
|
+
if self._writer_id is not None:
|
|
492
|
+
return self._is_current_writer()
|
|
493
|
+
return self._readers_active == 0
|
|
494
|
+
|
|
495
|
+
def _acquire_write_core(self):
|
|
496
|
+
self._set_current_writer()
|
|
497
|
+
self._write_count += 1
|
|
498
|
+
|
|
499
|
+
def _release_write_core(self):
|
|
500
|
+
if not self._is_current_writer():
|
|
501
|
+
raise RuntimeError("Permission denied")
|
|
502
|
+
self._write_count -= 1
|
|
503
|
+
if self._write_count == 0:
|
|
504
|
+
self._clear_current_writer()
|
|
505
|
+
self._on_writer_abort()
|
|
506
|
+
|
|
507
|
+
def _downgrade_core(self):
|
|
508
|
+
if not self._is_current_writer():
|
|
509
|
+
raise RuntimeError("Permission denied")
|
|
510
|
+
if self._write_count > 1:
|
|
511
|
+
raise RuntimeError("Cannot downgrade a nested write lock. Release inner locks first.")
|
|
512
|
+
self._clear_current_writer()
|
|
513
|
+
self._write_count = 0
|
|
514
|
+
self._readers_active += 1
|
|
515
|
+
self.read.condition.notify_all()
|
|
516
|
+
|
|
517
|
+
def _is_write_locked(self) -> bool:
|
|
518
|
+
return self._writer_id is not None
|
|
519
|
+
|
|
520
|
+
class RWLockRead(RWLockWithProxyBase):
|
|
444
521
|
"""
|
|
445
522
|
Read-preferring Read-Write Lock.
|
|
446
523
|
|
|
@@ -478,7 +555,55 @@ class RWLockRead(mixins._RWLockReadMixin, RWLockWithProxyBase):
|
|
|
478
555
|
self._writer_active = False
|
|
479
556
|
self._readers_active = 0
|
|
480
557
|
|
|
481
|
-
|
|
558
|
+
def _can_read(self) -> bool:
|
|
559
|
+
return not self._writer_active
|
|
560
|
+
|
|
561
|
+
def _acquire_read_core(self):
|
|
562
|
+
self._readers_active += 1
|
|
563
|
+
|
|
564
|
+
def _release_read_core(self):
|
|
565
|
+
if self._readers_active == 0:
|
|
566
|
+
raise RuntimeError("Unacquired read lock")
|
|
567
|
+
self._readers_active -= 1
|
|
568
|
+
if self._readers_active == 0:
|
|
569
|
+
self.write.condition.notify()
|
|
570
|
+
|
|
571
|
+
def _on_reader_abort(self):
|
|
572
|
+
if self.read.those_waiting == 0 and self._readers_active == 0:
|
|
573
|
+
self.write.condition.notify()
|
|
574
|
+
|
|
575
|
+
def _can_write(self) -> bool:
|
|
576
|
+
return not self._writer_active and self._readers_active == 0 and self.read.those_waiting == 0
|
|
577
|
+
|
|
578
|
+
def _acquire_write_core(self):
|
|
579
|
+
self._writer_active = True
|
|
580
|
+
|
|
581
|
+
def _release_write_core(self):
|
|
582
|
+
if not self._writer_active:
|
|
583
|
+
raise RuntimeError("Unacquired write lock")
|
|
584
|
+
self._writer_active = False
|
|
585
|
+
self._on_writer_abort()
|
|
586
|
+
|
|
587
|
+
def _downgrade_core(self):
|
|
588
|
+
if not self._writer_active:
|
|
589
|
+
raise RuntimeError("Cannot downgrade unlocked lock")
|
|
590
|
+
self._writer_active = False
|
|
591
|
+
self._readers_active += 1
|
|
592
|
+
self.read.condition.notify_all()
|
|
593
|
+
|
|
594
|
+
def _on_writer_abort(self):
|
|
595
|
+
if self.read.those_waiting > 0:
|
|
596
|
+
self.read.condition.notify_all()
|
|
597
|
+
else:
|
|
598
|
+
self.write.condition.notify()
|
|
599
|
+
|
|
600
|
+
def _is_write_locked(self) -> bool:
|
|
601
|
+
return self._writer_active
|
|
602
|
+
|
|
603
|
+
def _is_read_locked(self) -> bool:
|
|
604
|
+
return self._readers_active > 0
|
|
605
|
+
|
|
606
|
+
class RWLockReadReentrantWriter(RWLockRead):
|
|
482
607
|
"""
|
|
483
608
|
Read-preferring Read-Write Lock with Write-Reentrancy support.
|
|
484
609
|
|
|
@@ -527,7 +652,42 @@ class RWLockReadReentrantWriter(mixins._RWLockReadReentrantMixin, RWLockRead):
|
|
|
527
652
|
def _clear_current_writer(self) -> None:
|
|
528
653
|
self._writer_id = None
|
|
529
654
|
|
|
530
|
-
|
|
655
|
+
def _can_read(self) -> bool:
|
|
656
|
+
if self._writer_id is not None:
|
|
657
|
+
return self._is_current_writer()
|
|
658
|
+
return True
|
|
659
|
+
|
|
660
|
+
def _can_write(self) -> bool:
|
|
661
|
+
if self._writer_id is not None:
|
|
662
|
+
return self._is_current_writer()
|
|
663
|
+
return self._readers_active == 0 and self.read.those_waiting == 0
|
|
664
|
+
|
|
665
|
+
def _acquire_write_core(self):
|
|
666
|
+
self._set_current_writer()
|
|
667
|
+
self._write_count += 1
|
|
668
|
+
|
|
669
|
+
def _release_write_core(self):
|
|
670
|
+
if not self._is_current_writer():
|
|
671
|
+
raise RuntimeError("Permission denied")
|
|
672
|
+
self._write_count -= 1
|
|
673
|
+
if self._write_count == 0:
|
|
674
|
+
self._clear_current_writer()
|
|
675
|
+
self._on_writer_abort()
|
|
676
|
+
|
|
677
|
+
def _downgrade_core(self):
|
|
678
|
+
if not self._is_current_writer():
|
|
679
|
+
raise RuntimeError("Permission denied")
|
|
680
|
+
if self._write_count > 1:
|
|
681
|
+
raise RuntimeError("Cannot downgrade a nested write lock. Release inner locks first.")
|
|
682
|
+
self._clear_current_writer()
|
|
683
|
+
self._write_count = 0
|
|
684
|
+
self._readers_active += 1
|
|
685
|
+
self.read.condition.notify_all()
|
|
686
|
+
|
|
687
|
+
def _is_write_locked(self) -> bool:
|
|
688
|
+
return self._writer_id is not None
|
|
689
|
+
|
|
690
|
+
class RWLockFair(RWLockWithProxyBase):
|
|
531
691
|
"""
|
|
532
692
|
Fair (First-In-First-Out) Read-Write Lock.
|
|
533
693
|
|
|
@@ -564,8 +724,66 @@ class RWLockFair(mixins._RWLockFairMixin, RWLockWithProxyBase):
|
|
|
564
724
|
self._writer_active = False
|
|
565
725
|
self._readers_turn = False
|
|
566
726
|
self._readers_active = 0
|
|
727
|
+
|
|
728
|
+
def _can_read(self) -> bool:
|
|
729
|
+
if self._writer_active:
|
|
730
|
+
return False
|
|
731
|
+
return self._readers_turn or self.write.those_waiting == 0
|
|
732
|
+
|
|
733
|
+
def _acquire_read_core(self):
|
|
734
|
+
self._readers_active += 1
|
|
735
|
+
|
|
736
|
+
def _release_read_core(self):
|
|
737
|
+
if self._readers_active == 0:
|
|
738
|
+
raise RuntimeError("Unacquired read lock")
|
|
739
|
+
self._readers_active -= 1
|
|
740
|
+
if self._readers_active == 0:
|
|
741
|
+
self._readers_turn = False
|
|
742
|
+
self.write.condition.notify()
|
|
743
|
+
|
|
744
|
+
def _on_reader_abort(self):
|
|
745
|
+
if self._readers_turn and self.read.those_waiting == 0 and self._readers_active == 0:
|
|
746
|
+
self._readers_turn = False
|
|
747
|
+
self.write.condition.notify()
|
|
748
|
+
|
|
749
|
+
def _can_write(self) -> bool:
|
|
750
|
+
if self._writer_active or self._readers_active > 0:
|
|
751
|
+
return False
|
|
752
|
+
if self._readers_turn and self.read.those_waiting > 0:
|
|
753
|
+
return False
|
|
754
|
+
return True
|
|
755
|
+
|
|
756
|
+
def _acquire_write_core(self):
|
|
757
|
+
self._writer_active = True
|
|
758
|
+
|
|
759
|
+
def _release_write_core(self):
|
|
760
|
+
if not self._writer_active:
|
|
761
|
+
raise RuntimeError("Unacquired write lock")
|
|
762
|
+
self._writer_active = False
|
|
763
|
+
self._on_writer_abort()
|
|
764
|
+
|
|
765
|
+
def _downgrade_core(self):
|
|
766
|
+
if not self._writer_active:
|
|
767
|
+
raise RuntimeError("Cannot downgrade unlocked lock")
|
|
768
|
+
self._writer_active = False
|
|
769
|
+
self._readers_active += 1
|
|
770
|
+
self._readers_turn = True
|
|
771
|
+
self.read.condition.notify_all()
|
|
772
|
+
|
|
773
|
+
def _on_writer_abort(self):
|
|
774
|
+
if self.read.those_waiting > 0:
|
|
775
|
+
self._readers_turn = True
|
|
776
|
+
self.read.condition.notify_all()
|
|
777
|
+
else:
|
|
778
|
+
self.write.condition.notify()
|
|
779
|
+
|
|
780
|
+
def _is_write_locked(self) -> bool:
|
|
781
|
+
return self._writer_active
|
|
782
|
+
|
|
783
|
+
def _is_read_locked(self) -> bool:
|
|
784
|
+
return self._readers_active > 0
|
|
567
785
|
|
|
568
|
-
class RWLockFairReentrantWriter(
|
|
786
|
+
class RWLockFairReentrantWriter(RWLockFair):
|
|
569
787
|
"""
|
|
570
788
|
Fair (First-In-First-Out) Read-Write Lock with Write-Reentrancy support.
|
|
571
789
|
|
|
@@ -615,6 +833,50 @@ class RWLockFairReentrantWriter(mixins._RWLockFairReentrantMixin, RWLockFair):
|
|
|
615
833
|
def _clear_current_writer(self) -> None:
|
|
616
834
|
self._writer_id = None
|
|
617
835
|
|
|
836
|
+
def _can_read(self) -> bool:
|
|
837
|
+
if self._writer_id is not None:
|
|
838
|
+
if self._is_current_writer():
|
|
839
|
+
return True
|
|
840
|
+
return False
|
|
841
|
+
return self._readers_turn or self.write.those_waiting == 0
|
|
842
|
+
|
|
843
|
+
def _can_write(self) -> bool:
|
|
844
|
+
if self._writer_id is not None:
|
|
845
|
+
if self._is_current_writer():
|
|
846
|
+
return True
|
|
847
|
+
return False
|
|
848
|
+
if self._readers_active > 0:
|
|
849
|
+
return False
|
|
850
|
+
if self._readers_turn and self.read.those_waiting > 0:
|
|
851
|
+
return False
|
|
852
|
+
return True
|
|
853
|
+
|
|
854
|
+
def _acquire_write_core(self):
|
|
855
|
+
self._set_current_writer()
|
|
856
|
+
self._write_count += 1
|
|
857
|
+
|
|
858
|
+
def _release_write_core(self):
|
|
859
|
+
if not self._is_current_writer():
|
|
860
|
+
raise RuntimeError("Permission denied")
|
|
861
|
+
self._write_count -= 1
|
|
862
|
+
if self._write_count == 0:
|
|
863
|
+
self._clear_current_writer()
|
|
864
|
+
self._on_writer_abort()
|
|
865
|
+
|
|
866
|
+
def _downgrade_core(self):
|
|
867
|
+
if not self._is_current_writer():
|
|
868
|
+
raise RuntimeError("Permission denied")
|
|
869
|
+
if self._write_count > 1:
|
|
870
|
+
raise RuntimeError("Cannot downgrade a nested write lock. Release inner locks first.")
|
|
871
|
+
self._clear_current_writer()
|
|
872
|
+
self._write_count = 0
|
|
873
|
+
self._readers_active += 1
|
|
874
|
+
self._readers_turn = True
|
|
875
|
+
self.read.condition.notify_all()
|
|
876
|
+
|
|
877
|
+
def _is_write_locked(self) -> bool:
|
|
878
|
+
return self._writer_id is not None
|
|
879
|
+
|
|
618
880
|
# Standart Lock Adapter
|
|
619
881
|
class Lock(RWLockBase):
|
|
620
882
|
"""
|
|
@@ -671,7 +933,7 @@ class RWConditionBase(ABC):
|
|
|
671
933
|
`.write` proxy. Designed to act as a common type hint and contract.
|
|
672
934
|
"""
|
|
673
935
|
__slots__ = ('_lock', 'read', 'write')
|
|
674
|
-
def __init__(self, lock: Optional[
|
|
936
|
+
def __init__(self, lock: Optional[Lockable] = None):
|
|
675
937
|
self._lock = Lock() if lock is None else lock
|
|
676
938
|
self.write: ConditionLockable = threading.Condition(self._lock)
|
|
677
939
|
self.read: ConditionLockable = self.write
|
|
@@ -966,7 +1228,7 @@ class RWConditionWriterProxy(RWConditionProxy):
|
|
|
966
1228
|
self._lock_proxy.downgrade()
|
|
967
1229
|
|
|
968
1230
|
# Read Write Lock For Condition
|
|
969
|
-
class RWCondition(
|
|
1231
|
+
class RWCondition(RWConditionWithProxyBase):
|
|
970
1232
|
"""
|
|
971
1233
|
Standard implementation of a Read-Write Condition variable.
|
|
972
1234
|
|
|
@@ -1008,6 +1270,12 @@ class RWCondition(mixins._RWConditionMixin, RWConditionWithProxyBase):
|
|
|
1008
1270
|
self._internal_lock = threading.Lock()
|
|
1009
1271
|
super().__init__(lock)
|
|
1010
1272
|
|
|
1273
|
+
def _is_owned_read(self) -> bool:
|
|
1274
|
+
return self._lock._is_read_locked()
|
|
1275
|
+
|
|
1276
|
+
def _is_owned_write(self) -> bool:
|
|
1277
|
+
return self._lock._is_write_locked()
|
|
1278
|
+
|
|
1011
1279
|
def _add_waiter(self) -> threading.Lock:
|
|
1012
1280
|
waiter = threading.Lock()
|
|
1013
1281
|
waiter.acquire()
|
|
@@ -1080,7 +1348,7 @@ class Condition(RWConditionBase):
|
|
|
1080
1348
|
```
|
|
1081
1349
|
"""
|
|
1082
1350
|
__slots__ = ()
|
|
1083
|
-
def __init__(self, lock: Optional[
|
|
1351
|
+
def __init__(self, lock: Optional[Lockable] = None):
|
|
1084
1352
|
if lock is not None and isinstance(lock, RWLockWithProxyBase):
|
|
1085
1353
|
raise TypeError("Standard 'Condition' adapters cannot be used with proxy-based RWLocks. Use 'RWCondition' instead.")
|
|
1086
1354
|
super().__init__(lock)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rwlocker
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2
|
|
4
4
|
Summary: Advanced, High-Performance, and State-Machine Based Synchronous/Asynchronous Read-Write Locks.
|
|
5
5
|
Author-email: TahsinCr <TahsinCrs@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -486,13 +486,3 @@ Email: TahsinCrs@gmail.com
|
|
|
486
486
|
[linkedin-url]: https://linkedin.com/in/TahsinCr
|
|
487
487
|
|
|
488
488
|
[x-url]: https://twitter.com/TahsinCrs
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
<!-- File URL -->
|
|
493
|
-
|
|
494
|
-
[lang-tr-url]: https://github.com/TahsinCr/python-rwlocker/blob/main/README_tr.md
|
|
495
|
-
|
|
496
|
-
[lang-en-url]: https://github.com/TahsinCr/python-rwlocker/blob/main/README.md
|
|
497
|
-
|
|
498
|
-
[lang-ru-url]: https://github.com/TahsinCr/python-rwlocker/blob/main/README_ru.md
|
rwlocker-3.1/rwlocker/mixins.py
DELETED
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Shared state-machine Mixins for both Thread and Async RWLock implementations.
|
|
3
|
-
These mixins encapsulate the core scheduling algorithms (Write-Pref, Read-Pref, Fair)
|
|
4
|
-
to eliminate code duplication across synchronous and asynchronous domains.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
class _RWLockWriteMixin:
|
|
8
|
-
__slots__ = ()
|
|
9
|
-
|
|
10
|
-
def _can_read(self) -> bool:
|
|
11
|
-
return not self._writer_active and self.write.those_waiting == 0
|
|
12
|
-
|
|
13
|
-
def _acquire_read_core(self):
|
|
14
|
-
self._readers_active += 1
|
|
15
|
-
|
|
16
|
-
def _release_read_core(self):
|
|
17
|
-
if self._readers_active == 0:
|
|
18
|
-
raise RuntimeError("Unacquired read lock")
|
|
19
|
-
self._readers_active -= 1
|
|
20
|
-
if self._readers_active == 0:
|
|
21
|
-
self.write.condition.notify()
|
|
22
|
-
|
|
23
|
-
def _on_reader_abort(self):
|
|
24
|
-
pass
|
|
25
|
-
|
|
26
|
-
def _can_write(self) -> bool:
|
|
27
|
-
return not self._writer_active and self._readers_active == 0
|
|
28
|
-
|
|
29
|
-
def _acquire_write_core(self):
|
|
30
|
-
self._writer_active = True
|
|
31
|
-
|
|
32
|
-
def _release_write_core(self):
|
|
33
|
-
if not self._writer_active:
|
|
34
|
-
raise RuntimeError("Unacquired write lock")
|
|
35
|
-
self._writer_active = False
|
|
36
|
-
self._on_writer_abort()
|
|
37
|
-
|
|
38
|
-
def _downgrade_core(self):
|
|
39
|
-
if not self._writer_active:
|
|
40
|
-
raise RuntimeError("Cannot downgrade unlocked lock")
|
|
41
|
-
self._writer_active = False
|
|
42
|
-
self._readers_active += 1
|
|
43
|
-
self.read.condition.notify_all()
|
|
44
|
-
|
|
45
|
-
def _on_writer_abort(self):
|
|
46
|
-
if self.write.those_waiting > 0:
|
|
47
|
-
self.write.condition.notify()
|
|
48
|
-
else:
|
|
49
|
-
self.read.condition.notify_all()
|
|
50
|
-
|
|
51
|
-
def _is_write_locked(self) -> bool:
|
|
52
|
-
return self._writer_active
|
|
53
|
-
|
|
54
|
-
def _is_read_locked(self) -> bool:
|
|
55
|
-
return self._readers_active > 0
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class _RWLockWriteReentrantMixin:
|
|
59
|
-
__slots__ = ()
|
|
60
|
-
|
|
61
|
-
def _can_read(self) -> bool:
|
|
62
|
-
if self._writer_id is not None:
|
|
63
|
-
return self._is_current_writer()
|
|
64
|
-
return self.write.those_waiting == 0
|
|
65
|
-
|
|
66
|
-
def _can_write(self) -> bool:
|
|
67
|
-
if self._writer_id is not None:
|
|
68
|
-
return self._is_current_writer()
|
|
69
|
-
return self._readers_active == 0
|
|
70
|
-
|
|
71
|
-
def _acquire_write_core(self):
|
|
72
|
-
self._set_current_writer()
|
|
73
|
-
self._write_count += 1
|
|
74
|
-
|
|
75
|
-
def _release_write_core(self):
|
|
76
|
-
if not self._is_current_writer():
|
|
77
|
-
raise RuntimeError("Permission denied")
|
|
78
|
-
self._write_count -= 1
|
|
79
|
-
if self._write_count == 0:
|
|
80
|
-
self._clear_current_writer()
|
|
81
|
-
self._on_writer_abort()
|
|
82
|
-
|
|
83
|
-
def _downgrade_core(self):
|
|
84
|
-
if not self._is_current_writer():
|
|
85
|
-
raise RuntimeError("Permission denied")
|
|
86
|
-
if self._write_count > 1:
|
|
87
|
-
raise RuntimeError("Cannot downgrade a nested write lock. Release inner locks first.")
|
|
88
|
-
self._clear_current_writer()
|
|
89
|
-
self._write_count = 0
|
|
90
|
-
self._readers_active += 1
|
|
91
|
-
self.read.condition.notify_all()
|
|
92
|
-
|
|
93
|
-
def _is_write_locked(self) -> bool:
|
|
94
|
-
return self._writer_id is not None
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
class _RWLockReadMixin:
|
|
98
|
-
__slots__ = ()
|
|
99
|
-
|
|
100
|
-
def _can_read(self) -> bool:
|
|
101
|
-
return not self._writer_active
|
|
102
|
-
|
|
103
|
-
def _acquire_read_core(self):
|
|
104
|
-
self._readers_active += 1
|
|
105
|
-
|
|
106
|
-
def _release_read_core(self):
|
|
107
|
-
if self._readers_active == 0:
|
|
108
|
-
raise RuntimeError("Unacquired read lock")
|
|
109
|
-
self._readers_active -= 1
|
|
110
|
-
if self._readers_active == 0:
|
|
111
|
-
self.write.condition.notify()
|
|
112
|
-
|
|
113
|
-
def _on_reader_abort(self):
|
|
114
|
-
if self.read.those_waiting == 0 and self._readers_active == 0:
|
|
115
|
-
self.write.condition.notify()
|
|
116
|
-
|
|
117
|
-
def _can_write(self) -> bool:
|
|
118
|
-
return not self._writer_active and self._readers_active == 0 and self.read.those_waiting == 0
|
|
119
|
-
|
|
120
|
-
def _acquire_write_core(self):
|
|
121
|
-
self._writer_active = True
|
|
122
|
-
|
|
123
|
-
def _release_write_core(self):
|
|
124
|
-
if not self._writer_active:
|
|
125
|
-
raise RuntimeError("Unacquired write lock")
|
|
126
|
-
self._writer_active = False
|
|
127
|
-
self._on_writer_abort()
|
|
128
|
-
|
|
129
|
-
def _downgrade_core(self):
|
|
130
|
-
if not self._writer_active:
|
|
131
|
-
raise RuntimeError("Cannot downgrade unlocked lock")
|
|
132
|
-
self._writer_active = False
|
|
133
|
-
self._readers_active += 1
|
|
134
|
-
self.read.condition.notify_all()
|
|
135
|
-
|
|
136
|
-
def _on_writer_abort(self):
|
|
137
|
-
if self.read.those_waiting > 0:
|
|
138
|
-
self.read.condition.notify_all()
|
|
139
|
-
else:
|
|
140
|
-
self.write.condition.notify()
|
|
141
|
-
|
|
142
|
-
def _is_write_locked(self) -> bool:
|
|
143
|
-
return self._writer_active
|
|
144
|
-
|
|
145
|
-
def _is_read_locked(self) -> bool:
|
|
146
|
-
return self._readers_active > 0
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
class _RWLockReadReentrantMixin:
|
|
150
|
-
__slots__ = ()
|
|
151
|
-
|
|
152
|
-
def _can_read(self) -> bool:
|
|
153
|
-
if self._writer_id is not None:
|
|
154
|
-
return self._is_current_writer()
|
|
155
|
-
return True
|
|
156
|
-
|
|
157
|
-
def _can_write(self) -> bool:
|
|
158
|
-
if self._writer_id is not None:
|
|
159
|
-
return self._is_current_writer()
|
|
160
|
-
return self._readers_active == 0 and self.read.those_waiting == 0
|
|
161
|
-
|
|
162
|
-
def _acquire_write_core(self):
|
|
163
|
-
self._set_current_writer()
|
|
164
|
-
self._write_count += 1
|
|
165
|
-
|
|
166
|
-
def _release_write_core(self):
|
|
167
|
-
if not self._is_current_writer():
|
|
168
|
-
raise RuntimeError("Permission denied")
|
|
169
|
-
self._write_count -= 1
|
|
170
|
-
if self._write_count == 0:
|
|
171
|
-
self._clear_current_writer()
|
|
172
|
-
self._on_writer_abort()
|
|
173
|
-
|
|
174
|
-
def _downgrade_core(self):
|
|
175
|
-
if not self._is_current_writer():
|
|
176
|
-
raise RuntimeError("Permission denied")
|
|
177
|
-
if self._write_count > 1:
|
|
178
|
-
raise RuntimeError("Cannot downgrade a nested write lock. Release inner locks first.")
|
|
179
|
-
self._clear_current_writer()
|
|
180
|
-
self._write_count = 0
|
|
181
|
-
self._readers_active += 1
|
|
182
|
-
self.read.condition.notify_all()
|
|
183
|
-
|
|
184
|
-
def _is_write_locked(self) -> bool:
|
|
185
|
-
return self._writer_id is not None
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
class _RWLockFairMixin:
|
|
189
|
-
__slots__ = ()
|
|
190
|
-
|
|
191
|
-
def _can_read(self) -> bool:
|
|
192
|
-
if self._writer_active:
|
|
193
|
-
return False
|
|
194
|
-
return self._readers_turn or self.write.those_waiting == 0
|
|
195
|
-
|
|
196
|
-
def _acquire_read_core(self):
|
|
197
|
-
self._readers_active += 1
|
|
198
|
-
|
|
199
|
-
def _release_read_core(self):
|
|
200
|
-
if self._readers_active == 0:
|
|
201
|
-
raise RuntimeError("Unacquired read lock")
|
|
202
|
-
self._readers_active -= 1
|
|
203
|
-
if self._readers_active == 0:
|
|
204
|
-
self._readers_turn = False
|
|
205
|
-
self.write.condition.notify()
|
|
206
|
-
|
|
207
|
-
def _on_reader_abort(self):
|
|
208
|
-
if self._readers_turn and self.read.those_waiting == 0 and self._readers_active == 0:
|
|
209
|
-
self._readers_turn = False
|
|
210
|
-
self.write.condition.notify()
|
|
211
|
-
|
|
212
|
-
def _can_write(self) -> bool:
|
|
213
|
-
if self._writer_active or self._readers_active > 0:
|
|
214
|
-
return False
|
|
215
|
-
if self._readers_turn and self.read.those_waiting > 0:
|
|
216
|
-
return False
|
|
217
|
-
return True
|
|
218
|
-
|
|
219
|
-
def _acquire_write_core(self):
|
|
220
|
-
self._writer_active = True
|
|
221
|
-
|
|
222
|
-
def _release_write_core(self):
|
|
223
|
-
if not self._writer_active:
|
|
224
|
-
raise RuntimeError("Unacquired write lock")
|
|
225
|
-
self._writer_active = False
|
|
226
|
-
self._on_writer_abort()
|
|
227
|
-
|
|
228
|
-
def _downgrade_core(self):
|
|
229
|
-
if not self._writer_active:
|
|
230
|
-
raise RuntimeError("Cannot downgrade unlocked lock")
|
|
231
|
-
self._writer_active = False
|
|
232
|
-
self._readers_active += 1
|
|
233
|
-
self._readers_turn = True
|
|
234
|
-
self.read.condition.notify_all()
|
|
235
|
-
|
|
236
|
-
def _on_writer_abort(self):
|
|
237
|
-
if self.read.those_waiting > 0:
|
|
238
|
-
self._readers_turn = True
|
|
239
|
-
self.read.condition.notify_all()
|
|
240
|
-
else:
|
|
241
|
-
self.write.condition.notify()
|
|
242
|
-
|
|
243
|
-
def _is_write_locked(self) -> bool:
|
|
244
|
-
return self._writer_active
|
|
245
|
-
|
|
246
|
-
def _is_read_locked(self) -> bool:
|
|
247
|
-
return self._readers_active > 0
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
class _RWLockFairReentrantMixin:
|
|
251
|
-
__slots__ = ()
|
|
252
|
-
|
|
253
|
-
def _can_read(self) -> bool:
|
|
254
|
-
if self._writer_id is not None:
|
|
255
|
-
if self._is_current_writer():
|
|
256
|
-
return True
|
|
257
|
-
return False
|
|
258
|
-
return self._readers_turn or self.write.those_waiting == 0
|
|
259
|
-
|
|
260
|
-
def _can_write(self) -> bool:
|
|
261
|
-
if self._writer_id is not None:
|
|
262
|
-
if self._is_current_writer():
|
|
263
|
-
return True
|
|
264
|
-
return False
|
|
265
|
-
if self._readers_active > 0:
|
|
266
|
-
return False
|
|
267
|
-
if self._readers_turn and self.read.those_waiting > 0:
|
|
268
|
-
return False
|
|
269
|
-
return True
|
|
270
|
-
|
|
271
|
-
def _acquire_write_core(self):
|
|
272
|
-
self._set_current_writer()
|
|
273
|
-
self._write_count += 1
|
|
274
|
-
|
|
275
|
-
def _release_write_core(self):
|
|
276
|
-
if not self._is_current_writer():
|
|
277
|
-
raise RuntimeError("Permission denied")
|
|
278
|
-
self._write_count -= 1
|
|
279
|
-
if self._write_count == 0:
|
|
280
|
-
self._clear_current_writer()
|
|
281
|
-
self._on_writer_abort()
|
|
282
|
-
|
|
283
|
-
def _downgrade_core(self):
|
|
284
|
-
if not self._is_current_writer():
|
|
285
|
-
raise RuntimeError("Permission denied")
|
|
286
|
-
if self._write_count > 1:
|
|
287
|
-
raise RuntimeError("Cannot downgrade a nested write lock. Release inner locks first.")
|
|
288
|
-
self._clear_current_writer()
|
|
289
|
-
self._write_count = 0
|
|
290
|
-
self._readers_active += 1
|
|
291
|
-
self._readers_turn = True
|
|
292
|
-
self.read.condition.notify_all()
|
|
293
|
-
|
|
294
|
-
def _is_write_locked(self) -> bool:
|
|
295
|
-
return self._writer_id is not None
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
class _RWConditionMixin:
|
|
299
|
-
__slots__ = ()
|
|
300
|
-
|
|
301
|
-
def _is_owned_read(self) -> bool:
|
|
302
|
-
return self._lock._is_read_locked()
|
|
303
|
-
|
|
304
|
-
def _is_owned_write(self) -> bool:
|
|
305
|
-
return self._lock._is_write_locked()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|