[comp.sys.amiga.programmer] Creating a 'Front-End' For Library Functions

dix@clinet.fi (Risto Kaivola) (06/25/91)

In a recent project I've had to create a front-end for certain dos.library
functions, meaning that first I patch a piece of code so that it will jump
to the library routine in question, and then change the library jump vector
so that it will jump to my code. So far, no problem (provided, of course,
that I remember to call the appropriate cache-handling library routines).
But when I'm finished, and want to remove the front-ends, and thus return
the system to the state in which it was earlier on, problems arise.
Obviously, I can't just return the library jump vector to its earlier state,
and then free the memory allocated for my code. If I did that, I would
take the chance that the system crashes when some task is executing off
non-allocated memory, and some other task allocates this memory block then
placing its data in this block. The possible solutions I've thought of are
as follows:

   (a) Create a front-end for the OpenLibrary function, and implement my
       own version of resource tracking. The front-ends for the dos.library
       functions will not be freed until all processes that have opened
       the dos.library after I inserted the front-end have closed the
       dos.library. To prevent the same kind of system malfunction as
       with the dos.library functions in the first-mentioned scenario,
       leave this front-end there when we're finished. Not very clean,
       but there isn't so much memory lost.

   (b) Do not fiddle with any other routines (like OpenLibrary), but rather,
       when finished, first make the library jump vector point to the
       real library routine, and then Forbid task switching. Check each
       processes task structure to determine whether it's executing my
       code. If there is a process that is doing so, wait for a while,
       then do the same check again. When there no longer are processes
       executing my code, free the memory block allocated for the code.

   (c) Do not worry about the memory loss caused by leaving the front-end
       or front-ends hanging around. This is no real solution.
 
Please tell me your suggestions and opinions on the issue. I apologize
for the lengthy posting.
 
Risto
-- 
Risto Kaivola (dix@clinet.fi) or (Risto.Kaivola@f123.n220.z2.FIDONET.ORG)

mks@cbmvax.commodore.com (Michael Sinz) (06/25/91)

In article <1991Jun25.084622.13642@clinet.fi> dix@clinet.fi (Risto Kaivola) writes:
>In a recent project I've had to create a front-end for certain dos.library
>functions, meaning that first I patch a piece of code so that it will jump
>to the library routine in question, and then change the library jump vector
>so that it will jump to my code. So far, no problem (provided, of course,
>that I remember to call the appropriate cache-handling library routines).
>But when I'm finished, and want to remove the front-ends, and thus return
>the system to the state in which it was earlier on, problems arise.
>Obviously, I can't just return the library jump vector to its earlier state,
>and then free the memory allocated for my code. If I did that, I would
>take the chance that the system crashes when some task is executing off
>non-allocated memory, and some other task allocates this memory block then
>placing its data in this block. The possible solutions I've thought of are
>as follows:

The problem with removing a setfunction are more complex that what you
have stated.  There is at least one additional case that is very hard
to even think about:  What if another application does the same sort of
thing?

So, in general, it is best to not setfunction the system.  If you absolutely
must setfunction the system, you should make sure part of the setfunction
stays around.  The method I have used in the past was to have a structure
much like below...  Note that once installed, it stays there for good
and all that is needed is the FP_NewVec is set up/removed at the right
time and that programs are not in your code.

struct FunctionPatch
{
   struct SignalSemaphore FP_Semaphore;   /* The semaphore */
   ULONG FP_OldVec;                       /* Storage for old address */
   ULONG FP_NewVec;                       /* Storage for new address */
   UWORD FP_Code[?];                      /* Storage for the code */
   char  FP_Name[30];                     /* Storage for semaphore name */
}

Then, I setup the semaphore and add it to the public list (as long as it
is not there already)  If it is already there, I grab the semaphore, make
sure no one else it using it (FP_NewAdd) and install my new address there.

In installing the semaphore, I sefunction the code below which is stored
in FP_Code[] and store the old return address in FP_OldVec.

FP_OldVec:	dc.l	0
FP_NewVec:	dc.l	0
FP_Code:	move.l	FP_OldVec(pc),-(sp)	; Set up for old routine
		move.l	FP_NewVec(pc),-(sp)	; Set up for new routine
		bne.s	FP_Patch		; If not NULL patch, skip
		addq.l	#4,sp			; Ignore the patch...
FP_Patch:	rts				; Either jump to the patch
						; which returns to the real
						; one or just jump to the real
						; one (stack magic)

The above code would be different if the patch would happen after the real
routine:

FP_OldVec:	dc.l	0
FP_NewVec:	dc.l	0
FP_Code:	move.l	FP_NewVec(pc),-(sp)	; Set up for new routine
		bne.s	FP_Patch		; If not NULL patch, skip
		addq.l	#4,sp			; Ignore the patch...
FP_Patch:	move.l	FP_OldVec(pc),-(sp)	; Set up for old routine
		rts				; Jump to the real thing
						; and then, if there was a
						; patch, to the patch.

/----------------------------------------------------------------------\
|      /// Michael Sinz  -  Amiga Software Engineer                    |
|     ///                   Operating System Development Group         |
|    ///   BIX:  msinz      UUNET:  rutgers!cbmvax!mks                 |
|\\\///    Programming is like sex:                                    |
| \XX/     One mistake and you have to support it for life.            |
\----------------------------------------------------------------------/