44using System . Linq ;
55using System . Reflection ;
66using System . Runtime . InteropServices ;
7+ using System . Threading ;
78
89namespace Python . Runtime
910{
@@ -51,6 +52,9 @@ public static bool IsInitialized
5152 get { return initialized ; }
5253 }
5354
55+ /// <summary>Set to <c>true</c> to enable GIL debugging assistance.</summary>
56+ public static bool DebugGIL { get ; set ; } = false ;
57+
5458 internal static DelegateManager DelegateManager
5559 {
5660 get
@@ -633,7 +637,7 @@ public static GILState GIL()
633637 PythonEngine . Initialize ( ) ;
634638 }
635639
636- return new GILState ( ) ;
640+ return PythonEngine . DebugGIL ? new DebugGILState ( ) : new GILState ( ) ;
637641 }
638642
639643 public static PyScope CreateScope ( )
@@ -658,7 +662,7 @@ internal GILState()
658662 state = PythonEngine . AcquireLock ( ) ;
659663 }
660664
661- public void Dispose ( )
665+ public virtual void Dispose ( )
662666 {
663667 if ( this . isDisposed ) return ;
664668
@@ -669,7 +673,23 @@ public void Dispose()
669673
670674 ~ GILState ( )
671675 {
672- Dispose ( ) ;
676+ throw new InvalidOperationException ( "GIL must always be released, and it must be released from the same thread that acquired it." ) ;
677+ }
678+ }
679+
680+ public class DebugGILState : GILState
681+ {
682+ readonly Thread owner ;
683+ internal DebugGILState ( ) : base ( )
684+ {
685+ this . owner = Thread . CurrentThread ;
686+ }
687+ public override void Dispose ( )
688+ {
689+ if ( this . owner != Thread . CurrentThread )
690+ throw new InvalidOperationException ( "GIL must always be released from the same thread, that acquired it" ) ;
691+
692+ base . Dispose ( ) ;
673693 }
674694 }
675695
0 commit comments