Console.WriteLine causes deadlock when using /domain=none option

218 views
Skip to first unread message

Sly

unread,
Dec 20, 2008, 5:52:57 PM12/20/08
to NUnit-Discuss
Hi,

I am encountering a deadlock. The deadlock is caused while executing a
simple Console.WriteLine( ) statement. The deadlock only occurs while
using the /domain command line option. When you set this option to
'none', NUnit will sometimes deadlock when Console.WriteLine( ) in the
client test code is called (see below).

The issue was found for NUnit version 2.4.0, but it does also occur in
version 2.4.8.


How to reproduce?

1. Build the following test code:

namespace NUnitDeadlock
{
[TestFixture]
public class Tester
{
public Tester()
{

}

[TestFixtureSetUp]
public void Init()
{
Console.WriteLine("\n---- Init ----");
}

[TestFixtureTearDown]
public void TearDown()
{
Console.WriteLine("\n---- TearDown ----");
}

[Test]
public void Foo()
{
Console.WriteLine("\n---- Foo ----");
}
}
}

2. Run the generated assembly (NUnitDeadlock.dll) using nunit-
console.exe. Since the deadlock does not always occur, put the
following in a batch file and then run the batch file:

:start
nunit-console.exe nunitdeadlock.dll /domain=none /
xml=nunitdeadlock.xml
goto start


Note that running the same test assembly in a loop (batch file) is
necessary just to reproduce the deadlock. My test cases run as part of
a daily regression test. Test cases are performed only once per
regression test session. This leads to deadlocks (hang ups) as well
(occasionally).


You will notice that after some time NUnit ends up in a deadlock.
Attach a debugger to the running nunit-console.exe process and break
into the debugger. The following is clear from the call stack:


- For one thread, the debugger breaks at NUnit.Core.EventQueue.Enqueue
( ), line 182. Here, a lock is done. This method is called, because
Console.WriteLine("\n---- Foo ----"); is being executed.
- For another thread, the debugger breaks at
NUnit.Core.TestRunnerThread.Wait( ), line 118. Here, a thread.Join( )
is done.
- For the third thread, the debugger breaks at
NUnit.ConsoleRunner.ConsolUi.EventCollector.TestStarted( ), line 450.
Here, a Console.Write( ) is done.


When you run the same test assembly without the /domain option (I
guess, NUnit then assumes a single domain), no deadlock occurs. Just
remove /domain=none from the batch file, run the batch file, and you
will notice that NUnit will execute the test case 30 minutes or more
without problems.


Thus, it seems that executing Console.WriteLine in combination with /
domain=none can cause a deadlock. My question: is this is a known
issue? Is there a workaround? (other than just removing all
Console.Writelines from the test cases...). I definitely need the /
domain=none option.


I hope that someone can help me out.


Thanks.


Regards,
Sly

Charlie Poole

unread,
Dec 20, 2008, 7:19:03 PM12/20/08
to nunit-...@googlegroups.com
Hi Sly,

This is not a known issue. Could you file a bug please?
(http://sourceforge.net/tracker/?group_id=10749&atid=110749)

I can't, however guarantee we'll fix it, since domain=none
is a messy kluge, which could be removed in the future.

Can you explain why you need to use it?

Charlie

Sly

unread,
Dec 21, 2008, 4:10:12 PM12/21/08
to NUnit-Discuss
Hi Charlie.

Thanks a lot for your quick response. I have submitted the bug. Its ID
is 2455688.

The reason why I need the /domain=none option is the following. Our
software uses a dedicated event mechanism written in C++, which is
implemented in our infrastructure library (a framework that all of our
software modules use). In order to be able to use these events in
the .NET world, a "C++ events to .NET bridge" has been implemented.
This bridge is implemented in managed C++. This bridge works fine, but
we found out that NUnit tests that use this event bridge fail due to
the following error: "Cannot pass a GCHandle across AppDomains". If I
understand it correctly, NUnit by default creates an AppDomain per
test assembly. It seems that Microsoft C++ has its own AppDomain for
unmanaged code and that GCRoot does not allow marshaling across
AppDomains.

The problem is kind of identical to what is written here:
http://social.msdn.microsoft.com/Forums/en-US/vststest/thread/fc7bc074-ff05-407b-b646-d9e5532c6998.

Since we don't have any use case for which we need to support multiple
AppDomains, we decided to use the /domain=none option. However, it
turned out that this sometimes causes a deadlock when executing
Console.WriteLine( ).

Besides just removing all ConsoleWriteLines from my test code as a
workaround, do you have any other suggestions?

Regards,
Sly
> > Sly- Hide quoted text -
>
> - Show quoted text -

Charlie Poole

unread,
Dec 23, 2008, 1:02:54 PM12/23/08
to nunit-...@googlegroups.com
Hi Sly,

> Thanks a lot for your quick response. I have submitted the
> bug. Its ID is 2455688.

Got it.

> The reason why I need the /domain=none option is the
> following. Our software uses a dedicated event mechanism
> written in C++, which is implemented in our infrastructure
> library (a framework that all of our software modules use).
> In order to be able to use these events in the .NET world, a
> "C++ events to .NET bridge" has been implemented.
> This bridge is implemented in managed C++. This bridge works
> fine, but we found out that NUnit tests that use this event
> bridge fail due to the following error: "Cannot pass a
> GCHandle across AppDomains". If I understand it correctly,
> NUnit by default creates an AppDomain per test assembly. It
> seems that Microsoft C++ has its own AppDomain for unmanaged
> code and that GCRoot does not allow marshaling across AppDomains.
>
> The problem is kind of identical to what is written here:
> http://social.msdn.microsoft.com/Forums/en-US/vststest/thread/
> fc7bc074-ff05-407b-b646-d9e5532c6998.

It sure sounds similar, but it doesn't entirely make sense to me.
Why is this setup...
Primary AppDomain => Test AppDomain => C++ AppDomain
any different from this...
Primary AppDomain (with tests) => C++ AppDomain
since there's a cross-domain operation in either case?

> Since we don't have any use case for which we need to support
> multiple AppDomains, we decided to use the /domain=none
> option. However, it turned out that this sometimes causes a
> deadlock when executing Console.WriteLine( ).

Can you provide a simplified test case for this? You can attach
it to the bug.

> Besides just removing all ConsoleWriteLines from my test code
> as a workaround, do you have any other suggestions?

I'll need to understand this better first. It seems like a key
issue, if we want to adequately support C++.

Charlie
Reply all
Reply to author
Forward
0 new messages