moel@345: // Stephen Toub
moel@345: // stoub@microsoft.com
moel@345: 
moel@345: using System;
moel@345: using System.Collections.Generic;
moel@345: using System.Text;
moel@345: using System.Threading;
moel@345: 
moel@345: namespace Aga.Controls.Threading
moel@345: {
moel@345: 	public class AbortableThreadPool
moel@345: 	{
moel@345: 		private LinkedList<WorkItem> _callbacks = new LinkedList<WorkItem>();
moel@345: 		private Dictionary<WorkItem, Thread> _threads = new Dictionary<WorkItem, Thread>();
moel@345: 
moel@345: 		public WorkItem QueueUserWorkItem(WaitCallback callback)
moel@345: 		{
moel@345: 			return QueueUserWorkItem(callback, null);
moel@345: 		}
moel@345: 
moel@345: 		public WorkItem QueueUserWorkItem(WaitCallback callback, object state)
moel@345: 		{
moel@345: 			if (callback == null) throw new ArgumentNullException("callback");
moel@345: 
moel@345: 			WorkItem item = new WorkItem(callback, state, ExecutionContext.Capture());
moel@345: 			lock (_callbacks)
moel@345: 			{
moel@345: 				_callbacks.AddLast(item);
moel@345: 			}
moel@345: 			ThreadPool.QueueUserWorkItem(new WaitCallback(HandleItem));
moel@345: 			return item;
moel@345: 		}
moel@345: 
moel@345: 		private void HandleItem(object ignored)
moel@345: 		{
moel@345: 			WorkItem item = null;
moel@345: 			try
moel@345: 			{
moel@345: 				lock (_callbacks)
moel@345: 				{
moel@345: 					if (_callbacks.Count > 0)
moel@345: 					{
moel@345: 						item = _callbacks.First.Value;
moel@345: 						_callbacks.RemoveFirst();
moel@345: 					}
moel@345: 					if (item == null)
moel@345: 						return;
moel@345: 					_threads.Add(item, Thread.CurrentThread);
moel@345: 
moel@345: 				}
moel@345: 				ExecutionContext.Run(item.Context,
moel@345: 					delegate { item.Callback(item.State); }, null);
moel@345: 			}
moel@345: 			finally
moel@345: 			{
moel@345: 				lock (_callbacks)
moel@345: 				{
moel@345: 					if (item != null)
moel@345: 						_threads.Remove(item);
moel@345: 				}
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		public bool IsMyThread(Thread thread)
moel@345: 		{
moel@345: 			lock (_callbacks)
moel@345: 			{
moel@345: 				foreach (Thread t in _threads.Values)
moel@345: 				{
moel@345: 					if (t == thread)
moel@345: 						return true;
moel@345: 				}
moel@345: 				return false;
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		public WorkItemStatus Cancel(WorkItem item, bool allowAbort)
moel@345: 		{
moel@345: 			if (item == null)
moel@345: 				throw new ArgumentNullException("item");
moel@345: 			lock (_callbacks)
moel@345: 			{
moel@345: 				LinkedListNode<WorkItem> node = _callbacks.Find(item);
moel@345: 				if (node != null)
moel@345: 				{
moel@345: 					_callbacks.Remove(node);
moel@345: 					return WorkItemStatus.Queued;
moel@345: 				}
moel@345: 				else if (_threads.ContainsKey(item))
moel@345: 				{
moel@345: 					if (allowAbort)
moel@345: 					{
moel@345: 						_threads[item].Abort();
moel@345: 						_threads.Remove(item);
moel@345: 						return WorkItemStatus.Aborted;
moel@345: 					}
moel@345: 					else
moel@345: 						return WorkItemStatus.Executing;
moel@345: 				}
moel@345: 				else
moel@345: 					return WorkItemStatus.Completed;
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		public void CancelAll(bool allowAbort)
moel@345: 		{
moel@345: 			lock (_callbacks)
moel@345: 			{
moel@345: 				_callbacks.Clear();
moel@345: 				if (allowAbort)
moel@345: 				{
moel@345: 					foreach (Thread t in _threads.Values)
moel@345: 						t.Abort();
moel@345: 				}
moel@345: 			}
moel@345: 		}
moel@345: 	}
moel@345: }