NI TestStand

cancel
Showing results for 
Search instead for 
Did you mean: 

TestStand Engine.NewExecution and .Net AppDomain

I have a TestStand sequence that calls a generic .Net step. At some point in its execution, this .Net step needs to make a decision. Instead of simply hardcoding a behavior, our solution is to have the .Net component start a new TestStand sequence execution to

perform the decision making:

 

[…]

NationalInstruments.TestStand.Interop.API.Execution ex =

    seqCtx.Engine.NewExecution(

    seqCtx.SequenceFile, 

    "decisionMakingSequence",        

    null,      

    false,   

    0x1 | 0x2 | 0x10,

    parameterObj,

    null,

    null);

 

ex.WaitForEnd(-1, true, null);

 

switch(parameterObj.GetValString("status”, 0))

{

[…]

}

 

This allows a user of our .Net component override / enhances some behaviors.

 

However for a reason that I cannot explain, when the execution of the TestStand sequence terminates the .Net AppDomain that the execution was initially being used gets unloaded.  Is it possible that, when creating a new execution (seqCtx.Engine.NewExecution(…)) TestStand creates a new .Net AppDomain and then use it as default, unloading the previous one which is no longer required? This causes us some problems as static content gets garbage collected.

 

Thank,

Marc-Andre Parent,

Proligent development team.

0 Kudos
Message 1 of 8
(4,915 Views)

Hey Marc-Andre,

I created a .NET assembly in which I inserted the following function:

public void Test(SequenceContext a)
{
 int before = AppDomain.CurrentDomain.Id;
 System.Windows.Forms.
MessageBox.Show("Before: " + before);
 SequenceFile seqF = a.Engine.GetSequenceFile("C:\\test.seq", 0);
 Execution ex = a.Engine.NewExecution(seqF, "TestSeq", null, false, 0x1 | 0x2 | 0x10, null, null, null);
 ex.WaitForEnd(-1,
true, null);
 int after = AppDomain.CurrentDomain.Id;
 System.Windows.Forms.
MessageBox.Show("After: " + after);
}

When I ran this, the ID was the same value before and after.  Have you tried checking the ID value?

Thanks,

Andy McRorie
NI R&D
0 Kudos
Message 2 of 8
(4,876 Views)
I performed the test and got the same result: "before" domain id equals "after": 2. However, when execution completes and I close the sequence window, the appDomain #2 gets unloaded. I know this for sure because I added a static constructor to the test class which register the DomainUnload event. ex:
 

public

class TestClass

{

   static TestClass() //Static constructor

   {

      AppDomain.CurrentDomain.DomainUnload += new EventHandler(CurrentDomain_DomainUnload);

   }

   static

void CurrentDomain_DomainUnload(object sender, EventArgs e)

   {

      MessageBox.Show("CurrentDomain_DomainUnload :" + (sender as AppDomain).Id.ToString());

   }  

   public void Test(SequenceContext a){...}

...

After I close the sequence execution window, I get a "CurrentDomain_DomainUnload : 2" popup. Unfortunately, I have so far failed to write a short code sample that reproduce my bug (I can only repro it with my full app. which is not easily portable). I have also noticed that the bug repro depends a lot on the TestSand environment. ex: If I open the StationCallback.seq file, the bug's gone! Could the problem be in TestStand itself, it the way it handles .Net AppDomains? Has anybody ever heard of such an issue?

 

-Thanks for helping!

0 Kudos
Message 3 of 8
(4,859 Views)
Marc-Andre,

I was able to reproduce the problem.  TestStand uses only one execution AppDomain and there is no way of creating unique ones for each execution.  

You can work around the problem by saving a reference to any .NET object from inside the execution that you launch in the code module to a global variable.  You would need to release the variable in the cleanup of your main execution as long as all of the other executions are finished.  This will keep the AppDomain from deleting after the second execution finishes.  

Let me know what version of TestStand you are using and I will create an example on how to workaround the problem.  

Michael Dozier
National Instruments
0 Kudos
Message 4 of 8
(4,817 Views)
Thanks for helping. I'm currently using TestStand3.5 but I would like my .Net code to be also usable on both TestStand3.1 and 4.0.
 
0 Kudos
Message 5 of 8
(4,781 Views)

I just tried this: (not too sure if this is the fix that was suggested)

Have a static variable:

private static NationalInstruments.TestStand.Interop.API.Execution m_execution;

and use it to store every new execution:

m_execution = seqCtx.Engine.NewExecution(...);

This seems to work around my issue (but I really ain't too sure why!)

 

 

0 Kudos
Message 6 of 8
(4,766 Views)
Hey Marc-Andre,

The reason for this fix is that TestStand had a bug in the code in which executions created in a .NET code module ran the code from our support assembly in the execution AppDomain instead of the default AppDomain.  This caused some of our static variables to have a different value than we were expecting.  Creating executions in the sequence or any other type of code module would not have this problem.  Since the support assembly was not in the default AppDomain, the second execution did not get grouped with the original execution.  Therefore when the second execution closed, the .NET adapter thought all managed references were released and the AppDomain was closed.  By storing the second execution in a static variable, the second execution will not close and the AppDomain will not get released. 

You should add to the cleanup of the main execution a call to release the executions stored in the static variables.  If you don't do this, you will probably see property object leaks in applications that are written in .NET like the .NET UIs and the 4.0 Sequence Editor.  In any case, we are looking to fix this in a future version of TestStand, but for now this workaround should do the trick.
Thanks,

Andy McRorie
NI R&D
Message 7 of 8
(4,753 Views)

Thank you for

the explanation.

I will try

to think of a mechanism that avoids the memory leaks. Since I’m developing .Net plug-ins for TestStand (rather than an application that uses TestStand as its executing engine) I really don’t want to assume anything on the TestStand sequences that will use my .Net modules.

0 Kudos
Message 8 of 8
(4,745 Views)