mirror of https://github.com/lianthony/NT4.0
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.
736 lines
18 KiB
736 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
srvinit.c
|
|
|
|
Abstract:
|
|
|
|
This is the main initialization module for the OS/2 Subsystem Server
|
|
|
|
Author:
|
|
|
|
Steve Wood (stevewo) 22-Aug-1989
|
|
|
|
Environment:
|
|
|
|
User Mode Only
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "os2srv.h"
|
|
#include "os2tile.h"
|
|
#include "os2win.h"
|
|
#include "os2err.h"
|
|
#define NTOS2_ONLY
|
|
#include "sesport.h"
|
|
#include "os2ldr.h"
|
|
|
|
|
|
extern HANDLE FirstOs2ProcessHandle;
|
|
|
|
BOOLEAN
|
|
SetProcessShutdownParameters(
|
|
DWORD dwLevel,
|
|
DWORD dwFlags
|
|
);
|
|
|
|
BOOLEAN
|
|
InitializeSecurityDescriptor (
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
DWORD dwRevision
|
|
);
|
|
|
|
BOOLEAN
|
|
SetSecurityDescriptorDacl (
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
BOOLEAN bDaclPresent,
|
|
PACL pDacl,
|
|
BOOLEAN bDaclDefaulted
|
|
);
|
|
|
|
BOOLEAN
|
|
SetKernelObjectSecurity (
|
|
HANDLE Handle,
|
|
SECURITY_INFORMATION SecurityInformation,
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor
|
|
);
|
|
|
|
WCHAR Os2SystemDirectory[MAX_PATH];
|
|
ULONG Os2GlobalInfoSeg;
|
|
HANDLE Os2GlobalInfoSegHandle;
|
|
HANDLE UpDateInfoSegThreadHandle;
|
|
HANDLE Os2SyncSem;
|
|
|
|
|
|
APIRET
|
|
Os2GetSysInfo(VOID)
|
|
{
|
|
APIRET RetCode;
|
|
GINFOSEG *pGlobalInfo;
|
|
TIME_FIELDS NtDateTime;
|
|
LARGE_INTEGER nttime, LocalTime;
|
|
SYSTEM_TIMEOFDAY_INFORMATION SystemInformation;
|
|
ULONG utemp = 0xFFFFFFFF/10000;
|
|
SHORT TimeZone;
|
|
|
|
pGlobalInfo = (GINFOSEG *) Os2GlobalInfoSeg;
|
|
|
|
//
|
|
// fill in global info fields
|
|
//
|
|
|
|
RetCode = Or2GetDateTimeInfo(
|
|
&nttime,
|
|
&LocalTime,
|
|
&NtDateTime,
|
|
(PVOID)&SystemInformation,
|
|
&TimeZone
|
|
);
|
|
|
|
if (RetCode)
|
|
{
|
|
#if DBG
|
|
IF_OS2_DEBUG( MISC )
|
|
{
|
|
KdPrint(( "Os2GetSysInfo: Error at Or2GetDateTimeInfo %lu\n",
|
|
RetCode));
|
|
}
|
|
#endif
|
|
return (RetCode);
|
|
}
|
|
|
|
pGlobalInfo->year = NtDateTime.Year;
|
|
pGlobalInfo->month = (UCHAR)(NtDateTime.Month);
|
|
pGlobalInfo->day = (UCHAR)(NtDateTime.Day);
|
|
pGlobalInfo->weekday = (UCHAR)(NtDateTime.Weekday);
|
|
pGlobalInfo->hour = (UCHAR)(NtDateTime.Hour);
|
|
pGlobalInfo->minutes = (UCHAR)(NtDateTime.Minute);
|
|
pGlobalInfo->seconds = (UCHAR)(NtDateTime.Second);
|
|
pGlobalInfo->hundredths = (UCHAR)(NtDateTime.Milliseconds / 10);
|
|
pGlobalInfo->weekday = (UCHAR)NtDateTime.Weekday;
|
|
pGlobalInfo->timezone = TimeZone;
|
|
|
|
RtlTimeToSecondsSince1970 ( &LocalTime, &(pGlobalInfo->time) );
|
|
|
|
//
|
|
// Convert UTC to Local time: no need beacuse the subtract between 2 UTCs
|
|
//
|
|
|
|
SystemInformation.BootTime = RtlLargeIntegerSubtract(nttime,
|
|
SystemInformation.BootTime);
|
|
pGlobalInfo->msecs = SystemInformation.BootTime.LowPart/10000 +
|
|
((ULONG)SystemInformation.BootTime.HighPart)*utemp;
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
VOID
|
|
UpdateInfoSegThread(
|
|
ULONG param
|
|
)
|
|
{
|
|
APIRET rc;
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER DelayInterval;
|
|
|
|
UNREFERENCED_PARAMETER(param);
|
|
|
|
|
|
#if DBG
|
|
IF_OS2_DEBUG( MISC ) {
|
|
KdPrint(("Entering UpdateInfoSeg.\n"));
|
|
}
|
|
#endif
|
|
|
|
DelayInterval = RtlEnlargedIntegerMultiply( 10, -10000 );
|
|
for (;;) {
|
|
rc = Os2GetSysInfo();
|
|
if (rc) {
|
|
#if DBG
|
|
KdPrint(("UpdateInfoSegThread: error at Os2GetSysInfo %d\n", rc));
|
|
#endif
|
|
ASSERT (FALSE);
|
|
NtTerminateThread(UpDateInfoSegThreadHandle, rc);
|
|
}
|
|
Status = NtDelayExecution( TRUE, &DelayInterval );
|
|
DelayInterval = RtlEnlargedIntegerMultiply( 10, -10000 );
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Os2InitializeGlobalInfoSeg( VOID )
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
ULONG AllocationAttributes;
|
|
LARGE_INTEGER SectionSize;
|
|
ULONG RegionSize = 0;
|
|
GINFOSEG *pGlobalInfoSeg;
|
|
CLIENT_ID ClientId;
|
|
|
|
AllocationAttributes = SEC_COMMIT;
|
|
SectionSize.LowPart = sizeof(GINFOSEG);
|
|
SectionSize.HighPart = 0;
|
|
Status = NtCreateSection( &Os2GlobalInfoSegHandle,
|
|
SECTION_ALL_ACCESS,
|
|
NULL,
|
|
&SectionSize,
|
|
PAGE_READWRITE,
|
|
AllocationAttributes,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: unable to create the GINFOSEG section, Status=%x\n", Status));
|
|
#endif
|
|
return( Status );
|
|
}
|
|
|
|
Os2GlobalInfoSeg = GINFOSEG_BASE;
|
|
Status = NtMapViewOfSection( Os2GlobalInfoSegHandle,
|
|
NtCurrentProcess(),
|
|
(PVOID) &Os2GlobalInfoSeg,
|
|
0,
|
|
0,
|
|
NULL,
|
|
&RegionSize,
|
|
ViewUnmap,
|
|
0,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: unable to Map View of the GINFOSEG section, Status=%x\n", Status));
|
|
#endif
|
|
return( Status );
|
|
}
|
|
|
|
pGlobalInfoSeg = (GINFOSEG *) Os2GlobalInfoSeg;
|
|
|
|
// pGlobalInfoSeg->pidForeground = (USHORT)(Od2Process->Pib.ProcessId);
|
|
// pGlobalInfoSeg->sgCurrent = (UCHAR)Od2SessionNumber;
|
|
|
|
//
|
|
// Set Fixed Global Information Fields
|
|
//
|
|
pGlobalInfoSeg->uchMajorVersion = 10;
|
|
pGlobalInfoSeg->uchMinorVersion = 21;
|
|
pGlobalInfoSeg->cHugeShift = 3;
|
|
|
|
pGlobalInfoSeg->fProtectModeOnly = 1;
|
|
|
|
//
|
|
// GINFOSEG fields that are set arbitrarily or not
|
|
// set at all for now
|
|
//
|
|
pGlobalInfoSeg->chRevisionLetter = 0;
|
|
// pGlobalInfoSeg->sgCurrent = 0;
|
|
pGlobalInfoSeg->sgMax = 16;
|
|
pGlobalInfoSeg->fDynamicSched = 1;
|
|
pGlobalInfoSeg->csecMaxWait = (UCHAR)-1;
|
|
pGlobalInfoSeg->cmsecMinSlice = 100;
|
|
pGlobalInfoSeg->cmsecMaxSlice = 100;
|
|
pGlobalInfoSeg->timezone = (USHORT)(-1);
|
|
// pGlobalInfoSeg->amecRAS
|
|
// pGlobalInfoSeg->WindowableVioMax
|
|
// pGlobalInfoSeg->csgPMMax
|
|
#ifdef PMNT
|
|
// probably this PMNT can be removed because this is th
|
|
// value of global info seg field in OS2 (LiorM)
|
|
pGlobalInfoSeg->csgWindowableVioMax = 16;
|
|
pGlobalInfoSeg->csgPMMax = 16;
|
|
#endif
|
|
|
|
pGlobalInfoSeg->bootdrive = (USHORT)Os2BootDrive + 1;
|
|
|
|
//
|
|
// Get timer resolution
|
|
//
|
|
|
|
{
|
|
SYSTEM_BASIC_INFORMATION sysinfo;
|
|
|
|
Status = NtQuerySystemInformation(
|
|
SystemBasicInformation,
|
|
&sysinfo,
|
|
sizeof(sysinfo),
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( MISC ) {
|
|
KdPrint(("OS2SRV: unable to query system timer resolution, Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
pGlobalInfoSeg->cusecTimerInterval = 310; // default value, comes from OS/2
|
|
} else {
|
|
pGlobalInfoSeg->cusecTimerInterval = (USHORT) (sysinfo.TimerResolution / 1000L);
|
|
}
|
|
}
|
|
|
|
Status = RtlCreateUserThread( NtCurrentProcess(),
|
|
NULL,
|
|
TRUE,
|
|
0,
|
|
0x10000,
|
|
0, // Default to one page
|
|
(PUSER_THREAD_START_ROUTINE)UpdateInfoSegThread,
|
|
0, // param
|
|
&UpDateInfoSegThreadHandle,
|
|
&ClientId
|
|
);
|
|
if(!NT_SUCCESS(Status)){
|
|
#if DBG
|
|
KdPrint(("Os2InitializeGlobalInfoSeg: can't Create update thread %lx\n", Status));
|
|
#endif
|
|
return Status;
|
|
}
|
|
|
|
Status = NtResumeThread( UpDateInfoSegThreadHandle, NULL );
|
|
if(!NT_SUCCESS(Status)){
|
|
#if DBG
|
|
KdPrint(("Os2InitializeGlobalInfoSeg: can't Resume update thread %lx\n", Status));
|
|
#endif
|
|
return Status;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS Os2InitializeSyncSem()
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING SemString_U;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
CHAR sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
|
PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)&sd;
|
|
|
|
InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
|
|
SetSecurityDescriptorDacl(psd, TRUE, NULL, FALSE); // NULL DACL means access free to all
|
|
|
|
RtlInitUnicodeString( &SemString_U, OS2_SS_SYNCHRONIZATION_SEM);
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&SemString_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
psd);
|
|
|
|
//
|
|
// Create the global subsystem synchronization Nt semaphore
|
|
//
|
|
Status = NtCreateMutant(&Os2SyncSem,
|
|
MUTANT_ALL_ACCESS,
|
|
&Obja,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("Os2InitSyncSem: error at NtCreateSemaphore, Status %x\n", Status);
|
|
}
|
|
#endif
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
#if PMNT
|
|
NTSTATUS Os2InitializePMShellEvent()
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING EventString_U;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
HANDLE hPMShellEvent;
|
|
CHAR sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
|
PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)&sd;
|
|
|
|
InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
|
|
SetSecurityDescriptorDacl(psd, TRUE, NULL, FALSE); // NULL DACL means access free to all
|
|
|
|
RtlInitUnicodeString( &EventString_U, OS2_SS_PMSHELL_EVENT);
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&EventString_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
psd);
|
|
|
|
//
|
|
// Create the global subsystem PMShell synchronization Nt event
|
|
// (create in the unsignalled state - when PMShell comes up, it will
|
|
// signal it)
|
|
//
|
|
Status = NtCreateEvent(&hPMShellEvent,
|
|
EVENT_ALL_ACCESS,
|
|
&Obja,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
#if DBG
|
|
DbgPrint("Os2InitializePMShellEvent: error at NtCreateEvent, Status %x\n", Status);
|
|
#endif
|
|
}
|
|
return(Status);
|
|
}
|
|
#endif // PMNT
|
|
|
|
NTSTATUS
|
|
Os2Initialize( VOID )
|
|
{
|
|
NTSTATUS Status;
|
|
APIRET Rc;
|
|
CHAR sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
|
PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)&sd;
|
|
|
|
#if DBG
|
|
if (fService)
|
|
KdPrint(("Started OS2SRV init (as a service)\n"));
|
|
else
|
|
KdPrint(("Started OS2SRV init\n"));
|
|
#endif
|
|
|
|
//
|
|
// We have just created os2srv - set it's security so all clients
|
|
// can open it regardless of logon
|
|
//
|
|
|
|
InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
|
|
SetSecurityDescriptorDacl(psd, TRUE, NULL, FALSE); // NULL DACL means access free to all
|
|
SetKernelObjectSecurity(GetCurrentProcess(), DACL_SECURITY_INFORMATION, psd);
|
|
|
|
SetEventHandlersAndErrorMode(TRUE);
|
|
|
|
//
|
|
// Create a heap for the OS/2 Server to use for dynamic memory allocation.
|
|
//
|
|
|
|
Os2Heap = RtlCreateHeap( HEAP_GROWABLE,
|
|
NULL,
|
|
64 * 1024, // Initial size of heap is 64K
|
|
4 * 1024,
|
|
0,
|
|
NULL // reserved
|
|
);
|
|
if (Os2Heap == NULL) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Error at RtlCreateHeap of Os2Heap\n"));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Initialize the Process List
|
|
//
|
|
|
|
Status = Os2InitializeProcessStructure();
|
|
if (! NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot initialize process structure, Status = %X\n", Status));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Initialize the Object Manager
|
|
//
|
|
|
|
Status = Os2InitializeLocalObjectManager();
|
|
if (! NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot initialize local object manager, Status = %X\n", Status));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Initialize the Memory Management
|
|
//
|
|
|
|
Status = Os2InitializeMemory();
|
|
if (! NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot initialize shared memory, Status = %X\n", Status));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Initialize the Semaphore Table
|
|
//
|
|
|
|
Status = Os2InitializeSemaphores();
|
|
if (! NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot initialize semaphores, Status = %X\n", Status));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Initialize the Queue Table
|
|
//
|
|
|
|
Status = Os2InitializeQueues();
|
|
if (! NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot initialize queues, Status = %X\n", Status));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Initialize the Name Space
|
|
//
|
|
|
|
Status = Os2InitializeNameSpace();
|
|
if (! NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot initialize name space, Status = %X\n", Status));
|
|
#endif
|
|
ExitProcess(1);
|
|
}
|
|
|
|
Status = Os2InitializeSyncSem();
|
|
if (! NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Status %lx from Os2InitializeSyncSem\n", Status));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return Status;
|
|
}
|
|
|
|
#if PMNT
|
|
Status = Os2InitializePMShellEvent();
|
|
if (! NT_SUCCESS( Status ))
|
|
{
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Status %lx from Os2InitializePMShellSem\n", Status));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return Status;
|
|
}
|
|
#endif // PMNT
|
|
|
|
// Make it so that OS2SRV gets the shutdown/logoff message last. Default
|
|
// is 0x280, minimum range for app is 0x100
|
|
if (!SetProcessShutdownParameters(
|
|
0x27e, // Just below the priority of PMShell
|
|
0))
|
|
{
|
|
#if DBG
|
|
DbgPrint("Os2srv: SetProcessShutdownParameters failed !\n");
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Initialize the registry
|
|
//
|
|
|
|
if (GetSystemDirectoryW(Os2SystemDirectory, MAX_PATH) == 0) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot obtain name of system directory\n"));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
Status = Os2InitializeRegistry();
|
|
if (! NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot initialize registry, Status = %X\n", Status));
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Initialize the NLS
|
|
//
|
|
|
|
if( Rc = Os2InitializeNLS() )
|
|
{
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot initialize NLS, Rc = %d\n", Rc ));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Initialize the loader
|
|
//
|
|
if (!ldrInit()) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot initialize Loader\n"));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Initialize the Global info seg
|
|
//
|
|
|
|
if( Status = Os2InitializeGlobalInfoSeg() )
|
|
{
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot initialize Global Info, Status = %d\n", Status ));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Initialize the OS2 Server Console Session Port, the listen thread and one
|
|
// request threads.
|
|
//
|
|
|
|
Status = Os2InitializeConsolePort();
|
|
|
|
if (! NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot initialize Console Port, Status = %X\n", Status ));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Initialize the OS2 Server API Port, the listen thread and one or more
|
|
// request threads.
|
|
//
|
|
|
|
Status = Os2DebugPortInitialize();
|
|
if (! NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Cannot initialize Debug Port, Status = %X\n", Status ));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return Status;
|
|
}
|
|
|
|
Status = DbgSsInitialize(Os2SessionPort, Os2UiLookup, NULL, NULL);
|
|
if (! NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Status %lx from DbgSsInitialize\n", Status));
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return Status;
|
|
}
|
|
|
|
if (! NT_SUCCESS(Os2GetClientId())) {
|
|
#if DBG
|
|
KdPrint(("OS2SRV: Can not debug\n"));
|
|
#endif
|
|
}
|
|
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
ULONG
|
|
NtGetIntegerFromUnicodeString(IN WCHAR *WString)
|
|
{
|
|
ULONG Code = 0;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
RtlInitUnicodeString(
|
|
&UnicodeString,
|
|
WString);
|
|
|
|
Status = RtlUnicodeStringToInteger(
|
|
&UnicodeString,
|
|
10,
|
|
&Code);
|
|
|
|
#if DBG
|
|
if (! NT_SUCCESS( Status ))
|
|
{
|
|
IF_OS2_DEBUG( NLS )
|
|
{
|
|
KdPrint(("InitNLS: RtlUnicodeStringToInteger failed, Status %lu\n",
|
|
Status ));
|
|
}
|
|
}
|
|
#endif
|
|
return(Code);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Os2SrvHandleCtrlEvent(
|
|
IN int CtrlType
|
|
)
|
|
{
|
|
BOOLEAN Wait = FALSE/*, Rc*/;
|
|
OS2SESREQUESTMSG RequestMsg;
|
|
ULONG i;
|
|
LARGE_INTEGER DelayInterval;
|
|
|
|
#if DBG
|
|
IF_OS2_DEBUG( SIG )
|
|
{
|
|
KdPrint(("OS2SRV(EventHandlerRoutine): Ctr-Type %u\n", CtrlType));
|
|
}
|
|
#endif
|
|
|
|
Os2AcquireStructureLock();
|
|
for ( i = 1 ; ( i < OS2_MAX_SESSION ) ; i++ )
|
|
{
|
|
if ( SessionTable[i].Session != NULL )
|
|
{
|
|
RequestMsg.Session = SessionTable[i].Session;
|
|
RequestMsg.d.Signal.Type = CtrlType;
|
|
Os2CtrlSignalHandler(&RequestMsg, NULL);
|
|
Wait = TRUE;
|
|
}
|
|
}
|
|
Os2ReleaseStructureLock();
|
|
|
|
while (Wait)
|
|
{
|
|
#if DBG
|
|
KdPrint(("OS2SRV(EventHandlerRoutine): Waiting 2 seconds for all sessions to clear\n"));
|
|
#endif
|
|
DelayInterval = RtlEnlargedIntegerMultiply( 2000, -10000 );
|
|
NtDelayExecution( (BOOLEAN)TRUE, &DelayInterval );
|
|
Wait = FALSE;
|
|
|
|
for ( i = 1 ; ( i < OS2_MAX_SESSION ) ; i++ )
|
|
{
|
|
if ( SessionTable[i].Session != NULL )
|
|
{
|
|
Wait = TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
//
|
|
// Wait for the first application that created the server -
|
|
// The logoff/shutdown logic is LIFO, so we want to prevent
|
|
// os2srv from exiting if that app is not gone yet, otherwise
|
|
// the kernel hangs because of debug port handshake
|
|
//
|
|
if ( FirstOs2ProcessHandle != 0 && FirstOs2ProcessHandle != (HANDLE)-1 ) {
|
|
NtWaitForSingleObject(
|
|
FirstOs2ProcessHandle,
|
|
TRUE, // Alertable
|
|
NULL
|
|
);
|
|
}
|
|
//
|
|
// Now we can exit the server
|
|
//
|
|
Os2SrvExitProcess(0);
|
|
return(TRUE);
|
|
}
|