******************************* MODULE HEADER *******************************
*                                                                           *
* FILE: AsyncService.c                                                      *
*                                                                           *
* MACHINE: SGenNGen   LANGUAGE: METAWARE C V1.0  OS: CTOS                  *
*                                                                           *
* DESCRIPTION: Main program of CTOS Asynchronous Service Model              *
*                                                                           *
*  Uses AsyncService library procedures.                                    *
*                                                                           *
* HISTORY:                                                                  *
*                                                                           *
* MMDDYY VVVVMM PROGRAMMER    DESCRIPTION OF CHANGE (Most recent first) *
*                                                                           *
* 091692 12.300 S. Ahn        Added attribute information               *
* 120389 120E02 S. Emmons     Moved rgwRqs[], rqwOldExch, and nRqCodes  *
*                                 into this module; Add check, in           *
*                                 HandleRequest (), so that we don't respond*
*                                 on forwarded requests.                    *
* 120289 120E01 S. Emmons     Fixed NULL pointer to AllocMemoryInit (); *
*                                 changed from c typing to CTOSbased naming*
*                                 and typing conventions; Changed references*
*                                 from server to service; Gratuitous        *
*                                 reformatting.                             *
* 2389  TAB	Used CTOS_CALLING_CONVENTIONS                                *
* 10Nov88 PBC	Set PLM calling conventions to _default                      *
* 16Sep88 Ken Burgett: change offset parameters to pointer to make          *
*                      compatible with calling sequence standards for both  *
*                      PLM and HighC                                      *
* 28Jul88 Ken Burgett: built from Jim Frandeen PLM prototype.              *
*                                                                           *
*                                                                           *
* Attributes exhibited by this software: (See SSAttributes.doc)             *
* Use attribute levels 0, E, A, S, F, I and 1...9 as decribed.              *
*                                                                           *
*  VID: 0                                                                  *
*  FIL: 0                                                                  *
*  KBD: 0                                                                  *
*  CLS: 0                                                                  *
*  KNL: 0                                                                  *
*  MEM: 0                                                                  *
*  COM: 0                                                                  *
*  TIM: 0                                                                  *
*  PFM: 0                                                                  *
*  HDW: 0                                                                  *
*  DSK: 0                                                                  *
*  DEV: 0                                                                  *
*  NLS: 0                                                                  *
*                                                                           *
* TITLE:  CTOS SYSTEM SOFTWARE                                              *
*                                                                           *
*            PROPRIETARY PROGRAM MATERIAL                                   *
*                                                                           *
* THIS MATERIAL IS PROPRIETARY TO UNISYS CORPORATION AND IS NOT TO BE       *
* REPRODUCED, USED OR DISCLOSED EXCEPT IN ACCORDANCE WITH PROGRAM LICENSE   *
* OR UPON WRITTEN AUTHORIZATION OF THE PATENT DIVISION OF UNISYS            *
* CORPORATION, DETROIT, MICHIGAN 48232, USA.                                *
*                                                                           *
* COPYRIGHT (C) 1980, 1989 CONVERGENT INCORPORATED. ALL RIGHTS RESERVED     *
* COPYRIGHT (C) 1980, 1989 UNISYS CORPORATION. ALL RIGHTS RESERVED          *
* ************************************************************************* *
*                                                                           *
* UNISYS BELIEVES THAT THE SOFTWARE FURNISHED HEREWITH IS ACCURATE AND      *
* RELIABLE, AND MUCH CARE HAS BEEN TAKEN IN ITS PREPARATION.  HOWEVER,      *
* NO RESPONSIBILITY, FINANCIAL OR OTHERWISE, CAN BE ACCEPTED FOR ANY        *
* CONSEQUENCES ARISING OUT OF THE USE OF THIS MATERIAL, INCLUDING LOSS OF   *
* PROFIT, INDIRECT, SPECIAL, OR CONSEQUENTIAL DAMAGES, THERE ARE NO         *
* WARRANTIES WHICH EXTEND BEYOND THE PROGRAM SPECIFICATION.                 *
*                                                                           *
* THE CUSTOMER SHOULD EXERCISE CARE TO ASSURE THAT USE OF THE SOFTWARE      *
* WILL BE IN FULL COMPLIANCE WITH LAWS, RULES AND REGULATIONS OF THE        *
* JURISDICTIONS WITH RESPECT TO WHICH IT IS USED.                           *
*                                                                           *
*                                                                           *
*************************** END OF MODULE HEADER ****************************
*
	External Definitions
