[comp.sys.amiga.tech] Memory allocation

armhold@topaz.rutgers.edu (George Armhold) (12/31/89)

I've a rather neophyte question for the net:

I have a program that employs a recursive routine to traverse a
directory structure on a disk.  If I have the program simply traverse
the structure and "visit" each file and directory, the program works
fine.  But when I try to copy each file I find, the program crashes the
machine, usually with a "Task held" requester.  Here is the copyfile()
function I call whenever I find a file:  


void copyfile(source, destination)
char *source, *destination;

{
int  file1, file2;	/* file descriptors */
int n;
char buf[1024];	/* buffer for data transfer */
	 
	if ((file1=open(source, O_RDONLY))==-1) 	/* open READ file */
		my_error("Error opening ", source , FATAL);
		

	if ((file2=creat(destination, S_IWRITE | S_IREAD)) <0) 	
		my_error("Error opening ", destination, FATAL);

	while ((n=read(file1, buf, BUFSIZE)) >0 )
		if (write(file2, buf, n) !=n) 
			my_error("Write error on file ", destination, FATAL);

	close(file1);
	close(file2);

}


The program crashes when it is only 2 or 3 levels deep into the
recursion (ie 2 or 3 directory levels.) If I increase the stack size to 
something like 10000 befre I run the program it works fine. My
question is, where does the memory come from when the program calls 
copyfile()?  Memory for variables comes from the stack, and
dynamically alocated memory comes from the heap?  If so, is it really
necessary to increase the stack size for simple programs such as this?

In an attempt to figure out what happens with the stack during
recursive routines, I wrote the following program:


main(argc, argv)
int argc;
char *argv[];

{ 
	foobar(1);
}

foobar(counter)
int counter;
{
	printf("%d", counter);
	if (counter<10000)	
		foobar(counter+1);
	}
}
	

When I let it run, sometimes it crashes, and sometimes I get a requester
saying "Program_foo:  Stack overflow".  Is Lattice inserting this into
my code when it compiles?  And why does it only work SOMETIMES??  

Finally, can anyone recommend a good book for learning to program the
Amiga in C?  I ordered "Programmers Guide to the Amiga" by Rob Peck
which I should get my hands on shortly.  Any and all help much
appreciated!

-George

a464@mindlink.UUCP (Bruce Dawson) (12/31/89)

     The stack is _not_ used as the heap on the Amiga.  Local variables,
including arrays are allocated on the stack.  mallocs, AllocMem()s etc. are
allocated out of the free memory 'heap', which includes all memory that has not
already been allocated.  Since stack memory has already been allocated, it
won't be used by one of these calls.  However, since the example program was
declaring an array on the stack, it would indeed chew up stack space at an
enormous rate.

.Bruce.

caw@jolnet.ORPK.IL.US (Chris Wichura) (12/31/89)

Every time a routine is called it will use the stack.  The return address
gets pushed on and then most coimpilers will use a LINK command to get
a local frame to store variables in.  Thus, your copyfile() routine will
eat up well over 1024 bytes from the stack when it is called as you have
the buffer set at that size.  On the amiga the stack is usually used as
the heap as well.
 
So there are two things you can do to help your program be less of a
stack-o-hollic:
 
1)  Instead of using the char buf[1024] use a char *buf and call your
    favorite memory alloc routine (ArpAlloc(), AllocMem(), malloc(), etc)
    to get the storage for the buffer and then free the memory after the
    copy file routine is done.  This will drastically reduce the amount
    of stack space your copyfile routine needs.
 
