/*
* Process Hacker -
* handle table
*
* 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.Collections.Generic;
namespace ProcessHacker.Common.Objects
{
public class HandleTableEntry
{
private int _handle;
private IRefCounted _object;
public int Handle
{
get { return _handle; }
internal set { _handle = value; }
}
public IRefCounted Object
{
get { return _object; }
internal set { _object = value; }
}
}
///
/// Provides methods for managing handles to objects.
///
public class HandleTable : HandleTable
{ }
///
/// Provides methods for managing handles to objects.
///
/// The type of each handle table entry.
public class HandleTable : BaseObject
where TEntry : HandleTableEntry, new()
{
///
/// Represents a callback function for handle table enumeration.
///
/// The current handle.
/// The current object.
/// Return true to stop enumerating; otherwise return false.
public delegate bool EnumerateHandleTableDelegate(int handle, TEntry entry);
private IdGenerator _handleGenerator = new IdGenerator(4, 4);
private Dictionary _handles =
new Dictionary();
protected override void DisposeObject(bool disposing)
{
lock (_handles)
{
foreach (var entry in _handles.Values)
entry.Object.Dereference(disposing);
}
}
///
/// Creates a handle to the specified object.
///
/// The object to reference.
/// The new handle.
public int Allocate(IRefCounted obj)
{
TEntry entry = new TEntry();
return this.Allocate(obj, entry);
}
///
/// Creates a handle to the specified object.
///
/// The object to reference.
/// The handle table entry to use.
/// The new handle.
public int Allocate(IRefCounted obj, TEntry entry)
{
int handle = _handleGenerator.Pop();
// Reference the object so it does not get freed while
// it is stored in the handle table.
obj.Reference();
// GC should not own the object.
obj.Dispose();
// Initialize the entry.
entry.Handle = handle;
entry.Object = obj;
// Add the handle entry.
lock (_handles)
{
_handles.Add(handle, entry);
}
return handle;
}
///
/// Enumerates the handles in the handle table.
///
/// The callback for the enumeration.
/// Whether the enumeration was stopped by the callback.
public bool Enumerate(EnumerateHandleTableDelegate callback)
{
lock (_handles)
{
foreach (var entry in _handles.Values)
{
if (callback(entry.Handle, entry))
return true;
}
return false;
}
}
///
/// Closes a handle.
///
/// The handle to close.
/// Whether the handle was closed.
public bool Free(int handle)
{
IRefCounted obj;
lock (_handles)
{
if (!_handles.ContainsKey(handle))
return false;
// Store the object reference for dereferencing later.
obj = _handles[handle].Object;
// Remove the handle so it can no longer be used.
_handles.Remove(handle);
}
// Make the handle value available.
_handleGenerator.Push(handle);
// Dereference the object (this doesn't need to be in the locking block).
obj.Dereference();
return true;
}
///
/// Gets the handle table entry for a handle.
///
/// The handle to lookup.
/// A handle table entry.
public TEntry LookupEntry(int handle)
{
lock (_handles)
{
if (_handles.ContainsKey(handle))
return _handles[handle];
else
return null;
}
}
///
/// Gets the object referenced by a handle.
///
/// The handle to lookup.
///
/// An object. This object has not been referenced and is
/// not guaranteed to be valid.
///
public IRefCounted LookupObject(int handle)
{
return this.LookupEntry(handle).Object;
}
///
/// Gets the object referenced by a handle.
///
/// The type of the object to retrieve.
/// The handle to lookup.
///
/// An object. This object has not been referenced and is
/// not guaranteed to be valid.
///
public T LookupObject(int handle)
where T : class, IRefCounted
{
return this.LookupObject(handle) as T;
}
///
/// References an object using a handle.
///
/// The handle to lookup.
///
/// An object. This object has been referenced and must be
/// dereferenced once it is no longer needed.
///
public IRefCounted ReferenceByHandle(int handle)
{
TEntry entry;
return this.ReferenceByHandle(handle, out entry);
}
///
/// References an object using a handle.
///
/// The handle to lookup.
/// The handle table entry.
///
/// An object. This object has been referenced and must be
/// dereferenced once it is no longer needed.
///
public IRefCounted ReferenceByHandle(int handle, out TEntry entry)
{
lock (_handles)
{
if (_handles.ContainsKey(handle))
{
IRefCounted obj = _handles[handle].Object;
obj.Reference();
entry = _handles[handle];
return obj;
}
else
{
entry = null;
return null;
}
}
}
///
/// References an object using a handle.
///
/// The type of the object to reference.
/// The handle to lookup.
///
/// An object. This object has been referenced and must be
/// dereferenced once it is no longer needed.
///
public T ReferenceByHandle(int handle)
where T : class, IRefCounted
{
TEntry entry;
return this.ReferenceByHandle(handle, out entry);
}
///
/// References an object using a handle.
///
/// The type of the object to reference.
/// The handle to lookup.
/// The handle table entry.
///
/// An object. This object has been referenced and must be
/// dereferenced once it is no longer needed.
///
public T ReferenceByHandle(int handle, out TEntry entry)
where T : class, IRefCounted
{
IRefCounted obj = this.ReferenceByHandle(handle, out entry);
if (obj == null)
return null;
// Check the type.
if (obj is T)
{
return (T)obj;
}
else
{
// Wrong type. Dereference and return.
obj.Dereference();
return null;
}
}
}
}