@@ -433,16 +433,29 @@ internal static unsafe godot_bool AddScriptBridge(IntPtr scriptPtr, godot_string
433433
434434 private static unsafe bool AddScriptBridgeCore ( IntPtr scriptPtr , string scriptPath )
435435 {
436- lock ( _scriptTypeBiMap . ReadWriteLock )
436+ _scriptTypeBiMap . ReadWriteLock . EnterUpgradeableReadLock ( ) ;
437+ try
437438 {
438439 if ( ! _scriptTypeBiMap . IsScriptRegistered ( scriptPtr ) )
439440 {
440441 if ( ! _pathTypeBiMap . TryGetScriptType ( scriptPath , out Type ? scriptType ) )
441442 return false ;
442443
443- _scriptTypeBiMap . Add ( scriptPtr , scriptType ) ;
444+ _scriptTypeBiMap . ReadWriteLock . EnterWriteLock ( ) ;
445+ try
446+ {
447+ _scriptTypeBiMap . Add ( scriptPtr , scriptType ) ;
448+ }
449+ finally
450+ {
451+ _scriptTypeBiMap . ReadWriteLock . ExitWriteLock ( ) ;
452+ }
444453 }
445454 }
455+ finally
456+ {
457+ _scriptTypeBiMap . ReadWriteLock . ExitUpgradeableReadLock ( ) ;
458+ }
446459
447460 return true ;
448461 }
@@ -465,7 +478,8 @@ internal static unsafe void GetOrCreateScriptBridgeForPath(godot_string* scriptP
465478
466479 private static unsafe void GetOrCreateScriptBridgeForType ( Type scriptType , godot_ref * outScript )
467480 {
468- lock ( _scriptTypeBiMap . ReadWriteLock )
481+ _scriptTypeBiMap . ReadWriteLock . EnterUpgradeableReadLock ( ) ;
482+ try
469483 {
470484 if ( _scriptTypeBiMap . TryGetScriptPtr ( scriptType , out IntPtr scriptPtr ) )
471485 {
@@ -477,14 +491,19 @@ private static unsafe void GetOrCreateScriptBridgeForType(Type scriptType, godot
477491 // This path is slower, but it's only executed for the first instantiation of the type
478492 CreateScriptBridgeForType ( scriptType , outScript ) ;
479493 }
494+ finally
495+ {
496+ _scriptTypeBiMap . ReadWriteLock . ExitUpgradeableReadLock ( ) ;
497+ }
480498 }
481499
482500 internal static unsafe void GetOrLoadOrCreateScriptForType ( Type scriptType , godot_ref * outScript )
483501 {
484502 static bool GetPathOtherwiseGetOrCreateScript ( Type scriptType , godot_ref * outScript ,
485503 [ MaybeNullWhen ( false ) ] out string scriptPath )
486504 {
487- lock ( _scriptTypeBiMap . ReadWriteLock )
505+ _scriptTypeBiMap . ReadWriteLock . EnterUpgradeableReadLock ( ) ;
506+ try
488507 {
489508 if ( _scriptTypeBiMap . TryGetScriptPtr ( scriptType , out IntPtr scriptPtr ) )
490509 {
@@ -512,6 +531,10 @@ static bool GetPathOtherwiseGetOrCreateScript(Type scriptType, godot_ref* outScr
512531 scriptPath = null ;
513532 return false ;
514533 }
534+ finally
535+ {
536+ _scriptTypeBiMap . ReadWriteLock . ExitUpgradeableReadLock ( ) ;
537+ }
515538 }
516539
517540 static string GetVirtualConstructedGenericTypeScriptPath ( Type scriptType , string scriptPath )
@@ -541,7 +564,16 @@ static string GetVirtualConstructedGenericTypeScriptPath(Type scriptType, string
541564 // IMPORTANT: The virtual path must be added to _pathTypeBiMap before the first
542565 // load of the script, otherwise the loaded script won't be added to _scriptTypeBiMap.
543566 scriptPath = GetVirtualConstructedGenericTypeScriptPath ( scriptType , scriptPath ) ;
544- _pathTypeBiMap . Add ( scriptPath , scriptType ) ;
567+
568+ _scriptTypeBiMap . ReadWriteLock . EnterWriteLock ( ) ;
569+ try
570+ {
571+ _pathTypeBiMap . Add ( scriptPath , scriptType ) ;
572+ }
573+ finally
574+ {
575+ _scriptTypeBiMap . ReadWriteLock . ExitWriteLock ( ) ;
576+ }
545577 }
546578
547579 // This must be done outside the read-write lock, as the script resource loading can lock it
@@ -571,89 +603,108 @@ private static unsafe void CreateScriptBridgeForType(Type scriptType, godot_ref*
571603 {
572604 Debug . Assert ( ! scriptType . IsGenericTypeDefinition , $ "Script type must be a constructed generic type or not generic at all. Type: { scriptType } .") ;
573605
574- NativeFuncs . godotsharp_internal_new_csharp_script ( outScript ) ;
575- IntPtr scriptPtr = outScript ->Reference ;
606+ _scriptTypeBiMap . ReadWriteLock . EnterWriteLock ( ) ;
607+ try
608+ {
609+ NativeFuncs . godotsharp_internal_new_csharp_script ( outScript ) ;
610+ IntPtr scriptPtr = outScript ->Reference ;
576611
577- // Caller takes care of locking
578- _scriptTypeBiMap . Add ( scriptPtr , scriptType ) ;
612+ _scriptTypeBiMap . Add ( scriptPtr , scriptType ) ;
613+ }
614+ finally
615+ {
616+ _scriptTypeBiMap . ReadWriteLock . ExitWriteLock ( ) ;
617+ }
579618
580- NativeFuncs . godotsharp_internal_reload_registered_script ( scriptPtr ) ;
619+ NativeFuncs . godotsharp_internal_reload_registered_script ( outScript -> Reference ) ;
581620 }
582621
583622 [ UnmanagedCallersOnly ]
584623 internal static void RemoveScriptBridge ( IntPtr scriptPtr )
585624 {
625+ _scriptTypeBiMap . ReadWriteLock . EnterWriteLock ( ) ;
586626 try
587627 {
588- lock ( _scriptTypeBiMap . ReadWriteLock )
589- {
590- _scriptTypeBiMap . Remove ( scriptPtr ) ;
591- }
628+ _scriptTypeBiMap . Remove ( scriptPtr ) ;
592629 }
593630 catch ( Exception e )
594631 {
595632 ExceptionUtils . LogException ( e ) ;
596633 }
634+ finally
635+ {
636+ _scriptTypeBiMap . ReadWriteLock . ExitWriteLock ( ) ;
637+ }
597638 }
598639
599640 [ UnmanagedCallersOnly ]
600641 internal static godot_bool TryReloadRegisteredScriptWithClass ( IntPtr scriptPtr )
601642 {
643+ _scriptTypeBiMap . ReadWriteLock . EnterUpgradeableReadLock ( ) ;
602644 try
603645 {
604- lock ( _scriptTypeBiMap . ReadWriteLock )
646+ if ( _scriptTypeBiMap . TryGetScriptType ( scriptPtr , out _ ) )
605647 {
606- if ( _scriptTypeBiMap . TryGetScriptType ( scriptPtr , out _ ) )
607- {
608- // NOTE:
609- // Currently, we reload all scripts, not only the ones from the unloaded ALC.
610- // As such, we need to handle this case instead of treating it as an error.
611- NativeFuncs . godotsharp_internal_reload_registered_script ( scriptPtr ) ;
612- return godot_bool . True ;
613- }
648+ // NOTE:
649+ // Currently, we reload all scripts, not only the ones from the unloaded ALC.
650+ // As such, we need to handle this case instead of treating it as an error.
651+ NativeFuncs . godotsharp_internal_reload_registered_script ( scriptPtr ) ;
652+ return godot_bool . True ;
653+ }
614654
615- if ( ! _scriptDataForReload . TryGetValue ( scriptPtr , out var dataForReload ) )
616- {
617- GD . PushError ( "Missing class qualified name for reloading script" ) ;
618- return godot_bool . False ;
619- }
655+ if ( ! _scriptDataForReload . TryGetValue ( scriptPtr , out var dataForReload ) )
656+ {
657+ GD . PushError ( "Missing class qualified name for reloading script" ) ;
658+ return godot_bool . False ;
659+ }
620660
621- _ = _scriptDataForReload . TryRemove ( scriptPtr , out _ ) ;
661+ _ = _scriptDataForReload . TryRemove ( scriptPtr , out _ ) ;
622662
623- if ( dataForReload . assemblyName == null )
624- {
625- GD . PushError (
626- $ "Missing assembly name of class '{ dataForReload . classFullName } ' for reloading script") ;
627- return godot_bool . False ;
628- }
663+ if ( dataForReload . assemblyName == null )
664+ {
665+ GD . PushError (
666+ $ "Missing assembly name of class '{ dataForReload . classFullName } ' for reloading script") ;
667+ return godot_bool . False ;
668+ }
629669
630- var scriptType = ReflectionUtils . FindTypeInLoadedAssemblies ( dataForReload . assemblyName ,
631- dataForReload . classFullName ) ;
670+ var scriptType = ReflectionUtils . FindTypeInLoadedAssemblies ( dataForReload . assemblyName ,
671+ dataForReload . classFullName ) ;
632672
633- if ( scriptType == null )
634- {
635- // The class was removed, can't reload
636- return godot_bool . False ;
637- }
673+ if ( scriptType == null )
674+ {
675+ // The class was removed, can't reload
676+ return godot_bool . False ;
677+ }
638678
639- if ( ! typeof ( GodotObject ) . IsAssignableFrom ( scriptType ) )
640- {
641- // The class no longer inherits GodotObject, can't reload
642- return godot_bool . False ;
643- }
679+ if ( ! typeof ( GodotObject ) . IsAssignableFrom ( scriptType ) )
680+ {
681+ // The class no longer inherits GodotObject, can't reload
682+ return godot_bool . False ;
683+ }
644684
685+ _scriptTypeBiMap . ReadWriteLock . EnterWriteLock ( ) ;
686+ try
687+ {
645688 _scriptTypeBiMap . Add ( scriptPtr , scriptType ) ;
689+ }
690+ finally
691+ {
692+ _scriptTypeBiMap . ReadWriteLock . ExitWriteLock ( ) ;
693+ }
646694
647- NativeFuncs . godotsharp_internal_reload_registered_script ( scriptPtr ) ;
695+ NativeFuncs . godotsharp_internal_reload_registered_script ( scriptPtr ) ;
648696
649- return godot_bool . True ;
650- }
697+ return godot_bool . True ;
651698 }
652699 catch ( Exception e )
653700 {
654701 ExceptionUtils . LogException ( e ) ;
655702 return godot_bool . False ;
656703 }
704+ finally
705+ {
706+ _scriptTypeBiMap . ReadWriteLock . ExitUpgradeableReadLock ( ) ;
707+ }
657708 }
658709
659710 private static unsafe void GetScriptTypeInfo ( Type scriptType , godot_csharp_type_info * outTypeInfo )
0 commit comments