[comp.sys.atari.st.tech] Malloc

dcrevier@jarthur.Claremont.EDU (Dan Crevier) (07/20/90)

I remember a long time ago a discussion about malloc, and bugs in it.  Was
there ever a new version of malloc posted or a good fix?

Dan Crevier

dcrevier@jarthur.claremont.edu

steve@thelake.mn.org (Steve Yelvington) (07/23/90)

[In article <7885@jarthur.Claremont.EDU>,
     dcrevier@jarthur.Claremont.EDU (Dan Crevier) writes ... ]

> I remember a long time ago a discussion about malloc, and bugs in it.  Was
> there ever a new version of malloc posted or a good fix?

The problem is in Malloc(), GEMDOS function 0x48. There is a limit on how
many times you can call it, and I think you have to free memory in the
reverse order. TOS 1.4 may have fixed some of these problems, but you can
hardly depend on TOS 1.4 being installed in the average ST when Atari is
still shipping computers without it.

Most C compilers get around the difficulties by calling Malloc() to
allocate a large chunk of memory, then parceling out little chunks as
necessary. You can see how this works by examining the source code to the
dLibs C library. 

(There is a bug in dLibs realloc() function. First person to *post* a fix
gets a banana split at the Cup 'N' Cone in White Bear Lake. Transportation
not included. Offer void where prohibited by cholesterol levels.)

-- 
   Steve Yelvington at the lake in Minnesota
   steve@thelake.mn.org

steve@thelake.mn.org (Steve Yelvington) (08/24/90)

I've seen comments to the effect that calling Malloc() from a desk
accessory is a Bad Thing, and I wonder if that is always true.

