2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/session.c
5 * PURPOSE: Session support routines
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 #define MODULE_INVOLVED_IN_ARM3
16 #include "../ARM3/miarm.h"
18 /* GLOBALS ********************************************************************/
20 PMM_SESSION_SPACE MmSessionSpace
;
21 PFN_NUMBER MiSessionDataPages
, MiSessionTagPages
, MiSessionTagSizePages
;
22 PFN_NUMBER MiSessionBigPoolPages
, MiSessionCreateCharge
;
23 KGUARDED_MUTEX MiSessionIdMutex
;
24 LONG MmSessionDataPages
;
25 PRTL_BITMAP MiSessionIdBitmap
;
26 volatile LONG MiSessionLeaderExists
;
29 /* PRIVATE FUNCTIONS **********************************************************/
33 MmGetSessionLocaleId(VOID
)
39 // Get the current process
41 Process
= PsGetCurrentProcess();
44 // Check if it's the Session Leader
46 if (Process
->Vm
.Flags
.SessionLeader
)
49 // Make sure it has a valid Session
56 return ((PMM_SESSION_SPACE
)Process
->Session
)->LocaleId
;
61 // Not a session leader, return the default
63 return PsDefaultThreadLocaleId
;
68 MiInitializeSessionIds(VOID
)
70 ULONG Size
, BitmapSize
;
71 PFN_NUMBER TotalPages
;
73 /* Setup the total number of data pages needed for the structure */
74 TotalPages
= MI_SESSION_DATA_PAGES_MAXIMUM
;
75 MiSessionDataPages
= ROUND_TO_PAGES(sizeof(MM_SESSION_SPACE
)) >> PAGE_SHIFT
;
76 ASSERT(MiSessionDataPages
<= MI_SESSION_DATA_PAGES_MAXIMUM
- 3);
77 TotalPages
-= MiSessionDataPages
;
79 /* Setup the number of pages needed for session pool tags */
80 MiSessionTagSizePages
= 2;
81 MiSessionBigPoolPages
= 1;
82 MiSessionTagPages
= MiSessionTagSizePages
+ MiSessionBigPoolPages
;
83 ASSERT(MiSessionTagPages
<= TotalPages
);
84 ASSERT(MiSessionTagPages
< MI_SESSION_TAG_PAGES_MAXIMUM
);
86 /* Total pages needed for a session (FIXME: Probably different on PAE/x64) */
87 MiSessionCreateCharge
= 1 + MiSessionDataPages
+ MiSessionTagPages
;
89 /* Initialize the lock */
90 KeInitializeGuardedMutex(&MiSessionIdMutex
);
92 /* Allocate the bitmap */
93 Size
= MI_INITIAL_SESSION_IDS
;
94 BitmapSize
= ((Size
+ 31) / 32) * sizeof(ULONG
);
95 MiSessionIdBitmap
= ExAllocatePoolWithTag(PagedPool
,
96 sizeof(RTL_BITMAP
) + BitmapSize
,
98 if (MiSessionIdBitmap
)
100 /* Free all the bits */
101 RtlInitializeBitMap(MiSessionIdBitmap
,
102 (PVOID
)(MiSessionIdBitmap
+ 1),
104 RtlClearAllBits(MiSessionIdBitmap
);
108 /* Die if we couldn't allocate the bitmap */
109 KeBugCheckEx(INSTALL_MORE_MEMORY
,
110 MmNumberOfPhysicalPages
,
111 MmLowestPhysicalPage
,
112 MmHighestPhysicalPage
,
119 MiSessionLeader(IN PEPROCESS Process
)
123 /* Set the flag while under the expansion lock */
124 OldIrql
= KeAcquireQueuedSpinLock(LockQueueExpansionLock
);
125 Process
->Vm
.Flags
.SessionLeader
= TRUE
;
126 KeReleaseQueuedSpinLock(LockQueueExpansionLock
, OldIrql
);
131 MmGetSessionId(IN PEPROCESS Process
)
133 PMM_SESSION_SPACE SessionGlobal
;
135 /* The session leader is always session zero */
136 if (Process
->Vm
.Flags
.SessionLeader
== 1) return 0;
138 /* Otherwise, get the session global, and read the session ID from it */
139 SessionGlobal
= (PMM_SESSION_SPACE
)Process
->Session
;
140 if (!SessionGlobal
) return 0;
141 return SessionGlobal
->SessionId
;
146 MmGetSessionIdEx(IN PEPROCESS Process
)
148 PMM_SESSION_SPACE SessionGlobal
;
150 /* The session leader is always session zero */
151 if (Process
->Vm
.Flags
.SessionLeader
== 1) return 0;
153 /* Otherwise, get the session global, and read the session ID from it */
154 SessionGlobal
= (PMM_SESSION_SPACE
)Process
->Session
;
155 if (!SessionGlobal
) return -1;
156 return SessionGlobal
->SessionId
;
161 MiReleaseProcessReferenceToSessionDataPage(IN PMM_SESSION_SPACE SessionGlobal
)
165 PFN_NUMBER PageFrameIndex
[MI_SESSION_DATA_PAGES_MAXIMUM
];
169 /* Is there more than just this reference? If so, bail out */
170 if (InterlockedDecrement(&SessionGlobal
->ProcessReferenceToSession
)) return;
172 /* Get the session ID */
173 SessionId
= SessionGlobal
->SessionId
;
174 DPRINT1("Last process in session %lu going down!!!\n", SessionId
);
176 /* Free the session page tables */
178 ExFreePoolWithTag(SessionGlobal
->PageTables
, 'tHmM');
180 ASSERT(!MI_IS_PHYSICAL_ADDRESS(SessionGlobal
));
182 /* Capture the data page PFNs */
183 PointerPte
= MiAddressToPte(SessionGlobal
);
184 for (i
= 0; i
< MiSessionDataPages
; i
++)
186 PageFrameIndex
[i
] = PFN_FROM_PTE(PointerPte
+ i
);
190 MiReleaseSystemPtes(PointerPte
, MiSessionDataPages
, SystemPteSpace
);
192 /* Mark them as deleted */
193 for (i
= 0; i
< MiSessionDataPages
; i
++)
195 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
[i
]);
196 MI_SET_PFN_DELETED(Pfn1
);
199 /* Loop every data page and drop a reference count */
200 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
201 for (i
= 0; i
< MiSessionDataPages
; i
++)
203 /* Sanity check that the page is correct, then decrement it */
204 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
[i
]);
205 ASSERT(Pfn1
->u2
.ShareCount
== 1);
206 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 1);
207 MiDecrementShareCount(Pfn1
, PageFrameIndex
[i
]);
210 /* Done playing with pages, release the lock */
211 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
213 /* Decrement the number of data pages */
214 InterlockedDecrement(&MmSessionDataPages
);
216 /* Free this session ID from the session bitmap */
217 KeAcquireGuardedMutex(&MiSessionIdMutex
);
218 ASSERT(RtlCheckBit(MiSessionIdBitmap
, SessionId
));
219 RtlClearBit(MiSessionIdBitmap
, SessionId
);
220 KeReleaseGuardedMutex(&MiSessionIdMutex
);
225 MiSessionRemoveProcess(VOID
)
227 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
229 /* If the process isn't already in a session, or if it's the leader... */
230 if (!(CurrentProcess
->Flags
& PSF_PROCESS_IN_SESSION_BIT
) ||
231 (CurrentProcess
->Vm
.Flags
.SessionLeader
))
233 /* Then there's nothing to do */
238 ASSERT(MmIsAddressValid(MmSessionSpace
) == TRUE
);
240 /* Remove the process from the list ,and dereference the session */
241 // DO NOT ENABLE THIS UNLESS YOU FIXED THE NP POOL CORRUPTION THAT IT CAUSES!!!
242 //RemoveEntryList(&CurrentProcess->SessionProcessLinks);
243 //MiDereferenceSession();
248 MiSessionAddProcess(IN PEPROCESS NewProcess
)
250 PMM_SESSION_SPACE SessionGlobal
;
252 /* The current process must already be in a session */
253 if (!(PsGetCurrentProcess()->Flags
& PSF_PROCESS_IN_SESSION_BIT
)) return;
256 ASSERT(MmIsAddressValid(MmSessionSpace
) == TRUE
);
258 /* Get the global session */
259 SessionGlobal
= MmSessionSpace
->GlobalVirtualAddress
;
261 /* Increment counters */
262 InterlockedIncrement((PLONG
)&SessionGlobal
->ReferenceCount
);
263 InterlockedIncrement(&SessionGlobal
->ResidentProcessCount
);
264 InterlockedIncrement(&SessionGlobal
->ProcessReferenceToSession
);
266 /* Set the session pointer */
267 ASSERT(NewProcess
->Session
== NULL
);
268 NewProcess
->Session
= SessionGlobal
;
270 /* Insert it into the process list */
271 // DO NOT ENABLE THIS UNLESS YOU FIXED THE NP POOL CORRUPTION THAT IT CAUSES!!!
272 //InsertTailList(&SessionGlobal->ProcessList, &NewProcess->SessionProcessLinks);
275 PspSetProcessFlag(NewProcess
, PSF_PROCESS_IN_SESSION_BIT
);
280 MiSessionInitializeWorkingSetList(VOID
)
283 PMMPTE PointerPte
, PointerPde
;
286 PFN_NUMBER PageFrameIndex
;
287 PMM_SESSION_SPACE SessionGlobal
;
288 BOOLEAN AllocatedPageTable
;
289 PMMWSL WorkingSetList
;
291 /* Get pointers to session global and the session working set list */
292 SessionGlobal
= MmSessionSpace
->GlobalVirtualAddress
;
293 WorkingSetList
= (PMMWSL
)MiSessionSpaceWs
;
295 /* Fill out the two pointers */
296 MmSessionSpace
->Vm
.VmWorkingSetList
= WorkingSetList
;
297 MmSessionSpace
->Wsle
= (PMMWSLE
)WorkingSetList
->UsedPageTableEntries
;
299 /* Get the PDE for the working set, and check if it's already allocated */
300 PointerPde
= MiAddressToPde(WorkingSetList
);
301 if (PointerPde
->u
.Hard
.Valid
== 1)
303 /* Nope, we'll have to do it */
304 ASSERT(PointerPde
->u
.Hard
.Global
== 0);
305 AllocatedPageTable
= FALSE
;
309 /* Yep, that makes our job easier */
310 AllocatedPageTable
= TRUE
;
313 /* Get the PTE for the working set */
314 PointerPte
= MiAddressToPte(WorkingSetList
);
316 /* Initialize the working set lock, and lock the PFN database */
317 ExInitializePushLock(&SessionGlobal
->Vm
.WorkingSetMutex
);
318 //MmLockPageableSectionByHandle(ExPageLockHandle);
319 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
321 /* Check if we need a page table */
322 if (AllocatedPageTable
== TRUE
)
324 /* Get a zeroed colored zero page */
325 Color
= MI_GET_NEXT_COLOR();
326 PageFrameIndex
= MiRemoveZeroPageSafe(Color
);
329 /* No zero pages, grab a free one */
330 PageFrameIndex
= MiRemoveAnyPage(Color
);
332 /* Zero it outside the PFN lock */
333 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
334 MiZeroPhysicalPage(PageFrameIndex
);
335 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
338 /* Write a valid PDE for it */
339 TempPte
.u
.Long
= ValidKernelPdeLocal
.u
.Long
;
340 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
341 MI_WRITE_VALID_PTE(PointerPde
, TempPte
);
343 /* Add this into the list */
344 Index
= ((ULONG_PTR
)WorkingSetList
- (ULONG_PTR
)MmSessionBase
) >> 22;
346 MmSessionSpace
->PageTables
[Index
] = TempPte
;
348 /* Initialize the page directory page, and now zero the working set list itself */
349 MiInitializePfnForOtherProcess(PageFrameIndex
,
351 MmSessionSpace
->SessionPageDirectoryIndex
);
352 KeZeroPages(PointerPte
, PAGE_SIZE
);
355 /* Get a zeroed colored zero page */
356 Color
= MI_GET_NEXT_COLOR();
357 PageFrameIndex
= MiRemoveZeroPageSafe(Color
);
360 /* No zero pages, grab a free one */
361 PageFrameIndex
= MiRemoveAnyPage(Color
);
363 /* Zero it outside the PFN lock */
364 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
365 MiZeroPhysicalPage(PageFrameIndex
);
366 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
369 /* Write a valid PTE for it */
370 TempPte
.u
.Long
= ValidKernelPteLocal
.u
.Long
;
371 TempPte
.u
.Hard
.Dirty
= TRUE
;
372 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
374 /* Initialize the working set list page */
375 MiInitializePfnAndMakePteValid(PageFrameIndex
, PointerPte
, TempPte
);
377 /* Now we can release the PFN database lock */
378 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
380 /* Fill out the working set structure */
381 MmSessionSpace
->Vm
.Flags
.SessionSpace
= 1;
382 MmSessionSpace
->Vm
.MinimumWorkingSetSize
= 20;
383 MmSessionSpace
->Vm
.MaximumWorkingSetSize
= 384;
384 WorkingSetList
->LastEntry
= 20;
385 WorkingSetList
->HashTable
= NULL
;
386 WorkingSetList
->HashTableSize
= 0;
387 WorkingSetList
->Wsle
= MmSessionSpace
->Wsle
;
389 /* FIXME: Handle list insertions */
390 ASSERT(SessionGlobal
->WsListEntry
.Flink
== NULL
);
391 ASSERT(SessionGlobal
->WsListEntry
.Blink
== NULL
);
392 ASSERT(SessionGlobal
->Vm
.WorkingSetExpansionLinks
.Flink
== NULL
);
393 ASSERT(SessionGlobal
->Vm
.WorkingSetExpansionLinks
.Blink
== NULL
);
395 /* All done, return */
396 //MmUnlockPageableImageSection(ExPageLockHandle);
397 return STATUS_SUCCESS
;
402 MiSessionCreateInternal(OUT PULONG SessionId
)
404 PEPROCESS Process
= PsGetCurrentProcess();
405 ULONG NewFlags
, Flags
, Size
, i
, Color
;
407 PMMPTE PointerPte
, PageTables
, SessionPte
;
409 PMM_SESSION_SPACE SessionGlobal
;
413 PFN_NUMBER SessionPageDirIndex
;
414 PFN_NUMBER TagPage
[MI_SESSION_TAG_PAGES_MAXIMUM
];
415 PFN_NUMBER DataPage
[MI_SESSION_DATA_PAGES_MAXIMUM
];
417 /* This should not exist yet */
418 ASSERT(MmIsAddressValid(MmSessionSpace
) == FALSE
);
420 /* Loop so we can set the session-is-creating flag */
421 Flags
= Process
->Flags
;
424 /* Check if it's already set */
425 if (Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
)
428 DPRINT1("Lost session race\n");
429 return STATUS_ALREADY_COMMITTED
;
432 /* Now try to set it */
433 NewFlags
= InterlockedCompareExchange((PLONG
)&Process
->Flags
,
434 Flags
| PSF_SESSION_CREATION_UNDERWAY_BIT
,
436 if (NewFlags
== Flags
) break;
438 /* It changed, try again */
442 /* Now we should own the flag */
443 ASSERT(Process
->Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
);
446 * Session space covers everything from 0xA0000000 to 0xC0000000.
447 * Allocate enough page tables to describe the entire region
449 Size
= (0x20000000 / PDE_MAPPED_VA
) * sizeof(MMPTE
);
450 PageTables
= ExAllocatePoolWithTag(NonPagedPool
, Size
, 'tHmM');
451 ASSERT(PageTables
!= NULL
);
452 RtlZeroMemory(PageTables
, Size
);
454 /* Lock the session ID creation mutex */
455 KeAcquireGuardedMutex(&MiSessionIdMutex
);
457 /* Allocate a new Session ID */
458 *SessionId
= RtlFindClearBitsAndSet(MiSessionIdBitmap
, 1, 0);
459 if (*SessionId
== 0xFFFFFFFF)
461 /* We ran out of session IDs, we should expand */
462 DPRINT1("Too many sessions created. Expansion not yet supported\n");
463 ExFreePoolWithTag(PageTables
, 'tHmM');
464 return STATUS_NO_MEMORY
;
467 /* Unlock the session ID creation mutex */
468 KeReleaseGuardedMutex(&MiSessionIdMutex
);
470 /* Reserve the global PTEs */
471 SessionPte
= MiReserveSystemPtes(MiSessionDataPages
, SystemPteSpace
);
472 ASSERT(SessionPte
!= NULL
);
474 /* Acquire the PFN lock while we set everything up */
475 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
477 /* Loop the global PTEs */
478 TempPte
.u
.Long
= ValidKernelPte
.u
.Long
;
479 for (i
= 0; i
< MiSessionDataPages
; i
++)
481 /* Get a zeroed colored zero page */
482 Color
= MI_GET_NEXT_COLOR();
483 DataPage
[i
] = MiRemoveZeroPageSafe(Color
);
486 /* No zero pages, grab a free one */
487 DataPage
[i
] = MiRemoveAnyPage(Color
);
489 /* Zero it outside the PFN lock */
490 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
491 MiZeroPhysicalPage(DataPage
[i
]);
492 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
495 /* Fill the PTE out */
496 TempPte
.u
.Hard
.PageFrameNumber
= DataPage
[i
];
497 MI_WRITE_VALID_PTE(SessionPte
+ i
, TempPte
);
500 /* Set the pointer to global space */
501 SessionGlobal
= MiPteToAddress(SessionPte
);
503 /* Get a zeroed colored zero page */
504 Color
= MI_GET_NEXT_COLOR();
505 SessionPageDirIndex
= MiRemoveZeroPageSafe(Color
);
506 if (!SessionPageDirIndex
)
508 /* No zero pages, grab a free one */
509 SessionPageDirIndex
= MiRemoveAnyPage(Color
);
511 /* Zero it outside the PFN lock */
512 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
513 MiZeroPhysicalPage(SessionPageDirIndex
);
514 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
517 /* Fill the PTE out */
518 TempPte
.u
.Long
= ValidKernelPdeLocal
.u
.Long
;
519 TempPte
.u
.Hard
.PageFrameNumber
= SessionPageDirIndex
;
521 /* Setup, allocate, fill out the MmSessionSpace PTE */
522 PointerPde
= MiAddressToPde(MmSessionSpace
);
523 ASSERT(PointerPde
->u
.Long
== 0);
524 MI_WRITE_VALID_PTE(PointerPde
, TempPte
);
525 MiInitializePfnForOtherProcess(SessionPageDirIndex
,
527 SessionPageDirIndex
);
528 ASSERT(MI_PFN_ELEMENT(SessionPageDirIndex
)->u1
.WsIndex
== 0);
530 /* Loop all the local PTEs for it */
531 TempPte
.u
.Long
= ValidKernelPteLocal
.u
.Long
;
532 PointerPte
= MiAddressToPte(MmSessionSpace
);
533 for (i
= 0; i
< MiSessionDataPages
; i
++)
535 /* And fill them out */
536 TempPte
.u
.Hard
.PageFrameNumber
= DataPage
[i
];
537 MiInitializePfnAndMakePteValid(DataPage
[i
], PointerPte
+ i
, TempPte
);
538 ASSERT(MI_PFN_ELEMENT(DataPage
[i
])->u1
.WsIndex
== 0);
541 /* Finally loop all of the session pool tag pages */
542 for (i
= 0; i
< MiSessionTagPages
; i
++)
544 /* Grab a zeroed colored page */
545 Color
= MI_GET_NEXT_COLOR();
546 TagPage
[i
] = MiRemoveZeroPageSafe(Color
);
549 /* No zero pages, grab a free one */
550 TagPage
[i
] = MiRemoveAnyPage(Color
);
552 /* Zero it outside the PFN lock */
553 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
554 MiZeroPhysicalPage(TagPage
[i
]);
555 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
558 /* Fill the PTE out */
559 TempPte
.u
.Hard
.PageFrameNumber
= TagPage
[i
];
560 MiInitializePfnAndMakePteValid(TagPage
[i
],
561 PointerPte
+ MiSessionDataPages
+ i
,
565 /* PTEs have been setup, release the PFN lock */
566 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
568 /* Fill out the session space structure now */
569 MmSessionSpace
->GlobalVirtualAddress
= SessionGlobal
;
570 MmSessionSpace
->ReferenceCount
= 1;
571 MmSessionSpace
->ResidentProcessCount
= 1;
572 MmSessionSpace
->u
.LongFlags
= 0;
573 MmSessionSpace
->SessionId
= *SessionId
;
574 MmSessionSpace
->LocaleId
= PsDefaultSystemLocaleId
;
575 MmSessionSpace
->SessionPageDirectoryIndex
= SessionPageDirIndex
;
576 MmSessionSpace
->Color
= Color
;
577 MmSessionSpace
->NonPageablePages
= MiSessionCreateCharge
;
578 MmSessionSpace
->CommittedPages
= MiSessionCreateCharge
;
580 MmSessionSpace
->PageTables
= PageTables
;
581 MmSessionSpace
->PageTables
[PointerPde
- MiAddressToPde(MmSessionBase
)] = *PointerPde
;
583 InitializeListHead(&MmSessionSpace
->ImageList
);
584 DPRINT1("Session %lu is ready to go: 0x%p 0x%p, %lx 0x%p\n",
585 *SessionId
, MmSessionSpace
, SessionGlobal
, SessionPageDirIndex
, PageTables
);
587 /* Initialize session pool */
588 //Status = MiInitializeSessionPool();
589 Status
= STATUS_SUCCESS
;
590 ASSERT(NT_SUCCESS(Status
) == TRUE
);
592 /* Initialize system space */
593 Result
= MiInitializeSystemSpaceMap(&SessionGlobal
->Session
);
594 ASSERT(Result
== TRUE
);
596 /* Initialize the process list, make sure the workign set list is empty */
597 ASSERT(SessionGlobal
->WsListEntry
.Flink
== NULL
);
598 ASSERT(SessionGlobal
->WsListEntry
.Blink
== NULL
);
599 InitializeListHead(&SessionGlobal
->ProcessList
);
601 /* We're done, clear the flag */
602 ASSERT(Process
->Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
);
603 PspClearProcessFlag(Process
, PSF_SESSION_CREATION_UNDERWAY_BIT
);
605 /* Insert the process into the session */
606 ASSERT(Process
->Session
== NULL
);
607 ASSERT(SessionGlobal
->ProcessReferenceToSession
== 0);
608 SessionGlobal
->ProcessReferenceToSession
= 1;
611 InterlockedIncrement(&MmSessionDataPages
);
612 return STATUS_SUCCESS
;
617 MmSessionCreate(OUT PULONG SessionId
)
619 PEPROCESS Process
= PsGetCurrentProcess();
620 ULONG SessionLeaderExists
;
623 /* Fail if the process is already in a session */
624 if (Process
->Flags
& PSF_PROCESS_IN_SESSION_BIT
)
626 DPRINT1("Process already in session\n");
627 return STATUS_ALREADY_COMMITTED
;
630 /* Check if the process is already the session leader */
631 if (!Process
->Vm
.Flags
.SessionLeader
)
633 /* Atomically set it as the leader */
634 SessionLeaderExists
= InterlockedCompareExchange(&MiSessionLeaderExists
, 1, 0);
635 if (SessionLeaderExists
)
637 DPRINT1("Session leader race\n");
638 return STATUS_INVALID_SYSTEM_SERVICE
;
641 /* Do the work required to upgrade him */
642 MiSessionLeader(Process
);
645 /* Create the session */
646 KeEnterCriticalRegion();
647 Status
= MiSessionCreateInternal(SessionId
);
648 if (!NT_SUCCESS(Status
))
650 KeLeaveCriticalRegion();
654 /* Set up the session working set */
655 Status
= MiSessionInitializeWorkingSetList();
656 if (!NT_SUCCESS(Status
))
659 //MiDereferenceSession();
661 KeLeaveCriticalRegion();
666 KeLeaveCriticalRegion();
668 /* Set and assert the flags, and return */
669 MmSessionSpace
->u
.Flags
.Initialized
= 1;
670 PspSetProcessFlag(Process
, PSF_PROCESS_IN_SESSION_BIT
);
671 ASSERT(MiSessionLeaderExists
== 1);
677 MmSessionDelete(IN ULONG SessionId
)
679 PEPROCESS Process
= PsGetCurrentProcess();
681 /* Process must be in a session */
682 if (!(Process
->Flags
& PSF_PROCESS_IN_SESSION_BIT
))
684 DPRINT1("Not in a session!\n");
685 return STATUS_UNABLE_TO_FREE_VM
;
688 /* It must be the session leader */
689 if (!Process
->Vm
.Flags
.SessionLeader
)
691 DPRINT1("Not a session leader!\n");
692 return STATUS_UNABLE_TO_FREE_VM
;
695 /* Remove one reference count */
696 KeEnterCriticalRegion();
698 KeLeaveCriticalRegion();
701 return STATUS_SUCCESS
;