[comp.sys.amiga.tech] UnLoadSeg

rouaix@inria.inria.fr (Francois Rouaix) (07/03/89)

Hello dear techies,
I  have a doubt on the possibility that UnLoadSeg() might
Wait() somewhere. Does anybody knows for sure ?
The reason I ask this is the following:
A program detaches itself from CLI (ya know, hacking the
SegList), runs, and at the end, unloads itself with UnLoadSeg().
The very end of the code (ASM) looks like
callsys Forbid
* setup UnLoadSeg
callsys UnLoadSeg
moveq.l 0,d0
rts

And occasionally, I get a Guru (4)...
The only explanation I have yet is thatUnLoadSeg() waits,
memory freed is reallocated, the last two lines get
trashed, and boom.
Am I wrong ?
I could think of replacing the JSR to UnLoadSeg by a JMP, therefore
using the RTS of the routine, but since this bug appears quite randomly,
I'd like to be certain of its reason.

Thanx for any help
--Francois

-- 
*- Francois Rouaix                 //       We are all prisonners here       *
*- rouaix@inria.inria.fr         \X/           of our own device             *
*- SYSOP of Sgt. Flam's Lonely Amigas Club. (33) (1) 39-55-84-59 (Videotext) *
Disclaimer: Opinions expressed are my own, not those of my employer.

451061@UOTTAWA.BITNET (Valentin Pepelea) (07/04/89)

Francois Rouaix <rouaix@inria.inria.fr> in message <1364@inria.inria.fr> writes

> I  have a doubt on the possibility that UnLoadSeg() might
> Wait() somewhere. Does anybody knows for sure ?

There is no reason why UnLoadSeg would want to call Wait().

> A program detaches itself from CLI (ya know, hacking the
> SegList), runs, and at the end, unloads itself with UnLoadSeg().
> The very end of the code (ASM) looks like
>
> callsys Forbid
> * setup UnLoadSeg
> callsys UnLoadSeg
> moveq.l 0,d0
> rts

What happened to "callsys Permit"? Jette dans l'oubliette?

> And occasionally, I get a Guru (4)...

No wonder. "Merde alors!" Eh?

> The only explanation I have yet is that UnLoadSeg() waits,
> memory freed is reallocated, the last two lines get trashed, and boom.
> Am I wrong ?

I think there is a logic mistake here. Does UnLoadSeg() also remove the task
associated with it? If so, then the Forbid() is immediately obsoleted, the
memory associated with the task gets freed, but somehow you still insist
running code within a task that does not exist anymore. I am surprised your
code runs some of the time, it should fail instantly every time.

> I could think of replacing the JSR to UnLoadSeg by a JMP, therefore
> using the RTS of the routine, but since this bug appears quite randomly,
> I'd like to be certain of its reason.

Perhaps you should UnLoadSeg only other segments, never your-self.

> Thanx for any help
> --Francois

For what it's worth...

Valentin
_________________________________________________________________________
"An  operating  system  without         Name:   Valentin Pepelea
 virtual memory is an operating         Phonet: (613) 231-7476 (New!)
 system without virtue."                Bitnet: 451061@Uottawa.bitnet
                                        Usenet: Use cunyvm.cuny.edu gate
         - Ancient Inca Proverb         Planet: 451061@acadvm1.UOttawa.CA

jesup@cbmvax.UUCP (Randell Jesup) (07/04/89)

In article <1364@inria.inria.fr> rouaix@inria.inria.fr (Francois Rouaix) writes:
>I  have a doubt on the possibility that UnLoadSeg() might
>Wait() somewhere. Does anybody knows for sure ?
>The reason I ask this is the following:
>A program detaches itself from CLI (ya know, hacking the
>SegList), runs, and at the end, unloads itself with UnLoadSeg().
>The very end of the code (ASM) looks like
>callsys Forbid
>* setup UnLoadSeg
>callsys UnLoadSeg
>moveq.l 0,d0
>rts
>
>And occasionally, I get a Guru (4)...

	UnLoadSeg() will not Wait() UNLESS the seglist is overlaid, in which
case it must Close() the program file.

	I would look for something trashing a seglist pointer, some reference
