What is its significance and how it is effected in layman's terms, please?
(not sure about the "layman's term" part)
On the Amiga (and on a lot of other systems including modern ones), stack size is the number of bytes that the operating system reserves for "automatic" memory at program startup and places the stack pointer (A7/SP register) at the top of that reserved zone. There can be only one stack by process/task.
Now, if you have an assembly program, the stack is mostly going to be used for:
- storing return address when the program calls a subroutine
- storing registers at start of subroutines to preserve them so the caller of the subroutine doesn't get them trashed (unless specified)
When using compiled programs (C mainly), the stack has a more extensive usage.
- same as above but also:
- allocating memory for local variables, so the routines can be recursive/reentrant (call themselves/be called from several processes concurrently)
- parameter passing (assembly programs usually use registers, compilers use stack unless specially directives are given)
The compiler doesn't know the caller context so it "plays safe" and saves a lot of stuff. In assembly programs (generally hand written) the coder uses a lot of global variables because they know that it cannot be called recursively.
That stack management explains why compiled programs generally use more stack than assembly programs.
Native, old C/BCPL/assembly applications try not to "abuse" the stack so they can usually run with 4000 bytes (the default stack for the shell), and sometimes 8000, but not much more. The compilers are also Amiga-specific and use registers a lot more.
Ported applications (or complex applications) like Python use a lot more stack, first because they're big, and second because most of the time gcc
was used to build them because Manx/Aztec-C or SAS wasn't compatible enough. Python is probably one of them, being very demanding in the compiler area.
And the old versions of Amiga GCC weren't very good at optimizing (which isn't the case of the new GCC 10)
Shouldn't apps and system have functionality to adjust it for the best performance at any given time?
Old Kickstart versions didn't have a dedicated routine to "swap the stack" (of course it can be done manually in assembly). Post kick 1.3 OS have the StackSwap
function that does exactly this: it allocates some stack and replaces the shell stack by a bigger one. But it has to be done at startup. So a C program could crash if this was called mid-program or even at the start of the main
program, because you can't control the startup (some linkers may have an option to increase the stack size in their crt0.o
startup though.
That is a specific Amiga routine, so a ported program may not do that, and require that the stack is expanded before starting the program by using the stack
command.
But the "at any given time" is a little more problematic. Stack cannot be easily moved when the program is running, as all the callers and the stack itself may have references to stack addresses (LINK
instruction for instance).
And the OS doesn't use virtual memory/translation tables for programs, so we can't fool a program by using address translation. Not yet :)
Size can be reallocated at runtime (using the same base location) but it can also fail if the system cannot find a contiguous bigger block (even if there is plenty of memory somewhere else)
As a conclusion, Python must have been ported with a compiler that doesn't support stack reallocation or stack reallocation options weren't used in link options: you have to use
stack 100000
in the shell you're using to run the program or it will crash almost instantly by writing to memory it doesn't own. Increase if problems still persist.
(note that Windows executables headers carry the stack size information, and there's no stack
command, but Linux/Unix still have a stack
equivalent (ulimit
) so Amiga looks more like Unix than Windows on that aspect)