/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    procblk.c

Abstract:

    This module implements process block and unblock

Author:

    Mark Lucovsky (markl) 30-Mar-1989

Revision History:

--*/


#include "psxsrv.h"


NTSTATUS
BlockProcess(
	IN PPSX_PROCESS p,
	IN PVOID Context,
	IN INTHANDLER Handler,
	IN PPSX_API_MSG m,
	IN PLIST_ENTRY BlockList OPTIONAL,
	IN PRTL_CRITICAL_SECTION CriticalSectionToRelease OPTIONAL
	)
{
	PINTCB IntCb;
	PPSX_API_MSG NewM;
	int Sig;

	IntCb = RtlAllocateHeap(PsxHeap, 0, sizeof(INTCB));
	if (NULL == IntCb) {
		return STATUS_NO_MEMORY;
	}
	
	NewM = RtlAllocateHeap(PsxHeap, 0, sizeof(PSX_API_MSG));
	if (NULL == NewM) {
		RtlFreeHeap(PsxHeap, 0, IntCb);
		return STATUS_NO_MEMORY;
	}

	*NewM = *m;
	
	IntCb->IntHandler = Handler;
	IntCb->IntMessage = NewM;
	IntCb->IntContext = Context;

	RtlEnterCriticalSection(&BlockLock);

	p->IntControlBlock = IntCb;
	
	if (ARGUMENT_PRESENT(BlockList)) {
        	InsertTailList(BlockList, &IntCb->Links);
	} else {
        	InsertTailList(&DefaultBlockList, &IntCb->Links);
	}

	AcquireProcessLock(p);

	//
	// Check for signals
	//
	
	if (0 != (Sig = PsxCheckPendingSignals(p))) {

        	ReleaseProcessLock(p);

        	//
        	// Block is interrupted by a signal
        	//

		if (ARGUMENT_PRESENT(CriticalSectionToRelease)) {
			RtlLeaveCriticalSection(CriticalSectionToRelease);
		}
		UnblockProcess(p, SignalInterrupt, TRUE, Sig);

		return STATUS_SUCCESS;

	}
	if (ARGUMENT_PRESENT(CriticalSectionToRelease)) {
		RtlLeaveCriticalSection(CriticalSectionToRelease);
        }

       	ReleaseProcessLock(p);
        RtlLeaveCriticalSection(&BlockLock);

	return STATUS_SUCCESS;
}


BOOLEAN
UnblockProcess(
	IN PPSX_PROCESS p,
	IN PSX_INTERRUPTREASON InterruptReason,
	IN BOOLEAN BlockLockHeld,
	IN int Signal			// Signal causing wakeup, if any
	)
{
	PINTCB IntCb;
	if (!BlockLockHeld) {
	        RtlEnterCriticalSection(&BlockLock);
	}

	if (p->IntControlBlock) {
	        IntCb = p->IntControlBlock;
	        RemoveEntryList(&IntCb->Links);
	        p->IntControlBlock = (PINTCB) NULL;
	        (IntCb->IntHandler)(p,IntCb,InterruptReason,Signal);
		return TRUE;
	}

	if (!BlockLockHeld) {
        	RtlLeaveCriticalSection(&BlockLock);
    	}

	return FALSE;
}