Newsgroups: comp.sys.atari.st
  From: [email protected] (Allan Pratt)
  Date: Tue, 18-Aug-87 13:56:59 EDT
  Subject: Pexec cookbook!

  This is in response to a request from Christian Kaernbach which I got
  from  BITNET: I can't reply directly to BITNET, but I'm sure other
  people will find this interesting, too: it's a preliminary version of
  the long-awaited Pexec cookbook!

  In broad terms, the things you have to know about Pexec are that it
  starts up a process, lets it execute, then returns to the caller when
  that process terminates.  The "caller" -- the process which used
  Pexec in the first place -- has some responsibilities: it has to make
  memory available to the OS for allocation to the child, and it has to
  build up the argument string for the child.

  All GEMDOS programs are started with the largest block of OS memory
  allocated to them.  Except in very rare circumstances, this block is
  the one stretching from the end of the accessories and resident
  utilities to the beginning of screen memory. The point is that your
  program has probably been allocated ALL of free memory.  In order to
  make memory available for a child process, you have to SHRINK the
  block you own, returning the top part of it to GEMDOS.  The time to
  do this is when you start up.

  If you use Alcyon C (from the developer's kit), you know that you
  always link with a file called GEMSTART.  If you've been paying
  attention, you should have gotten the *new* GEMSTART from Compuserve
  (or from somebody else who got it): I wrote that GEMSTART.  In
  GEMSTART.S, there is a lot of discussion about memory models, and
  then a variable you set telling how much memory you want to keep or
  give back to the OS.  Make your choice (when in doubt, use STACK=1),
  assemble GEMSTART.S, call the result GEMSEXEC.O (or something), and
  link the programs which Pexec with that file rather than the normal
  GEMSTART.

  Now here's a discussion of what GEMSTART has to do with respect to
  keeping or returning memory:

  Your program is invoked with the address of its own basepage as the
  argument to a function (that is, at 4(sp).l).  In this basepage is
  the structure you can find in your documentation.  The interesting
  fields are HITPA (the address of first byte NOT in your TPA), BSSBASE
  (the first address of your bss) and BSSLEN (the length of your BSS).

  Your stack pointer starts at HITPA-8 (because 8 is the length of the
  basepage argument and the dummy return PC on the stack).  The space
  from BSSBASE+BSSLEN to your SP is the "stack+heap" space.  Library
  malloc() calls use this space, moving a pointer called the "break"
  (in the variable __break, or the C variable _break if you use Alcyon
  C) up as it uses memory.  Your stack pointer moves down from the top
  as it uses memory, and if the sp and _break ever meet, you're out of
  memory.  In fact, if they ever come close (within a "chicken factor"
  of about 512 bytes or 1K), malloc() will fail because it doesn't want
  your stack to overwrite good data.

  When a process starts, it gets *all* of memory allocated to it: from
  the end of any accessories or resident utilities up to the default
  screen memory.  If you want to use Pexec, you have to give some
  memory back to the OS.  You do this with the Mshrink call.  Its
  arguments are the address of the memory block to shrink (your
  basepage address) and the new size to shrink it to.  You should be
  sure to leave enough room above your BSS for a reasonable stack (at
  least 2K) plus any malloc() calls you expect to make.  Let's say
  you're writing "make" and you want to leave about 32K for malloc()
  (for your dependency structures).  Also, since make is recursive, you
  should leave lots of space for the stack - maybe another 16K.  The
  new top of memory that your program needs is:

  newtop = your bss base address + your bss size + 16K stack + 32K heap

  Since your stack pointer is at the top of your CURRENT TPA, and
  you're about to shrink that, you'd better move your stack:

      move.l      newtop,sp

  Now you want to compute your new TPA size and call Mshrink:

      move.l      newtop,d0
      sub.l       basepage,d0     ; newtop-basepage is desired TPA size
      move.l      d0,-(sp)        ; set up Mshrink(basepage,d0)
      move.l      basepage,-(sp)
      move.w      #$4a            ; fn code for Mshrink
      trap        #1
      add.l       #10,sp          ; clean up args

  Now that you've shrunk your TPA, the OS can allocate this new memory
  to your child.  It can also use this memory for Malloc(), which is
  used occasionally by GEM VDI for blt buffers, etc.  Note that you
  only have to do this once, when you start up: after that, you can do
  as much Pexec'ing as you want.

  When you want to exec a child, you build its complete filespec into
  one string, and its arguments into another.  The argument string is a
  little strange: the first character of the argument string is the
  length of the rest of the string!

  Here is a simple system call: pass it the name of the file to execute
  and the argument string to use.

          long system(cmd,args)
          char *cmd, *args;
          {
              char buf[128];

              if (strlen(args) > 126) {
                  printf("argument string too long\n");
                  return -1;
              }
              strcpy(buf+1,args);                 /* copy args to
  buffer+1 */
              buf[0] = strlen(args);              /* set buffer[0] to
  len */
              return Pexec(0,cmd,buf,0L);
          }

  The first zero in the Pexec call is the Pexec function code: load and
  go.  The cmd argument is the full filespec, with the path, file name,
  and file type.  The third argument is the command-line argument
  string, and the fourth argument is the environment pointer.  A null
  environment pointer means "let the child inherit A COPY OF my
  environment."

  This call will load the program, pass the arguments and environment
  to it, and execute it.  When the program terminates, the call returns
  the exit code from the program.  If the Pexec fails (not enough
  memory, file not found, etc.) a negative code is returned, and you
  should deal with it accordingly.  Note that error returns from Pexec
  are always negative LONGS, while return codes from the child will
  have zeros in the upper 16 bits.

  EXIT CODES:

  GEMDOS, like MS-DOS before it, allows programs to return a 16-bit
  exit code to their parents when they terminate.  This is done with
  the Pterm(errcode) call.  The value in errcode is passed to the
  parent as the return value of the Pexec system call.  The C library
  function exit(errcode) usually uses this call.

  Unfortunately, the people who wrote the startup file for the Alcyon C
  compiler didn't use this.  The compiler calls exit() with an error
  code, and exit() calls _exit(), but _exit always uses Pterm0(), which
  returns zero as the exit code.  I fixed this by rewriting GEMSTART.S,
  the file you link with first when using Alcyon.

  Even though new programs return the right exit code, the compiler
  itself still doesn't.  Well, I have patched the binaries of all the
  passes of the compiler so they DO.  It isn't hard, and I will post
  instructions at a later date for doing it.  IF YOU DO THIS, PLEASE
  DON'T BOTHER OUR CUSTOMER SUPPORT PEOPLE IF IT DOESN'T WORK.  THEY
  DON'T KNOW ANYTHING ABOUT IT.

  I hope that this little cookbook makes Pexec less mysterious.  I
  haven't covered such topics as the critical-error and terminate
  vectors, even though they are intimately connected with the idea of
  exec'ing children.  A more complete cookbook should be forthcoming.

  If there are any errors or gross omissions in the above text, please
  let me know BY MAIL so I can correct them coherently.  Landon isn't
  here to check my semantics, so I may have missed something.  [Landon
  is on vacation in France until early September.]

  ********************************************************************

  C. Kaernbach's question was why his accessory, which basically did a
  Pexec from a file selector, didn't always work.  The answer is that
  it works when used within a program which has returned enough memory
  to the OS for the child.  Why might it bomb?  Because if a program
  has returned a *little* memory to the OS (only about 2K), a bug in
  Pexec shows up that breaks the memory manager.  Accessories are
  strange beasts anyway, so for the most part combining two strange
  beasts (Accessories and Pexec) is bad news.

  /----------------------------------------------\
  | Opinions expressed above do not necessarily  |  -- Allan Pratt,
  Atari Corp.
  | reflect those of Atari Corp. or anyone else. |
  ...lll-lcc!atari!apratt
  \----------------------------------------------/        (APRATT on
  GEnie)


  Newsgroups: comp.sys.atari.st
  From: [email protected]
  Date: Wed, 19-Aug-87 12:11:44 EDT
  Subject: Re: Pexec cookbook! (w/ Lattice C)

  In article <[email protected]> [email protected] (Allan Pratt) writes:
  >All GEMDOS programs are started with the largest block of OS memory
  >allocated to them...  The point is that your
  >program has probably been allocated ALL of free memory.  In order to
  >make memory available for a child process, you have to SHRINK the
  >block you own, returning the top part of it to GEMDOS.  The time to
  >do this is when you start up.

     Does anybody know exactly how I do this using Lattice C?  The
  documentation
  (for version 3.04) is less than clear on this point, and everything
  I've
  tried hasn't worked.  I have never really *needed* to give the extra
  700K
  or so of memory back, but the sheer wastefulness of it annoys me (:-),
  and
  someday I may want to use that memory.  I'd appreciate any pointers on
  the
  subject.
     And while I'm asking advice on Lattice C, is there any special
  startup
  module needed to link a program used as a desk accessory, as there
  (apparently) is with other C's?
  --
    Joel Plutchak

    Arpanet: [email protected]
    Bitnet:  plutchak@WISCMACC
    uucp: Who knows-- it's Eunice; try ...ihnp4!uwvax!uwwircs!plutchak


  Newsgroups: comp.sys.atari.st
  From: [email protected] (Gert Poletiek)
  Date: Thu, 20-Aug-87 12:08:00 EDT
  Subject: Re: Pexec cookbook! (w/ Lattice C)

  In article <[email protected]> [email protected] writes:
  >In article <[email protected]> [email protected] (Allan Pratt) writes:
  >>All GEMDOS programs are started with the largest block of OS memory
  >>allocated to them...  The point is that your
  >>program has probably been allocated ALL of free memory.  In order to

  >>make memory available for a child process, you have to SHRINK the
  >>block you own, returning the top part of it to GEMDOS.  The time to
  >>do this is when you start up.

  >   Does anybody know exactly how I do this using Lattice C?  The
  documentation
  >(for version 3.04) is less than clear on this point, and everything
  I've
  >tried hasn't worked.  I have never really *needed* to give the extra
  700K
  >or so of memory back, but the sheer wastefulness of it annoys me
  (:-), and
  >someday I may want to use that memory.  I'd appreciate any pointers
  on the
  >subject.
  >   And while I'm asking advice on Lattice C, is there any special
  startup
  >module needed to link a program used as a desk accessory, as there
  >(apparently) is with other C's?
  >--
  >  Joel Plutchak

  The Lattice C compiler is a different story. When the Metacomco guys
  wrote their
  memory management on top of the *not perfect* memory allocation
  mechanism
  that GemDos offers they made it static. I.e., When  a Lattice program
  starts
  it does a shrink only for the amount:

          available - ( (_memneed)L + (_stksiz)L )

  When you write a program that needs to execute the Pexec GemDos call
  you have to find out how much memory your program requires during its
  run.  Watch out: The memory allocation mechanism from the Lattice C
  library (malloc and the like) all work in the heap that is _memneed
  bytes large. As soon as your program requests more than _memneed it
  will break. Hence you must know how much heap space your program will
  need.

  You will need a malloc that allows you to request memory from the
  system, not a malloc that gives yu a chuck from a pool that was
  requested from the system during program startup. Such a malloc would
  request blocks from GemDos using trap#1 call Malloc of about 16
  kbytes. (If you request 10 bytes a time using Malloc from GemDos the
  40 folder bug will turn out to be a 2 folder bug).

  If you want I could post a primitive set of memory allocation
  routines that work on 520's 1040' and Mega4's


  Newsgroups: comp.sys.atari.st
  From: [email protected] (Jim Kaubisch)
  Date: Thu, 20-Aug-87 20:15:12 EDT
  Subject: Re: Pexec cookbook! (w/ Lattice C)

   [ discussion about memory allocation ]

  >    Does anybody know exactly how I do this using Lattice C?  The
  documentation
  > (for version 3.04) is less than clear on this point, and everything
  I've
  > tried hasn't worked.  I have never really *needed* to give the extra
  700K
  > or so of memory back, but the sheer wastefulness of it annoys me
  (:-), and
  > someday I may want to use that memory.  I'd appreciate any pointers
  on the
  > subject.

  I've been trying to figure this out for some time. I'm trying to get
  the Lattice compiler and programs it generates to run under the
  Beckemeyer MT-C shell. Because of Lattice's "taking all memory"
  approach, all Lattice progs crash the shell. I haven't been able to
  get around it. My current efforts are in the area of trying to build
  an alternate STARTUP.BIN.  My fall-back position is to throw away
  Lattice C.

  >    And while I'm asking advice on Lattice C, is there any special
  startup
  > module needed to link a program used as a desk accessory, as there
  > (apparently) is with other C's?

  You do need a special startup module. The latest version of Lattice
  supposedly includes one.

  ----------------
  Jim Kaubisch,              ----=----  ACSnet: [email protected]
  Austec International Ltd,  ---===---  UUCP: ...!munnari!ausmelb.oz!whk

  344 St Kilda Rd,           --== ==--  ARPA: whk%ausmelb.oz.au
  Melbourne 3004 AUSTRALIA   -=== ===-  Phone: +61 3 699 4511
  --
  Jim Kaubisch,              ----=----  ACSnet: [email protected]
  Austec International Ltd,  ---===---  UUCP: ...!munnari!ausmelb.oz!whk

  344 St Kilda Rd,           --== ==--  ARPA: whk%ausmelb.oz.au
  Melbourne 3004 AUSTRALIA   -=== ===-  Phone: +61 3 699 4511
  D


  Newsgroups: comp.sys.atari.st
  From: [email protected] (Robert Hamilton)
  Date: Mon, 24-Aug-87 10:10:07 EDT
  Subject: Re: Pexec cookbook! (w/ Lattice C)

  In article <[email protected]> [email protected] (Jim Kaubisch)
  writes:

  > [ discussion about memory allocation ]

  >>    Does anybody know exactly how I do this using Lattice C?  The
  documentation
  >> (for version 3.04) is less than clear on this point, and everything
  I've
  >> tried hasn't worked.  I have never really *needed* to give the
  extra 700K
  >> or so of memory back, but the sheer wastefulness of it annoys me
  (:-), and
  >> someday I may want to use that memory.  I'd appreciate any pointers
  on the
  >> subject.

  I don't see the problem here... Cant you just set _mneed as described
  in the manual???

  In fact I'm writing after trying out the latest version of lattice
  3.04 Its very strange indeed. Most of the old lattice bugs have been
  fixed (20 file bug, redirection problem, malloc etc) and the debugger
  is very usable (macros already!)

  But I find that very often the linker crashes out !!  Its not
  consistent either sometimes a bus, sometimes an address error.

  But the resultant prog is invariably ok!
  Trying a link with the old linker reports an "internal phase error"
  Very puzzling. Anybody come across this?
  --
  JANET:  [email protected]            | Computing Science
  EMAIL:  [email protected]            | Paisley College
  UUCP:   ...!seismo!mcvax!ukc!paisley!rh | High St., Paisley
  Phone:  +44 41 887 1241 Ext. 219        | Scotland , PA12BE


  Newsgroups: comp.sys.atari.st
  From: [email protected] (John R. Bane)
  Date: Tue, 25-Aug-87 12:30:54 EDT
  Subject: Re: Pexec cookbook! (w/ Lattice C)

  In article <[email protected]>, [email protected] (Robert
  Hamilton) writes:
  > But I find that very often the linker crashes out !!
  > Its not consistent either sometimes a bus, sometimes an address
  error.
  > But the resultant prog is invariably ok!

  The Lattice linker always crashes on me when I link more than one
  .BIN file (i.e., whenever I link any significant system).  Programs
  with only one object module link OK, and even if the linker crashes,
  the link succeeds; it produces a .PRG file that runs fine.  --
          Rene P.S. Bane [email protected] ...!parcvax!bane.UUCP