/*++ Copyright (c) 1991 Microsoft Corporation Module Name: dllsig16.c Abstract: This module implements 32 equivalents of OS/2 V1.21 Signal API Calls. These are called from 16->32 thunks (i386\doscalls.asm). Author: Yaron Shamir (YaronS) 30-May-1991 Revision History: --*/ #define INCL_OS2V20_MEMORY #define INCL_OS2V20_FILESYS #define INCL_OS2V20_ERRORS #include "os2dll.h" #include "os2dll16.h" extern OD2_SIG_HANDLER_REC SigHandlerRec; extern POD2_VEC_HANDLER_REC pVecHandlerRec; extern PVOID __cdecl Od2JumpTo16SignalDispatch(ULONG address, ULONG regs, ULONG usFlagNum, ULONG usFlagArg); extern BOOLEAN LDRIsLDTValid(SEL sel); extern APIRET DosFreeSeg(SEL sel); VOID Od2PrepareEnterToSignalHandler( PCONTEXT pContext, POD2_CONTEXT_SAVE_AREA pSaveArea ); VOID Od2MakeSignalHandlerContext( POS2_REGISTER16_SIGNAL pContext16 ); VOID Od2ExitFromSignalHandler( PCONTEXT Context, POD2_CONTEXT_SAVE_AREA pSaveArea ); APIRET DosFlagProcess( ULONG pid, ULONG fScope, ULONG usFlagNum, ULONG usFlagArg, ULONG pstack ) { OS2_API_MSG m; POS2_DISPATCH16_SIGNAL a = &m.u.Dispatch16Signal; if (usFlagNum > 2) { return(ERROR_INVALID_FLAG_NUMBER); } if (pid == 0 || pid == 0xffff) { return(ERROR_INVALID_FUNCTION); } if (fScope != FLGP_SUBTREE && fScope != FLGP_PID) { return(ERROR_INVALID_FUNCTION); } if ((ULONG) Od2Process->Pib.ProcessId == pid && Od2CurrentThreadId() == 1) { Od2JumpTo16SignalDispatch(SigHandlerRec.sighandler[usFlagNum + SIG_PFLG_A - 1], pstack, usFlagNum + SIG_PFLG_A, usFlagArg); return(NO_ERROR); } a->usFlagNum = (USHORT) (usFlagNum + SIG_PFLG_A); a->usFlagArg = (USHORT) usFlagArg; a->fscope = fScope; a->pidProcess = (ULONG) pid; a->routine = (ULONG) _Od2ProcessSignal16; a->sighandleraddr = (ULONG) &SigHandlerRec; if (Od2CallSubsystem( &m, NULL, Os2Dispatch16Signal, sizeof( *a ) )) { return( m.ReturnedErrorValue ); } return(NO_ERROR); } APIRET DosHoldSignal( ULONG fDisable, ULONG pstack ) { OS2_API_MSG m; POS2_DISPATCH16_SIGNAL a = &m.u.Dispatch16Signal; ULONG i; UNREFERENCED_PARAMETER(pstack); if (fDisable == HLDSIG_DISABLE) { SigHandlerRec.fholdenable++; return NO_ERROR; } if (fDisable == HLDSIG_ENABLE && SigHandlerRec.fholdenable > 0) { SigHandlerRec.fholdenable--; if (SigHandlerRec.fholdenable == 0) { for (i = 0; i < 7; ++i) { if (SigHandlerRec.outstandingsig[i].sighandleraddr != 0) { a->usFlagNum = HOLD_SIGNAL_CLEARED; a->usFlagArg = (USHORT) (i + 1); a->fscope = 0; a->pidProcess = (ULONG) Od2Process->Pib.ProcessId; a->routine = (ULONG) _Od2ProcessSignal16; a->sighandleraddr = (ULONG) &SigHandlerRec; Od2CallSubsystem( &m, NULL, Os2Dispatch16Signal, sizeof( *a )); } } } return NO_ERROR; } else { return ERROR_INVALID_FUNCTION; } } APIRET DosSendSignal( ULONG idProcess, ULONG usSigNumber, ULONG pstack ) { OS2_API_MSG m; POS2_DISPATCH16_SIGNAL a = &m.u.Dispatch16Signal; UNREFERENCED_PARAMETER(pstack); if (usSigNumber != SIG_CTRLC && usSigNumber != SIG_CTRLBREAK) return(ERROR_INVALID_FLAG_NUMBER); a->usFlagNum = (USHORT) usSigNumber; a->usFlagArg = 0; a->fscope = 0; a->pidProcess = (ULONG) idProcess; a->routine = (ULONG) _Od2ProcessSignal16; a->sighandleraddr = (ULONG) &SigHandlerRec; if (Od2CallSubsystem( &m, NULL, Os2Dispatch16Signal, sizeof( *a ) )) { return( m.ReturnedErrorValue ); } return (NO_ERROR); } APIRET DosSetSigHandler( PFNSIGHANDLER pfnSigHandler, PFNSIGHANDLER *pfnPrev, PUSHORT pfAction, ULONG fAction, ULONG usSigNum ) { OS2_API_MSG m; ULONG address; POS2_REGISTER_HANDLER b = &m.u.DosRegisterCtrlHandler; POS2_DISPATCH16_SIGNAL a = &m.u.Dispatch16Signal; if (usSigNum < SIG_CTRLC || usSigNum >= SIG_CSIGNALS) { return ERROR_INVALID_SIGNAL_NUMBER; } if (usSigNum == SIG_BROKENPIPE && fAction != SIGA_ACKNOWLEDGE) { return ERROR_INVALID_SIGNAL_NUMBER; } if (fAction > SIGA_ACKNOWLEDGE || usSigNum >= SIG_CSIGNALS) { return ERROR_INVALID_SIGNAL_NUMBER; } // if (!LDRIsLDTValid(((FLATTOSEL((ULONG) pfnSigHandler) | 4 | 3)))) { // return ERROR_INVALID_STARTING_RING; // } // // Check if signal outstanding if so the next command from the user // has to be an acknowledge // if (SigHandlerRec.action[usSigNum - 1] == SIGA_ACKNOWLEDGE && fAction != SIGA_ACKNOWLEDGE) { return ERROR_SIGNAL_PENDING; } // // If signal is acknowledge check to see if a signal is pending, // process the pending signal then set to clear pending. This must be // done while signal is being processed to permit the signal to be // used again. // if (fAction == SIGA_ACKNOWLEDGE) { if (SigHandlerRec.outstandingsig[usSigNum - 1].sighandleraddr != 0) { SigHandlerRec.action[usSigNum - 1] = SIGA_ACKNOWLEDGE_AND_ACCEPT; a->usFlagNum = HOLD_SIGNAL_CLEARED; a->usFlagArg = (USHORT) usSigNum; a->fscope = 0; a->pidProcess = (ULONG) Od2Process->Pib.ProcessId; a->routine = (ULONG) _Od2ProcessSignal16; a->sighandleraddr = (ULONG) &SigHandlerRec; Od2CallSubsystem( &m, NULL, Os2Dispatch16Signal, sizeof( *a )); return NO_ERROR; } SigHandlerRec.action[usSigNum - 1] = SIGA_ACCEPT; return NO_ERROR; } if (pfnSigHandler == 0 && fAction != SIGA_IGNORE) { // // means set default handling // fAction = SIGA_KILL; } // // Check to see if we should remove the signal // if (fAction == SIGA_KILL) { // // Reinstall default handler, same as done in \loader\loader.c // address = SigHandlerRec.doscallssel; switch (usSigNum) { case SIG_CTRLC: SigHandlerRec.sighandler[SIG_CTRLC - 1] = (ULONG) (address | ThunkOffsetExitProcessStub); SigHandlerRec.action[SIG_CTRLC - 1] = SIGA_ACCEPT; break; case SIG_BROKENPIPE: SigHandlerRec.sighandler[SIG_BROKENPIPE - 1] = (ULONG) (address | ThunkOffsetDosReturn); SigHandlerRec.action[SIG_BROKENPIPE - 1] = SIGA_IGNORE; break; case SIG_KILLPROCESS: SigHandlerRec.sighandler[SIG_KILLPROCESS - 1] = (ULONG) (address | ThunkOffsetExitProcessStub); SigHandlerRec.action[SIG_KILLPROCESS - 1] = SIGA_ACCEPT; break; case SIG_CTRLBREAK: SigHandlerRec.sighandler[SIG_CTRLBREAK - 1] = (ULONG) (address | ThunkOffsetExitProcessStub); SigHandlerRec.action[SIG_CTRLBREAK - 1] = SIGA_ACCEPT; break; case SIG_PFLG_A: SigHandlerRec.sighandler[SIG_PFLG_A - 1] = (ULONG) (address | ThunkOffsetDosReturn); SigHandlerRec.action[SIG_PFLG_A - 1] = SIGA_ACCEPT; break; case SIG_PFLG_B: SigHandlerRec.sighandler[SIG_PFLG_B - 1] = (ULONG) (address | ThunkOffsetDosReturn); SigHandlerRec.action[SIG_PFLG_B - 1] = SIGA_ACCEPT; break; case SIG_PFLG_C: SigHandlerRec.sighandler[SIG_PFLG_C - 1] = (ULONG) (address | ThunkOffsetDosReturn); SigHandlerRec.action[SIG_PFLG_C - 1] = SIGA_ACCEPT; break; } if (usSigNum == SIG_CTRLC || usSigNum == SIG_KILLPROCESS || usSigNum == SIG_CTRLBREAK) { b->usFlagNum = usSigNum; b->fAction = SIGA_KILL; Od2CallSubsystem(&m, NULL, Os2RegisterCtrlHandler, sizeof( *b )); } return NO_ERROR; } try { if (pfnPrev != NULL) { *pfnPrev = (PFNSIGHANDLER) SigHandlerRec.sighandler[usSigNum - 1]; } if (pfAction != NULL) { *pfAction = SigHandlerRec.action[usSigNum - 1]; } } except( EXCEPTION_EXECUTE_HANDLER ) { return ERROR_INVALID_FUNCTION; } if (pfnSigHandler) { // // fAction is SIGA_IGNORE // SigHandlerRec.sighandler[usSigNum - 1] = (ULONG)(FLATTOFARPTR((ULONG)pfnSigHandler)); } SigHandlerRec.action[usSigNum - 1] = (USHORT) fAction; if (usSigNum == SIG_CTRLC || usSigNum == SIG_KILLPROCESS || usSigNum == SIG_CTRLBREAK) { b->usFlagNum = usSigNum; if (fAction == SIGA_IGNORE) b->fAction = SIGA_IGNORE; else b->fAction = SIGA_ACCEPT; Od2CallSubsystem(&m, NULL, Os2RegisterCtrlHandler, sizeof( *b )); } return NO_ERROR; } VOID Od2ProcessSignal16 ( IN ULONG rEax, // The value of EAX during interrupt. It will be useful // if this is the return code of any wait. The value of // EAX was set after that the context was read. IN POS2_REGISTER16_SIGNAL pa ) { CONTEXT Context; PCONTEXT pContext; ULONG size; ULONG address; ULONG signum; NTSTATUS Status; OD2_CONTEXT_SAVE_AREA SaveArea; pContext = (PCONTEXT) ((PCHAR) pa + sizeof(OS2_REGISTER16_SIGNAL)); Od2PrepareEnterToSignalHandler(pContext, &SaveArea); Od2Process->Pib.SignalWasntDelivered = FALSE; signum = pa->usFlagNum; // // Since the signal handler routine can not run on stack of the // process which called DosFlagProcess get stack from process // context and run on that. But check to see where the program // was excuting, if the CS is = 0x1b "Flat CS" then it was in the client // or server. So restore registers from pointer to 16-bit stack // saved at thunk entry. // pContext->Eax = rEax; // Set the right value of EAX to the saved context // // Copy context of process we stopped on to stack so we can free the // memory later which was allocated in the other process to pass the // context // RtlMoveMemory(&Context, pContext, sizeof(Context)); if (SigHandlerRec.signature == 0xdead) { Od2MakeSignalHandlerContext(pa); if (SigHandlerRec.sighandler[signum - 1] != 0 ) { Od2JumpTo16SignalDispatch(SigHandlerRec.sighandler[signum - 1], (ULONG) pa, signum, (ULONG) pa->usFlagArg); } } size = 0; address = (ULONG) pa; Status = NtFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &address, &size, MEM_RELEASE); ASSERT(NT_SUCCESS(Status)); Od2ExitFromSignalHandler(&Context, &SaveArea); } APIRET DosSetVec( ULONG usVecNum, PFN pfnFun, PFN* ppfnPrev ) { ULONG index; PFN fn; try { fn = *ppfnPrev; fn = pfnFun; } except( EXCEPTION_EXECUTE_HANDLER ) { Od2ExitGP(); } switch (usVecNum) { case VECTOR_DIVIDE_BY_ZERO: index = 0; break; case VECTOR_OVERFLOW: index = 1; break; case VECTOR_OUTOFBOUNDS: index = 2; break; case VECTOR_INVALIDOPCODE: index = 3; break; case VECTOR_NO_EXTENSION: index = 4; break; case VECTOR_EXTENSION_ERROR: index = 5; break; default: return ERROR_INVALID_FUNCTION; } if (fn == 0) { if (pVecHandlerRec->VecHandler[index] == (ULONG) (pVecHandlerRec->doscallssel | ThunkOffsetDosReturn)) { *ppfnPrev = 0; } else { *ppfnPrev = (PFN) pVecHandlerRec->VecHandler[index]; } pVecHandlerRec->VecHandler[index] = (ULONG) (pVecHandlerRec->doscallssel | ThunkOffsetDosReturn); } else { if (pVecHandlerRec->VecHandler[index] == (ULONG) (pVecHandlerRec->doscallssel | ThunkOffsetDosReturn)) { *ppfnPrev = 0; } else { *ppfnPrev = (PFN) pVecHandlerRec->VecHandler[index]; } pVecHandlerRec->VecHandler[index] = (ULONG)(FLATTOFARPTR((ULONG)(pfnFun))); } return NO_ERROR; } VOID Od2EnableCtrlHandling() { OS2_API_MSG m; POS2_REGISTER_HANDLER b = &m.u.DosRegisterCtrlHandler; b->usFlagNum = 0; b->fAction = SIGA_ENABLE_HANDLING; Od2CallSubsystem(&m, NULL, Os2RegisterCtrlHandler, sizeof( *b )); }