blob: 157fd7b24e26395b050ae77e483c8c5ea90ea170 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
#pragma warning disable 618
namespace Apache.Geode.DUnitFramework
{
using NUnit.Framework;
public class UnitThread : ClientBase
{
#region Private members
private ManualResetEvent m_start;
private ManualResetEvent m_end;
private Thread m_thread;
private volatile bool m_endThread;
private Delegate m_currDeleg;
private object[] m_currParams;
private object m_result;
private Exception m_exception;
private const string _m_disposeExceptionStr = "Thread has exited since the object has been Disposed";
#endregion
/// <summary>
/// A global dictionary of threads maintained so that the list of managed
/// threads (at least created using <c>UnitThread</c> can be obtained.
/// </summary>
public static Dictionary<Thread, bool> GlobalUnitThreads
= new Dictionary<Thread, bool>();
public UnitThread()
{
m_start = new ManualResetEvent(false);
m_end = new ManualResetEvent(true);
m_endThread = false;
m_currDeleg = null;
m_thread = new Thread(new ThreadStart(ThreadMain));
m_thread.Start();
lock (((ICollection)GlobalUnitThreads).SyncRoot)
{
GlobalUnitThreads.Add(m_thread, true);
}
}
public static UnitThread Create()
{
return new UnitThread();
}
private void ThreadMain()
{
while (true)
{
m_start.WaitOne();
if (m_endThread)
{
lock (((ICollection)GlobalUnitThreads).SyncRoot)
{
GlobalUnitThreads.Remove(m_thread);
}
return;
}
m_start.Reset();
m_exception = null;
if (m_currDeleg != null)
{
try
{
if (m_result != null)
{
m_result = m_currDeleg.DynamicInvoke(m_currParams);
}
else
{
m_currDeleg.DynamicInvoke(m_currParams);
}
}
catch (Exception ex)
{
m_exception = ex;
}
}
m_end.Set();
}
}
#region ClientBase Members
public override void RemoveObjectID(int objectID)
{
// TODO: Nothing for now.
}
public override void CallFn(Delegate deleg, params object[] paramList)
{
object result = null;
CallFnP(deleg, paramList, ref result);
}
public override object CallFnR(Delegate deleg, params object[] paramList)
{
object result = true;
CallFnP(deleg, paramList, ref result);
return result;
}
public override string HostName
{
get
{
return "localhost";
}
}
public override void SetLogFile(string logFile)
{
// Nothing for now since this shall be done anyway at the process level
//Util.LogFile = logFile;
}
public override void SetLogLevel(Util.LogLevel logLevel)
{
// Nothing for now since this shall be done anyway at the process level
//Util.CurrentLogLevel = logLevel;
}
public override void DumpStackTrace()
{
string trace = GetStackTrace();
if (trace != null)
{
Util.Log(trace);
}
}
public static string GetStackTrace(Thread thread)
{
string traceStr = null;
try
{
thread.Suspend();
}
catch
{
}
StackTrace trace = new StackTrace(thread, true);
traceStr = string.Format("Dumping stack for managed thread [{0}]:{1}{2}",
thread.ManagedThreadId, Environment.NewLine, trace.ToString());
try
{
thread.Resume();
}
catch
{
}
return traceStr;
}
public string GetStackTrace()
{
if (!m_endThread)
{
return GetStackTrace(m_thread);
}
return null;
}
public override void ForceKill(int waitMillis)
{
if (!m_endThread)
{
bool failed = true;
m_endThread = true;
m_start.Set();
if (waitMillis > 0 && m_thread.Join(waitMillis))
{
failed = false;
}
if (failed)
{
m_exception = new ClientTimeoutException(
"Timeout occurred in calling '" + m_currDeleg.Method.ToString() +
'\'');
m_end.Set();
}
}
}
public override ClientBase CreateNew(string clientId)
{
ClientBase newClient = new UnitThread();
newClient.ID = clientId;
return newClient;
}
public override void TestCleanup()
{
}
public override void Exit()
{
if (!m_endThread)
{
m_endThread = true;
m_start.Set();
}
}
public override string ID
{
get
{
return base.ID;
}
set
{
base.ID = value;
m_thread.Name = value;
}
}
#endregion
private void CallFnP(Delegate deleg, object[] paramList, ref object result)
{
lock (m_end)
{
if (m_endThread)
{
throw new ClientExitedException(_m_disposeExceptionStr);
}
m_end.WaitOne();
m_end.Reset();
m_currDeleg = deleg;
m_currParams = paramList;
m_result = result;
m_start.Set();
}
m_end.WaitOne();
if (m_exception != null)
{
throw m_exception;
}
if (result != null)
{
result = m_result;
}
}
}
}