VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/GVMR0.cpp@ 4971

Last change on this file since 4971 was 4971, checked in by vboxsync, 17 years ago

GVM.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 20.4 KB
Line 
1/* $Id: GVMR0.cpp 4971 2007-09-21 22:19:12Z vboxsync $ */
2/** @file
3 * GVM - Global VM Manager.
4 */
5
6/*
7 * Copyright (C) 2007 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 */
18
19
20/** @page pg_GVM GVM - Global VM Manager
21 *
22 * The Global VM Manager lives in ring-0. It's main function at the moment
23 * is to manage a list of all running VMs and assign unique identifiers to
24 * each of them (so GMM can track page owners). The idea for the future is
25 * to add an idle priority kernel thread that can take care of tasks like
26 * page sharing.
27 *
28 * The GVM will create a ring-0 object for each VM when it's registered, this
29 * is both for session cleanup purposes and for having a point where it's
30 * possible to implement usage polices later (in SUPR0ObjRegister).
31 */
32
33
34/*******************************************************************************
35* Header Files *
36*******************************************************************************/
37#define LOG_GROUP LOG_GROUP_GVM
38#include <VBox/gvm.h>
39/* #include "GVMInternal.h" */
40#include <VBox/vm.h>
41#include <VBox/err.h>
42#include <iprt/alloc.h>
43#include <iprt/semaphore.h>
44#include <iprt/log.h>
45#include <iprt/thread.h>
46#include <iprt/param.h>
47#include <iprt/string.h>
48
49
50/*******************************************************************************
51* Structures and Typedefs *
52*******************************************************************************/
53
54/**
55 * Global VM handle.
56 */
57typedef struct GVMHANDLE
58{
59 /** The index of the next handle in the list (free or used). (0 is nil.) */
60 uint16_t volatile iNext;
61 /** Our own index / handle value. */
62 uint16_t iSelf;
63 /** Whether to free the VM structure or not. */
64 bool fFreeVM;
65 /** The ring-0 mapping of the VM instance data. */
66 PVM pVM;
67 /** The virtual machine object. */
68 void *pvObj;
69 /** The session this VM is associated with. */
70 PSUPDRVSESSION pSession;
71 /** The ring-0 handle of the EMT thread.
72 * This is used for assertions and similar cases where we need to find the VM handle. */
73 RTNATIVETHREAD hEMT;
74} GVMHANDLE;
75/** Pointer to a global VM handle. */
76typedef GVMHANDLE *PGVMHANDLE;
77
78/**
79 * The GVM instance data.
80 */
81typedef struct
82{
83 /** Eyecatcher / magic. */
84 uint32_t u32Magic;
85 /** The index of the head of the free handle chain. (0 is nil.) */
86 uint16_t volatile iFreeHead;
87 /** The index of the head of the active handle chain. (0 is nil.) */
88 uint16_t volatile iUsedHead;
89 /** The lock used to serialize registration and deregistration. */
90 RTSEMFASTMUTEX Lock;
91 /** The handle array.
92 * The size of this array defines the maximum number of currently running VMs.
93 * The first entry is unused as it represents the NIL handle. */
94 GVMHANDLE aHandles[128];
95} GVM;
96/** Pointer to the GVM instance data. */
97typedef GVM *PGVM;
98
99/** The GVM::u32Magic value (Charlie Haden). */
100#define GVM_MAGIC 0x19370806
101
102
103
104/*******************************************************************************
105* Global Variables *
106*******************************************************************************/
107/** Pointer to the GVM instance data.
108 * (Just my general dislike for global variables.) */
109static PGVM g_pGVM = NULL;
110
111
112/*******************************************************************************
113* Internal Functions *
114*******************************************************************************/
115static DECLCALLBACK(void) gvmR0HandleObjDestructor(void *pvObj, void *pvGVM, void *pvHandle);
116
117
118/**
119 * Initializes the GVM.
120 *
121 * This is called while owninng the loader sempahore (see supdrvIOCtl_LdrLoad()).
122 *
123 * @returns VBox status code.
124 */
125GVMR0DECL(int) GVMR0Init(void)
126{
127 SUPR0Printf("GVMR0Init:\n");
128
129 /*
130 * Allocate and initialize the instance data.
131 */
132 PGVM pGVM = (PGVM)RTMemAllocZ(sizeof(*pGVM));
133 if (!pGVM)
134 return VERR_NO_MEMORY;
135 int rc = RTSemFastMutexCreate(&pGVM->Lock);
136 if (RT_SUCCESS(rc))
137 {
138 pGVM->u32Magic = GVM_MAGIC;
139 pGVM->iUsedHead = 0;
140 pGVM->iFreeHead = 1;
141
142 /* the nil handle */
143 pGVM->aHandles[0].iSelf = 0;
144 pGVM->aHandles[0].iNext = 0;
145
146 /* the tail */
147 unsigned i = RT_ELEMENTS(pGVM->aHandles);
148 pGVM->aHandles[i].iSelf = i;
149 pGVM->aHandles[i].iNext = 0; /* nil */
150
151 /* the rest */
152 while (i-- > 1)
153 {
154 pGVM->aHandles[i].iSelf = i;
155 pGVM->aHandles[i].iNext = i + 1;
156 }
157
158 g_pGVM = pGVM;
159 SUPR0Printf("GVMR0Init: pGVM=%p\n", pGVM);
160 return VINF_SUCCESS;
161 }
162
163 RTMemFree(pGVM);
164 return rc;
165}
166
167
168/**
169 * Terminates the GVM.
170 *
171 * This is called while owning the loader semaphore (see supdrvLdrFree()).
172 * And unless something is wrong, there should be absolutely no VMs
173 * registered at this point.
174 */
175GVMR0DECL(void) GVMR0Term(void)
176{
177 SUPR0Printf("GVMR0Term:\n");
178
179 PGVM pGVM = g_pGVM;
180 g_pGVM = NULL;
181 if (RT_UNLIKELY(!VALID_PTR(pGVM)))
182 {
183 SUPR0Printf("GVMR0Term: pGVM=%p\n", pGVM);
184 return;
185 }
186
187 RTSemFastMutexDestroy(pGVM->Lock);
188 pGVM->Lock = NIL_RTSEMFASTMUTEX;
189 pGVM->u32Magic++;
190 pGVM->iFreeHead = 0;
191 if (pGVM->iUsedHead)
192 {
193 SUPR0Printf("GVMR0Term: iUsedHead=%#x!\n", pGVM->iUsedHead);
194 pGVM->iUsedHead = 0;
195 }
196
197 RTMemFree(pGVM);
198}
199
200
201/**
202 * Allocates the VM structure and registers it with GVM.
203 *
204 * @returns VBox status code.
205 * @param pSession The support driver session.
206 * @param ppVM Where to store the pointer to the VM structure.
207 *
208 * @thread EMT.
209 */
210GVMR0DECL(int) GVMR0CreateVM(PSUPDRVSESSION pSession, PVM *ppVM)
211{
212 SUPR0Printf("GVMR0CreateVM: pSession=%p\n", pSession);
213 PGVM pGVM = g_pGVM;
214 AssertPtrReturn(pGVM, VERR_INTERNAL_ERROR);
215
216 AssertPtrReturn(ppVM, VERR_INVALID_POINTER);
217 *ppVM = NULL;
218
219 RTNATIVETHREAD hEMT = RTThreadNativeSelf();
220 AssertReturn(hEMT != NIL_RTNATIVETHREAD, VERR_INTERNAL_ERROR);
221
222 /*
223 * The whole allocation process is protected by the lock.
224 */
225 int rc = RTSemFastMutexRequest(pGVM->Lock);
226 AssertRCReturn(rc, rc);
227
228 /*
229 * Allocate a handle first so we don't waste resources unnecessarily.
230 */
231 uint16_t iHandle = pGVM->iFreeHead;
232 if (iHandle)
233 {
234 PGVMHANDLE pHandle = &pGVM->aHandles[iHandle];
235
236 /* consistency checks, a bit paranoid as always. */
237 if ( !pHandle->pVM
238 && !pHandle->pvObj
239 && pHandle->iSelf == iHandle)
240 {
241 pHandle->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_VM, gvmR0HandleObjDestructor, pGVM, pHandle);
242 if (pHandle->pvObj)
243 {
244 /*
245 * Move the handle from the free to used list and perform permission checks.
246 */
247 pGVM->iFreeHead = pHandle->iNext;
248 pHandle->iNext = pGVM->iUsedHead;
249 pGVM->iUsedHead = iHandle;
250
251 pHandle->fFreeVM = true;
252 pHandle->pVM = NULL;
253 pHandle->pSession = pSession;
254 pHandle->hEMT = hEMT;
255
256 rc = SUPR0ObjVerifyAccess(pHandle->pvObj, pSession, NULL);
257 if (RT_SUCCESS(rc))
258 {
259 /*
260 * Allocate and initialize the VM structure.
261 */
262 RTR3PTR paPagesR3;
263 PRTHCPHYS paPagesR0;
264 size_t cPages = RT_ALIGN_Z(sizeof(VM), PAGE_SIZE) >> PAGE_SHIFT;
265 rc = SUPR0MemAlloc(pSession, cPages * sizeof(RTHCPHYS), (void **)&paPagesR0, &paPagesR3);
266 if (RT_SUCCESS(rc))
267 {
268 PVM pVM;
269 PVMR3 pVMR3;
270 rc = SUPR0LowAlloc(pSession, cPages, (void **)&pVM, &pVMR3, paPagesR0);
271 if (RT_SUCCESS(rc))
272 {
273 memset(pVM, 0, cPages * PAGE_SIZE);
274 pVM->enmVMState = VMSTATE_CREATING;
275 pVM->paVMPagesR3 = paPagesR3;
276 pVM->pVMR3 = pVMR3;
277 pVM->pVMR0 = pVM;
278 pVM->pSession = pSession;
279 pVM->hSelf = iHandle;
280 RTSemFastMutexRelease(pGVM->Lock);
281
282 *ppVM = pVM;
283 SUPR0Printf("GVMR0CreateVM: pVM=%p pVMR3=%p\n", pVM, pVMR3);
284 return VINF_SUCCESS;
285 }
286
287 SUPR0MemFree(pSession, (uintptr_t)paPagesR0);
288 }
289 }
290 /* else: The user wasn't permitted to create this VM. */
291
292 /*
293 * The handle will be freed by gvmR0HandleObjDestructor as we release the
294 * object reference here. A little extra mess because of non-recursive lock.
295 */
296 void *pvObj = pHandle->pvObj;
297 pHandle->pvObj = NULL;
298 RTSemFastMutexRelease(pGVM->Lock);
299
300 SUPR0ObjRelease(pvObj, pSession);
301
302 SUPR0Printf("GVMR0CreateVM: failed, rc=%d\n", rc);
303 return rc;
304 }
305
306 rc = VERR_NO_MEMORY;
307 }
308 else
309 rc = VERR_INTERNAL_ERROR;
310 }
311 else
312 rc = VERR_GVM_TOO_MANY_VMS;
313
314 RTSemFastMutexRelease(pGVM->Lock);
315 return rc;
316}
317
318
319/**
320 * Deregistres the VM and destroys the VM structure.
321 *
322 * @returns VBox status code.
323 * @param pVM Where to store the pointer to the VM structure.
324 *
325 * @thread EMT.
326 */
327GVMR0DECL(int) GVMR0DestroyVM(PVM pVM)
328{
329 SUPR0Printf("GVMR0DestroyVM: pVM=%p\n", pVM);
330
331 PGVM pGVM = g_pGVM;
332 AssertPtrReturn(pGVM, VERR_INTERNAL_ERROR);
333
334 /*
335 * Validate the VM structure, state and caller.
336 */
337 AssertPtrReturn(pVM, VERR_INVALID_POINTER);
338 AssertReturn(!((uintptr_t)pVM & PAGE_OFFSET_MASK), VERR_INVALID_POINTER);
339 AssertMsgReturn(pVM->enmVMState >= VMSTATE_CREATING && pVM->enmVMState <= VMSTATE_TERMINATED, ("%d\n", pVM->enmVMState), VERR_WRONG_ORDER);
340
341 uint32_t hGVM = pVM->hSelf;
342 AssertReturn(hGVM != NIL_GVM_HANDLE, VERR_INVALID_HANDLE);
343 AssertReturn(hGVM < RT_ELEMENTS(pGVM->aHandles), VERR_INVALID_HANDLE);
344
345 PGVMHANDLE pHandle = &pGVM->aHandles[hGVM];
346 AssertReturn(pHandle->hEMT != NIL_RTNATIVETHREAD, VERR_WRONG_ORDER);
347 AssertReturn(pHandle->pVM == pVM, VERR_NOT_OWNER);
348
349 RTNATIVETHREAD hSelf = RTThreadNativeSelf();
350 AssertReturn(pHandle->hEMT == hSelf, VERR_NOT_OWNER);
351
352 /*
353 * Lookup the handle and destroy the object.
354 * Since the lock isn't recursive, we have to make sure nobody can
355 * race us as we leave the lock and call SUPR0ObjRelease.
356 */
357 int rc = RTSemFastMutexRequest(pGVM->Lock);
358 AssertRC(rc);
359
360 /* be very careful here because we might be racing someone else cleaning up... */
361 if ( pHandle->pVM == pVM
362 && pHandle->hEMT == hSelf
363 && VALID_PTR(pHandle->pvObj))
364 {
365 void *pvObj = pHandle->pvObj;
366 pHandle->pvObj = NULL;
367 RTSemFastMutexRelease(pGVM->Lock);
368
369 SUPR0ObjRelease(pvObj, pVM->pSession);
370 }
371 else
372 {
373 RTSemFastMutexRelease(pGVM->Lock);
374 rc = VERR_INTERNAL_ERROR;
375 }
376
377 return rc;
378}
379
380
381#if 1 /* this approach is unsafe wrt to the freeing of pVM. Keeping it as a possible fallback for 1.5.x. */
382/**
383 * Register the specified VM with the GGVM.
384 *
385 * Permission polices and resource consumption polices may or may
386 * not be checked that this poin, be ready to deald nicely with failure.
387 *
388 * @returns VBox status code.
389 *
390 * @param pVM The VM instance data (aka handle), ring-0 mapping of ccourse.
391 * The VM::hGVM field may be updated by this call.
392 * @thread EMT.
393 */
394GVMR0DECL(int) GVMR0RegisterVM(PVM pVM)
395{
396 SUPR0Printf("GVMR0RegisterVM: pVM=%p\n", pVM);
397 PGVM pGVM = g_pGVM;
398 AssertPtrReturn(pGVM, VERR_INTERNAL_ERROR);
399
400 /*
401 * Validate the VM structure and state.
402 */
403 AssertPtrReturn(pVM, VERR_INVALID_POINTER);
404 AssertReturn(!((uintptr_t)pVM & PAGE_OFFSET_MASK), VERR_INVALID_POINTER);
405 AssertMsgReturn(pVM->enmVMState == VMSTATE_CREATING, ("%d\n", pVM->enmVMState), VERR_WRONG_ORDER);
406
407 RTNATIVETHREAD hEMT = RTThreadNativeSelf();
408 AssertReturn(hEMT != NIL_RTNATIVETHREAD, VERR_NOT_SUPPORTED);
409
410 /*
411 * Take the lock and call the worker function.
412 */
413 int rc = RTSemFastMutexRequest(pGVM->Lock);
414 AssertRCReturn(rc, rc);
415
416 /*
417 * Allocate a handle.
418 */
419 uint16_t iHandle = pGVM->iFreeHead;
420 if (iHandle)
421 {
422 PGVMHANDLE pHandle = &pGVM->aHandles[iHandle];
423
424 /* consistency checks, a bit paranoid as always. */
425 if ( !pHandle->pVM
426 && !pHandle->pvObj
427 && pHandle->iSelf == iHandle)
428 {
429 pHandle->pvObj = SUPR0ObjRegister(pVM->pSession, SUPDRVOBJTYPE_VM, gvmR0HandleObjDestructor, pGVM, pHandle);
430 if (pHandle->pvObj)
431 {
432 /*
433 * Move the handle from the free to used list and
434 * perform permission checks.
435 */
436 pGVM->iFreeHead = pHandle->iNext;
437 pHandle->iNext = pGVM->iUsedHead;
438 pGVM->iUsedHead = iHandle;
439
440 pHandle->fFreeVM = false;
441 pHandle->pVM = pVM;
442 pHandle->pSession = pVM->pSession;
443 pHandle->hEMT = hEMT;
444
445 rc = SUPR0ObjVerifyAccess(pHandle->pvObj, pVM->pSession, NULL);
446 if (RT_SUCCESS(rc))
447 {
448 pVM->hSelf = iHandle;
449 RTSemFastMutexRelease(pGVM->Lock);
450 }
451 else
452 {
453 /*
454 * The user wasn't permitted to create this VM.
455 * Must use gvmR0HandleObjDestructor via SUPR0ObjRelease to do the
456 * cleanups. The lock isn't recursive, thus the extra mess.
457 */
458 void *pvObj = pHandle->pvObj;
459 pHandle->pvObj = NULL;
460 RTSemFastMutexRelease(pGVM->Lock);
461
462 SUPR0ObjRelease(pvObj, pVM->pSession);
463 }
464 if (RT_FAILURE(rc))
465 SUPR0Printf("GVMR0RegisterVM: permission denied, rc=%d\n", rc);
466 return rc;
467 }
468
469 rc = VERR_NO_MEMORY;
470 }
471 else
472 rc = VERR_INTERNAL_ERROR;
473 }
474 else
475 rc = VERR_GVM_TOO_MANY_VMS;
476
477 RTSemFastMutexRelease(pGVM->Lock);
478 SUPR0Printf("GVMR0RegisterVM: failed, rc=%d, iHandle=%d\n", rc, iHandle);
479 return rc;
480}
481
482
483/**
484 * Deregister a VM previously registered using the GVMR0RegisterVM API.
485 *
486 *
487 * @returns VBox status code.
488 * @param pVM The VM handle.
489 * @thread EMT.
490 */
491GVMR0DECL(int) GVMR0DeregisterVM(PVM pVM)
492{
493 SUPR0Printf("GVMR0DeregisterVM: pVM=%p\n", pVM);
494 return GVMR0DestroyVM(pVM);
495}
496#endif /* ... */
497
498
499/**
500 * Handle destructor.
501 *
502 * @param pvGVM The GVM instance pointer.
503 * @param pvHandle The handle pointer.
504 */
505static DECLCALLBACK(void) gvmR0HandleObjDestructor(void *pvObj, void *pvGVM, void *pvHandle)
506{
507 SUPR0Printf("gvmR0HandleObjDestructor: %p %p %p\n", pvObj, pvGVM, pvHandle);
508
509 /*
510 * Some quick, paranoid, input validation.
511 */
512 PGVMHANDLE pHandle = (PGVMHANDLE)pvHandle;
513 AssertPtr(pHandle);
514 PGVM pGVM = (PGVM)pvGVM;
515 Assert(pGVM == g_pGVM);
516 const uint16_t iHandle = pHandle - &pGVM->aHandles[0];
517 if ( !iHandle
518 || iHandle >= RT_ELEMENTS(pGVM->aHandles)
519 || iHandle != pHandle->iSelf)
520 {
521 SUPR0Printf("GVM: handle %d is out of range or corrupt (iSelf=%d)!\n", iHandle, pHandle->iSelf);
522 return;
523 }
524
525 int rc = RTSemFastMutexRequest(pGVM->Lock);
526 AssertRC(rc);
527
528 /*
529 * This is a tad slow but a doubly linked list is too much hazzle.
530 */
531 if (RT_UNLIKELY(pHandle->iNext >= RT_ELEMENTS(pGVM->aHandles)))
532 {
533 SUPR0Printf("GVM: used list index %d is out of range!\n", pHandle->iNext);
534 RTSemFastMutexRelease(pGVM->Lock);
535 return;
536 }
537
538 if (pGVM->iUsedHead == iHandle)
539 pGVM->iUsedHead = pHandle->iNext;
540 else
541 {
542 uint16_t iPrev = pGVM->iUsedHead;
543 int c = RT_ELEMENTS(pGVM->aHandles) + 2;
544 while (!iPrev)
545 {
546 if (RT_UNLIKELY(iPrev >= RT_ELEMENTS(pGVM->aHandles)))
547 {
548 SUPR0Printf("GVM: used list index %d is out of range!\n");
549 RTSemFastMutexRelease(pGVM->Lock);
550 return;
551 }
552 if (RT_UNLIKELY(c-- <= 0))
553 {
554 iPrev = 0;
555 break;
556 }
557
558 if (pGVM->aHandles[iPrev].iNext == iHandle)
559 break;
560 iPrev = pGVM->aHandles[iPrev].iNext;
561 }
562 if (!iPrev)
563 {
564 SUPR0Printf("GVM: can't find the handle previous previous of %d!\n", pHandle->iSelf);
565 RTSemFastMutexRelease(pGVM->Lock);
566 return;
567 }
568
569 pGVM->aHandles[iPrev].iNext = pHandle->iNext;
570 }
571 pHandle->iNext = 0;
572
573 /*
574 * Do the global cleanup round, currently only GMM.
575 * Can't trust the VM pointer unless it was allocated in ring-0...
576 */
577 PVM pVM = pHandle->pVM;
578 if ( VALID_PTR(pVM)
579 && VALID_PTR(pHandle->pSession)
580 && pHandle->fFreeVM)
581 {
582 /// @todo GMMR0CleanupVM(pVM);
583
584 /*
585 * Free the VM structure.
586 */
587 ASMAtomicXchgU32((uint32_t volatile *)&pVM->hSelf, NIL_GVM_HANDLE);
588 SUPR0MemFree(pHandle->pSession, pVM->paVMPagesR3);
589 SUPR0LowFree(pHandle->pSession, (uintptr_t)pVM);
590 }
591
592 /*
593 * Free the handle.
594 */
595 pHandle->iNext = pGVM->iFreeHead;
596 pHandle->fFreeVM = false;
597 pGVM->iFreeHead = iHandle;
598 ASMAtomicXchgPtr((void * volatile *)&pHandle->pVM, NULL);
599 ASMAtomicXchgPtr((void * volatile *)&pHandle->pvObj, NULL);
600 ASMAtomicXchgPtr((void * volatile *)&pHandle->pSession, NULL);
601 ASMAtomicXchgSize(&pHandle->hEMT, NIL_RTNATIVETHREAD);
602
603 RTSemFastMutexRelease(pGVM->Lock);
604 SUPR0Printf("gvmR0HandleObjDestructor: returns\n");
605}
606
607
608/**
609 * Lookup a VM by its global handle.
610 *
611 * @returns The VM handle on success, NULL on failure.
612 * @param hGVM The global VM handle. Asserts on bad handle.
613 */
614GVMR0DECL(PVM) GVMR0ByHandle(uint32_t hGVM)
615{
616 PGVM pGVM = g_pGVM;
617 AssertPtrReturn(pGVM, NULL);
618
619 /*
620 * Validate.
621 */
622 AssertReturn(hGVM != NIL_GVM_HANDLE, NULL);
623 AssertReturn(hGVM < RT_ELEMENTS(pGVM->aHandles), NULL);
624
625 /*
626 * Look it up.
627 */
628 AssertReturn(VALID_PTR(pGVM->aHandles[hGVM].pvObj), NULL);
629 AssertReturn(pGVM->aHandles[hGVM].hEMT != NIL_RTNATIVETHREAD, NULL);
630 Assert(VALID_PTR(pGVM->aHandles[hGVM].pVM));
631
632 return pGVM->aHandles[hGVM].pVM;
633}
634
635
636/**
637 * Looks up the VM belonging to the specified EMT thread.
638 *
639 * This is used by the assertion machinery in VMMR0.cpp to avoid causing
640 * unnecessary kernel panics when the EMT thread hits an assertion. The
641 * call may or not be an EMT thread.
642 *
643 * @returns The VM handle on success, NULL on failure.
644 * @param hEMT The native thread handle of the EMT.
645 * NIL_RTNATIVETHREAD means the current thread
646 */
647GVMR0DECL(PVM) GVMR0ByEMT(RTNATIVETHREAD hEMT)
648{
649 /*
650 * Be very careful here as we're called in AssertMsgN context.
651 */
652 PGVM pGVM = g_pGVM;
653 if (!VALID_PTR(pGVM))
654 return NULL;
655
656 if (hEMT == NIL_RTNATIVETHREAD)
657 hEMT = RTThreadNativeSelf();
658
659 /*
660 * Search the handles, we don't dare take the lock (assert).
661 */
662 for (unsigned i = 1; i < RT_ELEMENTS(pGVM->aHandles); i++)
663 if ( pGVM->aHandles[i].hEMT == hEMT
664 && pGVM->aHandles[i].iSelf == i
665 && VALID_PTR(pGVM->aHandles[i].pvObj)
666 && VALID_PTR(pGVM->aHandles[i].pVM))
667 return pGVM->aHandles[i].pVM;
668
669 return NULL;
670}
671
672
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette