4
4
using System . Reflection ;
5
5
using System . Diagnostics ;
6
6
using System . Runtime . InteropServices ;
7
+ using System . Threading ;
7
8
8
9
namespace SGScript
9
10
{
@@ -143,6 +144,7 @@ public Context( IntPtr c, bool acquire = true ) : base( PartiallyConstructed.Val
143
144
else
144
145
{
145
146
_sgsEngine = GetEngine ( ) ;
147
+ _sgsEngine . ProcessVarRemoveQueue ( ) ;
146
148
_sgsEngine . _RegisterObj ( this ) ;
147
149
}
148
150
}
@@ -194,8 +196,7 @@ public override void Release()
194
196
{
195
197
if ( ctx != IntPtr . Zero )
196
198
{
197
- NI . ReleaseState ( ctx ) ;
198
- ctx = IntPtr . Zero ;
199
+ _sgsEngine . _ReleaseCtx ( ref ctx ) ;
199
200
HDL . FreeIfAlloc ( ref hMsgFunc ) ;
200
201
}
201
202
}
@@ -617,11 +618,13 @@ public struct WeakRefWrap
617
618
public WeakReference wr ;
618
619
}
619
620
620
- Dictionary < WeakReference , Nothing > _objRefs = new Dictionary < WeakReference , Nothing > ( ) ; // Key.Target = ISGSBase
621
+ public Dictionary < WeakReference , Nothing > _objRefs = new Dictionary < WeakReference , Nothing > ( ) ; // Key.Target = ISGSBase
621
622
public Dictionary < Type , DNMetaObject > _metaObjects = new Dictionary < Type , DNMetaObject > ( ) ;
622
- public Dictionary < Type , SGSClassInfo > _sgsClassInfo = new Dictionary < Type , SGSClassInfo > ( ) ;
623
- public Dictionary < Type , SGSClassInfo > _sgsStaticClassInfo = new Dictionary < Type , SGSClassInfo > ( ) ;
624
- public static Dictionary < IntPtr , WeakReference > _engines = new Dictionary < IntPtr , WeakReference > ( ) ; // Value.Target = Engine
623
+ public Dictionary < Type , SGSClassInfo > _sgsClassInfo = new Dictionary < Type , SGSClassInfo > ( ) ; // < contains native memory, must be freed
624
+ public Dictionary < Type , SGSClassInfo > _sgsStaticClassInfo = new Dictionary < Type , SGSClassInfo > ( ) ; // < contains native memory, must be freed
625
+ public static Dictionary < IntPtr , WeakReference > _engines = new Dictionary < IntPtr , WeakReference > ( ) ; // Value.Target = Engine
626
+ public Thread owningThread ;
627
+ public Queue < NI . Variable > _varReleaseQueue = new Queue < NI . Variable > ( ) ;
625
628
626
629
public static Engine GetFromCtx ( IntPtr ctx )
627
630
{
@@ -634,11 +637,13 @@ public static Engine GetFromCtx( IntPtr ctx )
634
637
IntPtr hMem = IntPtr . Zero ;
635
638
public Engine ( ) : base ( IntPtr . Zero , false )
636
639
{
640
+ owningThread = Thread . CurrentThread ;
637
641
ctx = NI . CreateEngine ( out d_memfunc ) ;
638
642
_engines . Add ( ctx , _sgsWeakRef ) ;
639
643
}
640
644
public Engine ( IMemory mem ) : base ( IntPtr . Zero , false )
641
645
{
646
+ owningThread = Thread . CurrentThread ;
642
647
hMem = HDL . Alloc ( mem ) ;
643
648
d_memfunc = new NI . MemFunc ( IMemory . _MemFunc ) ;
644
649
ctx = NI . CreateEngineExt ( d_memfunc , hMem ) ;
@@ -648,32 +653,96 @@ public override void Release()
648
653
{
649
654
if ( ctx != IntPtr . Zero )
650
655
{
651
- WeakReference [ ] objrefs ;
652
- for ( int i = 0 ; i < 10 && _objRefs . Count != 0 ; ++ i )
656
+ lock ( _objRefs )
657
+ {
658
+ lock ( _varReleaseQueue )
659
+ {
660
+ WeakReference [ ] objrefs ;
661
+ objrefs = new WeakReference [ _objRefs . Count ] ;
662
+ _objRefs . Keys . CopyTo ( objrefs , 0 ) ;
663
+ foreach ( WeakReference wr in objrefs )
664
+ {
665
+ IDisposable d = ( ( IDisposable ) wr . Target ) ;
666
+ d . Dispose ( ) ;
667
+ }
668
+
669
+ ProcessVarRemoveQueue ( ) ;
670
+
671
+ if ( _objRefs . Count != 0 )
672
+ throw new Exception ( "[SGSINT] _objRefs.Count != 0 but is " + _objRefs . Count ) ;
673
+ if ( _varReleaseQueue . Count != 0 )
674
+ throw new Exception ( "[SGSINT] _varReleaseQueue.Count != 0 but is " + _varReleaseQueue . Count ) ;
675
+
676
+ _engines . Remove ( ctx ) ;
677
+ NI . DestroyEngine ( ctx ) ;
678
+ ctx = IntPtr . Zero ;
679
+
680
+ // release interfaces
681
+ foreach ( SGSClassInfo ci in _sgsClassInfo . Values )
682
+ MDL . Free ( ci . iface ) ;
683
+ foreach ( SGSClassInfo ci in _sgsStaticClassInfo . Values )
684
+ MDL . Free ( ci . iface ) ;
685
+
686
+ HDL . FreeIfAlloc ( ref hMem ) ;
687
+ }
688
+ }
689
+ }
690
+ }
691
+
692
+ public void _ReleaseVar ( ref NI . Variable v )
693
+ {
694
+ if ( v . type == VarType . String || v . type == VarType . Func || v . type == VarType . Object || v . type == VarType . Thread )
695
+ {
696
+ if ( ctx == IntPtr . Zero )
653
697
{
654
- lock ( _objRefs )
655
- {
656
- objrefs = new WeakReference [ _objRefs . Count ] ;
657
- _objRefs . Keys . CopyTo ( objrefs , 0 ) ;
658
- }
659
- foreach ( WeakReference wr in objrefs )
698
+ throw new Exception ( "[SGSINT] Tried to release variable after engine has been freed!" ) ;
699
+ }
700
+ if ( Thread . CurrentThread == owningThread )
701
+ {
702
+ NI . Release ( ctx , ref v ) ;
703
+ }
704
+ else
705
+ {
706
+ lock ( _varReleaseQueue )
660
707
{
661
- if ( wr != null )
662
- {
663
- IDisposable d = ( ( IDisposable ) wr . Target ) ;
664
- if ( d != null )
665
- d . Dispose ( ) ;
666
- }
708
+ _varReleaseQueue . Enqueue ( v ) ;
667
709
}
668
- GC . Collect ( ) ;
669
- GC . WaitForPendingFinalizers ( ) ;
670
710
}
671
- if ( _objRefs . Count != 0 )
672
- throw new SGSException ( NI . EINPROC , "Failed to clean up handles" ) ;
673
- _engines . Remove ( ctx ) ;
674
- NI . DestroyEngine ( ctx ) ;
675
- ctx = IntPtr . Zero ;
676
- HDL . FreeIfAlloc ( ref hMem ) ;
711
+ }
712
+ v = new NI . Variable ( ) { type = VarType . Null } ;
713
+ }
714
+ public void _ReleaseCtx ( ref IntPtr c )
715
+ {
716
+ if ( c == IntPtr . Zero )
717
+ return ;
718
+ NI . Variable v = new NI . Variable ( ) { type = VarType . Thread } ;
719
+ v . data . T = c ;
720
+ _ReleaseVar ( ref v ) ;
721
+ c = IntPtr . Zero ;
722
+ }
723
+ public void _ReleaseObj ( ref IntPtr o )
724
+ {
725
+ if ( o == IntPtr . Zero )
726
+ return ;
727
+ NI . Variable v = new NI . Variable ( ) { type = VarType . Object } ;
728
+ v . data . O = o ;
729
+ _ReleaseVar ( ref v ) ;
730
+ o = IntPtr . Zero ;
731
+ }
732
+ public void ProcessVarRemoveQueue ( )
733
+ {
734
+ if ( Thread . CurrentThread != owningThread )
735
+ throw new SGSException ( NI . ENOTSUP , "ProcessVarRemoveQueue can be called only on the owning thread" ) ;
736
+ for ( ; ; )
737
+ {
738
+ NI . Variable var ;
739
+ lock ( _varReleaseQueue )
740
+ {
741
+ if ( _varReleaseQueue . Count == 0 )
742
+ break ;
743
+ var = _varReleaseQueue . Dequeue ( ) ;
744
+ }
745
+ NI . Release ( ctx , ref var ) ;
677
746
}
678
747
}
679
748
@@ -696,9 +765,12 @@ public void _RegisterObj( ISGSBase obj )
696
765
}
697
766
public void _UnregisterObj ( ISGSBase obj )
698
767
{
768
+ if ( obj is Engine )
769
+ return ;
699
770
lock ( _objRefs )
700
771
{
701
- _objRefs . Remove ( obj . _sgsWeakRef ) ;
772
+ if ( ! _objRefs . Remove ( obj . _sgsWeakRef ) )
773
+ throw new SGSException ( NI . EINPROC , "Failed to unregister SGS object" ) ;
702
774
}
703
775
}
704
776
}
0 commit comments