I want to write a desk accessory that will filter ASCII text into a
format suitable for Pagestream. The Pagestream ASCII import function is
brain-damaged -- it will not properly handle normal text with hard returns 
at the end of each line and paragraphs separated by a blank line (which is
what you're reading right now).

I want the DA to 
   wake up from evnt_multi
      get a filename using fsel_exinput
      compute the file size
      open the file
      Malloc() enough memory for the whole file
      read all of it into the buffer
      strip line enders (except blank lines)
      write the modified file back to the disk
      close the file
      Mfree() the buffer
   return to evnt_multi

There would not be a chance for an application to terminate while the
allocated memory was being held.  If the memory allocation follows the
same rules as file handle ownership, there would not be a problem.  True
or false?

 --
 Steve Yelvington up at the lake in Minnesota
 steve@thelake.mn.org     plains!umn-cs!steve

kbad@atari.UUCP (Ken Badertscher) (08/29/90)

As long as you don't go back into an event wait, you can Malloc all day
long (Mfreeing what you Malloc when you're done with it, of course).

The only time DA's have Malloc headaches if they try to Malloc memory
outside their startup sequence is if they give the parent application a
chance to terminate out from under them.  The problem arises when an
application calls appl_exit().  The AES does not give DA's enough time
to clean up after themselves before the parent application's resources
are released.  It is possible for a DA to not get an AC_CLOSE message
until you're already back at the desktop.

Note that this also causes problems with DA's that open virtual
workstations, since the VDI Mallocs memory for workstation information. 

A sequence of events like the following could cause problems:

  Run an application.
  Open a DA that opens a workstation or Mallocs some memory.
  Quit the application without closing the DA.

At this point, the application calls appl_exit(), which returns before
giving all DA's a chance to clean up.  The application then terminates,
and GEMDOS frees all the memory that was allocated while the program 
was running.  Eventually, the AES will get around to telling the DA,
"Oh, by the way, shut yourself down now."  If the DA then tries to
access any of the memory it had Malloced, it would be messing with
memory that had already been freed.  If this memory had since been
reallocated, the DA would be changing someone else's memory.  If it
happened that the memory had been reallocated to someone else _at the
same starting address_, it would be disastrous for the DA to Mfree that
block.

The solution is simple.  DA's must only Malloc memory in an atomic
(from the AES's point of view) operation, as Steve outlined.  If a DA has
more dynamic memory needs, it can allocate a heap for itself at
startup, BEFORE IT MAKES ANY AES CALLS.  The DA can then use it's own
memory management within this heap.

-- 
   |||   Ken Badertscher  (ames!atari!kbad)
   |||   Atari R&D System Software Engine
  / | \  #include <disclaimer>

jhenders@van-bc.wimsey.bc.ca (John Henders) (08/29/90)

	Thanks for the explanation Ken. Would using an auto program to serve
DA memory requests work? Could the auto program somehow wake up once Gem was
initialized so it could use the gem pipeline to get requests for memory from
DA's and attach them to it's basepage. If this worked,it would seem we could
have one auto program handle requests from many DA's. I know this is off-
topic from Steve's question,but I'm curious. Actually,I'd guess this is how
the non reset proof version of Shadow works.

	John Henders
	Vancouver,BC

7103_2622@uwovax.uwo.ca (Eric Smith) (08/29/90)

In article <1632@van-bc.wimsey.bc.ca>, jhenders@van-bc.wimsey.bc.ca (John Henders) writes:
> 	Thanks for the explanation Ken. Would using an auto program to serve
> DA memory requests work? Could the auto program somehow wake up once Gem was
> initialized so it could use the gem pipeline to get requests for memory from
> DA's and attach them to it's basepage. If this worked,it would seem we could
> have one auto program handle requests from many DA's. I know this is off-
> topic from Steve's question,but I'm curious. Actually,I'd guess this is how
> the non reset proof version of Shadow works.
> 
(I'm not Ken, but...)
I would say not. There's no way to "wake up" a TSR under TOS; from TOS's
point of view the program is dead and buried. If you want to go for
non-portable code, the desk accessory certainly could dig through the TOS
memory allocation list and "attach" any memory it allocates to some other
program that won't terminate (the desktop being an obvious candidate).
This strikes me as being quite ugly, and moreover I'm not sure that it would
be guaranteed to work.

Your suggestion of having a "server" handle memory requests from DA's would
work quite well under a multi-tasking system such as RTX or MiNT, and should
be easy to code under either of those two systems.
--
Eric R. Smith                     email:
Dept. of Mathematics            ersmith@uwovax.uwo.ca
University of Western Ontario   ersmith@uwovax.bitnet
London, Ont. Canada N6A 5B7
ph: (519) 661-3638

fischer-michael@cs.yale.edu (Michael Fischer) (08/30/90)

In article <6828.26dba802@uwovax.uwo.ca> 7103_2622@uwovax.uwo.ca (Eric Smith) writes:
>In article <1632@van-bc.wimsey.bc.ca>, jhenders@van-bc.wimsey.bc.ca (John Henders) writes:
>> 	Thanks for the explanation Ken. Would using an auto program to serve
>> DA memory requests work? Could the auto program somehow wake up once Gem was
>> initialized so it could use the gem pipeline to get requests for memory from
>> DA's and attach them to it's basepage. If this worked,it would seem we could
>> have one auto program handle requests from many DA's. I know this is off-
>> topic from Steve's question,but I'm curious. Actually,I'd guess this is how
>> the non reset proof version of Shadow works.
>> 
>(I'm not Ken, but...)
>I would say not. There's no way to "wake up" a TSR under TOS; from TOS's
>point of view the program is dead and buried. If you want to go for
>non-portable code, the desk accessory certainly could dig through the TOS
>memory allocation list and "attach" any memory it allocates to some other
>program that won't terminate (the desktop being an obvious candidate).
>This strikes me as being quite ugly, and moreover I'm not sure that it would
>be guaranteed to work.

There is a trick that will work (at least in TOS 1.4) but is also not
portable.  Namely, change the current process pointer to point to the
DA before doing the Malloc, and restore it to its original value
immediately afterwards.  This causes Gemdos to think that the DA is
the owner of the newly-allocated block, not the currently-running
application, which is what you want.  The current process pointer is
kept in a documented low-memory location.  What isn't officially
sanctioned is changing the pointer; it is supposed to be read-only.
Thus, the behavior of TOS when you change it is not guaranteed to be
the same in future versions of TOS.  Another warning besides the
non-portability issue: memory fragmentation can become a real problem
if DA's go around Mallocing memory at random times.  What Ken
described is much safer.

-- 
==================================================
| Michael Fischer <fischer-michael@cs.yale.edu>  |
==================================================

uace0@uhnix2.uh.edu (Michael B. Vederman) (08/30/90)

In article <1632@van-bc.wimsey.bc.ca> jhenders@van-bc.wimsey.bc.ca (John Henders) writes:
>
>	Thanks for the explanation Ken. Would using an auto program to serve
>DA memory requests work? Could the auto program somehow wake up once Gem was
>initialized so it could use the gem pipeline to get requests for memory from
>DA's and attach them to it's basepage. If this worked,it would seem we could
>have one auto program handle requests from many DA's. I know this is off-
>topic from Steve's question,but I'm curious. 

hmm...  Interesting idea, but I doubt you'd get any better results.  You'd
have to hook into the evnt_multi or evnt_mesag handler or even hook into
the appl_write handler and fake a waiting event or entirely intercept the
appl_write call...  Too much trouble, but interesting concept.

>Actually,I'd guess this is how
>the non reset proof version of Shadow works.

Not actually...  For what you suggest above, tho, a similar handler to Shadow
could be implemented for DAs.  It would require your intercepting the Malloc()
call from Gemdos.

What Shadow does is change the p_run pointer to it's basepage before mallocing
a buffer, then switches it back to the value before.  p_run is the current
process basepage pointer.  It's location is documented for TOS 1.2 and greater.

>
>	John Henders
>	Vancouver,BC

- mike vederman (co-author of Shadow)

-- 
------------------------------------------------------------------------------
Double Click Me | Double Click Software | P.O. Box 741206 | Houston, Tx, 77274
------------------------------------------------------------------------------
Voice: (713)977-6520 | DC DESKTOP | DC FORMATTER | DC UTILITIES | and others

7103_2622@uwovax.uwo.ca (Eric Smith) (08/31/90)

In article <25938@cs.yale.edu>, fischer-michael@cs.yale.edu (Michael Fischer) writes:
[ In response to a question about how a DA can Malloc memory ]
> 
> There is a trick that will work (at least in TOS 1.4) but is also not
> portable.  Namely, change the current process pointer to point to the
> DA before doing the Malloc, and restore it to its original value
> immediately afterwards.  This causes Gemdos to think that the DA is
> the owner of the newly-allocated block, not the currently-running
> application, which is what you want.  The current process pointer is
> kept in a documented low-memory location.  What isn't officially
> sanctioned is changing the pointer; it is supposed to be read-only.
> Thus, the behavior of TOS when you change it is not guaranteed to be
> the same in future versions of TOS.  Another warning besides the
> non-portability issue: memory fragmentation can become a real problem
> if DA's go around Mallocing memory at random times.  What Ken
> described is much safer.
> 
I hadn't thought of that trick; it's not a bad idea. As you say, though,
it may not work in future versions of TOS. It certainly doesn't work
under MiNT (which sets the current process pointer, but otherwise ignores
it). I don't know about RTX, but I'd suspect that it would have similar
problems.
--
Eric R. Smith                     email:
Dept. of Mathematics            ersmith@uwovax.uwo.ca
University of Western Ontario   ersmith@uwovax.bitnet
London, Ont. Canada N6A 5B7
ph: (519) 661-3638

gt1448b@prism.gatech.EDU (David P. Forrai) (09/02/90)

In a previous post on this subject, it was mentioned that making a call
to v_opnvwk() did a Malloc, thus problems can result from DA's which
call it.  In ACSKEL.C, a v_opnvwk() is called when the DA is opened,
and a v_clsvwk() is called when a DA is closed.  Therfore, this example
of a desk accessory is not coded "correctly".  What is the correct way
to call v_opnvwk()?  Should it be done before the event loop and
v_clsvwk() never called?

kbad@atari.UUCP (Ken Badertscher) (09/03/90)

gt1448b@prism.gatech.EDU (David P. Forrai) asks:

| What is the correct way to call v_opnvwk()?  Should it be done before
| the event loop and v_clsvwk() never called?

The best way for desk accessories to handle opening virtual workstations
is for them to use them in the same way they would use any other dynamically
allocated resources.  Open the workstation, do VDI calls, close the
workstation.  It isn't a good idea to suck up a virtual workstation slot
which may never be used.

You're right, if that's what ACSKEL does, the behaviour in ACSKEL is
incorrect.

The effects of dynamic DA Malloc() and v_opnvwk() calls only recently
became apparent, when the GEMDOS internal memory management was
improved for TT TOS.  A side effect of the change he made was that the
likelihood of a freed block getting reallocated soon after being freed
became much greater.  In previous TOS versions, it takes longer for
freed blocks to be reallocated.  Because of this, you are less likely
to see problems arise when DA's don't get a chance to clean up after
themselves.  It is still and always will be A Bad Idea to mess with
memory you don't own, and that's effectively what DA's do if they
dynamically Malloc memory (either directly or indirectly).

To end on a happy note--the problem of DA's not getting a chance to
free up their resources before having them yanked out from under them
is FIXED in the AES version 3.0.  The AES now actually waits until all
desk accessories are back in an event wait before allowing an appl_exit
caller to terminate.  The new Control Panel (XCONTROL) takes advantage
of this fact, and dynamically allocates memory to load Control Panel
Extensions if it sees that it's on a TT.  This should also be a great
boon to desk accessory text editors and the like.

-- 
   |||   Ken Badertscher  (ames!atari!kbad)
   |||   Atari R&D System Software Engine
  / | \  #include <disclaimer>