31
31
cast ,
32
32
)
33
33
34
+ from readerwriterlock .rwlock import RWLockFair
35
+
34
36
from basilisp .lang import keyword as kw
35
37
from basilisp .lang import list as llist
36
38
from basilisp .lang import map as lmap
@@ -223,7 +225,8 @@ class Var(IDeref, ReferenceBase):
223
225
"_is_bound" ,
224
226
"_tl" ,
225
227
"_meta" ,
226
- "_lock" ,
228
+ "_rlock" ,
229
+ "_wlock" ,
227
230
)
228
231
229
232
def __init__ (
@@ -240,7 +243,9 @@ def __init__(
240
243
self ._is_bound = False
241
244
self ._tl = None
242
245
self ._meta = meta
243
- self ._lock = threading .Lock ()
246
+ lock = RWLockFair ()
247
+ self ._rlock = lock .gen_rlock ()
248
+ self ._wlock = lock .gen_wlock ()
244
249
245
250
if dynamic :
246
251
self ._tl = _VarBindings ()
@@ -268,10 +273,6 @@ def name(self) -> sym.Symbol:
268
273
def dynamic (self ) -> bool :
269
274
return self ._dynamic
270
275
271
- @dynamic .setter
272
- def dynamic (self , is_dynamic : bool ):
273
- self ._dynamic = is_dynamic
274
-
275
276
@property
276
277
def is_private (self ) -> Optional [bool ]:
277
278
if self ._meta is not None :
@@ -282,20 +283,25 @@ def is_private(self) -> Optional[bool]:
282
283
def is_bound (self ) -> bool :
283
284
return self ._is_bound or self .is_thread_bound
284
285
286
+ def _set_root (self , val ) -> None :
287
+ # Private setter which does not include lock so it can be used
288
+ # by other properties and methods which already manage the lock.
289
+ self ._is_bound = True
290
+ self ._root = val
291
+
285
292
@property
286
293
def root (self ):
287
- with self ._lock :
294
+ with self ._rlock :
288
295
return self ._root
289
296
290
297
@root .setter
291
298
def root (self , val ):
292
- with self ._lock :
293
- self ._is_bound = True
294
- self ._root = val
299
+ with self ._wlock :
300
+ self ._set_root (val )
295
301
296
302
def alter_root (self , f , * args ):
297
- with self ._lock :
298
- self ._root = f (self ._root , * args )
303
+ with self ._wlock :
304
+ self ._set_root ( f (self ._root , * args ) )
299
305
300
306
def push_bindings (self , val ):
301
307
if self ._tl is None :
@@ -316,22 +322,24 @@ def is_thread_bound(self):
316
322
317
323
@property
318
324
def value (self ):
319
- if self ._dynamic :
320
- assert self ._tl is not None
321
- if len (self ._tl .bindings ) > 0 :
322
- return self ._tl .bindings [- 1 ]
323
- return self .root
325
+ with self ._rlock :
326
+ if self ._dynamic :
327
+ assert self ._tl is not None
328
+ if len (self ._tl .bindings ) > 0 :
329
+ return self ._tl .bindings [- 1 ]
330
+ return self ._root
324
331
325
332
@value .setter
326
333
def value (self , v ):
327
- if self ._dynamic :
328
- assert self ._tl is not None
329
- if len (self ._tl .bindings ) > 0 :
330
- self ._tl .bindings [- 1 ] = v
331
- else :
332
- self .push_bindings (v )
333
- return
334
- self .root = v
334
+ with self ._wlock :
335
+ if self ._dynamic :
336
+ assert self ._tl is not None
337
+ if len (self ._tl .bindings ) > 0 :
338
+ self ._tl .bindings [- 1 ] = v
339
+ else :
340
+ self .push_bindings (v )
341
+ return
342
+ self ._set_root (v )
335
343
336
344
@staticmethod
337
345
def intern (
@@ -496,7 +504,8 @@ class Namespace(ReferenceBase):
496
504
"_name" ,
497
505
"_module" ,
498
506
"_meta" ,
499
- "_lock" ,
507
+ "_rlock" ,
508
+ "_wlock" ,
500
509
"_interns" ,
501
510
"_refers" ,
502
511
"_aliases" ,
@@ -509,7 +518,9 @@ def __init__(self, name: sym.Symbol, module: BasilispModule = None) -> None:
509
518
self ._module = Maybe (module ).or_else (lambda : _new_module (name .as_python_sym ()))
510
519
511
520
self ._meta : Optional [IPersistentMap ] = None
512
- self ._lock = threading .Lock ()
521
+ lock = RWLockFair ()
522
+ self ._rlock = lock .gen_rlock ()
523
+ self ._wlock = lock .gen_wlock ()
513
524
514
525
self ._aliases : NamespaceMap = lmap .PersistentMap .empty ()
515
526
self ._imports : ModuleMap = lmap .map (
@@ -545,36 +556,36 @@ def module(self, m: BasilispModule):
545
556
def aliases (self ) -> NamespaceMap :
546
557
"""A mapping between a symbolic alias and another Namespace. The
547
558
fully qualified name of a namespace is also an alias for itself."""
548
- with self ._lock :
559
+ with self ._rlock :
549
560
return self ._aliases
550
561
551
562
@property
552
563
def imports (self ) -> ModuleMap :
553
564
"""A mapping of names to Python modules imported into the current
554
565
namespace."""
555
- with self ._lock :
566
+ with self ._rlock :
556
567
return self ._imports
557
568
558
569
@property
559
570
def import_aliases (self ) -> AliasMap :
560
571
"""A mapping of a symbolic alias and a Python module name."""
561
- with self ._lock :
572
+ with self ._rlock :
562
573
return self ._import_aliases
563
574
564
575
@property
565
576
def interns (self ) -> VarMap :
566
577
"""A mapping between a symbolic name and a Var. The Var may point to
567
578
code, data, or nothing, if it is unbound. Vars in `interns` are
568
579
interned in _this_ namespace."""
569
- with self ._lock :
580
+ with self ._rlock :
570
581
return self ._interns
571
582
572
583
@property
573
584
def refers (self ) -> VarMap :
574
585
"""A mapping between a symbolic name and a Var. Vars in refers are
575
586
interned in another namespace and are only referred to without an
576
587
alias in this namespace."""
577
- with self ._lock :
588
+ with self ._rlock :
578
589
return self ._refers
579
590
580
591
def __repr__ (self ):
@@ -605,41 +616,41 @@ def require(self, ns_name: str, *aliases: sym.Symbol) -> BasilispModule:
605
616
606
617
def add_alias (self , namespace : "Namespace" , * aliases : sym .Symbol ) -> None :
607
618
"""Add Symbol aliases for the given Namespace."""
608
- with self ._lock :
619
+ with self ._wlock :
609
620
new_m = self ._aliases
610
621
for alias in aliases :
611
622
new_m = new_m .assoc (alias , namespace )
612
623
self ._aliases = new_m
613
624
614
625
def get_alias (self , alias : sym .Symbol ) -> "Optional[Namespace]" :
615
626
"""Get the Namespace aliased by Symbol or None if it does not exist."""
616
- with self ._lock :
627
+ with self ._rlock :
617
628
return self ._aliases .val_at (alias , None )
618
629
619
630
def remove_alias (self , alias : sym .Symbol ) -> None :
620
631
"""Remove the Namespace aliased by Symbol. Return None."""
621
- with self ._lock :
632
+ with self ._wlock :
622
633
self ._aliases = self ._aliases .dissoc (alias )
623
634
624
635
def intern (self , sym : sym .Symbol , var : Var , force : bool = False ) -> Var :
625
636
"""Intern the Var given in this namespace mapped by the given Symbol.
626
637
If the Symbol already maps to a Var, this method _will not overwrite_
627
638
the existing Var mapping unless the force keyword argument is given
628
639
and is True."""
629
- with self ._lock :
640
+ with self ._wlock :
630
641
old_var = self ._interns .val_at (sym , None )
631
642
if old_var is None or force :
632
643
self ._interns = self ._interns .assoc (sym , var )
633
644
return self ._interns .val_at (sym )
634
645
635
646
def unmap (self , sym : sym .Symbol ) -> None :
636
- with self ._lock :
647
+ with self ._wlock :
637
648
self ._interns = self ._interns .dissoc (sym )
638
649
639
650
def find (self , sym : sym .Symbol ) -> Optional [Var ]:
640
651
"""Find Vars mapped by the given Symbol input or None if no Vars are
641
652
mapped by that Symbol."""
642
- with self ._lock :
653
+ with self ._rlock :
643
654
v = self ._interns .val_at (sym , None )
644
655
if v is None :
645
656
return self ._refers .val_at (sym , None )
@@ -648,7 +659,7 @@ def find(self, sym: sym.Symbol) -> Optional[Var]:
648
659
def add_import (self , sym : sym .Symbol , module : Module , * aliases : sym .Symbol ) -> None :
649
660
"""Add the Symbol as an imported Symbol in this Namespace. If aliases are given,
650
661
the aliases will be applied to the"""
651
- with self ._lock :
662
+ with self ._wlock :
652
663
self ._imports = self ._imports .assoc (sym , module )
653
664
if aliases :
654
665
m = self ._import_aliases
@@ -662,7 +673,7 @@ def get_import(self, sym: sym.Symbol) -> Optional[BasilispModule]:
662
673
663
674
First try to resolve a module directly with the given name. If no module
664
675
can be resolved, attempt to resolve the module using import aliases."""
665
- with self ._lock :
676
+ with self ._rlock :
666
677
mod = self ._imports .val_at (sym , None )
667
678
if mod is None :
668
679
alias = self ._import_aliases .get (sym , None )
@@ -674,17 +685,17 @@ def get_import(self, sym: sym.Symbol) -> Optional[BasilispModule]:
674
685
def add_refer (self , sym : sym .Symbol , var : Var ) -> None :
675
686
"""Refer var in this namespace under the name sym."""
676
687
if not var .is_private :
677
- with self ._lock :
688
+ with self ._wlock :
678
689
self ._refers = self ._refers .assoc (sym , var )
679
690
680
691
def get_refer (self , sym : sym .Symbol ) -> Optional [Var ]:
681
692
"""Get the Var referred by Symbol or None if it does not exist."""
682
- with self ._lock :
693
+ with self ._rlock :
683
694
return self ._refers .val_at (sym , None )
684
695
685
696
def refer_all (self , other_ns : "Namespace" ) -> None :
686
697
"""Refer all the Vars in the other namespace."""
687
- with self ._lock :
698
+ with self ._wlock :
688
699
final_refers = self ._refers
689
700
for s , var in other_ns .interns .items ():
690
701
if not var .is_private :
0 commit comments