/*****************************************************************************
* GRACE.C
*
* 91-02-16 Matt Hagen, Novell, Inc.
*****************************************************************************/

#include <nwtypes.h>
#include <nwsemaph.h>
#include <nwipxspx.h>
#include <conio.h>
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>

typedef struct WorkerStructure
{
	struct WorkerStructure *sLink;
	int threadID;
}WORKER;

void SignalRoutine(
	void);

void WorkerRoutine(
	void);

void UpdateRoutine(
	void);

#define CONTINUE 0
#define WAIT 1
#define EXIT 2

LONG semaphore;
BYTE threadCount=0;
WORKER *sList=NULL;
int updateThread;
BYTE globalExitFlag=CONTINUE;
BYTE threadInitFlag;

/*****************************************************************************
* main
*****************************************************************************/

main(
	int argc,
	char *argv[])
{
	int a;
	WORKER *w;

	signal(SIGTERM,SignalRoutine);
	threadCount++;

	semaphore=OpenLocalSemaphore(0);
	if(semaphore==NULL)
	{
		ConsolePrintf("  Cannot allocate semaphore.\n");
		globalExitFlag=EXIT;
		goto exit0;
	}

	for(a=0;a<5;a++)
	{
		threadInitFlag=WAIT;
		if(BeginThreadGroup(WorkerRoutine,NULL,NULL,NULL)==EFAILURE)
		{
			ConsolePrintf("  Cannot create session thread #%d.\n",a+1);
			globalExitFlag=EXIT;
			goto exit1;
		}

		while(threadInitFlag==WAIT)
			ThreadSwitch();

		if(threadInitFlag!=CONTINUE)
		{
			globalExitFlag=EXIT;
			goto exit1;
		}
	}

	threadInitFlag=WAIT;
	if(BeginThreadGroup(UpdateRoutine,NULL,NULL,NULL)==EFAILURE)
	{
		ConsolePrintf("  Cannot create screen thread.\n");
		globalExitFlag=EXIT;
		goto exit1;
	}

	while(threadInitFlag==WAIT)
		ThreadSwitch();

	if(threadInitFlag!=CONTINUE)
	{
		globalExitFlag=EXIT;
		goto exit1;
	}

	while(TRUE)
	{
		WaitOnLocalSemaphore(semaphore);
		if(globalExitFlag!=CONTINUE)
			goto exit2;

		/* take worker off sleep list */
		/* give request to worker */
		/* wake up worker */
	}

exit2:;
	ResumeThread(updateThread);

exit1:;
	w=sList;
	while(w!=NULL)
	{
		ResumeThread(w->threadID);
		w=w->sLink;
	}

	while(threadCount>1)
		ThreadSwitch();

exit0:;
	CloseLocalSemaphore(semaphore);

	threadCount--;
}

/*****************************************************************************
* SignalRoutine
*****************************************************************************/

void SignalRoutine(
	void)
{
	globalExitFlag=EXIT;

	SignalLocalSemaphore(semaphore);

	while(threadCount>0)
		ThreadSwitch();
}

/*****************************************************************************
* WorkerRoutine
*****************************************************************************/

void WorkerRoutine(
	void)
{
	WORKER *w;
	void *ecb;

	signal(SIGTERM,SignalRoutine);
	threadCount++;

	w=malloc(sizeof(WORKER));
	if(w==NULL)
	{
		ConsolePrintf("  Cannot allocate WORKER structure.\n");
		threadInitFlag=EXIT;
		goto exit0;
	}

	ecb=malloc(sizeof(IPX_ECB));
	if(ecb==NULL)
	{
		ConsolePrintf("  Cannot allocate session memory.\n");
		threadInitFlag=EXIT;
		goto exit1;
	}

	w->threadID=GetThreadID();
	threadInitFlag=CONTINUE;

	while(TRUE)
	{
		w->sLink=sList;
		sList=w;
		SuspendThread(w->threadID);

		if(globalExitFlag!=CONTINUE)
			goto exit2;

		/* service the request */
	}

exit2:;
	free(ecb);

exit1:;
	free(w);

exit0:;
	threadCount--;
	SuspendThread(GetThreadID());
}

/*****************************************************************************
* UpdateRoutine
*****************************************************************************/

void UpdateRoutine(
	void)
{
	int screen;
	LONG count=0;

	signal(SIGTERM,SignalRoutine);
	threadCount++;

	updateThread=GetThreadID();

	screen=CreateScreen("Graceful Screen",AUTO_DESTROY_SCREEN);
	if(screen==EFAILURE)
	{
		ConsolePrintf("  Cannot create screen.\n");
		threadInitFlag=EXIT;
		goto exit0;
	}

	HideInputCursor();

	if(DisplayScreen(screen)!=ESUCCESS)
	{
		ConsolePrintf("  Cannot display screen.\n");
		threadInitFlag=EXIT;
		goto exit1;
	}

	threadInitFlag=CONTINUE;

	gotoxy(20,0);
	printf("Graceful Init/Deinit Example Screen");

	while(TRUE)
	{
		SetCurrentScreen(screen);

		gotoxy(0,2);
		printf("Update Count = %u\n",count++);
		printf("Thread Count = %u",threadCount);
		delay(1000);

		if(globalExitFlag!=CONTINUE)
			goto exit1;
	}

exit1:;
	DestroyScreen(screen);

exit0:;
	threadCount--;

	SuspendThread(updateThread);
}

/****************************************************************************/
/****************************************************************************/
