diff --git a/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs b/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs
index 8c1ba9b64..5f2dbff91 100644
--- a/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs
+++ b/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs
@@ -39,6 +39,7 @@ namespace ProcessHacker.Native.Api
public const int GdiHandleBufferSize = 34;
#endif
public const int MaximumSupportedExtension = 512;
+ public const int MaximumWaitObjects = 64;
public const int SecurityDescriptorMinLength = 20;
public const int SecurityDescriptorRevision = 1;
public static readonly int SecurityMaxSidSize =
diff --git a/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj b/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj
index 058deeb7a..1c5cb68e9 100644
--- a/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj
+++ b/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj
@@ -142,6 +142,7 @@
+
Form
diff --git a/trunk/ProcessHacker.Native/Security/ObjectSecurityInformation.cs b/trunk/ProcessHacker.Native/Security/ObjectSecurityInformation.cs
index 23fcc99a7..bb11c3f9e 100644
--- a/trunk/ProcessHacker.Native/Security/ObjectSecurityInformation.cs
+++ b/trunk/ProcessHacker.Native/Security/ObjectSecurityInformation.cs
@@ -74,6 +74,7 @@ namespace ProcessHacker.Native.Security
private void ClearPool()
{
_pool.ForEach((alloc) => alloc.Dispose());
+ _pool.Clear();
}
#region ISecurityInformation Members
diff --git a/trunk/ProcessHacker.Native/Threading/WaiterThread.cs b/trunk/ProcessHacker.Native/Threading/WaiterThread.cs
new file mode 100644
index 000000000..0b86efa8b
--- /dev/null
+++ b/trunk/ProcessHacker.Native/Threading/WaiterThread.cs
@@ -0,0 +1,226 @@
+/*
+ * Process Hacker -
+ * waiter thread
+ *
+ * Copyright (C) 2009 wj32
+ *
+ * This file is part of Process Hacker.
+ *
+ * Process Hacker is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Process Hacker is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Process Hacker. If not, see .
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using ProcessHacker.Native.Api;
+using ProcessHacker.Native.Objects;
+using ProcessHacker.Native.Security;
+
+namespace ProcessHacker.Native.Threading
+{
+ public delegate void ObjectSignaledDelegate(ISynchronizable obj);
+
+ public class WaiterThread : IDisposable
+ {
+ private enum WaiterThreadMessageType
+ {
+ AddObject,
+ RemoveObject
+ }
+
+ private class WaiterThreadMessage
+ {
+ private WaiterThreadMessageType _type;
+ private object _param;
+
+ public WaiterThreadMessage(WaiterThreadMessageType type)
+ : this(type, null)
+ { }
+
+ public WaiterThreadMessage(WaiterThreadMessageType type, object param)
+ {
+ _type = type;
+ _param = param;
+ }
+
+ public WaiterThreadMessageType Type { get { return _type; } }
+ public object Param { get { return _param; } }
+ }
+
+ ///
+ /// Raised when an object is signaled.
+ ///
+ public event ObjectSignaledDelegate ObjectSignaled;
+
+ private bool _disposed = false;
+ private bool _terminating = false;
+ private object _disposeLock = new object();
+
+ private Thread _waiterThread;
+ private List _waitObjects = new List();
+
+ private Queue _waitMessageQueue = new Queue();
+ private Event _waitMessageEvent = new Event(true, false);
+
+ ///
+ /// Creates a waiter thread.
+ ///
+ public WaiterThread()
+ {
+ _waiterThread = new Thread(this.WaiterThreadStart);
+ _waiterThread.IsBackground = true;
+ _waiterThread.SetApartmentState(ApartmentState.STA);
+ _waiterThread.Start();
+ }
+
+ ~WaiterThread()
+ {
+ this.Dispose(false);
+ }
+
+ ///
+ /// Releases resources used by the waiter thread.
+ ///
+ public void Dispose()
+ {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (disposing)
+ Monitor.Enter(_disposeLock);
+
+ try
+ {
+ if (!_disposed)
+ {
+ // Tell the waiter thread to terminate.
+ _terminating = true;
+ _waitMessageEvent.Set();
+
+ _disposed = true;
+ }
+ }
+ finally
+ {
+ Monitor.Exit(_disposeLock);
+ }
+ }
+
+ ///
+ /// Adds an object for the waiter thread to wait on.
+ ///
+ /// The object to wait for.
+ public void Add(ISynchronizable obj)
+ {
+ lock (_waitMessageQueue)
+ {
+ if (_waitObjects.Count >= Win32.MaximumWaitObjects - 1)
+ throw new TooManyWaitObjectsException();
+
+ this.SendWaiterThreadMessage(new WaiterThreadMessage(WaiterThreadMessageType.AddObject, obj));
+ }
+ }
+
+ private void OnObjectSignaled(ISynchronizable obj)
+ {
+ if (ObjectSignaled != null)
+ ObjectSignaled(obj);
+ }
+
+ ///
+ /// Removes an object the waiter thread is waiting on.
+ ///
+ /// An object which is currently being waited on.
+ public void Remove(ISynchronizable obj)
+ {
+ this.SendWaiterThreadMessage(new WaiterThreadMessage(WaiterThreadMessageType.RemoveObject, obj));
+ }
+
+ private void SendWaiterThreadMessage(WaiterThreadMessage message)
+ {
+ lock (_waitMessageQueue)
+ {
+ _waitMessageQueue.Enqueue(message);
+ _waitMessageEvent.Set();
+ }
+ }
+
+ private void WaiterThreadStart()
+ {
+ ISynchronizable[] waitObjects;
+
+ while (!_terminating)
+ {
+ waitObjects = new ISynchronizable[_waitObjects.Count + 1];
+ waitObjects[0] = _waitMessageEvent.Handle;
+ Array.Copy(_waitObjects.ToArray(), 0, waitObjects, 1, _waitObjects.Count);
+
+ NtStatus waitStatus = NativeHandle.WaitAny(waitObjects);
+
+ if (waitStatus == NtStatus.Wait0)
+ {
+ // We have a message in the message queue (or we are terminating).
+ WaiterThreadMessage message;
+
+ // Lock and retrieve the message.
+ lock (_waitMessageQueue)
+ {
+ if (_waitMessageQueue.Count > 0)
+ message = _waitMessageQueue.Dequeue();
+ else
+ continue;
+ }
+
+ switch (message.Type)
+ {
+ case WaiterThreadMessageType.AddObject:
+ {
+ _waitObjects.Add((ISynchronizable)message.Param);
+ }
+ break;
+ case WaiterThreadMessageType.RemoveObject:
+ {
+ _waitObjects.Remove((ISynchronizable)message.Param);
+ }
+ break;
+ }
+ }
+ else if (waitStatus > NtStatus.Wait0 && waitStatus <= NtStatus.Wait63)
+ {
+ // One of the objects was signaled.
+ ISynchronizable signaledObject = waitObjects[(int)(waitStatus - NtStatus.Wait0)];
+ // Remove the object now that it is signaled.
+ _waitObjects.Remove(signaledObject);
+ // Call the object-signaled event.
+ OnObjectSignaled(signaledObject);
+ }
+ }
+ }
+ }
+
+ public class TooManyWaitObjectsException : Exception
+ {
+ public override string Message
+ {
+ get
+ {
+ return "An attempt was made to add too many objects to the wait list.";
+ }
+ }
+ }
+}