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.
 
 
 
 
 
 

1885 lines
54 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
srvxcpt.c
Abstract:
This module implements the OS/2 V2.0 exception handling API calls.
Author:
Therese Stowell (thereses) 29-June-1990
Revision History:
--*/
#define INCL_OS2V20_EXCEPTIONS
#define INCL_OS2V20_ERRORS
#define SIG_CTRLC 1
#define SIG_CTRLBREAK 4
#include "os2srv.h"
#include "os2tile.h"
APIRET
SendSignalException(
IN POS2_THREAD Thread,
IN int Signal
);
NTSTATUS
Os2CompleteResumeThread(
IN POS2_THREAD Thread
);
BOOLEAN
Os2DosEnterMustComplete(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
/*++
Routine Description:
This routine implements the DosEnterMustComplete API.
Arguments:
t - calling thread
m - message
Return Value:
TRUE - create a return message
--*/
{
POS2_DOSENTERMUSTCOMPLETE_MSG a = &m->u.DosEnterMustComplete;
if (t->MustComplete == MAXIMUM_MUST_COMPLETE) { /* Counter wrapped */
m->ReturnedErrorValue = ERROR_NESTING_TOO_DEEP;
}
else {
m->ReturnedErrorValue = NO_ERROR;
a->NestingLevel = ++t->MustComplete;
}
return (TRUE);
}
BOOLEAN
Os2DosExitMustComplete(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
/*++
Routine Description:
This routine implements the DosExitMustComplete API.
Arguments:
t - calling thread
m - message
Return Value:
TRUE - create a return message
--*/
{
POS2_DOSEXITMUSTCOMPLETE_MSG a = &m->u.DosExitMustComplete;
if (t->MustComplete == 0) { /* Counter wrapped */
m->ReturnedErrorValue = ERROR_ALREADY_RESET;
}
else {
m->ReturnedErrorValue = NO_ERROR;
a->NestingLevel = --t->MustComplete;
if ((t->MustComplete == 0) && (t->PendingSignals != 0)) {
//
// if we are no longer in a MustComplete region, we need to
// issue any pending signals.
//
// possible pending signals are:
// SIG_APTERM
// SIG_KILLPROC
// SIG_INTR
// SIG_BREAK
//
if (t->PendingSignals & SIGNAL_TO_FLAG(XCPT_SIGNAL_INTR)) {
t->PendingSignals &= ~SIGNAL_TO_FLAG(XCPT_SIGNAL_INTR);
SendSignalException(t,XCPT_SIGNAL_INTR);
}
if (t->PendingSignals & SIGNAL_TO_FLAG(XCPT_SIGNAL_KILLPROC)) {
t->PendingSignals &= ~SIGNAL_TO_FLAG(XCPT_SIGNAL_KILLPROC);
SendSignalException(t,XCPT_SIGNAL_KILLPROC);
}
if (t->PendingSignals & SIGNAL_TO_FLAG(XCPT_SIGNAL_BREAK)) {
t->PendingSignals &= ~SIGNAL_TO_FLAG(XCPT_SIGNAL_BREAK);
SendSignalException(t,XCPT_SIGNAL_BREAK);
}
if (t->PendingSignals & SIGNAL_TO_FLAG(SIGAPTERM)) {
ASSERT(FALSE);
t->PendingSignals &= ~SIGNAL_TO_FLAG(SIGAPTERM);
SendSignalException(t,SIGAPTERM);
}
}
}
return (TRUE);
}
BOOLEAN
Os2DosSetSignalExceptionFocus(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
/*++
Routine Description:
This routine implements the DosSetSignalExceptionFocus API.
Arguments:
t - calling thread
m - message
Return Value:
TRUE - create a return message
--*/
{
POS2_DOSSETSIGNALEXCEPTIONFOCUS_MSG a = &m->u.DosSetSignalExceptionFocus;
if (a->Flag == SIG_SETFOCUS) {
if (t->Process->ExceptionFocus == SIG_MAXSF) {
m->ReturnedErrorValue = ERROR_NESTING_TOO_DEEP;
}
else {
m->ReturnedErrorValue = NO_ERROR;
a->NestingLevel = ++t->Process->ExceptionFocus;
}
}
else if (a->Flag == SIG_UNSETFOCUS) {
if (t->Process->ExceptionFocus == 0) {
m->ReturnedErrorValue = ERROR_ALREADY_RESET;
}
else {
m->ReturnedErrorValue = NO_ERROR;
a->NestingLevel = --t->Process->ExceptionFocus;
}
}
else
ASSERT (FALSE);
return (TRUE);
}
VOID
FindExceptionFocus(
IN POS2_PROCESS RootProcess,
IN ULONG CurrentDepth,
IN OUT POS2_PROCESS *CurrentFocus,
IN OUT PULONG CurrentFocusDepth
)
/*++
Routine Description:
This routine finds the leafmost child of the current process that has
requested the signal exception focus (DosSetSignalExceptionFocus).
Arguments:
RootProcess - the process from which to begin the search
CurrentDepth - the depth of the rootprocess from the original root process
CurrentFocus - the process which is currently the leafmost with the signal focus
CurrentFocusDepth - the depth of the current focus from the original root process
Return Value:
none
--*/
{
PLIST_ENTRY ListHead, ListNext;
POS2_THREAD Thread1;
Thread1 = CONTAINING_RECORD( RootProcess->ThreadList.Flink, OS2_THREAD, Link );
if (Thread1->Dying == FALSE) {
//
// if the process we're looking at has requested the focus and it's
// leafward of the current focus, choose it as the current focus.
//
if ((RootProcess->ExceptionFocus != 0) &&
(*CurrentFocusDepth < CurrentDepth)) { // to pick the last created process, make this a <=
*CurrentFocus = RootProcess;
*CurrentFocusDepth = CurrentDepth;
}
}
ListHead = &RootProcess->ChildrenList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
FindExceptionFocus( CONTAINING_RECORD( ListNext,
OS2_PROCESS,
SiblingLink
),
CurrentDepth+1,
CurrentFocus,
CurrentFocusDepth
);
ListNext = ListNext->Flink;
}
}
APIRET
Os2SignalGetThreadContext(
POS2_THREAD Thread,
PCONTEXT pContext,
PULONG pNewSp,
PULONG pSuspendTimes
)
{
NTSTATUS Status;
ULONG SuspendCount;
POS2_PROCESS Process = Thread->Process;
BOOLEAN SignalWasntDelivered;
*pSuspendTimes = 0;
Status = NtReadVirtualMemory( Process->ProcessHandle,
&(Process->ClientPib->SignalWasntDelivered),
&SignalWasntDelivered,
sizeof(BOOLEAN),
NULL
);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint("[%d]Os2SignalGetThreadContext: Fail to read from client, Status=%x\n",
Process->ProcessId,
Status);
#endif // DBG
ASSERT(FALSE);
return ERROR_NOT_ENOUGH_MEMORY;
}
if (SignalWasntDelivered) {
//
// Thread1 wan't execute the entry code of signal handler, yet.
//
#if DBG
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d]Os2SignalGetThreadContext: Previous signal wasn't delivered yet\n",
Process->ProcessId);
}
#endif // DBG
return ERROR_SIGNAL_REFUSED;
}
__try {
//
// Thread1 will be suspended 3 times. There is the possibility that the thread will
// be resumed by the client process, but only 2 times (in DosSuspend/ResumeThread and
// DosEnter/ExitCritSect). By suspending for 3 times we insure that the the thread
// will be suspended.
// The thread might be resumed by client in the case that signal handler was executed
// and the flag that indicates that signal handler in progress already cleared. But
// any subsequent DosSuspendThread or DosEnterCritSect will actually suspend the
// thread and thier spouses will resume it with the same suspend count.
//
do {
Status = NtSuspendThread(Thread->ThreadHandle, &SuspendCount);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint("[%d]Os2SignalGetThreadContext: Fail to suspend thread, Status=%x\n",
Process->ProcessId,
Status);
#endif // DBG
ASSERT(FALSE);
return ERROR_NOT_ENOUGH_MEMORY;
}
#if DBG
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d]Os2SignalGetThreadContext: suspend thread, count = %d\n",
Process->ProcessId,
SuspendCount);
}
#endif // DBG
(*pSuspendTimes)++;
} while (SuspendCount < 2);
pContext->ContextFlags = CONTEXT_FULL;
Status = NtGetContextThread(Thread->ThreadHandle, pContext);
if (Status != STATUS_SUCCESS) {
#if DBG
DbgPrint("[%d]Os2SignalGetThreadContext: Fail to get context, Status=%x\n",
Process->ProcessId,
Status);
#endif //DBG
ASSERT(FALSE);
return ERROR_SIGNAL_REFUSED;
}
#if DBG
//
// Hack that avoid signal handler execution if the thread is using INT 3
// instruction. Relevant for checked build only.
//
if (pContext->SegCs == 0x1b && pContext->SegSs == 0x23) {
BYTE opcode;
Status = NtReadVirtualMemory( Process->ProcessHandle,
(PVOID)(pContext->Eip - 1), // previous byte
&opcode,
1,
NULL);
if (!NT_SUCCESS(Status)) {
DbgPrint("[%d]Os2SignalGetThreadContext: Fail to read instruction, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
return ERROR_NOT_ENOUGH_MEMORY;
}
if (opcode == 0xcc) { // INT 3
//
// Refuse to signal if the thread in INT 3 handler. It will not use
// the context to return, so there is no point to set new context and
// no possibility to perform signal handler. INT 3 is ised by
// ntdll!DebugService (from DbgPrint).
//
DbgPrint("[%d]Os2SignalGetThreadContext: after INT 3\n",
Process->ProcessId);
Status = 0xc0000000;
return ERROR_SIGNAL_REFUSED;
}
}
#endif // DBG
if (pContext->SegCs == 0x1b) {
//
// The values of DS and ES might be invalid in the context. Kernel don't update
// them if the thread was in 32bit (CS==1b).
//
pContext->SegDs = pContext->SegEs = 0x23;
}
if (pContext->SegSs != 0x23) {
//
// The thread was in 16 bit
//
Status = NtReadVirtualMemory( Process->ProcessHandle,
&(Process->ClientPib->Saved32Esp),
pNewSp,
sizeof(ULONG),
NULL);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint("[%d]Os2SignalGetThreadContext: Fail to read from client, Status=%x\n",
Process->ProcessId,
Status);
#endif // DBG
ASSERT(FALSE);
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// There are 8 bytes beyond the 32bit stack (that was saved) that are used by
// Od2JumpTo16SignalDispatch to store the jump instruction to 16bit signal
// handler.
//
*pNewSp -= 8;
#if DBG
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d]Os2GetThreadContext: Signal on 16bit(%x:%x) -- Stack=%x\n",
Process->ProcessId,
pContext->SegCs,
pContext->Eip,
*pNewSp);
}
#endif // DBG
}
else {
//
// 8 bytes beyond the stack are used by Od2Continue to return to original
// context.
//
*pNewSp = pContext->Esp - 8;
#if DBG
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d]Os2GetThreadContext: Signal on 32bit(%x) -- Stack=%x\n",
Process->ProcessId,
pContext->Eip,
*pNewSp);
}
#endif // DBG
}
(*pNewSp) &= 0xfffffffc;
}
__finally {
if (!NT_SUCCESS(Status)) {
while (*pSuspendTimes) {
Status = NtResumeThread(Thread->ThreadHandle, &SuspendCount);
#if DBG
if (!NT_SUCCESS(Status)) {
DbgPrint("[%d]Os2SignalGetThreadContext: Fail to resume thread, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
}
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d]Os2SignalGetThreadContext: resume thread, count = %d\n",
Process->ProcessId,
SuspendCount);
}
#endif // DBG
(*pSuspendTimes)--;
}
}
}
return NO_ERROR;
}
APIRET
Os2SignalSetThreadContext(
POS2_THREAD Thread,
PCONTEXT pContext
)
{
BOOLEAN true = TRUE;
POS2_PROCESS Process = Thread->Process;
NTSTATUS Status;
Status = NtWriteVirtualMemory( Process->ProcessHandle,
&(Process->ClientPib->SigHandInProgress),
&true,
sizeof(BOOLEAN),
NULL
);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint("[%d]Os2SignalSetThreadContext: Fail to write SigInProgress, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
#endif // DBG
return ERROR_NOT_ENOUGH_MEMORY;
}
Status = NtWriteVirtualMemory( Process->ProcessHandle,
&(Process->ClientPib->SignalWasntDelivered),
&true,
sizeof(BOOLEAN),
NULL
);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint("[%d]Os2SignalSetThreadContext: Fail to write SigWasntDelivered, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
#endif // DBG
return ERROR_NOT_ENOUGH_MEMORY;
}
#if DBG
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d]Os2SetThreadContext: Going to set new context, Eip=%x\n",
Process->ProcessId,
pContext->Eip);
}
#endif // DBG
pContext->ContextFlags = CONTEXT_FULL;
pContext->EFlags &= 0xfffffbff; // Clear direction flag. By defualt run-time
// library assume that direction flag is cleared.
// RtlMoveMemory, for example, don't clear this
// flag on entry, but assume it 0.
Status = NtSetContextThread(Thread->ThreadHandle, pContext);
if (Status != STATUS_SUCCESS) {
#if DBG
DbgPrint("[%d]Os2SignalSetThreadContext: Fail to set context, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(NT_SUCCESS(Status));
#endif // DBG
return ERROR_SIGNAL_REFUSED;
}
return NO_ERROR;
}
VOID
DeliverSignal(
IN POS2_THREAD Thread,
IN ULONG Signal
)
/*++
Routine Description:
This function is used to deliver a signal to a process. It
can safely assume that the target process is inside the client.
Arguments:
Thread - Supplies the handle of the thread to be signaled
Signal - Supplies the index of the signal to be delivered to the
process
Return Value:
None.
--*/
{
NTSTATUS Status;
ULONG Args[2];
CONTEXT Context;
ULONG NewSp;
POS2_PROCESS Process = Thread->Process;
ULONG SuspendCount;
APIRET rc;
ULONG SuspendTimes;
#if DBG
IF_OS2_DEBUG( EXCEPTIONS ) {
DbgPrint("Thread 0x%lx delivered signal %ld\n",Thread,Signal);
}
#endif
//
// Suspend the thread and get it's context
//
if ((rc = Os2SignalGetThreadContext(Thread, &Context, &NewSp, &SuspendTimes)) != NO_ERROR) {
//
// Continue without context switch. The signal will not be delivered.
//
return;
}
__try {
NewSp -= sizeof( CONTEXT );
Status = NtWriteVirtualMemory(
Process->ProcessHandle,
(PVOID)NewSp,
&Context,
sizeof( CONTEXT ),
NULL);
if (!NT_SUCCESS( Status )) {
#if DBG
DbgPrint("[%d]DeliverSignal: Fail to write old context to client stack, Status=%x\n",
Process->ProcessId,
Status);
#endif // DBG
ASSERT(FALSE);
__leave;
}
Args[0] = NewSp; // pass pointer to context
Args[1] = Signal;
NewSp -= 2 * sizeof( ULONG );
Status = NtWriteVirtualMemory(
Process->ProcessHandle,
(PVOID)NewSp,
Args,
2 * sizeof( ULONG ),
NULL);
if (!NT_SUCCESS( Status )) {
#if DBG
DbgPrint("[%d]DeliverSignal: Fail to write parameters to client stack, Status=%x\n",
Process->ProcessId,
Status);
#endif // DBG
ASSERT(FALSE);
__leave;
}
//
// Set the address of the target code into Eip, the new target stack
// into Esp, and reload context to make it happen.
//
Context.SegSs = Context.SegDs = Context.SegEs = 0x23;
Context.SegCs = 0x1b;
Context.Esp = NewSp;
Context.Eip = (ULONG)Process->SignalDeliverer;
rc = Os2SignalSetThreadContext(Thread, &Context);
}
__finally {
if (rc != NO_ERROR || !NT_SUCCESS(Status)) {
while (SuspendTimes) {
Status = NtResumeThread(Thread->ThreadHandle, &SuspendCount);
#if DBG
if (!NT_SUCCESS(Status)) {
DbgPrint("[%d]DeleverSignal: Fail to resume thread, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
}
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d]DeliverSignal: resume thread, count = %d\n",
Process->ProcessId,
SuspendCount);
}
#endif // DBG
SuspendTimes--;
}
}
else {
//
// Now alert the thread - in case it is blocked it will
// get the chance now to execute the signal handler
//
#if DBG
IF_OD2_DEBUG( TASKING ) {
DbgPrint("[%d,%d]DeliverSignal: Going to NtAlertThread(%x.%x)\n",
Process->ProcessId,
Thread->ThreadId,
Thread->ClientId.UniqueProcess,
Thread->ClientId.UniqueThread);
}
#endif
Status = NtAlertThread(Thread->ThreadHandle);
#if DBG
if (!NT_SUCCESS(Status)) {
//
// We can do nothing but to try to continue execution
//
DbgPrint("[%d]DeliverSignal: Fail to alert thread, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
}
#endif // DBG
Os2CompleteResumeThread(Thread);
}
}
}
APIRET
SendSignalException(
IN POS2_THREAD Thread,
IN int Signal
)
/*++
Routine Description:
This routine sends a signal to a particular thread. It will do the
correct thing based on whether the thread is in a mustcomplete section
or has signals pending.
Arguments:
Thread - thread to signal
Signal - signal to send
Return Value:
ERROR_SIGNAL_PENDING - the specified signal is already pending for the
thread.
--*/
{
ULONG SignalFlag;
//
// convert signal to bitmap value
//
SignalFlag = SIGNAL_TO_FLAG(Signal);
//
// if a signal of this type is already queued, return error.
//
if (Thread->PendingSignals & SignalFlag) {
return ERROR_SIGNAL_PENDING;
}
//
// if a signal of this type is currently being processed or
// the thread is in a mustcomplete region, queue the signal.
// otherwise, issue it.
//
// if the thread is in a wait block, wake it up.
//
if (!(Thread->CurrentSignals & SignalFlag) && !Thread->MustComplete) {
// Thread->CurrentSignals |= SignalFlag;
if (Thread->WaitBlock != NULL) {
Thread->WaitBlock->WaitReplyMessage.ReturnedErrorValue = ERROR_INTERRUPT;
Os2NotifyWaitBlock(Thread->WaitBlock,WaitInterrupt,NULL,NULL);
}
DeliverSignal(Thread,Signal);
}
else {
Thread->PendingSignals |= SignalFlag;
}
return NO_ERROR;
}
BOOLEAN
Os2DosSendSignalException(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
/*++
Routine Description:
This routine implements the DosSendSignalException API.
Arguments:
t - calling thread
m - message
Return Value:
TRUE - create a return message
--*/
{
POS2_DOSSENDSIGNALEXCEPTION_MSG a = &m->u.DosSendSignalException;
POS2_PROCESS Process;
POS2_PROCESS FocusProcess;
POS2_THREAD Thread;
ULONG Depth;
#if DBG
IF_OS2_DEBUG( EXCEPTIONS ) {
DbgPrint("entering Os2DosSendSignalException\n");
}
#endif
//
// find the specified process
//
Process = Os2LocateProcessByProcessId( m,
t->Process,
(PID)a->ProcessId,
(BOOLEAN)FALSE
);
if (Process == NULL) {
return( TRUE );
}
//
// verify that specified process is direct child of caller
// believe it or not, ERROR_INVALID_FUNCTION is the same error code
// as is returned by OS/2 v2.0
//
if (Process->Parent != t->Process) {
m->ReturnedErrorValue = ERROR_INVALID_FUNCTION;
return( TRUE );
}
//
// find the leafmost process that has requested the exception focus
//
FocusProcess = NULL;
Depth = 0;
FindExceptionFocus(Process,
(ULONG) 1,
&FocusProcess,
&Depth);
if (FocusProcess == NULL) {
m->ReturnedErrorValue = ERROR_NO_SIGNAL_SENT;
return (TRUE);
}
//
// find thread 1 of the exception focus process
//
Thread = CONTAINING_RECORD( FocusProcess->ThreadList.Flink, OS2_THREAD, Link );
if (Thread->Dying) {
#if DBG
ASSERT (FALSE);
DbgPrint( "Os2DosSendSignalException, Thread is dying\n");
#endif
}
//
// send the signal. this routine releases the Thread lock.
//
m->ReturnedErrorValue = SendSignalException(Thread,a->Exception);
#if DBG
IF_OS2_DEBUG( EXCEPTIONS ) {
DbgPrint("leaving Os2DosSendSignalException. rc is %ld\n",m->ReturnedErrorValue);
}
#endif
return (TRUE);
}
BOOLEAN
Os2DosAcknowledgeSignalException(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
/*++
Routine Description:
This routine implements the DosAcknowledgeSignalException API.
Arguments:
t - calling thread
m - message
Return Value:
TRUE - create a return message
--*/
{
POS2_DOSACKNOWLEDGESIGNALEXCEPTION_MSG a = &m->u.DosAcknowledgeSignalException;
//
// make sure this signal has been delivered to this thread
//
if (!(t->CurrentSignals & SIGNAL_TO_FLAG(a->SignalNumber))) {
m->ReturnedErrorValue = ERROR_INVALID_SIGNAL_NUMBER;
return (TRUE);
}
//
// turn off signal bit
//
t->CurrentSignals &= ~SIGNAL_TO_FLAG(a->SignalNumber);
if (t->PendingSignals & SIGNAL_TO_FLAG(a->SignalNumber)) {
t->PendingSignals &= ~SIGNAL_TO_FLAG(a->SignalNumber);
//
// LTS - 4/22/92 : Check for XCPT_SIGNAL_KILLPROC, don't send signal back to
// client.
if (a->SignalNumber != XCPT_SIGNAL_KILLPROC) {
SendSignalException(t,a->SignalNumber);
}
}
return (TRUE);
}
BOOLEAN
Os2GetSigHandlerRec(
IN POS2_API_MSG m,
POD2_SIG_HANDLER_REC psighandler,
POS2_PROCESS *pProcess
)
{
POS2_DISPATCH16_SIGNAL a = &m->u.Dispatch16Signal;
POS2_PROCESS Parent;
POS2_PROCESS prvProcess;
POS2_PROCESS curProcess;
POS2_PROCESS Process;
NTSTATUS Status;
Process = Parent = *pProcess;
//
// For ctrl-c and ctrl-break send signal to the last descendant process
// that has a corresponding signal handler installed
//
if (a->usFlagNum == SIG_CTRLC || a->usFlagNum == SIG_CTRLBREAK) {
//
// find leafmost process for SIG_CTRLC & SIG_CTRLBREAK which has
// a signal handler installed
//
// Get leaf-most process
//
while (!IsListEmpty( &Process->ChildrenList )) {
prvProcess = Process;
Process = CONTAINING_RECORD(Process->ChildrenList.Flink,
OS2_PROCESS,
SiblingLink );
}
}
while(TRUE) {
*pProcess = Process;
//
// Read signal handler Record for this process to check if
// signal handler installed.
//
Status = NtReadVirtualMemory( Process->ProcessHandle,
(PVOID) a->sighandleraddr,
(PVOID) psighandler,
sizeof(OD2_SIG_HANDLER_REC),
NULL
);
if (!(NT_SUCCESS(Status))) {
m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
ASSERT(NT_SUCCESS(Status));
return TRUE;
}
//
// Check signature of signal handler record for this process
//
if (psighandler->signature == 0xdead) {
//
// For all other signals we are done
//
if (a->usFlagNum != SIG_CTRLC && a->usFlagNum != SIG_CTRLBREAK) {
return FALSE;
}
//
// Check if default signal handler still installed (Doscalls
// selector is present)
//
if ((psighandler->sighandler[a->usFlagNum - 1] >> 16) !=
(psighandler->doscallssel >> 16)) {
return FALSE;
}
}
else {
#if DBG
DbgPrint("Os2GetSigHandlerRec: Hi There, I am not dead\n");
#endif
return TRUE;
}
if (Process == Parent ||
(a->usFlagNum != SIG_CTRLC && a->usFlagNum != SIG_CTRLBREAK)) {
break;
}
Process = Parent;
while (Process != prvProcess) {
curProcess = Process;
Process = CONTAINING_RECORD(Process->ChildrenList.Flink,
OS2_PROCESS,
SiblingLink );
}
prvProcess = curProcess;
}
m->ReturnedErrorValue = ERROR_SIGNAL_REFUSED;
ASSERT(NT_SUCCESS(Status));
return TRUE;
}
APIRET
Os2DispatchToHandler(
IN POS2_THREAD Thread,
IN POS2_DISPATCH16_SIGNAL a
)
{
APIRET rc;
NTSTATUS Status;
CONTEXT Context;
ULONG NewSp;
PVOID address = NULL;
ULONG Length;
POS2_PROCESS Process = Thread->Process;
OS2_REGISTER16_SIGNAL b;
ULONG SuspendCount;
ULONG SuspendTimes;
//
// Suspend the thread and get it's context
//
if ((rc = Os2SignalGetThreadContext(Thread, &Context, &NewSp, &SuspendTimes)) !=
NO_ERROR) {
//
// Continue without context switch. The signal will not be delivered.
//
return rc;
}
__try {
//
// Allocate memory in address space of process and copy context of process
// who called DosFlagProcess or DosSendSignal and context of thread we are
// going to run in.
//
Length = sizeof(OS2_REGISTER16_SIGNAL) + sizeof(CONTEXT);
address = 0;
Status = NtAllocateVirtualMemory(Process->ProcessHandle,
&address,
0,
&Length,
MEM_RESERVE|MEM_COMMIT,
PAGE_READWRITE);
if (!(NT_SUCCESS(Status))) {
rc = ERROR_NOT_ENOUGH_MEMORY;
#if DBG
DbgPrint("[%d]Os2DispatchToHandler: Fail to allocate memory for client, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
#endif // DBG
__leave;
}
//
// Write dummy register set of process who called us.
//
b.usFlagNum = a->usFlagNum;
b.usFlagArg = a->usFlagArg;
Status = NtWriteVirtualMemory( Process->ProcessHandle,
address,
(PVOID) &b.regSP,
sizeof(OS2_REGISTER16_SIGNAL),
NULL);
if (!(NT_SUCCESS(Status))) {
rc = ERROR_NOT_ENOUGH_MEMORY;
#if DBG
DbgPrint("[%d]Os2DispatchToHandler: Fail to write 16bit registes block, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
#endif // DBG
__leave;
}
Status = NtWriteVirtualMemory( Process->ProcessHandle,
(PVOID) ((PCHAR) address +
sizeof(OS2_REGISTER16_SIGNAL)),
(PVOID) &Context,
sizeof(CONTEXT),
NULL);
if (!(NT_SUCCESS(Status))) {
rc = ERROR_NOT_ENOUGH_MEMORY;
#if DBG
DbgPrint("[%d]Os2DispatchToHandler: Fail to write context, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
#endif // DBG
__leave;
}
Context.SegSs = Context.SegDs = Context.SegEs = 0x23;
Context.SegCs = 0x1b;
NewSp -= sizeof(ULONG);
Status = NtWriteVirtualMemory( Process->ProcessHandle,
(PVOID)NewSp,
&address,
sizeof(ULONG),
NULL);
if (!NT_SUCCESS( Status )) {
rc = ERROR_NOT_ENOUGH_MEMORY;
#if DBG
DbgPrint("[%d]Os2DispatchToHandler: Fail to write parameter, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
#endif // DBG
__leave;
}
//
// Set the address of the target code into Eip, the new target stack
// into Esp, and reload context to make it happen.
//
Context.Esp = NewSp;
Context.Eip = a->routine;
Context.ContextFlags = CONTEXT_FULL;
rc = Os2SignalSetThreadContext(Thread, &Context);
}
__finally {
if (rc != NO_ERROR) {
if (address) {
Status = NtFreeVirtualMemory(
Process->ProcessHandle,
&address,
&Length,
MEM_RESERVE|MEM_COMMIT);
#if DBG
if (!NT_SUCCESS(Status)) {
DbgPrint("[%d]Os2DispatchToHandler: Fail to free memory for client, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
}
#endif // DBG
}
while (SuspendTimes) {
Status = NtResumeThread(Thread->ThreadHandle, &SuspendCount);
#if DBG
if (!NT_SUCCESS(Status)) {
DbgPrint("[%d]Os2DispatchToHandler: Fail to resume thread, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
}
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d]Os2DispatchToHandler: resume thread, count = %d\n",
Process->ProcessId,
SuspendCount);
}
#endif // DBG
SuspendTimes--;
}
#if DBG
if (!NT_SUCCESS(Status)) {
DbgPrint("[%d]Os2DispatchToHandler: Fail to resume thread, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
}
#endif // DBG
}
}
return rc;
}
POS2_THREAD
Os2GetThread1(
POS2_PROCESS Process
)
{
PLIST_ENTRY ListHead, ListNext;
POS2_THREAD Thread = NULL;
ListHead = &Process->ThreadList;
ListNext = ListHead->Flink;
Thread = NULL;
while (ListNext != ListHead) {
Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
if (Thread->Flags & OS2_THREAD_THREAD1)
return Thread;
else
ListNext = ListNext->Flink;
}
return NULL;
}
BOOLEAN
Os2DosDispatch16Signal(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
POS2_DISPATCH16_SIGNAL a = &m->u.Dispatch16Signal;
POS2_THREAD Thread1 = NULL;
OD2_SIG_HANDLER_REC sighandler;
POS2_PROCESS NextProcess;
POS2_PROCESS Process;
POS2_PROCESS ParentProcess;
LARGE_INTEGER timeout;
PLARGE_INTEGER ptimeout = &timeout;
NTSTATUS Status;
OS2_API_MSG mhold;
ULONG SuspendCount;
//
// Get process which sent message
//
Process = Os2LocateProcessByProcessId( NULL,
t->Process,
(PID)a->pidProcess,
(BOOLEAN)FALSE
);
if (Process == NULL) {
m->ReturnedErrorValue = ERROR_INVALID_PROCID;
return TRUE;
}
ParentProcess = Process;
//
// Scan list of childern see if any exist
//
if (!IsListEmpty( &Process->ChildrenList )) {
NextProcess = CONTAINING_RECORD(Process->ChildrenList.Flink,
OS2_PROCESS,
SiblingLink);
}
else {
NextProcess = NULL;
}
doanother:
//
// Read Signal handler record from address space of process which is
// to receive the signal
//
Thread1 = Os2GetThread1(Process);
Status = NtSuspendThread(Thread1->ThreadHandle, &SuspendCount);
#if DBG
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d]Os2DosDispatch16Signal: suspend thread, count = %d, Status=%x\n",
Process->ProcessId,
SuspendCount,
Status);
}
#endif // DBG
if (!NT_SUCCESS(Status)) {
m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
ASSERT(FALSE);
}
else {
__try {
if (Os2GetSigHandlerRec(m, &sighandler, &Process)) {
__leave;
}
//
// Check to see if this is a Hold Signal message
//
if (a->usFlagNum == HOLD_SIGNAL_CLEARED) {
#if DBG
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d,%d]Os2DosDispatch16Signal: accept outstanding signal\n",
t->Process->ProcessId,
t->ThreadId);
}
#endif // DBG
mhold.u.Dispatch16Signal.usFlagNum =
sighandler.outstandingsig[a->usFlagArg - 1].usFlagNum;
sighandler.outstandingsig[a->usFlagArg - 1].usFlagNum = 0;
mhold.u.Dispatch16Signal.usFlagArg =
sighandler.outstandingsig[a->usFlagArg - 1].usFlagArg;
sighandler.outstandingsig[a->usFlagArg - 1].usFlagArg = 0;
mhold.u.Dispatch16Signal.pidProcess =
sighandler.outstandingsig[a->usFlagArg - 1].pidProcess;
sighandler.outstandingsig[a->usFlagArg - 1].pidProcess = 0;
mhold.u.Dispatch16Signal.routine =
sighandler.outstandingsig[a->usFlagArg - 1].routine;
sighandler.outstandingsig[a->usFlagArg - 1].routine = 0;
mhold.u.Dispatch16Signal.sighandleraddr =
sighandler.outstandingsig[a->usFlagArg - 1].sighandleraddr;
sighandler.outstandingsig[a->usFlagArg - 1].sighandleraddr = 0;
//
// Write Signal table back to process
//
Status = NtWriteVirtualMemory(Process->ProcessHandle,
(PVOID) a->sighandleraddr,
(PVOID) &sighandler,
sizeof(sighandler),
NULL);
if (!(NT_SUCCESS(Status))) {
m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
ASSERT(FALSE);
__leave;
}
if (Os2GetSigHandlerRec(&mhold, &sighandler, &Process)) {
__leave;
}
if (sighandler.action[a->usFlagArg - 1] == SIGA_ACKNOWLEDGE_AND_ACCEPT) {
sighandler.action[a->usFlagArg - 1] = SIGA_ACCEPT;
}
a = &mhold.u.Dispatch16Signal;
}
else if (sighandler.action[a->usFlagNum - 1] == SIGA_ACKNOWLEDGE ||
sighandler.action[a->usFlagNum - 1] == SIGA_ACKNOWLEDGE_AND_ACCEPT ||
sighandler.fholdenable) {
//
// See if we already are holding an unacknowleged signal or a hold
// signal
//
if (sighandler.outstandingsig[a->usFlagNum - 1].sighandleraddr != 0) {
#if DBG
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d,%d]Os2DosDispatch16Signal: Outstanding signal wasn't pended, refuse\n",
t->Process->ProcessId,
t->ThreadId);
}
#endif // DBG
m->ReturnedErrorValue = ERROR_SIGNAL_PENDING;
__leave;
}
#if DBG
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d,%d]Os2DosDispatch16Signal: Save outstanding signal\n",
t->Process->ProcessId,
t->ThreadId);
}
#endif // DBG
//
// Save this signal till other is processed
//
sighandler.outstandingsig[a->usFlagNum - 1].usFlagNum = a->usFlagNum;
sighandler.outstandingsig[a->usFlagNum - 1].usFlagArg = a->usFlagArg;
sighandler.outstandingsig[a->usFlagNum - 1].pidProcess = a->pidProcess;
sighandler.outstandingsig[a->usFlagNum - 1].routine = a->routine;
sighandler.outstandingsig[a->usFlagNum - 1].sighandleraddr =
a->sighandleraddr;
//
// Write Signal table back to process
//
Status = NtWriteVirtualMemory(Process->ProcessHandle,
(PVOID) a->sighandleraddr,
(PVOID) &sighandler,
sizeof(sighandler),
NULL
);
if (!(NT_SUCCESS(Status))) {
m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
ASSERT(FALSE);
}
__leave;
}
//
// Check if we should ignore signal
//
if (sighandler.action[a->usFlagNum - 1] == SIGA_IGNORE) {
m->ReturnedErrorValue = NO_ERROR;
__leave;
}
//
// Check to see if we can accept the signal
//
if (sighandler.action[a->usFlagNum - 1] != SIGA_ACCEPT) {
m->ReturnedErrorValue = ERROR_SIGNAL_REFUSED;
__leave;
}
#if DBG
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d,%d]Os2DosDispatch16Signal: Accept signal\n",
t->Process->ProcessId,
t->ThreadId);
}
#endif // DBG
//
// Disable this signal till we get a SIGA_ACKNOWLEDGE
//
sighandler.action[a->usFlagNum - 1] = SIGA_ACKNOWLEDGE;
//
// Write Signal table back to process
//
Status = NtWriteVirtualMemory(Process->ProcessHandle,
(PVOID) a->sighandleraddr,
(PVOID) &sighandler,
sizeof(sighandler),
NULL
);
if (!(NT_SUCCESS(Status))) {
m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
ASSERT(FALSE);
__leave;
}
//
// Search list to find thread 1. The signal handler function has to
// run in thread 1's context
//
if (Thread1 == NULL){
m->ReturnedErrorValue = ERROR_INVALID_PROCID;
#if DBG
IF_OS2_DEBUG( EXCEPTIONS ) {
DbgPrint("Os2Dispatch16Signal: Thread1 is already gone\n");
}
#endif
ASSERT(FALSE);
__leave;
}
if (Thread1->Dying == TRUE || !(Thread1->Flags & OS2_THREAD_THREAD1)) {
m->ReturnedErrorValue = ERROR_INVALID_PROCID;
#if DBG
IF_OS2_DEBUG( EXCEPTIONS ) {
DbgPrint("Os2Dispatch16Signal: Thread1->Dying\n");
}
#endif
__leave;
}
if((m->ReturnedErrorValue = Os2DispatchToHandler(Thread1,a)) != NO_ERROR) {
#if DBG
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d,%d]Os2DosDispatch16Signal: Skip signal\n",
t->Process->ProcessId,
t->ThreadId);
}
#endif // DBG
sighandler.action[a->usFlagNum - 1] = SIGA_ACCEPT;
Status = NtWriteVirtualMemory(Process->ProcessHandle,
(PVOID) a->sighandleraddr,
(PVOID) &sighandler,
sizeof(sighandler),
NULL);
if (!(NT_SUCCESS(Status))) {
m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
ASSERT(FALSE);
}
}
}
__finally {
Status = NtResumeThread(Thread1->ThreadHandle, &SuspendCount);
#if DBG
IF_OS2_DEBUG( SIG ) {
DbgPrint("[%d]Os2DosDispatch16Signal: resume thread, count = %d, Status=%x\n",
Process->ProcessId,
SuspendCount,
Status);
}
#endif // DBG
}
}
//
// Check for error return if found
//
if (m->ReturnedErrorValue != 0) {
return TRUE;
}
if (Thread1 != NULL) {
Status = NtAlertThread(Thread1->ThreadHandle);
#if DBG
if (!NT_SUCCESS(Status)) {
DbgPrint("[%d]Os2DosDispatch16Signal: Fail to alert thread, Status=%x\n",
Process->ProcessId,
Status);
ASSERT(FALSE);
}
#endif // DBG
Os2CompleteResumeThread(Thread1);
}
//
// For any other signal other than kill process & flag process
// we are done
//
if (a->usFlagNum == SIG_CTRLC || a->usFlagNum == SIG_CTRLBREAK) {
return TRUE;
}
//
// Check scope of signal, if scope is flag subtree continue sending
// signal to childern processes otherwise return
//
if (a->fscope) {
return TRUE;
}
if (NextProcess != NULL) {
Process = NextProcess;
if (ParentProcess == CONTAINING_RECORD(Process->SiblingLink.Flink,
OS2_PROCESS,
ChildrenList)) {
NextProcess = NULL;
}
else {
NextProcess = CONTAINING_RECORD(Process->SiblingLink.Flink,
OS2_PROCESS,
SiblingLink);
}
goto doanother;
}
else {
return TRUE;
}
}
BOOLEAN
Os2DispatchVector(
IN PDBGKM_APIMSG ReceiveMsg,
POS2_THREAD Thread,
CONTEXT Context
)
{
struct VectorHandlerRec {
ULONG VecHandler[6];
ULONG doscallssel;
};
struct VectorHandlerRec VectorHandler;
ULONG NewSp;
USHORT Args[4];
USHORT FPUStatus = 0;
NTSTATUS Status;
//
// Read Vector handler Record for this process
//
Status = NtReadVirtualMemory(Thread->Process->ProcessHandle,
Thread->Process->VectorHandler,
(PVOID) &VectorHandler,
sizeof(struct VectorHandlerRec),
NULL
);
if (!(NT_SUCCESS(Status))) {
return TRUE; // Dispatch failed
}
//
// Place on stack of process the machine status word and the return
// CS:IP of the process which is running before changing the CS:IP
// to the vector handler.
//
Args[3] = (USHORT) Context.EFlags; // flags
Args[2] = (USHORT) Context.SegCs; // CS
Args[1] = (USHORT) (Context.Eip & 0xffff); // IP
//
// Change CS:IP to vector handler address
//
switch(ReceiveMsg->u.Exception.ExceptionRecord.ExceptionCode) {
case STATUS_INTEGER_DIVIDE_BY_ZERO:
Context.SegCs = VectorHandler.VecHandler[0] >> 16;
Context.Eip = VectorHandler.VecHandler[0] & 0xffff;
break;
case STATUS_INTEGER_OVERFLOW:
Context.SegCs = VectorHandler.VecHandler[1] >> 16;
Context.Eip = VectorHandler.VecHandler[1] & 0xffff;
break;
case STATUS_ARRAY_BOUNDS_EXCEEDED:
Context.SegCs = VectorHandler.VecHandler[2] >> 16;
Context.Eip = VectorHandler.VecHandler[2] & 0xffff;
break;
case STATUS_ILLEGAL_INSTRUCTION:
Context.SegCs = VectorHandler.VecHandler[3] >> 16;
Context.Eip = VectorHandler.VecHandler[3] & 0xffff;
break;
case STATUS_ILLEGAL_FLOAT_CONTEXT:
Context.SegCs = VectorHandler.VecHandler[4] >> 16;
Context.Eip = VectorHandler.VecHandler[4] & 0xffff;
break;
case STATUS_FLOAT_DENORMAL_OPERAND:
FPUStatus = (USHORT) Context.FloatSave.StatusWord;
Context.SegCs = VectorHandler.VecHandler[5] >> 16;
Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
break;
case STATUS_FLOAT_DIVIDE_BY_ZERO:
FPUStatus = (USHORT) Context.FloatSave.StatusWord;
Context.SegCs = VectorHandler.VecHandler[5] >> 16;
Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
break;
case STATUS_FLOAT_INEXACT_RESULT:
FPUStatus = (USHORT) Context.FloatSave.StatusWord;
Context.SegCs = VectorHandler.VecHandler[5] >> 16;
Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
break;
case STATUS_FLOAT_INVALID_OPERATION:
FPUStatus = (USHORT) Context.FloatSave.StatusWord;
Context.SegCs = VectorHandler.VecHandler[5] >> 16;
Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
break;
case STATUS_FLOAT_OVERFLOW:
FPUStatus = (USHORT) Context.FloatSave.StatusWord;
Context.SegCs = VectorHandler.VecHandler[5] >> 16;
Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
break;
case STATUS_FLOAT_STACK_CHECK:
FPUStatus = (USHORT) Context.FloatSave.StatusWord;
Context.SegCs = VectorHandler.VecHandler[5] >> 16;
Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
break;
case STATUS_FLOAT_UNDERFLOW:
FPUStatus = (USHORT) Context.FloatSave.StatusWord;
Context.SegCs = VectorHandler.VecHandler[5] >> 16;
Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
break;
}
//
// Check to see if a vector handler exists
//
if (Context.SegCs == (VectorHandler.doscallssel >> 16)) {
return TRUE; // Dispatch failed
}
if (FPUStatus != 0) {
//
// mask floating point exceptions
//
Context.FloatSave.ControlWord |= 0x3f;
Args[0] = FPUStatus;
}
//
// Remove 32-bit eip, cs, Eflags from stack put on 16-bit ip, cs, flags
//
NewSp = (ULONG)(SELTOFLAT(Context.SegSs)) + (USHORT) Context.Esp;
Context.Esp += (FPUStatus == 0 ? 3 : 4) * sizeof(USHORT);
NewSp += (FPUStatus == 0 ? 3 : 4) * sizeof(USHORT);
Status = NtWriteVirtualMemory( Thread->Process->ProcessHandle,
(PVOID) NewSp,
(FPUStatus == 0 ? &Args[1] : &Args[0]),
(FPUStatus == 0 ? 3 : 4) * sizeof(USHORT),
NULL
);
if (!NT_SUCCESS( Status )) {
return TRUE; // Dispatch failed
}
Context.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
Status = NtSetContextThread(Thread->ThreadHandle, &Context);
if (!NT_SUCCESS( Status )) {
return TRUE; // Dispatch failed
}
return FALSE; // Dispatch completed
}
VOID
Os2IssueSignalTree(
IN POS2_PROCESS RootProcess,
IN int Signal
)
/*++
Routine Description:
This routine recursively issues a "Signal" signal to thread one
of each process in a tree.
Arguments:
RootProcess - root process of tree to issue Signal to
Signal - signal to send
Return Value:
none
--*/
{
PLIST_ENTRY ListHead, ListNext;
Os2IssueSignal( RootProcess, Signal );
ListHead = &RootProcess->ChildrenList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
Os2IssueSignalTree( CONTAINING_RECORD( ListNext,
OS2_PROCESS,
SiblingLink
),
Signal
);
ListNext = ListNext->Flink;
}
}
APIRET
Os2IssueSignal(
IN POS2_PROCESS Process,
IN int Signal
)
/*++
Routine Description:
This routine recursively issues a "Signal" signal to thread one
of a process.
Arguments:
Process - process to Signal
Signal - signal to send
Return Value:
ERROR_INVALID_PROCID - the specified process is dying.
ERROR_SIGNAL_PENDING - the specified signal is already pending for the
thread.
--*/
{
POS2_THREAD Thread1;
APIRET rc;
Thread1 = CONTAINING_RECORD( Process->ThreadList.Flink, OS2_THREAD, Link );
if (IsListEmpty( &Process->ThreadList )) {
//
// Process Termination in progress, no threads left to signal
//
#if DBG
IF_OS2_DEBUG( EXCEPTIONS ) {
DbgPrint("Os2IssueSignal: Process is dying\n");
}
#endif
return(ERROR_INVALID_PROCID);
}
if (Thread1->Dying == TRUE) {
rc = ERROR_INVALID_PROCID;
}
else {
rc = SendSignalException(Thread1, Signal);
}
return rc;
}
BOOLEAN
Os2DosRegisterCtrlHandler(
IN POS2_THREAD t,
IN POS2_API_MSG m
)
{
POS2_REGISTER_HANDLER a = &m->u.DosRegisterCtrlHandler;
POS2_PROCESS Process;
POS2_SESSION Session;
POS2_REGISTER_HANDLER_REC pRec;
POS2_REGISTER_HANDLER_REC pPRec;
Process = t->Process;
Session = Process->Session;
if (a->fAction == SIGA_ENABLE_HANDLING) {
Process->CtrlHandlerFlag = TRUE;
return TRUE;
}
if (a->fAction == SIGA_KILL) {
pRec = Session->RegisterCtrlHandler;
pPRec = pRec;
while (pRec != NULL) {
if (pRec->Process == Process && pRec->Signal == a->usFlagNum) {
if (pPRec != Session->RegisterCtrlHandler) {
pPRec->Link = pRec->Link;
}
else {
Session->RegisterCtrlHandler = pRec->Link;
}
RtlFreeHeap(Os2Heap, 0, pRec);
break;
}
pPRec = pRec;
pRec = pRec->Link;
}
return(TRUE);
}
pPRec = (POS2_REGISTER_HANDLER_REC)
RtlAllocateHeap(Os2Heap, 0,
sizeof(OS2_REGISTER_HANDLER_REC));
if (pPRec == NULL) {
#if DBG
DbgPrint("Os2DosRegisterCtrlHandler, no memory for heap\n");
#endif
ASSERT(FALSE);
return (TRUE);
}
pPRec->Signal = a->usFlagNum;
pPRec->fAction = a->fAction;
pPRec->Process = Process;
if (Session->RegisterCtrlHandler == NULL) {
Session->RegisterCtrlHandler = pPRec;
pPRec->Link = NULL;
}
else {
pRec = Session->RegisterCtrlHandler;
Session->RegisterCtrlHandler = pPRec;
pPRec->Link = pRec;
}
return(TRUE);
}
VOID
Os2DeRegisterCtrlHandler(
POS2_PROCESS Process
)
{
POS2_REGISTER_HANDLER_REC pRec;
POS2_REGISTER_HANDLER_REC pPRec;
POS2_REGISTER_HANDLER_REC pRecTmp;
POS2_SESSION Session;
Session = Process->Session;
if(Session!=NULL) {
pRec = Session->RegisterCtrlHandler;
pPRec = pRec;
while (pRec != NULL) {
if (pRec->Process == Process) {
if (pRec == Session->RegisterCtrlHandler) {
Session->RegisterCtrlHandler = pRec->Link;
pPRec = pRec->Link;
}
else {
pPRec->Link = pRec->Link;
}
pRecTmp = pRec->Link;
RtlFreeHeap(Os2Heap, 0, pRec);
pRec = pRecTmp;
}
else {
pPRec = pRec;
pRec = pRec->Link;
}
}
}
return;
}