Board index » delphi » Exec 'ing another prog {M} directive

Exec 'ing another prog {M} directive

Hi!
I have a large program that uses almost all the heap in which to
operate.  However I wish to append an EXEC command at the end of this
program and I want advice as to the correct {M} settings.

AFTER the first program has run I DISPOSE of the memory set aside for my
Tables and Collections. Presumably, because the main program has run and
been closed down I can swap *ALL* the heap to the child program (which
is what I want to do) ...... but what {M} settings should I put in the
parent program ?  How can I discover what heapmax is for the parent
program so that I can swap as much as possible.  Presumably heapmin is
0, or is it?

If someone could advise me I would be most obliged.

Happy Christmas to you all!
regards, John.
--
John Matthews

 

Re:Exec 'ing another prog {M} directive


In article <1yQrKCA8gog2E...@johnmatthews.demon.co.uk>,
John Matthews  <J...@johnmatthews.demon.co.uk> wrote:

Quote
>Hi!
>I have a large program that uses almost all the heap in which to
>operate.  However I wish to append an EXEC command at the end of this
>program and I want advice as to the correct {M} settings.

Use this, it swaps the heap and most of the stack to XMS or disk. After
that you can just do "Shell(command_line);" and not to worry about
memory.

Unit Xheap;

Interface

uses dos;

{$ifdef msdos }

{if protected mode one just provides push and shell(). The swapping is
 automatic in PM }

type string128=string[128];

procedure exec(const com,par:string128);
Function MaxProg:word;  { kilobytes }

Const Swapstack{:boolean}=true;    { Change if you wish }
      UseXMS{:boolean}=true;       { Swap to XMS }
      XmsInts{:boolean}=true;      { Use XMS for interrupts }
      Usedisk{:boolean}=true;      { Swap to disk (c:\) }

{$endif}

const Enough:word=736;             { Don't swap to disk is there is enough }
                                   { memory (KB) available }

{Note value 736 means swap always to disk. 0 means never. This has nothing
 to do with XMS swapping }

Const freeenv:word=300; { amount of free environment for shell/push }

Procedure Shell(const st:string);
Procedure Push;

Const errorcode=233;  { uses codes 233-236}

{ Logic of the swapping is:

Is there enough XMS to Swap the heap (and part of the stack)?
If there is then write the heap to the XMS
else
  if DiskUse is Disabled then Use What XMS one can get
  else
    Is if there "enough" (see above) free without swapping?
    if there is then do not swap, just use unused part of the heap
    else
      is there enough space to write the heap to disk
      if there is then write it to disk
      else do not swap
Is there enough XMS (1KB) to store the interrupts?
if there is use XMS for ints
else
  use conventional memory for ints
  if there is not enough free, set doserror=8 and do not exec()

Note:

  When one swaps to disk one always swaps all or nothing.
  If disk use is enabled (as it is normally) one does not swap
  partial heap to XMS. Interrupts are stored either to XMS or base
  memory, never to disk.

  The file is stored in the root of C-drive. The file name is in form of
  xheapX.swp where X is 0..999. If you reboot or power down while the
  program called with exec() is running the temporary file will be left to
  disk until manually deleted. You may put:

  if exist c:\xheap*.swp del c:\xheap*.swp >nul

  in your autoexec.bat to avoid that.

  Any attempt to tamper with the temporary file while the program called
  with exec() is running can cause a crash or any other unpleasant result.
  Just do not do it.

Memory map:

                          SS:0 SP      HO        HP           HE
                            v   v      v         v            v
     |--|--------------|----|-----|----|----------------------|
     PSP Code segments  Data Stack Over  Heap
                                   lay

SP: Stack pointer (CPU register)
HO: HeapOrg
HP: HeapPtr
HE: HeapEnd (typically at 640K)

If SP is large (>1500)

  1) Move SP to 1500
  2) write the memory between old SP and Heapptr to XMS/Disk:

                                orig
                             SP SP     HO        HP           HE
                             v  v      v         v            v
     |--|--------------|----|---XX|XXXX|XXXXXXXXXX------------|
     PSP Code segments  Data Stack Over Heap
                                   lay

Free memory after SP for the program to be executed:

                             SP
                             v
     |--|--------------|----|-|
     PSP Code segments  Data Stack

If SP is small (<1500)

   write the memory between SP and Heapptr to XMS/Disk:

                             SP        HO        HP           HE
                             v         v         v            v
     |--|--------------|----|-XXXX|XXXX|XXXXXXXXXX------------|
     PSP Code segments  Data Stack Ovl  Heap

Interrupt vectors are stored either on XMS or right after SP:

                             SP
                             v
     |--|--------------|----|-III|
     PSP  Code segments Data Stack Ovl  Heap

Note bytes in the unused parts of stack or heap change their values.

Interrupt vectors are saved so that possible TSRs can be unloaded
safely.

Quote
}

Implementation

{$ifdef msdos}

const spmin=1500;

{-------------------------- XMS routines -----------------------}

Var Handle:word;
    intHandle:word;
    xmsentry:pointer;

Procedure GetXMSentry; assembler;
             asm
             xor ax,ax
             mov word ptr xmsentry,ax
             mov word ptr xmsentry+2,ax

             mov ax,4300h
             int 2fh
             cmp al,80h
             jne @out
             mov ax,4310h
             int 2fh
             mov word ptr xmsentry,bx
             mov word ptr xmsentry+2,es
      @out:
             end;

Function FreeXms:word; assembler;
         asm
         mov ax,word ptr xmsentry
         or ax,word ptr xmsentry+2
         jz @out
         mov ah,8
         call xmsentry
@out:
         End;

Function XInit(Kb:word;var handle:word):byte; assembler;
         asm
         mov ax,word ptr xmsentry
         or ax,word ptr xmsentry+2
         mov al,255
         jz @out
         mov dx,kb
         mov ah,9
         call XmsEntry
         cmp ax,1
         mov al,bl
         jne @out
         xor al,al
         les di,handle
         mov es:[di],dx
  @out:
         end;

Procedure XWrite(handle:word;p:pointer; count:longint);
type  emm=record
            count:longint;
            zero:word;
            P:pointer;
            handle:word;
            Pos:longint;
          End;
const e:emm=(count:0;zero:0;p:nil;handle:0;pos:0);
begin
  e.count:=count;
  e.p:=p;
  e.handle:=handle;
  asm
   mov ah,$b
   mov si,offset e
   call XmsEntry
  end;
End;

Procedure XRead(handle:word;p:pointer; count:longint);
type  emm=record
            count:longint;
            handle:word;
            Pos:longint;
            zero:word;
            P:pointer;
          End;
const e:emm=(count:0;handle:0;pos:0;zero:0;p:nil);
begin
  e.count:=count;
  e.p:=p;
  e.handle:=handle;
  asm
   mov ah,$b
   mov si,offset e
   call XmsEntry
  end;
End;

procedure XDone(handle:word); assembler;
  asm
  mov dx,handle
  mov ah,$a
  call xmsentry
  end;

{-----------------------  End XMS routines ----------------------- }

var xmsinuse:boolean;
    ints:word;   { segment address }

Type Words=Record
             lo,hi:Word;
           End;

     pp=^longint;

Function p2i(p:pointer):longint; assembler;
         asm
         mov ax,word ptr p+2
         mov dx,ax
         {$ifopt g+}
         shl ax,4
         shr dx,12
         {$else}
         mov cl,4;  shl ax,cl
         mov cl,12; shl dx,cl
         {$endif}
         add ax,word ptr p
         adc dx,0
         end;

function i2p(i:longint):pointer; assembler;
         asm
         mov ax,word ptr i
         mov dx,word ptr i+2
         mov bx,ax
         {$ifopt g+}
         shl dx,12
         shr bx,4
         {$else}
         mov cl,12; shl dx,cl
         mov cl,4;  shr bx,cl
         {$endif}
         and ax,15
         add dx,bx
         end;

{ ------------------------ File IO routines ----------------------- }

var fname:string[14];

{$i-}
Procedure Fwrite(p:pointer; len:longint);
var fp:file;
    i:integer;
const bsize=63*1024;
begin
  assign(fp,fname);
  rewrite(fp,1);
  while len>bsize do begin
    blockwrite(fp,p^,bsize);
    dec(len,bsize);
    inc(words(p).hi,bsize shr 4);
  End;
  blockwrite(fp,p^,len);
  close(fp);
  i:=ioresult;
  if i>0 then begin
     erase(fp);
     inoutres:=i;
  End;

End;

{$i+}

Procedure Fread(p:pointer; len:longint);
var fp:file;
const bsize=63*1024;
begin
  assign(fp,fname);
  reset(fp,1);
  while len>bsize do begin
    blockread(fp,p^,bsize);
    dec(len,bsize);
    inc(words(p).hi,bsize shr 4);
  End;
  blockread(fp,p^,len);
  close(fp);
  erase(fp);
End;

Procedure GetTempName;
var rg:registers;
    s:string[14];
    i:0..1000;
    fp:file;
const first:word=0;
begin
  {$i-}
  i:=first;
  repeat
    str(i,s);
    s:='c:\xheap'+s+'.swp';
    assign(fp,s);
    reset(fp,1);
    close(fp);
    inc(i);
  until (i>=1000) or (ioresult<>0);
  if i>=1000 then fname:='..error'
             else fname:=s;
  first:=i-1;
  {$i+}
end;

{----------------------------------------------------------------}

var startptr:pointer;  { Start of the area swappted to XMS }
    len:longint;       { no of bytes in XMS }

{ Startptr: Start of the area to be written to XMS
  Endptr: End of area to be kept }

procedure HeapOut(stptr,endptr:pointer);
var rg:registers;
    fx:word;
Begin
  ints:=0;
  startptr:=stptr;

  inc(words(startptr).hi,words(startptr).lo shr 4);
  words(startptr).lo:=words(startptr).lo and 15;

  inc(words(endptr).hi,words(endptr).lo shr 4);
  words(endptr).lo:=words(endptr).lo and 15;

  len:=p2i(heapptr)-p2i(startptr);
  if usedisk then fname:='';
  if usexms and (xinit((len+1023) shr 10,handle)=0) then begin
     xwrite(handle,startptr,len);
     xmsinuse:=true;                           { Write the heap into XMS }
  End
  else begin
     if usexms then fx:=freexms;        { lets get what XMS we can get }
     if not usedisk and usexms and (fx>0) and (xinit(fx,handle)=0) then begin
        len:=longint(fx)*1024;
        startptr:=i2p(p2i(heapptr)-len);
        xwrite(handle,startptr,len);
        xmsinuse:=true;
        endptr:=startptr;
     end else begin
               {$i-}
               xmsinuse:=false;
               if usedisk and
                 (words(heapend).hi-words(heapptr).hi<enough*64+67) then
               begin
                  endPtr:=startptr;
                  Gettempname;
                  fwrite(startptr,len);
                  if ioresult<>0 then begin
                     fname:='';
...

read more »

Re:Exec 'ing another prog {M} directive


Thanks OSMO !
I wonder if I create a parent program and use XHEAP.PAS to run *all* the
child programs it is a quick and easy way of using XMS for *all* my
programs.  If this can be done, then memory difficulties in TP7 would go
forever.  Is this wishful thinking?

Happy Christmas!
regards, John

In article <75u75t$...@kruuna.Helsinki.FI>, Osmo Ronkanen
<ronka...@cc.helsinki.fi> writes

Quote

>Use this, it swaps the heap and most of the stack to XMS or disk. After
>that you can just do "Shell(command_line);" and not to worry about
>memory.

>Unit Xheap;

--
John Matthews

Re:Exec 'ing another prog {M} directive


In article <QyMiKFANE4g2E...@johnmatthews.demon.co.uk>,
John Matthews  <J...@johnmatthews.demon.co.uk> wrote:

Quote
>Thanks OSMO !
>I wonder if I create a parent program and use XHEAP.PAS to run *all* the
>child programs it is a quick and easy way of using XMS for *all* my
>programs.  If this can be done, then memory difficulties in TP7 would go
>forever.  Is this wishful thinking?

If you can break your program into such isolated units then you could
do much to break the 640K limit. Note, however, that Xheap does not swap
the actual code to XMS. There are units and external programs that can
be used for it if needed. But then one could do much the same with
overlays.

My intention was not to break the 640K barrier (I use BP for that) but
to allow heap extensive programs to use exec without need to make
compromises.

Osmo

Re:Exec 'ing another prog {M} directive


Osmo,
Lastly before we close on your XHeap.pas ......
Where do I put  USES XHeap?  Let me quickly explain.

I have come to the end of a large program that required 95% of the heap
in which to work.  I have free'ed up all the memory and I now wish to
EXEC a child program which calls a function in another unit - but it is
this function in another unit which does the SHELL(commandLineInstructio
ns).

Question:  does the USES XHeap clause go in the unit that does the
SHELL(commandLineInstructions) or in the main parent program?  I suspect
the answer is in the parent program, but if you could confirm or
otherwise I would be happier.

Kind regards,

John

In article <760ret$...@kruuna.Helsinki.FI>, Osmo Ronkanen
<ronka...@cc.helsinki.fi> writes

Quote
>My intention was not to break the 640K barrier (I use BP for that) but
>to allow heap extensive programs to use exec without need to make
>compromises.

>Osmo

--
John Matthews

Re:Exec 'ing another prog {M} directive


In article <mWIf9BAy+$g2E...@johnmatthews.demon.co.uk>,
John Matthews  <J...@johnmatthews.demon.co.uk> wrote:

Quote
>Osmo,
>Lastly before we close on your XHeap.pas ......
>Where do I put  USES XHeap?  Let me quickly explain.

In short there where you will use its services. It does not hook
any interrupts or change the behavior of existing services (like
dos.exec()).

Quote

>I have come to the end of a large program that required 95% of the heap
>in which to work.  I have free'ed up all the memory

Note that this is not necessary with Xheap, though doing so may save
the XMS needed.

Quote
>and I now wish to
>EXEC a child program which calls a function in another unit - but it is
>this function in another unit which does the SHELL(commandLineInstructio
>ns).

Then you use xheap in that unit. There is no harm in using it more than
once in a program.

Quote

>Question:  does the USES XHeap clause go in the unit that does the
>SHELL(commandLineInstructions) or in the main parent program?  I suspect
>the answer is in the parent program, but if you could confirm or
>otherwise I would be happier.

Please be careful with your terminology, program, is what is produced by
the main source file and all of the units it uses directly or
indirectly. especially when you are apparently creating a system, where
a program shells out to execute other programs you need to be careful.

In short put it where it is used. Also if you use DOS, you need to use
xheap after it or explicitly call xheap.exec(). If you only use the
Shell() and push procedures then there is no such need.

Osmo

Re:Exec 'ing another prog {M} directive


Osmo,
I don't like troubling you, but XHeap executes the child program
brilliantly and I am most impressed but the program crashes as it
(presumably) returns control to the parent. If I run my test program in
the IDE I can see that the crash is immediately after the HeapIn
Procedure .  
Thus in the Exec() procedure
     dos.exec(cm,pr);
     heapIn
     asm mov sp,spsave end; <<<<<< crash here

I am wondering if there are any settings to make?
regards, John
--
John Matthews

Re:Exec 'ing another prog {M} directive


In article <e2ghLCA6LMh2E...@johnmatthews.demon.co.uk>,
John Matthews  <J...@johnmatthews.demon.co.uk> wrote:

Quote
>Osmo,
>I don't like troubling you, but XHeap executes the child program
>brilliantly and I am most impressed but the program crashes as it
>(presumably) returns control to the parent. If I run my test program in
>the IDE I can see that the crash is immediately after the HeapIn
>Procedure .  
>Thus in the Exec() procedure
>     dos.exec(cm,pr);
>     heapIn
>     asm mov sp,spsave end; <<<<<< crash here

