1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*++
6
7
8
9Module Name:
10
11 handlemgr.cpp
12
13Abstract:
14
15 Implementation of a basic handle table
16
17
18
19--*/
20
21#include "pal/thread.hpp"
22#include "pal/handlemgr.hpp"
23#include "pal/cs.hpp"
24#include "pal/malloc.hpp"
25#include "pal/dbgmsg.h"
26
27using namespace CorUnix;
28
29SET_DEFAULT_DEBUG_CHANNEL(HANDLE);
30
31/* Constants */
32/* Special handles */
33/* Pseudo handles constant for current thread and process */
34const HANDLE hPseudoCurrentProcess = (HANDLE) 0xFFFFFF01;
35const HANDLE hPseudoCurrentThread = (HANDLE) 0xFFFFFF03;
36/* Pseudo handle constant for the global IO Completion port */
37const HANDLE hPseudoGlobalIOCP = (HANDLE) 0xFFFFFF05;
38
39PAL_ERROR
40CSimpleHandleManager::Initialize(
41 void
42 )
43{
44 PAL_ERROR palError = NO_ERROR;
45
46 InternalInitializeCriticalSection(&m_csLock);
47 m_fLockInitialized = TRUE;
48
49 m_dwTableGrowthRate = c_BasicGrowthRate;
50
51 /* initialize the handle table - the free list is stored in the 'object'
52 field, with the head in the global 'm_hiFreeListStart'. */
53 m_dwTableSize = m_dwTableGrowthRate;
54
55 m_rghteHandleTable = reinterpret_cast<HANDLE_TABLE_ENTRY*>(InternalMalloc((m_dwTableSize * sizeof(HANDLE_TABLE_ENTRY))));
56 if(NULL == m_rghteHandleTable)
57 {
58 ERROR("Unable to create initial handle table array");
59 palError = ERROR_OUTOFMEMORY;
60 goto InitializeExit;
61 }
62
63 for (DWORD i = 0; i < m_dwTableSize; i++)
64 {
65 m_rghteHandleTable[i].u.hiNextIndex = i + 1;
66 m_rghteHandleTable[i].fEntryAllocated = FALSE;
67 }
68
69 m_rghteHandleTable[m_dwTableSize - 1].u.hiNextIndex = (HANDLE_INDEX)-1;
70
71 m_hiFreeListStart = 0;
72 m_hiFreeListEnd = m_dwTableSize - 1;
73
74 TRACE("Handle Manager initialization complete.\n");
75
76InitializeExit:
77
78 return palError;
79}
80
81PAL_ERROR
82CSimpleHandleManager::AllocateHandle(
83 CPalThread *pThread,
84 IPalObject *pObject,
85 DWORD dwAccessRights,
86 bool fInheritable,
87 HANDLE *ph
88 )
89{
90 PAL_ERROR palError = NO_ERROR;
91 DWORD dwIndex;
92
93 Lock(pThread);
94
95 /* if no free handles are available, we need to grow the handle table and
96 add new handles to the pool */
97 if (m_hiFreeListStart == c_hiInvalid)
98 {
99 HANDLE_TABLE_ENTRY* rghteTempTable;
100
101 TRACE("Handle pool empty (%d handles allocated), growing handle table "
102 "by %d entries.\n", m_dwTableSize, m_dwTableGrowthRate );
103
104 /* make sure handle values don't overflow */
105 if (m_dwTableSize + m_dwTableGrowthRate >= c_MaxIndex)
106 {
107 WARN("Unable to allocate handle : maximum (%d) reached!\n",
108 m_dwTableSize);
109 palError = ERROR_OUTOFMEMORY;
110 goto AllocateHandleExit;
111 }
112
113 /* grow handle table */
114 rghteTempTable = reinterpret_cast<HANDLE_TABLE_ENTRY*>(InternalRealloc(
115 m_rghteHandleTable,
116 (m_dwTableSize + m_dwTableGrowthRate) * sizeof(HANDLE_TABLE_ENTRY)));
117
118 if (NULL == rghteTempTable)
119 {
120 WARN("not enough memory to grow handle table!\n");
121 palError = ERROR_OUTOFMEMORY;
122 goto AllocateHandleExit;
123 }
124 m_rghteHandleTable = rghteTempTable;
125
126 /* update handle table and handle pool */
127 for (DWORD dw = m_dwTableSize; dw < m_dwTableSize + m_dwTableGrowthRate; dw += 1)
128 {
129 /* new handles are initially invalid */
130 /* the last "old" handle was m_dwTableSize-1, so the new
131 handles range from m_dwTableSize to
132 m_dwTableSize+m_dwTableGrowthRate-1 */
133 m_rghteHandleTable[dw].u.hiNextIndex = dw + 1;
134 m_rghteHandleTable[dw].fEntryAllocated = FALSE;
135 }
136
137 m_hiFreeListStart = m_dwTableSize;
138 m_dwTableSize += m_dwTableGrowthRate;
139 m_rghteHandleTable[m_dwTableSize - 1].u.hiNextIndex = (HANDLE_INDEX)-1;
140 m_hiFreeListEnd = m_dwTableSize - 1;
141
142 }
143
144 /* take the next free handle */
145 dwIndex = m_hiFreeListStart;
146
147 /* remove the handle from the pool */
148 m_hiFreeListStart = m_rghteHandleTable[dwIndex].u.hiNextIndex;
149
150 /* clear the tail record if this is the last handle slot available */
151 if(m_hiFreeListStart == c_hiInvalid)
152 {
153 m_hiFreeListEnd = c_hiInvalid;
154 }
155
156 /* save the data associated with the new handle */
157 *ph = HandleIndexToHandle(dwIndex);
158
159 pObject->AddReference();
160 m_rghteHandleTable[dwIndex].u.pObject = pObject;
161 m_rghteHandleTable[dwIndex].dwAccessRights = dwAccessRights;
162 m_rghteHandleTable[dwIndex].fInheritable = fInheritable;
163 m_rghteHandleTable[dwIndex].fEntryAllocated = TRUE;
164
165AllocateHandleExit:
166
167 Unlock(pThread);
168
169 return palError;
170}
171
172PAL_ERROR
173CSimpleHandleManager::GetObjectFromHandle(
174 CPalThread *pThread,
175 HANDLE h,
176 DWORD *pdwRightsGranted,
177 IPalObject **ppObject
178 )
179{
180 PAL_ERROR palError = NO_ERROR;
181 HANDLE_INDEX hi;
182
183 Lock(pThread);
184
185 if (!ValidateHandle(h))
186 {
187 ERROR("Tried to dereference an invalid handle %p\n", h);
188 palError = ERROR_INVALID_HANDLE;
189 goto GetObjectFromHandleExit;
190 }
191
192 hi = HandleToHandleIndex(h);
193
194 *pdwRightsGranted = m_rghteHandleTable[hi].dwAccessRights;
195 *ppObject = m_rghteHandleTable[hi].u.pObject;
196 (*ppObject)->AddReference();
197
198GetObjectFromHandleExit:
199
200 Unlock(pThread);
201
202 return palError;
203}
204
205PAL_ERROR
206CSimpleHandleManager::FreeHandle(
207 CPalThread *pThread,
208 HANDLE h
209 )
210{
211 PAL_ERROR palError = NO_ERROR;
212 IPalObject *pobj = NULL;
213 HANDLE_INDEX hi = HandleToHandleIndex(h);
214
215 Lock(pThread);
216
217 if (!ValidateHandle(h))
218 {
219 ERROR("Trying to free invalid handle %p.\n", h);
220 palError = ERROR_INVALID_HANDLE;
221 goto FreeHandleExit;
222 }
223
224 if (HandleIsSpecial(h))
225 {
226 ASSERT("Trying to free Special Handle %p.\n", h);
227 palError = ERROR_INVALID_HANDLE;
228 goto FreeHandleExit;
229 }
230
231 pobj = m_rghteHandleTable[hi].u.pObject;
232 m_rghteHandleTable[hi].fEntryAllocated = FALSE;
233
234 /* add handle to the free pool */
235 if(m_hiFreeListEnd != c_hiInvalid)
236 {
237 m_rghteHandleTable[m_hiFreeListEnd].u.hiNextIndex = hi;
238 }
239 else
240 {
241 m_hiFreeListStart = hi;
242 }
243
244 m_rghteHandleTable[hi].u.hiNextIndex = c_hiInvalid;
245 m_hiFreeListEnd = hi;
246
247FreeHandleExit:
248
249 Unlock(pThread);
250
251 if (NULL != pobj)
252 {
253 pobj->ReleaseReference(pThread);
254 }
255
256 return palError;
257}
258
259/*++
260Function :
261 ValidateHandle
262
263 Check if a handle was allocated by this handle manager
264
265Parameters :
266 HANDLE handle : handle to check.
267
268Return Value :
269 TRUE if valid, FALSE if invalid.
270--*/
271bool CSimpleHandleManager::ValidateHandle(HANDLE handle)
272{
273 DWORD dwIndex;
274
275 if (NULL == m_rghteHandleTable)
276 {
277 ASSERT("Handle Manager is not initialized!\n");
278 return FALSE;
279 }
280
281 if (handle == INVALID_HANDLE_VALUE || handle == 0)
282 {
283 TRACE( "INVALID_HANDLE_VALUE or NULL value is not a valid handle.\n" );
284 return FALSE;
285 }
286
287 if (HandleIsSpecial(handle))
288 {
289 //
290 // Special handles are valid in the general sense. They are not valid
291 // in this context, though, as they were not allocated by the handle
292 // manager. Hitting this case indicates a logic error within the PAL
293 // (since clients of the handle manager should have already dealt with
294 // the specialness of the handle) so we assert here.
295 //
296
297 ASSERT ("Handle %p is a special handle, returning FALSE.\n", handle);
298 return FALSE;
299 }
300
301 dwIndex = HandleToHandleIndex(handle);
302
303 if (dwIndex >= m_dwTableSize)
304 {
305 WARN( "The handle value(%p) is out of the bounds for the handle table.\n", handle );
306 return FALSE;
307 }
308
309 if (!m_rghteHandleTable[dwIndex].fEntryAllocated)
310 {
311 WARN("The handle value (%p) has not been allocated\n", handle);
312 return FALSE;
313 }
314
315 return TRUE;
316}
317
318bool
319CorUnix::HandleIsSpecial(
320 HANDLE h
321 )
322{
323 return (hPseudoCurrentProcess == h ||
324 hPseudoCurrentThread == h ||
325 hPseudoGlobalIOCP == h);
326}
327
328