/* Listing #23 */

#include <exec/execbase.h>


#include <exec/memory.h>


#include <proto/dos.h>


#include <proto/exec.h>



#include <string.h>



#ifdef __GNUC__


#define REG(reg, arg) register arg __asm__(#reg)


#define ASM


#else /* np. __SASC */


#define REG(reg, arg) register __##reg arg


#define ASM __asm


#endif



#define NAZWA_SEMAFORA "Listing23-Semafor"


#define ROZMIAR_KODU (((int)&koniec_kodu)-((int)&poczatek_kodu))


#define LVOOpenLibrary -552



extern void ASM koniec_kodu(void);


extern void ASM poczatek_kodu(void);


extern void ASM adres_funkcji(void);


extern void ASM adres_sem1(void);


extern void ASM adres_sem2(void);



struct NaszSemafor


{


	struct SignalSemaphore ns_Sem;


	struct Task* ns_Obecny; /* Obecny wîaôciciel */


	void* ns_Funkcja;


	char ns_Kod[1]; /* Rzeczywisty rozmiar ROZMIAR_KODU */


} *semafor=0;



struct NaszMsg


{


	struct Message nm_Msg;


	char* nm_Proces;


	char* nm_Biblioteka;


};



struct Library* ASM (*OrygOpenLibrary)(REG(a1, UBYTE*), REG(d0, ULONG), REG(a6, struct ExecBase*));


struct MsgPort *port;



char ZainstalujSemafor(void);


struct Library* __interrupt __saveds ASM NaszOpenLibrary(REG(a1, UBYTE*), REG(d0, ULONG), REG(a6, struct ExecBase*));


void ObslugaPortu(void);



int main(void)


{


	char mam_semafor=0;



	if (!(port=CreateMsgPort()))


		return 10;



	Forbid();


	if (!(semafor=(struct NaszSemafor*)FindSemaphore(NAZWA_SEMAFORA)))


		mam_semafor=ZainstalujSemafor();


	else /* Program byî juû wczeôniej uruchomiony */


	{


		ObtainSemaphore((struct SignalSemaphore*)semafor);


		if (!semafor->ns_Obecny)


		{


			semafor->ns_Obecny=FindTask(0);


			mam_semafor=1;


		}


		else /* Program dziaîa juû na innym procesie */


			ReleaseSemaphore((struct SignalSemaphore*)semafor);


	}


	
	if (!mam_semafor)
	
	
	{
	
		
				Permit();


		DeleteMsgPort(port);


		return 10;


	}



	OrygOpenLibrary=(struct Library* ASM (*)(REG(a1, UBYTE*), REG(d0, ULONG), REG(a6, struct ExecBase*)))semafor->ns_Funkcja;


	semafor->ns_Funkcja=(void*)&NaszOpenLibrary;


	ReleaseSemaphore((struct SignalSemaphore*)semafor);


	Permit();



	Printf("Monitor zainstalowany. Naciônij ^C aby wyjôê...\n");


	for (;;)


	{


		ULONG sig;


		sig=Wait((1 << port->mp_SigBit) | SIGBREAKF_CTRL_C);


		if (sig & (1 << port->mp_SigBit))


			ObslugaPortu();


		if (sig & SIGBREAKF_CTRL_C)


			break;


	}



	ObtainSemaphore((struct SignalSemaphore*)semafor);


	semafor->ns_Funkcja=(void*)OrygOpenLibrary;


	semafor->ns_Obecny=0;


	ReleaseSemaphore((struct SignalSemaphore*)semafor);


	Printf("Monitor usuniëty.\n");



	ObslugaPortu(); /* Koïcowe opróûnienie */


	DeleteMsgPort(port);


	return 0;


}



char ZainstalujSemafor(void)


{


	if (semafor=AllocMem(sizeof(struct NaszSemafor)+ROZMIAR_KODU-1, MEMF_PUBLIC))


	{


		char* nazwa;


		if (nazwa=AllocMem(strlen(NAZWA_SEMAFORA)+1, MEMF_PUBLIC))


		{


			strcpy(nazwa, NAZWA_SEMAFORA);


			semafor->ns_Sem.ss_Link.ln_Name=nazwa;


			semafor->ns_Sem.ss_Link.ln_Pri=0;


			semafor->ns_Obecny=FindTask(0);



			AddSemaphore((struct SignalSemaphore*)semafor);


			ObtainSemaphore((struct SignalSemaphore*)semafor);



			CopyMem(&poczatek_kodu, semafor->ns_Kod, ROZMIAR_KODU);


			*(void***)&semafor->ns_Kod[((int)&adres_funkcji)-((int)&poczatek_kodu)+2]=&semafor->ns_Funkcja;


			*(void**)&semafor->ns_Kod[((int)&adres_sem1)-((int)&poczatek_kodu)+2]=


			*(void**)&semafor->ns_Kod[((int)&adres_sem2)-((int)&poczatek_kodu)+2]=semafor;


			CacheClearE(semafor->ns_Kod, ROZMIAR_KODU, CACRF_ClearI | CACRF_ClearD);


			semafor->ns_Funkcja=SetFunction((struct Library*)SysBase, LVOOpenLibrary, (void*)semafor->ns_Kod);



			return 1;


		}


	}


	return 0;


}



struct Library* __interrupt __saveds ASM NaszOpenLibrary(REG(a1,
UBYTE* libName), REG(d0, ULONG version), REG(a6, struct ExecBase*
SysBase))


{


	struct Task* proces=FindTask(0);


	struct NaszMsg* msg;


	if (msg=AllocMem(sizeof(struct NaszMsg), MEMF_PUBLIC))


	{


		if (msg->nm_Proces=AllocVec(strlen(proces->tc_Node.ln_Name)+1,
		MEMF_PUBLIC))


		{


			strcpy(msg->nm_Proces, proces->tc_Node.ln_Name);


			if (msg->nm_Biblioteka=AllocVec(strlen(libName)+1,
            MEMF_PUBLIC))


			{


				strcpy(msg->nm_Biblioteka, libName);


				PutMsg(port, (struct Message*)msg);


				return OrygOpenLibrary(libName, version, SysBase);


			}


			FreeVec(msg->nm_Proces);


		}


		FreeMem(msg, sizeof(struct NaszMsg));


	}


	return OrygOpenLibrary(libName, version, SysBase);


}



void ObslugaPortu(void)


{


	struct NaszMsg *msg;


	while (msg=(struct NaszMsg*)GetMsg(port))


	{


		Printf("Proces \"%s\": próba otwarcia \"%s\"\n",
        msg->nm_Proces, msg->nm_Biblioteka);


		FreeVec(msg->nm_Biblioteka);


		FreeVec(msg->nm_Proces);


		FreeMem(msg, sizeof(struct NaszMsg));


	}


}


