/*++ 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; iListLink ); 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 ); }