2)  If you can get around using a recursive function then by all means so
    so.  I had a routine that scanned a dir and did various things that
    needed a stack of 30k to work with my HD (I have some rather sever
    levels of directory depth in some places...).  I re-wrote the routine
    inside a big for(;;) {} loop adding a couple of variables to make it
    `think' it was recursive and now the same program will work just dandy
    with a 4000 byte stack (the AmigaDOS default).
 
Idea two usually tends to be a fair amount trickier than the first one :-)
-- 
Christopher A. Wichura
u12401 @ uicvm.uic.edu  (my home account)
caw @ jolnet.UUCP       (my Usenet feed)

groo@dsoft.UUCP (Bill Squier) (01/02/90)

In article <Dec.30.13.09.02.1989.28450@topaz.rutgers.edu>
armhold@topaz.rutgers.edu (George Armhold) writes:
]
]I've a rather neophyte question for the net:
]
]I have a program that employs a recursive routine to traverse a
]directory structure on a disk.
] [stuff deleted] 
]Here is the copyfile() function I call whenever I find a file:  
]
]
]void copyfile(source, destination)
]char *source, *destination;
]
]{
]int  file1, file2;	/* file descriptors */
]int n;
]char buf[1024];	/* buffer for data transfer */
]	 
] [ rest of code deleted... ]
]
]The program crashes when it is only 2 or 3 levels deep into the
]recursion (ie 2 or 3 directory levels.)
] [ more creative deleting... ]

As was already mentioned, auto class variables created within functions
are always allocated off the stack.  The two previous suggestions for
fixing this are valid, but it's my personal preference to declare
buffers (such as your buf[1024]) as external variables.  To do this, you
would declare it outside all functions.  I prefer to put my global
variables near the functions that use them.  For example:

char buf[1024];
void copyfile(source,dest) /* ... */

This avoids a new copy of ``buf'' being generated each time you call
copyfile().

]Finally, can anyone recommend a good book for learning to program the
]Amiga in C?  I ordered "Programmers Guide to the Amiga" by Rob Peck
]which I should get my hands on shortly.  Any and all help much
]appreciated!
]
]-George

The book you mention above is a good one, but you may also want to try
"Programming in C" by Stephen Kochan, now in its second edition, I
believe.  This book will also teach you more about 'C' in general, such
as recursion, and how different types of variables are stored.
-- 
Bill Squier - Stevens Inst. of Tech  |   //  "Only Amiga makes it possible"
Bitnet: u93_wsquier@stevens          | \X/
Internet: u93_wsquier@vaxc.stevens-tech.edu
Temporary Inet (Please use until Jan. 13):  ...uunet!tronsbox!dsoft!groo

walker@sas.UUCP (Doug Walker) (01/02/90)

In article <2617@jolnet.ORPK.IL.US> caw@jolnet.UUCP (Chris Wichura) writes:
>1)  Instead of using the char buf[1024] use a char *buf and call your
>    favorite memory alloc routine (ArpAlloc(), AllocMem(), malloc(), etc)
>    to get the storage for the buffer and then free the memory after the
>    copy file routine is done.  This will drastically reduce the amount
>    of stack space your copyfile routine needs.

Or, much simpler, just declare the buffer to be global (declare it outside
the scope of the function, or put the 'static' keyword on it).  Since you
only need the buffer during the scope of the routine, this will work for
your case.  If you really needed a new buffer for each invocation of
the routine, you would have to allocate and free each call, but in your
case you don't.

  *****
=*|_o_o|\\=====Doug Walker, Software Distiller=======================
 *|. o.| ||
  | o  |//     "READY!   FIRE!   AIM!   (Software under development!)
  ======
usenet: ...mcnc!rti!sas!walker   plink: dwalker  bix: djwalker 

duncant@mbunix.mitre.org (Thomson) (01/12/90)

Regarding the problem of stack usage with recursive functions, note that it
is possible to use static allocation of data structures with recursive 
functions, as long as the usage of the data structure does not span a recur-
sive call.

In the copyfile() example under consideration, it would appear to be safe to
allocate buff[ ... ] outside the function.  This would solve your stack 
overflow problems without any major code changes.

Duncan Thomson

P.S. I think the best book for learning C programming, on the Amiga as
well as on any other system, is the Kernighan and Ritchie classic, "The
C Programming Language."