Well I have not had any problems, nor can I find any problem with it.
Do you have $M setting? What is it? Does it swap to disk or XMS? You
could try changing the constants at the top. For example you could turn
the stack swapping off. Set them off one at a time and report when the
problem disappears.

What is the value of Sptr in the exec() when you are calling it?

What version of TP are you using?

Do you have stack checking on???

Osmo

Re:Exec 'ing another prog {M} directive


JRS:  In article <1yQrKCA8gog2E...@johnmatthews.demon.co.uk> of Thu, 24
Dec 1998 18:30:20 in news:comp.lang.pascal.borland, John Matthews

Quote
<J...@johnmatthews.demon.co.uk> wrote:
>I have a large program that uses almost all the heap in which to
>operate.  However I wish to append an EXEC command at the end of this
>program and I want advice as to the correct {M} settings.

Depending on circumstances, another approach might be simpler.

Run your program from a batch file A, and let your program P1 write a
batch file B which is then invoked by A and itself invokes P2 which you
wanted to Exec.  This means that the program P1 is no longer in memory
when P2 runs.

  A.BAT : P1 <parameters> / B
  B.BAT : P2 <parameters>

For security, A.BAT should begin with something like
  echo rem Nothing has been written to B.BAT > B.BAT
and B.BAT *may* be able to commit suicide as it terminates.

Untested, but should be about right.

Alternatively, omit A.BAT, and get P1, as its last act, to put B<enter>
in the keyboard buffer - see TSFAQP #120, and use interrupts.

--
John Stockton, Surrey, UK.    j...@merlyn.demon.co.uk    Turnpike v4.00    MIME.
  Web <URL: http://www.merlyn.demon.co.uk/> - TP/BP/&c. FAQqish topics & links.
  Timo's TurboPascal <A HREF="ftp://garbo.uwasa.fi/pc/link/tsfaqp.zip">FAQ</A>.
  <A HREF="http://www.merlyn.demon.co.uk/clpb-faq.txt">Mini-FAQ</A> of c.l.p.b.

Re:Exec 'ing another prog {M} directive


In article <762kth$...@kruuna.Helsinki.FI>, Osmo Ronkanen
<ronka...@cc.helsinki.fi> writes
Quote
>In article <e2ghLCA6LMh2E...@johnmatthews.demon.co.uk>,
>John Matthews  <J...@johnmatthews.demon.co.uk> wrote:
>>Osmo,
>>I don't like troubling you, but XHeap executes the child program
>>brilliantly and I am most impressed but the program crashes as it
>>(presumably) returns control to the parent. If I run my test program in
>>the IDE I can see that the crash is immediately after the HeapIn

Thanks Osmo!  xHeap is working fine now.

The problem was that the Stack was being moved out, so on return to the
parent program the program crashed.  SwapStack := False and it is all
fine.

Thank you for your help.
regards, John

--
John Matthews

Re:Exec 'ing another prog {M} directive


In article <wOLq1IAWn0h2E...@johnmatthews.demon.co.uk>,
John Matthews  <J...@johnmatthews.demon.co.uk> wrote:

Quote
>In article <762kth$...@kruuna.Helsinki.FI>, Osmo Ronkanen
><ronka...@cc.helsinki.fi> writes
>>In article <e2ghLCA6LMh2E...@johnmatthews.demon.co.uk>,
>>John Matthews  <J...@johnmatthews.demon.co.uk> wrote:
>>>Osmo,
>>>I don't like troubling you, but XHeap executes the child program
>>>brilliantly and I am most impressed but the program crashes as it
>>>(presumably) returns control to the parent. If I run my test program in
>>>the IDE I can see that the crash is immediately after the HeapIn
>Thanks Osmo!  xHeap is working fine now.

>The problem was that the Stack was being moved out, so on return to the
>parent program the program crashed.  SwapStack := False and it is all
>fine.

Well it should not have c hashed. I still would like to see the details
so I can fix if there is a problem. You can E-mail me if you want.

Osmo

Other Threads