in a system structure to memory in your seglist (interrupt structures, nodes
on a public list, whatever), writing past the end of some data area (unlikely),
or passing the wrong seglist pointer to UnLoadSeg (must be a BPTR to the
first segment's next segment BPTR - the value returned by LoadSeg()).

-- 
Randell Jesup, Keeper of AmigaDos, Commodore Engineering.
{uunet|rutgers}!cbmvax!jesup, jesup@cbmvax.cbm.commodore.com  BIX: rjesup  
Common phrase heard at Amiga Devcon '89: "It's in there!"

jesup@cbmvax.UUCP (Randell Jesup) (07/07/89)

In article <8907032258.AA16367@jade.berkeley.edu> 451061@UOTTAWA.BITNET (Valentin Pepelea) writes:
>Francois Rouaix <rouaix@inria.inria.fr> in message <1364@inria.inria.fr> writes
>
>> I  have a doubt on the possibility that UnLoadSeg() might
>> Wait() somewhere. Does anybody knows for sure ?
>
>There is no reason why UnLoadSeg would want to call Wait().

	For overlaid modules it will Wait().

>> callsys Forbid
>> * setup UnLoadSeg
>> callsys UnLoadSeg
>> moveq.l 0,d0
>> rts
>
>What happened to "callsys Permit"? Jette dans l'oubliette?

	Not needed: he's exiting his task with that rts, so his task will
go away, and the Forbid() dies at that time also.

>I think there is a logic mistake here. Does UnLoadSeg() also remove the task
>associated with it? If so, then the Forbid() is immediately obsoleted, the
>memory associated with the task gets freed, but somehow you still insist
>running code within a task that does not exist anymore. I am surprised your
>code runs some of the time, it should fail instantly every time.

	UnLoadSeg() has no knowlege of tasks (think about it).  However, it
is safe to reference memory that has been freed under a Forbid() so long
as it isn't the first N (where N=8) bytes of the freed hunk.  For seglists,
the first 8 bytes are the segment size and next segment BPTR, so the code/
data isn't touched.  Once you explicitly or implicitly break the Forbid
(via Permit or Wait()), the memory can be trashed.

-- 
Randell Jesup, Keeper of AmigaDos, Commodore Engineering.
{uunet|rutgers}!cbmvax!jesup, jesup@cbmvax.cbm.commodore.com  BIX: rjesup  
Common phrase heard at Amiga Devcon '89: "It's in there!"

rouaix@inria.inria.fr (Francois Rouaix) (07/10/89)

In article <7225@cbmvax.UUCP>, jesup@cbmvax.UUCP (Randell Jesup) writes:
> >Francois Rouaix <rouaix@inria.inria.fr> in message <1364@inria.inria.fr> writes
> >> I  have a doubt on the possibility that UnLoadSeg() might
> >> Wait() somewhere. Does anybody knows for sure ?
> 	For overlaid modules it will Wait().
> >> callsys Forbid
> >> * setup UnLoadSeg
> >> callsys UnLoadSeg
> >> moveq.l 0,d0
> >> rts
> 	UnLoadSeg() has no knowlege of tasks (think about it).  However, it
> is safe to reference memory that has been freed under a Forbid() so long
> as it isn't the first N (where N=8) bytes of the freed hunk.  For seglists,
> the first 8 bytes are the segment size and next segment BPTR, so the code/
> data isn't touched.  Once you explicitly or implicitly break the Forbid
> (via Permit or Wait()), the memory can be trashed.

We (Jean-Michel Forgeas and I) think we finally found the reason of this
guru. It has to do with nested Forbid()/Permit(). 

Forbid() and Permit() work by incrementing and decrementing a counter
(TDNestCount (sp?)) which tells the scheduler if the task may be switched
or not. Now if you write too much Permit() (ie more than Forbid()) in the
code, then the value in the counter might get negative. A later Forbid() will
then have NO effect.
This is what happen in the code above (there is one superfluous Permit()
in the init code of the task). Therefore, the
callsys Forbid()
does not prevent the process from being switched, although UnLoadSeg() does
not Wait(). In some cases, the memory where the code resides is reallocated
and trashed, invoking a 4 guru.
Since this was so much pain to debug, I'll make a wish for 1.4 !
I want that Permit() checks the counter so that it can never get
negative (one MOVE is enough...).
(Note how it is similar to some Lisps that allow superfluous closing
parenthesis)
Much thanx to all people who helped in this battle against the guru,
especially to Randell Jesup and Peter da Silva
--Francois-- 
*- Francois Rouaix                 //       We are all prisoners here,       *
*- rouaix@inria.inria.fr         \X/           of our own device             *
*- SYSOP of Sgt. Flam's Lonely Amigas Club. (33) (1) 39-55-84-59 (Videotext) *
Disclaimer: Opinions expressed are my own, not those of my employer.

janhen@kunivv1.sci.kun.nl (Jan Hendrikx) (07/14/89)

In article <7225@cbmvax.UUCP> jesup@cbmvax.UUCP (Randell Jesup) writes:
|	UnLoadSeg() has no knowlege of tasks (think about it).  However, it
|is safe to reference memory that has been freed under a Forbid() so long
|as it isn't the first N (where N=8) bytes of the freed hunk.  For seglists,
|the first 8 bytes are the segment size and next segment BPTR, so the code/
|data isn't touched.  Once you explicitly or implicitly break the Forbid
|(via Permit or Wait()), the memory can be trashed.

This is, of course, very handy for those programs that UnLoadSeg()
themselves. And I have written at least two of those.

|Randell Jesup, Keeper of AmigaDos, Commodore Engineering.
|{uunet|rutgers}!cbmvax!jesup, jesup@cbmvax.cbm.commodore.com  BIX: rjesup  
|Common phrase heard at Amiga Devcon '89: "It's in there!"

-Olaf Seibert