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. | \----------------------------------------------------------------------/