blob: 291c191dc10b83e6b148aa6015bd15babbdf5166 [file]
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
/*++
Module Name:
handlemgr.cpp
Abstract:
Implementation of a basic handle table
--*/
#include "pal/thread.hpp"
#include "pal/handlemgr.hpp"
#include "pal/cs.hpp"
#include "pal/malloc.hpp"
#include "pal/dbgmsg.h"
using namespace CorUnix;
SET_DEFAULT_DEBUG_CHANNEL(HANDLE);
/* Constants */
/* Special handles */
/* Pseudo handles constant for current thread and process */
const HANDLE hPseudoCurrentProcess = (HANDLE) 0xFFFFFF01;
const HANDLE hPseudoCurrentThread = (HANDLE) 0xFFFFFF03;
/* Pseudo handle constant for the global IO Completion port */
const HANDLE hPseudoGlobalIOCP = (HANDLE) 0xFFFFFF05;
PAL_ERROR
CSimpleHandleManager::Initialize(
void
)
{
PAL_ERROR palError = NO_ERROR;
InternalInitializeCriticalSection(&m_csLock);
m_fLockInitialized = TRUE;
m_dwTableGrowthRate = c_BasicGrowthRate;
/* initialize the handle table - the free list is stored in the 'object'
field, with the head in the global 'm_hiFreeListStart'. */
m_dwTableSize = m_dwTableGrowthRate;
m_rghteHandleTable = reinterpret_cast<HANDLE_TABLE_ENTRY*>(InternalMalloc((m_dwTableSize * sizeof(HANDLE_TABLE_ENTRY))));
if(NULL == m_rghteHandleTable)
{
ERROR("Unable to create initial handle table array");
palError = ERROR_OUTOFMEMORY;
goto InitializeExit;
}
for (DWORD i = 0; i < m_dwTableSize; i++)
{
m_rghteHandleTable[i].u.hiNextIndex = i + 1;
m_rghteHandleTable[i].fEntryAllocated = FALSE;
}
m_rghteHandleTable[m_dwTableSize - 1].u.hiNextIndex = (HANDLE_INDEX)-1;
m_hiFreeListStart = 0;
m_hiFreeListEnd = m_dwTableSize - 1;
TRACE("Handle Manager initialization complete.\n");
InitializeExit:
return palError;
}
PAL_ERROR
CSimpleHandleManager::AllocateHandle(
CPalThread *pThread,
IPalObject *pObject,
DWORD dwAccessRights,
bool fInheritable,
HANDLE *ph
)
{
PAL_ERROR palError = NO_ERROR;
DWORD dwIndex;
Lock(pThread);
/* if no free handles are available, we need to grow the handle table and
add new handles to the pool */
if (m_hiFreeListStart == c_hiInvalid)
{
HANDLE_TABLE_ENTRY* rghteTempTable;
TRACE("Handle pool empty (%d handles allocated), growing handle table "
"by %d entries.\n", m_dwTableSize, m_dwTableGrowthRate );
/* make sure handle values don't overflow */
if (m_dwTableSize + m_dwTableGrowthRate >= c_MaxIndex)
{
WARN("Unable to allocate handle : maximum (%d) reached!\n",
m_dwTableSize);
palError = ERROR_OUTOFMEMORY;
goto AllocateHandleExit;
}
/* grow handle table */
rghteTempTable = reinterpret_cast<HANDLE_TABLE_ENTRY*>(InternalRealloc(
m_rghteHandleTable,
(m_dwTableSize + m_dwTableGrowthRate) * sizeof(HANDLE_TABLE_ENTRY)));
if (NULL == rghteTempTable)
{
WARN("not enough memory to grow handle table!\n");
palError = ERROR_OUTOFMEMORY;
goto AllocateHandleExit;
}
m_rghteHandleTable = rghteTempTable;
/* update handle table and handle pool */
for (DWORD dw = m_dwTableSize; dw < m_dwTableSize + m_dwTableGrowthRate; dw += 1)
{
/* new handles are initially invalid */
/* the last "old" handle was m_dwTableSize-1, so the new
handles range from m_dwTableSize to
m_dwTableSize+m_dwTableGrowthRate-1 */
m_rghteHandleTable[dw].u.hiNextIndex = dw + 1;
m_rghteHandleTable[dw].fEntryAllocated = FALSE;
}
m_hiFreeListStart = m_dwTableSize;
m_dwTableSize += m_dwTableGrowthRate;
m_rghteHandleTable[m_dwTableSize - 1].u.hiNextIndex = (HANDLE_INDEX)-1;
m_hiFreeListEnd = m_dwTableSize - 1;
}
/* take the next free handle */
dwIndex = m_hiFreeListStart;
/* remove the handle from the pool */
m_hiFreeListStart = m_rghteHandleTable[dwIndex].u.hiNextIndex;
/* clear the tail record if this is the last handle slot available */
if(m_hiFreeListStart == c_hiInvalid)
{
m_hiFreeListEnd = c_hiInvalid;
}
/* save the data associated with the new handle */
*ph = HandleIndexToHandle(dwIndex);
pObject->AddReference();
m_rghteHandleTable[dwIndex].u.pObject = pObject;
m_rghteHandleTable[dwIndex].dwAccessRights = dwAccessRights;
m_rghteHandleTable[dwIndex].fInheritable = fInheritable;
m_rghteHandleTable[dwIndex].fEntryAllocated = TRUE;
AllocateHandleExit:
Unlock(pThread);
return palError;
}
PAL_ERROR
CSimpleHandleManager::GetObjectFromHandle(
CPalThread *pThread,
HANDLE h,
DWORD *pdwRightsGranted,
IPalObject **ppObject
)
{
PAL_ERROR palError = NO_ERROR;
HANDLE_INDEX hi;
Lock(pThread);
if (!ValidateHandle(h))
{
ERROR("Tried to dereference an invalid handle %p\n", h);
palError = ERROR_INVALID_HANDLE;
goto GetObjectFromHandleExit;
}
hi = HandleToHandleIndex(h);
*pdwRightsGranted = m_rghteHandleTable[hi].dwAccessRights;
*ppObject = m_rghteHandleTable[hi].u.pObject;
(*ppObject)->AddReference();
GetObjectFromHandleExit:
Unlock(pThread);
return palError;
}
PAL_ERROR
CSimpleHandleManager::FreeHandle(
CPalThread *pThread,
HANDLE h
)
{
PAL_ERROR palError = NO_ERROR;
IPalObject *pobj = NULL;
HANDLE_INDEX hi = HandleToHandleIndex(h);
Lock(pThread);
if (!ValidateHandle(h))
{
ERROR("Trying to free invalid handle %p.\n", h);
palError = ERROR_INVALID_HANDLE;
goto FreeHandleExit;
}
if (HandleIsSpecial(h))
{
ASSERT("Trying to free Special Handle %p.\n", h);
palError = ERROR_INVALID_HANDLE;
goto FreeHandleExit;
}
pobj = m_rghteHandleTable[hi].u.pObject;
m_rghteHandleTable[hi].fEntryAllocated = FALSE;
/* add handle to the free pool */
if(m_hiFreeListEnd != c_hiInvalid)
{
m_rghteHandleTable[m_hiFreeListEnd].u.hiNextIndex = hi;
}
else
{
m_hiFreeListStart = hi;
}
m_rghteHandleTable[hi].u.hiNextIndex = c_hiInvalid;
m_hiFreeListEnd = hi;
FreeHandleExit:
Unlock(pThread);
if (NULL != pobj)
{
pobj->ReleaseReference(pThread);
}
return palError;
}
/*++
Function :
ValidateHandle
Check if a handle was allocated by this handle manager
Parameters :
HANDLE handle : handle to check.
Return Value :
TRUE if valid, FALSE if invalid.
--*/
bool CSimpleHandleManager::ValidateHandle(HANDLE handle)
{
DWORD dwIndex;
if (NULL == m_rghteHandleTable)
{
ASSERT("Handle Manager is not initialized!\n");
return FALSE;
}
if (handle == INVALID_HANDLE_VALUE || handle == 0)
{
TRACE( "INVALID_HANDLE_VALUE or NULL value is not a valid handle.\n" );
return FALSE;
}
if (HandleIsSpecial(handle))
{
//
// Special handles are valid in the general sense. They are not valid
// in this context, though, as they were not allocated by the handle
// manager. Hitting this case indicates a logic error within the PAL
// (since clients of the handle manager should have already dealt with
// the specialness of the handle) so we assert here.
//
ASSERT ("Handle %p is a special handle, returning FALSE.\n", handle);
return FALSE;
}
dwIndex = HandleToHandleIndex(handle);
if (dwIndex >= m_dwTableSize)
{
WARN( "The handle value(%p) is out of the bounds for the handle table.\n", handle );
return FALSE;
}
if (!m_rghteHandleTable[dwIndex].fEntryAllocated)
{
WARN("The handle value (%p) has not been allocated\n", handle);
return FALSE;
}
return TRUE;
}
bool
CorUnix::HandleIsSpecial(
HANDLE h
)
{
return (hPseudoCurrentProcess == h ||
hPseudoCurrentThread == h ||
hPseudoGlobalIOCP == h);
}