*
define Syslit
define RqHeaderType
include <Ctostypes.h>

define AllocExch
define ChangePriority
define Check
define CheckErc
define ConvertToSys
define ErrorExit
define FatalError
define GetPartitionHandle
define GetUserNumber
define QueryRequestInfo
define ResetStack
define Respond
define ServeRq
define SetPartitionLock
define SetPartitionName
define ShrinkAreaSL
define Wait
include <CtosLib.h>

define FsErc
define RqErc
include <Erc.h>

include <string.h>

*
	Async.lib Definitions
*
define AllocMemoryInit
define CreateContext
define HeapInit
define LogMsgIn
define LogRespond
define ResumeContext
define TerminateAllOtherContexts
define TerminateContext
include async.h

include exdef.h

pragma Calling_convention(CTOS_CALLING_CONVENTIONS,_DEFAULT);

*
	External variables provided by async.lib
*
extern Pointer	pToDeallocate;	* set up by InitAlloc *
extern Word		cbFree;			* set up by InitAlloc *
*
	External functions, provided by user.
*
extern void		InitializeServer (void);
extern ErcType	ServeRequest (void);
extern void		HandleTimer (void);
extern void 	InitializeTimer (void);

*
	External Variables, provided by user.
*
extern Word		cbHeap;				* size of service heap *
extern Word		defaultStackSize;	* size of stack allocated per context *
extern Word		wOSRel;
extern FlagType	fConvertToSys;
extern FlagType	fRespond;
extern Word		priorityServ;		* process priority of service *
extern char		rgbPartitionName[];	* name of partition *
*
	PUBLIC Variables required by the AsyncService procedures:
*
Word rgwRqs[10] = {			* request codes served by this service *
	rcAbortExample,
	rcChangeUserNumExample,
	rcDeinstallExample,
	rcOpenFile,
	rcOpenFileLL,
	rcStartRecord,
	rcStopRecord,
	rcSwapExample,
	rcTerminateExample,
	rcReOpenFile};
Word nRqCodes = 10;			* number of request codes served *
Word rgwOldExch[10];		* temp. storage of old exchange values *

ErcType ercAsync;
*
	The erc from BuildAsyncRequest or BuildAsyncRequestDirect is
	returned here.
*

ExchType exchServ;
*
	This is the exchange where the service waits in its WaitLoop.
	This variable is stored in the exchResp field of the Request
	block that is built by BuildAsyncRequest or BuildAsyncRequestDirect.
*

RqHeaderType *pRq;
*
	pRq points to the current client request. It is set by the 
	service in its WaitLoop by the call to Wait:

		erc = Wait(exchServ, pRq);

	It is saved in the current Context Control Block by BuildAsyncRequest.
	It is restored by ResumeContext.
*

Pointer	pZero = 0;
Word	saveSpBp[2] = {0, 0};	* storage locations for sp  bp *
Word	*pSave;
Pointer	*pbHeap;				* pointer to allocated heap storage *
void FatalServerError (ErcType erc)
{
	FatalError (erc) * Kill the system service *;
}ErcType DeinstallServer (void)
{
	*
		This function is invoked as a result of deinstall request.
	*
	typedef struct { 
		RqHeaderType rqhdr;
		Word *pPhRet
	}	DeinstallType;
	ErcType			erc;
	Word			i;
	DeinstallType	*prx;
	RqHeaderType	*pRqBlk;

	prx = (DeinstallType*) pRq;
	* 
		Unserve all requests by serving them to the exchange
		previously served.
	*
	for (i = 0; i < nRqCodes; i++)
	{
		erc = ServeRq (rgwRqs[i], rgwOldExch[i]);
		if (erc = ercOK)
			FatalServerError (erc);
	}

	* 
		Terminate all contexts except for the current context.
	*
	erc = TerminateAllOtherContexts (ercOK);
	if (erc = ercOK)
		FatalServerError (erc);

	*
		Reject all further incoming requests to service's exchange.
	*
	while (erc == ercOK)
	{
		erc = Check (exchServ, pRqBlk);
		if (erc == ercOK)
		{
			pRqBlk>ercRet = ercServiceNotAvail;
			LogRespond (pRqBlk);
			erc = Respond (pRqBlk);
			if (erc = ercOK)
				FatalServerError(erc);
		}
	}

	*
		Return partition handle to calling program so that the
		calling program can vacate the partition and remove it.
	*
	ercAsync = SetPartitionLock (FALSE);
	return GetPartitionHandle (rgbPartitionName, strlen(rgbPartitionName),
								prx>pPhRet);
}
*
	HandleRequest: The request pointed to by pRq is a new Request or a TRB.
	Given a request code, call the routine which processes the request.
	NOTE that this procedure is NOT REENTRANT.  After the call to
	CreateContext, its stack pointer has changed, so it cannot access
	any local variables on the stack.
