11using System ;
22using System . Collections . Concurrent ;
33using System . Collections . Generic ;
4+ using System . Diagnostics ;
45using System . Linq ;
56using System . Runtime . InteropServices ;
67using System . Threading ;
@@ -24,16 +25,23 @@ public class ErrorArgs : EventArgs
2425 public event EventHandler < CollectArgs > CollectOnce ;
2526 public event EventHandler < ErrorArgs > ErrorHandler ;
2627
27- private ConcurrentQueue < IDisposable > _objQueue = new ConcurrentQueue < IDisposable > ( ) ;
28+ public int Threshold { get ; set ; }
29+ public bool Enable { get ; set ; }
30+
31+ [ StructLayout ( LayoutKind . Sequential , CharSet = CharSet . Ansi ) ]
32+ struct PendingArgs
33+ {
34+ public bool cancelled ;
35+ }
2836
2937 [ UnmanagedFunctionPointer ( CallingConvention . Cdecl ) ]
3038 private delegate int PendingCall ( IntPtr arg ) ;
3139 private readonly PendingCall _collectAction ;
3240
41+ private ConcurrentQueue < IDisposable > _objQueue = new ConcurrentQueue < IDisposable > ( ) ;
3342 private bool _pending = false ;
3443 private readonly object _collectingLock = new object ( ) ;
35- public int Threshold { get ; set ; }
36- public bool Enable { get ; set ; }
44+ private IntPtr _pendingArgs ;
3745
3846 private Finalizer ( )
3947 {
@@ -92,6 +100,23 @@ internal static void Shutdown()
92100 return ;
93101 }
94102 Instance . DisposeAll ( ) ;
103+ if ( Thread . CurrentThread . ManagedThreadId != Runtime . MainManagedThreadId )
104+ {
105+ if ( Instance . _pendingArgs == IntPtr . Zero )
106+ {
107+ Instance . ResetPending ( ) ;
108+ return ;
109+ }
110+ // Not in main thread just cancel the pending operation to avoid error in different domain
111+ // It will make a memory leak
112+ unsafe
113+ {
114+ PendingArgs * args = ( PendingArgs * ) Instance . _pendingArgs ;
115+ args ->cancelled = true ;
116+ }
117+ Instance . ResetPending ( ) ;
118+ return ;
119+ }
95120 Instance . CallPendingFinalizers ( ) ;
96121 }
97122
@@ -108,8 +133,12 @@ private void AddPendingCollect()
108133 return ;
109134 }
110135 _pending = true ;
136+ var args = new PendingArgs ( ) { cancelled = false } ;
137+ IntPtr p = Marshal . AllocHGlobal ( Marshal . SizeOf ( typeof ( PendingArgs ) ) ) ;
138+ Marshal . StructureToPtr ( args , p , false ) ;
139+ _pendingArgs = p ;
111140 IntPtr func = Marshal . GetFunctionPointerForDelegate ( _collectAction ) ;
112- if ( Runtime . Py_AddPendingCall ( func , IntPtr . Zero ) != 0 )
141+ if ( Runtime . Py_AddPendingCall ( func , p ) != 0 )
113142 {
114143 // Full queue, append next time
115144 _pending = false ;
@@ -119,8 +148,24 @@ private void AddPendingCollect()
119148
120149 private static int OnPendingCollect ( IntPtr arg )
121150 {
122- Instance . DisposeAll ( ) ;
123- Instance . _pending = false ;
151+ Debug . Assert ( arg == Instance . _pendingArgs ) ;
152+ try
153+ {
154+ unsafe
155+ {
156+ PendingArgs * pendingArgs = ( PendingArgs * ) arg ;
157+ if ( pendingArgs ->cancelled )
158+ {
159+ return 0 ;
160+ }
161+ }
162+ Instance . DisposeAll ( ) ;
163+ }
164+ finally
165+ {
166+ Instance . ResetPending ( ) ;
167+ Marshal . FreeHGlobal ( arg ) ;
168+ }
124169 return 0 ;
125170 }
126171
@@ -148,5 +193,14 @@ private void DisposeAll()
148193 }
149194 }
150195 }
196+
197+ private void ResetPending ( )
198+ {
199+ lock ( _collectingLock )
200+ {
201+ _pending = false ;
202+ _pendingArgs = IntPtr . Zero ;
203+ }
204+ }
151205 }
152206}
0 commit comments