// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Server.Kestrel.Networking;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Server.Kestrel
{
///
/// Summary description for KestrelThread
///
public class KestrelThread
{
KestrelEngine _engine;
Thread _thread;
UvLoopHandle _loop;
UvAsyncHandle _post;
Queue _workAdding = new Queue();
Queue _workRunning = new Queue();
Queue _closeHandleAdding = new Queue();
Queue _closeHandleRunning = new Queue();
object _workSync = new Object();
bool _stopImmediate = false;
private ExceptionDispatchInfo _closeError;
public KestrelThread(KestrelEngine engine)
{
_engine = engine;
_loop = new UvLoopHandle();
_post = new UvAsyncHandle();
_thread = new Thread(ThreadStart);
QueueCloseHandle = PostCloseHandle;
}
public UvLoopHandle Loop { get { return _loop; } }
public ExceptionDispatchInfo FatalError { get { return _closeError; } }
public Action, IntPtr> QueueCloseHandle { get; internal set; }
public Task StartAsync()
{
var tcs = new TaskCompletionSource();
_thread.Start(tcs);
return tcs.Task;
}
public void Stop(TimeSpan timeout)
{
Post(OnStop, null);
if (!_thread.Join((int)timeout.TotalMilliseconds))
{
Post(OnStopRude, null);
if (!_thread.Join((int)timeout.TotalMilliseconds))
{
Post(OnStopImmediate, null);
if (!_thread.Join((int)timeout.TotalMilliseconds))
{
#if DNX451
_thread.Abort();
#endif
}
}
}
if (_closeError != null)
{
_closeError.Throw();
}
}
private void OnStop(object obj)
{
_post.Unreference();
}
private void OnStopRude(object obj)
{
_engine.Libuv.walk(
_loop,
(ptr, arg) =>
{
var handle = UvMemory.FromIntPtr(ptr);
if (handle != _post)
{
handle.Dispose();
}
},
IntPtr.Zero);
}
private void OnStopImmediate(object obj)
{
_stopImmediate = true;
_loop.Stop();
}
public void Post(Action