Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

813 lines
22 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
process.c
Abstract:
This module contains the worker routines called to create and maintain
the OS/2 process structure.
Author:
Steve Wood (stevewo) 04-Oct-1989
Revision History:
--*/
#define INCL_OS2V20_ERRORS
#define INCL_OS2V20_TASKING
#include "os2srv.h"
#include "os2tile.h"
#define THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN
#define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1)
#define THREAD_PRIORITY_NORMAL 0
#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX
#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1)
#define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT
#define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE
BOOLEAN
SetThreadPriority(
HANDLE hThread,
LONG priority
);
NTSTATUS
Os2InitializeProcessStructure( VOID )
{
NTSTATUS Status;
ULONG i;
APIRET rc;
Status = RtlInitializeCriticalSection( &Os2StructureLock );
ASSERT( NT_SUCCESS( Status ) );
// // Obsolete code below: OS/2 ss was keeping processes around as zombie so
// // that DosCWait doesn't fail when father calls it after child termination.
// // However, it turns out that OS/2 doesn't do this.
// InitializeListHead( &Os2ZombieList );
for (i=0; i<MaxWaitReason; i++) {
InitializeListHead( &Os2WaitLists[ i ] );
}
for ( i = 0 ; (i < OS2_MAX_SESSION) ; i++ ) {
SessionTable[i].Session = NULL;
}
Os2LastProcessId = (PID)0;
Os2NextHigherProcessId = MAXIMUM_PROCESS_ID;
Os2RootProcess = NULL;
Os2RootProcess = Os2AllocateProcess();
ASSERT( Os2RootProcess != NULL );
InitializeListHead( &Os2SessionList );
InitializeListHead( &Os2RootProcess->ListLink );
Os2RootProcess->ProcessHandle = (HANDLE)0xFFFFFFFF;
Os2RootProcess->ClientId.UniqueProcess = (HANDLE)0xFFFFFFFF;
Os2RootProcess->ClientId.UniqueThread = (HANDLE)0xFFFFFFFF;
Os2RootProcess->Session = Os2AllocateSession(NULL, 0, &rc);
ASSERT(Os2RootProcess->Session);
return( Status );
}
PVOID
Os2CreateTidBitmap(
)
{
PVOID TidBMHeap;
PRTL_BITMAP TidBitMapHeader = (PRTL_BITMAP)RtlAllocateHeap( Os2Heap, 0,
sizeof( RTL_BITMAP )
);
/* TidBMHeap = RtlCreateHeap( HEAP_GROWABLE,
NULL,
(_64K + 7) / 8, // 8 bits per byte
(_64K + 7) / 8, // 8 bits per byte
NULL,
0
);
*/
TidBMHeap = RtlAllocateHeap(Os2Heap, 0, (_64K + 7) / 8);
if (TidBMHeap == NULL) {
return(NULL);
}
RtlInitializeBitMap(TidBitMapHeader ,TidBMHeap, _64K);
RtlClearAllBits(TidBitMapHeader);
RtlSetBits (TidBitMapHeader,0,1); // We don't use TID 0.
#ifdef PMNT
RtlSetBits (TidBitMapHeader,
PMNTFIRSTHIDDENTHREAD,
PMNTMAXHIDDENTHREADS); //PMNT Hidden thread
#endif
return(TidBitMapHeader);
}
ULONG
Os2AllocateTid(
#ifdef PMNT
IN ULONG Flags,
#endif
POS2_PROCESS Process
)
{
#ifdef PMNT
//
// BUGBUG - PMNT Hidden thread do not exit so there is no reason to resycle
// the numbers of the hidden thread.
//
if (Flags == DCT_RUNABLE_HIDDEN){
if (Process->LastHiddenThreadId == 0) {
Process->LastHiddenThreadId=PMNTFIRSTHIDDENTHREAD-1;
}
if (Process->LastHiddenThreadId >=
(PMNTFIRSTHIDDENTHREAD+PMNTMAXHIDDENTHREADS))
return(0xFFFFFFFF);
return(++Process->LastHiddenThreadId);
}
else
return((RtlFindClearBitsAndSet( Process->TidBitMapHeader,
1,
0
)));
#else
return((RtlFindClearBitsAndSet( Process->TidBitMapHeader,
1,
0
)));
#endif
}
VOID
Os2FreeTid(
ULONG Index,
POS2_PROCESS Process
)
{
if (Index > (_64K)) {
return;
}
RtlClearBits( Process->TidBitMapHeader,
Index,
1
);
}
POS2_PROCESS
Os2AllocateProcess( VOID )
{
PLIST_ENTRY ListHead, ListNext;
POS2_PROCESS Process = NULL;
POS2_PROCESS ScanProcess;
BOOLEAN SearchMode;
BOOLEAN NextHigherWasSet;
//
// Allocate an OS/2 Process Object
//
Process = (POS2_PROCESS)RtlAllocateHeap( Os2Heap, 0,
sizeof( OS2_PROCESS )
);
if (Process == NULL) {
return( NULL );
}
//
// Initialize the fields of the process object
//
RtlZeroMemory( Process, sizeof( OS2_PROCESS ) );
InitializeListHead( &Process->ChildrenList );
InitializeListHead( &Process->ThreadList );
InitializeListHead( &Process->SharedMemoryList );
//
// if there are 64K-1 processes in the system and there are two process
// creates occuring at the same time, they would both end up with the
// same pid, if the first to find it was not inserted in the process tree
// before the second found the pid. we don't worry about this case.
//
if (Os2RootProcess == NULL) {
Process->ProcessId = (PID)0; // root process has ProcessId 0
return( Process );
}
Process->TidBitMapHeader = Os2CreateTidBitmap();
if (Process->TidBitMapHeader == NULL) {
RtlFreeHeap(Os2Heap, 0, (PVOID)Process);
return( NULL );
}
SearchMode = FALSE;
while (TRUE) {
if (Os2LastProcessId == MAXIMUM_PROCESS_ID) {
Os2LastProcessId = MINIMUM_PROCESS_ID;
SearchMode = TRUE;
}
else if (!SearchMode && (Os2LastProcessId == Os2NextHigherProcessId)) {
Os2LastProcessId = (PID)((ULONG)Os2LastProcessId + 1);
SearchMode = TRUE;
}
else {
Os2LastProcessId = (PID)((ULONG)Os2LastProcessId + 1);
if (!SearchMode) {
break;
}
}
// verify that the ProcessID is not allocated to another process
ListHead = &Os2RootProcess->ListLink;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
ScanProcess = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
if ((ScanProcess->ProcessId == Os2LastProcessId) ||
(ScanProcess->CommandSubTreeId == Os2LastProcessId)
) {
break;
}
ListNext = ListNext->Flink;
}
if (ListNext != ListHead) { // This ProcessId is already allocated
continue; // to another process.
}
// find the next maximum available free number
NextHigherWasSet = FALSE;
Os2NextHigherProcessId = MAXIMUM_PROCESS_ID;
ListHead = &Os2RootProcess->ListLink;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
ScanProcess = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
if ((ScanProcess->ProcessId > Os2LastProcessId) &&
(Os2NextHigherProcessId >= ScanProcess->ProcessId)) {
Os2NextHigherProcessId = ScanProcess->ProcessId;
NextHigherWasSet = TRUE;
}
if ((ScanProcess->CommandSubTreeId > Os2LastProcessId) &&
(Os2NextHigherProcessId >= ScanProcess->CommandSubTreeId)) {
Os2NextHigherProcessId = ScanProcess->CommandSubTreeId;
NextHigherWasSet = TRUE;
}
ListNext = ListNext->Flink;
}
if (NextHigherWasSet) {
Os2NextHigherProcessId = (PID)((ULONG)Os2NextHigherProcessId - 1);
}
break;
}
Process->ProcessId = Os2LastProcessId;
Process->CommandSubTreeId = Os2LastProcessId;
Process->ErrorAction = OS2_ENABLE_ACCESS_VIO_POPUP | OS2_ENABLE_HARD_ERROR_POPUP;
Process->FirstPtrace = TRUE;
Process->LinkMte = RtlAllocateHeap(Os2Heap, 0, sizeof(LinkMTE));
if (Process->LinkMte == NULL) {
RtlFreeHeap(Os2Heap, 0, ((PRTL_BITMAP)(Process->TidBitMapHeader))->Buffer);
RtlFreeHeap(Os2Heap, 0, Process->TidBitMapHeader);
RtlFreeHeap(Os2Heap, 0, (PVOID)(Process));
return(NULL);
}
((LinkMTE *)Process->LinkMte)->MTE = 0;
((LinkMTE *)Process->LinkMte)->NextMTE = NULL;
((LinkMTE *)Process->LinkMte)->NeedToTransfer = FALSE;
return( Process );
}
VOID
Os2DeallocateProcess(
IN POS2_PROCESS Process
)
{
LinkMTE *pLinkMte, *tmpMte;
if (Process->TidBitMapHeader) {
RtlFreeHeap(Os2Heap, 0, ((PRTL_BITMAP)(Process->TidBitMapHeader))->Buffer);
RtlFreeHeap(Os2Heap, 0, Process->TidBitMapHeader);
}
//
// Free LinkMTE list
//
pLinkMte = ((LinkMTE *)Process->LinkMte);
while ((tmpMte = pLinkMte) != NULL) {
pLinkMte = pLinkMte->NextMTE;
RtlFreeHeap(Os2Heap, 0, tmpMte);
}
RtlFreeHeap( Os2Heap, 0, Process );
}
VOID
Os2InsertProcess(
IN POS2_PROCESS ParentProcess,
IN POS2_PROCESS Process
)
{
if (!ARGUMENT_PRESENT( ParentProcess )) {
ParentProcess = Os2RootProcess;
}
ASSERT( Process->Parent == NULL );
ASSERT( IsListEmpty( &Process->ChildrenList ) );
Process->Parent = ParentProcess;
InsertTailList( &ParentProcess->ChildrenList, &Process->SiblingLink );
InsertTailList( &Os2RootProcess->ListLink, &Process->ListLink );
}
VOID
Os2RemoveProcess(
IN POS2_PROCESS Process
)
{
PLIST_ENTRY ListHead, ListNext, NextNext;
RemoveEntryList( &Process->SiblingLink );
RemoveEntryList( &Process->ListLink );
if ( !IsListEmpty( &Process->ChildrenList ) ) {
//
// Process is about to die and some childrent are still
// alive - Link all children into parent process
//
ListHead = &Process->ChildrenList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
NextNext = ListNext->Flink;
InsertTailList( &Process->Parent->ChildrenList, ListNext );
(CONTAINING_RECORD( ListNext,OS2_PROCESS,SiblingLink))->Parent = Process->Parent;
ListNext = NextNext;
}
}
Os2FreeAllSharedMemoryForProcess( Process );
Os2DeRegisterCtrlHandler(Process);
}
NTSTATUS
Os2SetProcessContext(
IN POS2_PROCESS Process,
IN POS2_THREAD Thread,
IN BOOLEAN StartedBySm,
IN ULONG HandleTableLength,
IN ULONG CurrentDrive,
IN ULONG CodePage
)
{
UNREFERENCED_PARAMETER(Thread);
Process->InitialPebOs2Data.Length = sizeof( Process->InitialPebOs2Data );
Process->InitialPebOs2Data.ClientStartAddress = NULL;
Process->InitialPebOs2Data.StartedBySm = StartedBySm;
Process->InitialPebOs2Data.SizeOfInheritedHandleTable = HandleTableLength;
Process->InitialPebOs2Data.InitialDefaultDrive = CurrentDrive;
Process->InitialPebOs2Data.CodePage = CodePage;
return( STATUS_SUCCESS );
}
POS2_THREAD
Os2AllocateThread(
#ifdef PMNT
IN ULONG Flags,
#endif
IN POS2_PROCESS Process
)
{
POS2_THREAD Thread;
//
// Allocate an OS/2 Thread Object
//
Thread = (POS2_THREAD)RtlAllocateHeap( Os2Heap, 0,
sizeof( OS2_THREAD )
);
if (Thread == NULL) {
return( NULL );
}
//
// Initialize the fields of the thread object
//
RtlZeroMemory( Thread, sizeof( OS2_THREAD ) );
Thread->Process = Process;
Thread->ThreadId = (TID)Os2AllocateTid(
#ifdef PMNT
Flags,
#endif
Thread->Process);
if (Thread->ThreadId == (TID)(0xFFFFFFFF))
return (NULL);
return( Thread );
}
VOID
Os2DeallocateThread(
IN POS2_THREAD Thread
)
{
if (Thread->WaitBlock != NULL) {
Os2DestroyWait( Thread->WaitBlock );
Thread->WaitBlock = NULL;
}
Os2FreeTid(
(ULONG)(Thread->ThreadId),
Thread->Process );
RtlFreeHeap( Os2Heap, 0, Thread );
}
VOID
Os2InsertThread(
IN POS2_PROCESS Process,
IN POS2_THREAD Thread
)
{
InsertTailList( &Process->ThreadList, &Thread->Link );
}
VOID
Os2RemoveThread(
IN POS2_PROCESS Process,
IN POS2_THREAD Thread
)
{
RemoveEntryList( &Thread->Link );
}
VOID
Os2SetThreadPriority(
IN POS2_THREAD Thread,
IN ULONG NewClass,
IN ULONG Delta
)
{
NTSTATUS Status;
CHAR Level;
ULONG Os2Priority;
if (Thread->Dying == TRUE) {
return;
}
if (NewClass != PRTYC_NOCHANGE) {
Thread->Os2Class = (UCHAR)NewClass;
Level = (CHAR)Delta;
}
else {
Level = Thread->Os2Level + (CHAR)Delta;
if (Level < PRTYD_MINIMUM) {
Level = PRTYD_MINIMUM;
}
else if (Level > PRTYD_MAXIMUM) {
Level = PRTYD_MAXIMUM;
}
}
Thread->Os2Level = Level;
Thread->Priority = (KPRIORITY)(((Level + PRTYD_MAXIMUM) >> 3) |
((Thread->Os2Class-1) << 3));
if (Thread->Priority == 0) {
Thread->Priority = 1;
}
if (Thread->Os2Class == PRTYC_FOREGROUNDSERVER){
Thread->Priority = 15;
}
Os2Priority = (Thread->Os2Class << 8) | (UCHAR)Level;
Status = NtWriteVirtualMemory( Thread->Process->ProcessHandle,
&Thread->ClientOs2Tib->Priority,
&Os2Priority,
sizeof( Thread->ClientOs2Tib->Priority ),
NULL
);
ASSERT( NT_SUCCESS( Status ) );
//
// Write the priority into the 32-bit local info seg
// If the thread is in 16 bit, the next time it does
// an API, its local info seg will be updated
//
Status = NtWriteVirtualMemory( Thread->Process->ProcessHandle,
&Thread->ClientOs2Tib->LInfoSeg.prtyCurrent,
&Os2Priority,
sizeof( Thread->ClientOs2Tib->LInfoSeg.prtyCurrent ),
NULL
);
ASSERT( NT_SUCCESS( Status ) );
//
// YS - 6-21-93 - since os2 processes are win32 processes, csrss plays
// with their priorities. We can't set the process class to anything but
// normal, or we stop the system. Therefor - we have to set the priorities
// by win32 apis, as opposed to NT apis used so far.
// The way we map is clear from the code below. We are leaving the
// THREAD_PRIORITY_TIME_CRITICIAL to our service threads (os2ses\os2.c).
//
switch (Thread->Os2Class) {
case PRTYC_IDLETIME:
SetThreadPriority(Thread->ThreadHandle,
THREAD_PRIORITY_IDLE);
break;
case PRTYC_REGULAR:
//
// Set base level by priority, mapping from range (-31 , +31).
//
if (Level < -15) {
SetThreadPriority(Thread->ThreadHandle,
THREAD_PRIORITY_LOWEST);
}
else if (Level < 0) {
SetThreadPriority(Thread->ThreadHandle,
THREAD_PRIORITY_BELOW_NORMAL);
}
else if (Level < 15) {
SetThreadPriority(Thread->ThreadHandle,
THREAD_PRIORITY_NORMAL);
}
else {
SetThreadPriority(Thread->ThreadHandle,
THREAD_PRIORITY_ABOVE_NORMAL);
}
break;
case PRTYC_FOREGROUNDSERVER:
SetThreadPriority(Thread->ThreadHandle,
THREAD_PRIORITY_HIGHEST);
break;
case PRTYC_TIMECRITICAL:
SetThreadPriority(Thread->ThreadHandle,
THREAD_PRIORITY_HIGHEST);
break;
default:
break;
}
#if DBG
IF_OS2_DEBUG( TASKING ) {
KdPrint(("Os2SetThreadPriority - Set PID:TID %x:%x to priority %d. Class=%x, Level=%x\n",
Thread->Process->ProcessId, Thread->ThreadId, Thread->Priority, Thread->Os2Class, Level));
}
#endif
}
VOID
Os2SetProcessPriority(
IN POS2_PROCESS Process,
IN ULONG NewClass,
IN ULONG Delta
)
{
PLIST_ENTRY ListHead, ListNext;
ListHead = &Process->ThreadList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
Os2SetThreadPriority( CONTAINING_RECORD( ListNext, OS2_THREAD, Link ),
NewClass,
Delta
);
ListNext = ListNext->Flink;
}
}
VOID
Os2SetProcessTreePriority(
IN POS2_PROCESS RootProcess,
IN ULONG NewClass,
IN ULONG Delta
)
{
PLIST_ENTRY ListHead, ListNext;
Os2SetProcessPriority( RootProcess, NewClass, Delta );
ListHead = &RootProcess->ChildrenList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
Os2SetProcessTreePriority( CONTAINING_RECORD( ListNext,
OS2_PROCESS,
SiblingLink
),
NewClass,
Delta
);
ListNext = ListNext->Flink;
}
}
POS2_PROCESS
Os2LocateProcessByProcessId(
IN POS2_API_MSG m OPTIONAL,
IN POS2_PROCESS CurrentProcess,
IN PID ProcessId,
IN BOOLEAN MustBeChild
)
{
PLIST_ENTRY ListHead, ListNext;
POS2_PROCESS Process;
POS2_PROCESS Parent;
POS2_THREAD Thread;
UNREFERENCED_PARAMETER(Thread);
if (ProcessId == 0) {
return( CurrentProcess );
}
ListHead = &Os2RootProcess->ListLink;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
Process = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
if (Process->ProcessId == ProcessId) {
Parent = Process;
if (MustBeChild) {
while (Parent) {
if (Parent == CurrentProcess) {
break;
}
else {
Parent = Parent->Parent;
}
}
break;
}
else {
return( Process );
}
}
ListNext = ListNext->Flink;
}
if (ListNext != ListHead) {
if (Parent == CurrentProcess) {
return( Process );
}
else {
if (m != NULL) {
m->ReturnedErrorValue = ERROR_NOT_DESCENDANT;
}
return( NULL );
}
}
else {
if (m != NULL) {
m->ReturnedErrorValue = ERROR_INVALID_PROCID;
}
return( NULL );
}
}
POS2_THREAD
Os2LocateThreadByThreadId(
IN POS2_API_MSG m OPTIONAL,
IN POS2_THREAD CurrentThread,
IN TID ThreadId
)
{
PLIST_ENTRY ListHead, ListNext;
POS2_PROCESS Process;
POS2_THREAD Thread;
if (ThreadId == 0) {
return( CurrentThread );
}
Process = CurrentThread->Process;
ListHead = &Process->ThreadList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
if (Thread->ThreadId == ThreadId) {
break;
}
ListNext = ListNext->Flink;
}
if (ListNext != ListHead) {
if (Thread->Dying == FALSE) {
return( Thread );
}
}
if (m != NULL) {
//
// No, this is not suppose to be ERROR_INVALID_TID. Look in
// the Cruiser sources, src\dos\task\tkforce.c and you will see.
//
m->ReturnedErrorValue = ERROR_INVALID_THREADID;
}
return( NULL );
}
POS2_PROCESS
Os2LocateProcessByClientId(
IN PCLIENT_ID ClientId
)
{
PLIST_ENTRY ListHead, ListNext;
POS2_PROCESS Process = NULL;
ListHead = &Os2RootProcess->ListLink;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
Process = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
if (Process->ClientId.UniqueProcess == ClientId->UniqueProcess) {
break;
}
Process = NULL;
ListNext = ListNext->Flink;
}
return (Process);
}
POS2_THREAD
Os2LocateThreadByClientId(
POS2_PROCESS Process,
IN PCLIENT_ID ClientId
)
{
PLIST_ENTRY ListHead, ListNext;
POS2_THREAD Thread;
if (Process == NULL) {
ListHead = &Os2RootProcess->ListLink;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
Process = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
if (Process->ClientId.UniqueProcess == ClientId->UniqueProcess) {
break;
}
Process = NULL;
ListNext = ListNext->Flink;
}
}
if (Process != NULL) {
ListHead = &Process->ThreadList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
if (Thread->ClientId.UniqueThread == ClientId->UniqueThread) {
break;
}
ListNext = ListNext->Flink;
}
if (ListNext != ListHead) {
return( Thread );
}
}
return( NULL );
}