*
void HandleRequest (void)
{

	if (pRq>rqCode == 0)
	{	*
			rqCode = 0 indicates a timer request block
		*
		HandleTimer ();
		return;
	}

	ercAsync = CreateContext (defaultStackSize, pRq>userNum);
	if (ercAsync == ercOK)
	{	*
			Process request in usersupplied function
		*
		pRq>ercRet = ServeRequest ();
	}
	else
	{	*
			Context could not be started because no heap space
		*;
		pRq>ercRet = ercAsync;
	}

	if (fRespond) {
		LogRespond (pRq);
		ercAsync = Respond (pRq);
	}
	fRespond = TRUE;
	ercAsync = TerminateContext ();

	* 
		Only returns if error  normally calls WaitLoop 
	*
	FatalServerError (ercAsync);
}void Initialize(void)
{
	*
		This function is called to initialize the service.
	*
	Word i;
	Word userNumServ;

	pSave = saveSpBp[0]; * establish pointer to spbp save area *

	* 
		Allocate exchange for service.
	*
	CheckErc (AllocExch (exchServ));

	*
		Set process priority of service.
	*
	CheckErc (ChangePriority (priorityServ));

	* 
		Test Requests; 
	*
	if (wOSRel < 10)
		nRqCodes;

	for (i = 0; i < nRqCodes; i++)
		*
			Test each request enumerated in rgwRqs[] to verify that
			it also exists in the Request.sys file read at boot
			time.
		*
		CheckErc (QueryRequestInfo (rgwRqs[i], rgwOldExch[i], 2));

	*
		Allocate memory from DS space to be used for the heap.
	*
	CheckErc (AllocMemoryInit (cbHeap, pbHeap, FALSE));
	CheckErc (HeapInit (cbHeap, pbHeap));
	*
		Allocate any other memory required for tables, etc from
		DS space.
	*
	if (cbFree = 0) 
		*
			Free leftover memory used by the initialization code. 
		*
		CheckErc (ShrinkAreaSL (pToDeallocate, cbFree));

	* 
		Service specific initialization. 
	*
	InitializeServer ();

	*
		Initialize Timer Request Block as necessary.
	*
	InitializeTimer ();
	if (fConvertToSys)
		CheckErc (ConvertToSys ());

	* 
		Serve Requests
	*
	for (i = 0; i < nRqCodes; i++)
	{
		*
			Save the exchange previously served for this request
			so that it can be restored when the service is
			deinstalled.
		*
		CheckErc (QueryRequestInfo (rgwRqs[i], rgwOldExch[i], 2));
		*
			Serve each request code enumerated for this service.
		*
		CheckErc (ServeRq (rgwRqs[i], exchServ));
	}

	* 
		Call ErrorExit (ercOK) to 'become' part of OS.
	*
	ErrorExit (ercOK);

	ercAsync = GetUserNumber (userNumServ);
	*
		SetPartitionName must come after ConvertToSys.
	*
	ercAsync = SetPartitionName ((userNumServ  0xFF), rgbPartitionName, 
									strlen (rgbPartitionName));
}*
	WaitLoop: Main process loop. 
	It waits for a request or a response to come in.
*
void WaitLoop (void)
{
	ErcType	erc;

	erc = ResetStack (offsetof (pSave));
	FOREVER
	{
		erc = Wait (exchServ, pRq);
		LogMsgIn ();
		if (erc == ercOK)
		{
			*
				If the response exchange in the request block
				equals this service's service exchange, then
				the request was sent by this service.  If the
				request code is 0, then the request is a timer
				request block.
			*
			if ((pRq>exchResp == exchServ)  (pRq>rqCode = 0))
				*
					The request in rq is a response to an
					asynchronous request that we created
					and sent out. Handle the response.
				*
				erc = ResumeContext ();
				*
					Only returns if error was detected.
				*
			else 
				*
					We have a new Request or a Timer
					Request Block.
				*
				HandleRequest ();
		}
		if (erc = ercOK)
			FatalServerError (erc);
	}
}
void AsyncServer (void)
{
	Initialize ();
	WaitLoop ();
}
