Wimpslot extension code

Alex Waugh alex at alexwaugh.com
Mon Feb 17 15:11:09 PST 2003


For anyone who's interested, attached is the first part of the wimpslot
extension code. malloc and the stack behave as before, until they run
out of space. Any further allocations cause the wimpslot to be
extended. Thus the heaps may become non-contiguous. If the program is a
child program then it can expand the wimpslot above the parent, leaving
the parent where it is. Any attempt to run a second child will probably
fail as it won't be able to move the parent out of the way, but this is
better than the current situation where it would probably have run out
of memory before it got to this point. It seems to work quite well for
gcc though, provided the initial wimpslot is 3meg or so as the bit that
needs all the extra memory is cc1 which doesn't call any children.

However, it's not ready for commiting yet as there appears to be a bug
that I'm having trouble tracking down. When compiling one particular
source file with gcc using the new code, it causes a segfault in
free(). I've only ever seen it fail on that one file, others are fine
and my test programs are fine :-(
If anyone can spot anything wrong or sees similar problems with it,
please let me know.

Alex

-- 
Alex Waugh                                           alex at alexwaugh.com

PHP, Roots, Subversion, WebJames and more from http://www.alexwaugh.com/
-------------- next part --------------
Index: unixlib/source/alloc.c
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/alloc.c,v
retrieving revision 1.5
diff -u -r1.5 alloc.c
--- unixlib/source/alloc.c	15 Dec 2002 13:16:55 -0000	1.5
+++ unixlib/source/alloc.c	10 Feb 2003 23:20:22 -0000
@@ -870,6 +870,10 @@
 extern Void_t*     sbrk();
 #endif
 
+#ifdef __riscos
+#define MORECORE __internal_sbrk
+#endif
+
 #ifndef MORECORE
 #define MORECORE sbrk
 #endif
Index: unixlib/source/clib/unistd.h
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/clib/unistd.h,v
retrieving revision 1.5
diff -u -r1.5 unistd.h
--- unixlib/source/clib/unistd.h	29 Jan 2003 18:46:02 -0000	1.5
+++ unixlib/source/clib/unistd.h	10 Feb 2003 23:20:23 -0000
@@ -434,8 +434,12 @@
 
 /* BSD extensions.  */
 
-extern int brk (void *__addr);
-extern void *sbrk (int __incr);
+extern int brk (void *__addr) __attribute__ ((deprecated));
+extern void *sbrk (int __incr) __attribute__ ((deprecated));
+
+#ifdef __UNIXLIB_INTERNALS
+extern void *__internal_sbrk (int __incr);
+#endif
 
 /* Put the name of the current host in no more than len bytes of name.  */
 extern int gethostname (char *__name, size_t __len);
Index: unixlib/source/clib/unixlib/asm_dec.s
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/clib/unixlib/asm_dec.s,v
retrieving revision 1.5
diff -u -r1.5 asm_dec.s
--- unixlib/source/clib/unixlib/asm_dec.s	22 Dec 2002 18:22:28 -0000	1.5
+++ unixlib/source/clib/unixlib/asm_dec.s	10 Feb 2003 23:20:23 -0000
@@ -19,8 +19,6 @@
 PARANOID	EQU	0
 ; Use dynamic areas for heap on RISC OS 3.5+
 DYNAMIC_AREA	EQU	1
-; Align things to 4K boundaries for exec
-|__4K_BOUNDARY|	EQU	0
 ; Emulate the SWP instruction for ARM2 compatibility
 |__SWP_ARM2|	EQU	0
 
@@ -478,6 +476,7 @@
 
 XTaskWindow_TaskInfo		EQU	&043380 + X_Bit
 XWimp_ReadSysInfo		EQU	&0400F2 + X_Bit
+XWimp_SlotSize			EQU	&0400EC + X_Bit
 XDDEUtils_SetCLSize		EQU	&042581 + X_Bit
 
 XSharedUnixLibrary_RegisterUpCall	EQU	&55c80 + X_Bit
Index: unixlib/source/clib/unixlib/features.h
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/clib/unixlib/features.h,v
retrieving revision 1.6
diff -u -r1.6 features.h
--- unixlib/source/clib/unixlib/features.h	22 Dec 2002 18:22:28 -0000	1.6
+++ unixlib/source/clib/unixlib/features.h	10 Feb 2003 23:20:24 -0000
@@ -552,8 +552,8 @@
 #define __DYNAMIC_AREA 1
 #endif
 
-/* Align the stack on a 4K boundary.  */
-#undef __4K_BOUNDARY
+/* Amount to align the wimpslot or dynamic area. */
+#define __DA_WIMPSLOT_ALIGNMENT (32*1024-1)
 
 #undef __USEFILEPATH
 
Index: unixlib/source/clib/unixlib/unix.h
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/clib/unixlib/unix.h,v
retrieving revision 1.4
diff -u -r1.4 unix.h
--- unixlib/source/clib/unixlib/unix.h	15 Dec 2002 13:16:55 -0000	1.4
+++ unixlib/source/clib/unixlib/unix.h	10 Feb 2003 23:20:24 -0000
@@ -161,6 +161,7 @@
 extern void *__base;		/* BASE = Image$$RO$$Base */
 extern void *__lomem;		/* LOMEM = Image$$RW$$Limit */
 extern void *__himem;		/* HIMEM from OS_GetEnv */
+extern void *__real_himem;	/* Real HIMEM  - application space limit */
 extern void *__rwlimit;
 
 extern void *__break;		/* end of data area */
@@ -299,6 +300,7 @@
 extern void __stackfree (void *__ptr);
 extern int __stackalloc_trim (void);
 extern void __free_stack_chain (void *__ptr);
+extern void *__stackalloc_incr_wimpslot (int __incr);
 
 /* Initialise the UnixLib world.  */
 void __unixinit (void);
Index: unixlib/source/resource/initialise.c
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/resource/initialise.c,v
retrieving revision 1.3
diff -u -r1.3 initialise.c
--- unixlib/source/resource/initialise.c	14 Feb 2002 15:56:36 -0000	1.3
+++ unixlib/source/resource/initialise.c	10 Feb 2003 23:20:25 -0000
@@ -28,6 +28,7 @@
 __resource_initialise (struct proc *p)
 {
   int regs[10];
+  int max_wimpslot;
 
   /* The maximum amount of cpu time the process can use.  */
   p->limit[RLIMIT_CPU].rlim_cur = RLIM_INFINITY;
@@ -41,20 +42,21 @@
   p->limit[RLIMIT_CORE].rlim_cur = RLIM_INFINITY;
   p->limit[RLIMIT_CORE].rlim_max = RLIM_INFINITY;
 
-  /* The maximum size of data memory for the process.
-     Reference src.sys.c.brk for a clear example.
+  regs[0] = -1;
+  if (__os_swi (OS_ReadDynamicArea, regs))
+    /* If the call failed then it's probably because we are on
+       RISC OS < 3.5 so we know it can't be more than 16MB */
+    max_wimpslot = 16*1024*1024;
+  else
+    max_wimpslot = regs[2];
 
-     This should be the same for both cases of dynamic area or not.
-     Data area should lie between __lomem and __break. However, __break
-     can gradually grow as more memory is requested. For non dynamic
-     areas, the data area can lie between __lomem and __stack (yes
-     __stack can become less, but stack checking accounts for this).
+  /* The maximum size of data memory for the process.
 
      For dynamic areas the limit is current available memory size or
      the limit imposed by any virtual memory system such as Virtualise.  */
 
   if (__dynamic_num == -1)	/* No dynamic area */
-    p->limit[RLIMIT_DATA].rlim_max = (u_char *) __stack - (u_char *) __lomem;
+    p->limit[RLIMIT_DATA].rlim_max = max_wimpslot;
   else
     {
       regs[0] = __dynamic_num;
@@ -66,11 +68,9 @@
   p->limit[RLIMIT_DATA].rlim_cur = p->limit[RLIMIT_DATA].rlim_max;
 
 
-  /* The maximum stack size for the process. This lies between
-     __himem and __stack_limit.  */
-  p->limit[RLIMIT_STACK].rlim_max = (u_char *) __himem - (u_char *) __stack_limit;
-  /* Maximum (soft limit) stack size for the process lies between __stack
-     and __himem.  */
+  /* The maximum stack size for the process. As the stack is extensible then
+     it can grow up to the maximum wimpslot size */
+  p->limit[RLIMIT_STACK].rlim_max = max_wimpslot;
   p->limit[RLIMIT_STACK].rlim_cur = p->limit[RLIMIT_STACK].rlim_max;
 
 
@@ -85,7 +85,7 @@
      and beyond for dynamic areas.  */
   if (__dynamic_num == -1)	/* No dynamic area */
     {
-      p->limit[RLIMIT_RSS].rlim_max = (u_char *) __himem - (u_char *) __base;
+      p->limit[RLIMIT_RSS].rlim_max = max_wimpslot;
       p->limit[RLIMIT_RSS].rlim_cur = p->limit[RLIMIT_RSS].rlim_max;
     }
   else
Index: unixlib/source/sys/_exec.s
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/sys/_exec.s,v
retrieving revision 1.2
diff -u -r1.2 _exec.s
--- unixlib/source/sys/_exec.s	29 Jan 2001 15:10:21 -0000	1.2
+++ unixlib/source/sys/_exec.s	10 Feb 2003 23:20:25 -0000
@@ -102,13 +102,6 @@
 	EOR	v4,v2,v2,ROR #7
 	EOR	v6,v2,v2,ROR #13
 	EOR	ip,v2,v2,ROR #23
-	[ |__4K_BOUNDARY| = 1
-	; align top of wimpslot to 4k (downwards)
-	SUB	a3,a3,#32
-	BIC	a3,a3,#&ff
-	BIC	a3,a3,#&f00
-	ADD	a3,a3,#32
-	]
 	STMDB	a3!,{a4,v2,v3,v4,v5,v6,sl,ip}
 
 	; Set memory limit for new application.  Prevent it from writing
@@ -269,10 +262,6 @@
 	DCD	|__exec_s0|
 	EXPORT	|__exlen|
 |__exlen|
-	[ |__4K_BOUNDARY| = 1
-	DCD	(|__exec_s7|-|__exec_s0| + 4095) :AND: -4096
-	|
 	DCD	|__exec_s7|-|__exec_s0|
-	]
 
 	END
Index: unixlib/source/sys/_syslib.s
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/sys/_syslib.s,v
retrieving revision 1.11
diff -u -r1.11 _syslib.s
--- unixlib/source/sys/_syslib.s	5 Jan 2003 12:36:35 -0000	1.11
+++ unixlib/source/sys/_syslib.s	10 Feb 2003 23:20:26 -0000
@@ -93,12 +93,6 @@
 	;   a3 = pointer to real time the program was started (5 bytes)
 	SWI	XOS_GetEnv
 
-	[ |__4K_BOUNDARY| = 1
-	; align top of wimpslot to 4k (downwards)
-	BIC	a2, a2, #&ff
-	BIC	a2, a2, #&f00
-	]
-
 	; struct_base is the start of our memory environment variables
 	; See the end of this file.  For the initialisation here, we
 	; will always use ip as the base register.
@@ -111,20 +105,17 @@
 	STR	a1, [ip, #8]	; __time (low word)
 	STR	a2, [ip, #12]	; __time (high word)
 
+	MOV	a1, #14	; Read appspace value
+	MOV	a2, #0
+	MOV	a3, #0
+	SWI	XOS_ChangeEnvironment
+	STR	a2, [ip, #72]	; Default value of __real_himem is the size of application space
+
 	; For a description of the memory layout of a UnixLib application
 	; see sys/brk.c.
 	LDR	a1, [ip, #20]	; __robase
 	LDR	a2, [ip, #24]	; __rwlimit
 
-	[ |__4K_BOUNDARY| = 1
-	; align rwlimit to 4Kbyte boundary
-	ADD	a2, a2, #&1000
-	SUB	a2, a2, #1
-	BIC	a2, a2, #&ff
-	BIC	a2, a2, #&f00
-	STR	a2, [ip, #24]	; __rwlimit
-	]
-
 	STR	a1, [ip, #28]	; __base = __robase
 	STR	a2, [ip, #32]	; __lomem = __rwlimit
 	STR	a2, [ip, #36]	; __break = __rwlimit
@@ -138,11 +129,14 @@
 	; execute in stack space.
 
 	LDR	sp, [ip, #4]	; __himem
+	; 8 bytes are needed above the initial chunk
+	; for the stackalloc heap
+	SUB	sp, sp, #8
 	SUB	a1, sp, #4096
 	ADD	sl, a1, #512 + CHUNK_OVERHEAD
 
 	SUB	a3, a1, #8
-	; __stackalloc_init needs a minimum of 8 bytes more than the initial
+	; __stackalloc_init needs a minimum of 8 bytes below the initial
 	; chunk for its heap - check this doesn't overlap the code section
 	STR	a3, [ip, #16]	; __stack = bottom of stack
 	CMP	a3, a2
@@ -176,10 +170,10 @@
 
 	MOV	ip, v1		; Restore ip.
 
-	;LDR	a1, =|rmensure|
-	;SWI	XOS_CLI
-	;MOVVS	a1, #NO_SUL
-	;BVS	exit_with_error
+	LDR	a1, =|rmensure|
+	SWI	XOS_CLI
+	MOVVS	a1, #NO_SUL
+	BVS	exit_with_error
 
 	; use of da's explicitly overridden if __dynamic_no_da is declared
 	LDR	a1, =|__dynamic_no_da|
@@ -197,12 +191,10 @@
 
 	; use old dynamic area if possible
 	; if app mem size = mem size, then can't be a spawned program
-	MOV	a1, #14
-	MOVS	a2, #0			; Ensure Z flag set
-	SWI	XOS_ChangeEnvironment	; preserves Z
-	LDRVC	a1, [ip, #4]		; top of our app space at __himem
-	CMPVC	a2, a1			; only make check if SWI succeeds
-	BEQ	no_old_area		; B if eq or SWI failed
+	LDR	a1, [ip, #4]	; __himem
+	LDR	a2, [ip, #72]	; __real_himem
+	CMP	a2, a1
+	BEQ	no_old_area
 	; validate numbers at top of application memory (see sys.s._exec)
 	LDMIA	a1, {a1, a2, a3, a4, v1, v2, v3, v4}
 	EOR	a3, a3, a1, ROR #7
@@ -351,11 +343,6 @@
 	MOVVC	a1, #1
 	STR	a1, [ip, #52]	; __fpflag
 
-	; Initialise the stack heap in application space
-	MOV	v1, ip	; Preserve ip
-	BL	|__stackalloc_init|
-	MOV	ip, v1
-
 	; Now we'll initialise the C library, then call the user program.
 
 	; Check the environment variable UnixLib$env.  If set, then
@@ -380,6 +367,8 @@
 	BL	|__env_read|
 	; Install the Unixlib environment handlers
 	BL	|__env_unixlib|
+	; Initialise the stack heap in application space
+	BL	|__stackalloc_init|
 	; Initialise the UnixLib library
 	BL	|__unixinit|
 	; Run the users program.
@@ -442,6 +431,7 @@
 |__exit|
 	MOV	v1, a1
 	BL	|__dynamic_area_exit|
+	BL	|__env_riscos_and_wimpslot|
 	LDR	a3, =|__sharedunixlibrary_key|
 	LDR	a3, [a3]
 	SWI	XSharedUnixLibrary_DeRegisterUpCall
@@ -462,6 +452,7 @@
 	NAME	__exit_no_code
 |__exit_no_code|
 	BL	|__dynamic_area_exit|
+	BL	|__env_riscos_and_wimpslot|
 	MOV	a1, #0
 	MOV	a2, #0
 	MOV	a3, #0
@@ -472,20 +463,52 @@
 |___vret|
 	DCD	|__vret|
 
+	; Restore original wimpslot, appspace and himem limits, and original
+	; RISC OS environment handlers
+|__env_riscos_and_wimpslot|
+	; As we are reducing the wimpslot, the stack pointer may end up
+	; pointing to invalid memory, so we need to reset it.
+	; This will overwrite some of the original stack, but this is
+	; only called just before exiting so won't be a problem
+	LDR	a1, =|__calling_environment|
+	LDR	sp, [a1]	; Original himem value
+
+	STMFD	sp!, {v1, lr}
+	ADD	v1, a1, #14*3*4
+
+	LDR	a1, [v1]	; Original appspace value
+	SUB	a1, a1, #&8000
+	MOV	a2, #-1
+	SWI	XWimp_SlotSize
+
+	MOV	a1, #14
+	LDMIA	v1, {a2, a3, a4}
+	SWI	XOS_ChangeEnvironment
+	MOV	a1, #0
+	SUB	v1, v1, #14*3*4
+	LDMIA	v1, {a2, a3, a4}
+	SWI	XOS_ChangeEnvironment
+
+	LDMFD	sp!, {v1, lr}
+	; Fall through to __env_riscos
+
 	EXPORT	|__env_riscos|
 	; Restore original RISC OS environment handlers
 |__env_riscos|
-	STMFD	sp!, {a1, a2, a3, a4, v1, v2, lr}
+	STMFD	sp!, {v1, v2, lr}
+
 	MOV	v1, #0
 	LDR	v2, =|__calling_environment|
 t04
 	MOV	a1, v1
 	LDMIA	v2!, {a2, a3, a4}
-	SWI	XOS_ChangeEnvironment
+	CMP	a1, #0  ; Don't restore the himem limit
+	CMPNE	a1, #14 ; Don't restore the appspace limit
+	SWINE	XOS_ChangeEnvironment
 	ADD	v1, v1, #1
 	CMP	v1, #17		;  __ENVIRONMENT_HANDLERS
 	BLT	t04
-	LDMFD	sp!, {a1, a2, a3, a4, v1, v2, pc}^
+	stackreturn	AL, "v1, v2, pc"
 
 	; Get current environment handler setup
 	EXPORT	|__env_read|
@@ -529,7 +552,7 @@
 	CMP	v1, #17
 	BLT	t06
 
-	LDR	r1, =|__env_riscos|
+	LDR	r1, =|__env_riscos_and_wimpslot|
 	SWI	XSharedUnixLibrary_RegisterUpCall
 	LDR	r0, =|__sharedunixlibrary_key|
 	STR	r2, [r0]
@@ -921,7 +944,8 @@
 	EXPORT	|__wimpprogram| ; non-zero if executing as a Wimp program
 	EXPORT	|__dynamic_num|
 	EXPORT	|__u|		; pointer to proc structure
-		
+	EXPORT	|__real_himem|
+
 	; Altering this structure will require fixing __main.
 struct_base
 |__cli|		DCD	0				; offset = 0
@@ -946,5 +970,6 @@
 
 |__dynamic_num|	DCD	-1				; offset = 64
 |__u|		DCD	0				; offset = 68
+|__real_himem|	DCD	0				; offset = 72
 
 	END
Index: unixlib/source/sys/brk.c
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/sys/brk.c,v
retrieving revision 1.3
diff -u -r1.3 brk.c
--- unixlib/source/sys/brk.c	14 Feb 2002 15:56:37 -0000	1.3
+++ unixlib/source/sys/brk.c	10 Feb 2003 23:20:26 -0000
@@ -16,23 +16,26 @@
  *
  * Case 1: No dynamic area
  *
- *    +-------+-------------+         +--------+
- *    |       | heap ->     | ....... |        |
- *    +-------+-------------+         +--------+
- *    ^       ^             ^->     <-^        ^
- * __base  __rwlimit     __break   __stack  __himem
- *         __lomem       __stack_limit
+ *    +-------+-------------+         +--------+.....+
+ *    |       | heap ->     | ....... |        |     | ......
+ *    +-------+-------------+         +--------+.....+
+ *    ^       ^             ^->     <-^        ^     ^->
+ * __base  __rwlimit     __break   __stack     |  __real_himem
+ *         __lomem       __stack_limit      __himem
  *
  *
  * Case 2: Heap in dynamic area
- *                                        /
- *    +-------+          +--------+      /      +--------+.....+
- *    |       |  ....... |        |      \      | heap ->|     | ......
- *    +-------+          +--------+      /      +--------+.....+
- *    ^       ^        <-^        ^     /       ^        ^     ^->
- * __base  __rwlimit  __stack  __himem       __lomem     |  __real_break
- *         __stack_limit                              __break
+ *                                                    /
+ *    +-------+          +--------+.....+            /      +--------+.....+
+ *    |       |  ....... |        |     | ......     \      | heap ->|     | ......
+ *    +-------+          +--------+.....+            /      +--------+.....+
+ *    ^       ^        <-^        ^     ^->         /       ^        ^     ^->
+ * __base  __rwlimit  __stack     |  __real_himem        __lomem     |  __real_break
+ *         __stack_limit       __himem                            __break
  *
+ * The stack initially decends (in chunks) downto __stack_limit, then
+ * increases (in chunks) by increasing the wimpslot. If the malloc heap is
+ * also in the wimpslot then it can also cause the wimpslot to extend.
  ***************************************************************************/
 
 /* sys/brk.c: Complete rewrite by Peter Burwood, June 1997  */
@@ -62,16 +65,16 @@
 /* __real_break is the top limit of the dynamic area allocated.  */
 extern void * __real_break;
 
-int
-brk (void *addr)
+static int
+__internal_brk (void *addr, int internalcall)
 {
   addr = align (addr);
 
 #ifdef DEBUG
-  __os_print ("-- brk: addr = "); __os_prhex (addr); __os_print ("\r\n");
-  __os_print ("-- brk: __lomem = "); __os_prhex (__lomem); __os_print ("\r\n");
-  __os_print ("-- brk: __break = "); __os_prhex (__break); __os_print ("\r\n");
-  __os_print ("-- brk: __stack = "); __os_prhex (__stack); __os_print ("\r\n");
+  __os_print ("-- brk: addr = ");    __os_prhex ((int)addr);    __os_print ("\r\n");
+  __os_print ("-- brk: __lomem = "); __os_prhex ((int)__lomem); __os_print ("\r\n");
+  __os_print ("-- brk: __break = "); __os_prhex ((int)__break); __os_print ("\r\n");
+  __os_print ("-- brk: __stack = "); __os_prhex ((int)__stack); __os_print ("\r\n");
 #endif
 
   /* Check new limit isn't below minimum brk limit, i.e., __lomem.
@@ -117,7 +120,7 @@
 	  /* Align size to multiple of 32K to reduce number of expensive sbrk
 	     calls.  This is done because OS_ChangeDynamicArea can be expensive,
 	     so smaller [s]brk increments will fit inside __real_break.  */
-	  regs[1] = (regs[1] + 32767) & ~32767;
+	  regs[1] = (regs[1] + __DA_WIMPSLOT_ALIGNMENT) & ~__DA_WIMPSLOT_ALIGNMENT;
 	  if (__os_swi (OS_ChangeDynamicArea, regs))
 	    {
 #ifdef DEBUG
@@ -139,7 +142,7 @@
 	  __break = addr;
 	  regs[1] = (int) ((u_char *) __real_break - (u_char *) addr);
 	  /* Align size down to multiple of 32K */
-	  regs[1] = regs[1] & ~32767;
+	  regs[1] = regs[1] & ~__DA_WIMPSLOT_ALIGNMENT;
 	  /* Trim dynamic area by 32K multiples if enough unused memory.  */
 	  if (regs[1] > 0)
 	    {
@@ -162,17 +165,34 @@
 #ifdef DEBUG
            __os_print ("-- brk: addr > __stack\r\n");
 #endif
-	   return __set_errno (ENOMEM);
+
+           /* No space before stack, so try to increase wimpslot
+              If this is a userland call then increasing the wimpslot is
+              likely to give unexpected results so don't bother */
+           if (!internalcall || __stackalloc_incr_wimpslot((u_char *)addr - (u_char *)__himem) == 0)
+             return __set_errno (ENOMEM);
         }
-      /* Adjust stack and break limits.
+      else
+        {
+          /* Adjust stack limit.*/
+          __stack_limit = addr;
+        }
+      /* Adjust break limit.
 	 This allows +ve or -ve sbrk increments.  */
-      __stack_limit = addr;
       __real_break = __break = addr;
     }
 
   return 0;
 }
 
+int
+brk (void *addr)
+{
+  return __internal_brk (addr, 0);
+}
+
+/* External calls to sbrk can only increase __break upto __stack,
+   and cannot increase the wimplot as the stack will be in the way. */
 void *
 sbrk (int incr)
 {
@@ -182,7 +202,30 @@
   __os_print ("-- sbrk: incr = "); __os_prdec (incr); __os_print ("\r\n");
 #endif
 
-  if (incr != 0 && brk ((u_char *) oldbrk + incr) < 0)
+  if (incr != 0 && __internal_brk ((u_char *) oldbrk + incr, 0) < 0)
+    return ((void *)-1);
+
+  return (__dynamic_num == -1 && oldbrk > __stack_limit) ? __stack_limit : oldbrk;
+}
+
+/* sbrk for internal UnixLib callers (i.e. malloc) that are aware that
+   space allocated by consecutive calls may not be contiguous */
+void *
+__internal_sbrk (int incr)
+{
+  void *oldbrk;
+
+#ifdef DEBUG
+  __os_print ("-- __internal_sbrk: incr = ");
+  __os_prdec (incr); __os_print ("\r\n");
+#endif
+
+  if (__dynamic_num == -1 && ((u_char *)__break + incr > (u_char *)__stack))
+    oldbrk = __himem;
+  else
+    oldbrk = __break;
+
+  if (incr != 0 && __internal_brk ((u_char *) oldbrk + incr, 1) < 0)
     return ((void *)-1);
 
   return oldbrk;
Index: unixlib/source/sys/exec.c
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/sys/exec.c,v
retrieving revision 1.7
diff -u -r1.7 exec.c
--- unixlib/source/sys/exec.c	5 Jan 2003 12:27:55 -0000	1.7
+++ unixlib/source/sys/exec.c	10 Feb 2003 23:20:27 -0000
@@ -66,7 +66,7 @@
 __ushift (unsigned char *p, unsigned int v, unsigned int c, char *n)
 {
   void *r = (((void *)p >= __base && (void *)p < __rwlimit) ? p + c
-	     : ((void *)p >= __lomem && (void *)p < __break) ? p + v : p);
+	     : ((void *)p >= __lomem && (void *)p < __stack_limit) ? p + v : p);
   showmove ("ushift", n, p, r);
   return r;
 }
@@ -80,7 +80,7 @@
 __ushift (unsigned char *p, unsigned int v, unsigned int c)
 {
   return (((void *)p >= __base && (void *)p < __rwlimit) ? p + c
-	  : ((void *)p >= __lomem && (void *)p < __break) ? p + v : p);
+	  : ((void *)p >= __lomem && (void *)p < __stack_limit) ? p + v : p);
 }
 
 #endif
@@ -95,7 +95,7 @@
   void *q1 = p - c;
   void *q2 = p - v;
   void *r = ((q1 >= __base && q1 < __rwlimit) ? q1
-	     : (q2 >= __lomem && q2 < __break) ? q2 : p);
+	     : (q2 >= __lomem && q2 < __stack_limit) ? q2 : p);
   showmove ("dshift", n, p, r);
   return r;
 }
@@ -114,7 +114,7 @@
   /* This is only safe when 2 * maximum application space size < start of
      dynamic areas. This is not true, see PJB any real restrictions.  */
   return ((q1 >= __base && q1 < __rwlimit) ? q1
-	  : (q2 >= __lomem && q2 < __break) ? q2 : p);
+	  : (q2 >= __lomem && q2 < __stack_limit) ? q2 : p);
 }
 
 #endif
@@ -533,10 +533,6 @@
   if (((unsigned int) __base & ~0xff) == 0x8000)
     {
       __codeshift = ((char *) __stack - (char *) __stack_limit) - 512 - __exlen;
-#ifdef __4K_BOUNDARY
-      /* Align down to 4K boundary.  */
-      __codeshift = __codeshift & ~4095;
-#endif
       /* Heap might not be in a dynamic area (dynamic_num == -1).  */
       __exshift = (__dynamic_num == -1) ? __codeshift : 0;
     }
@@ -606,7 +602,7 @@
     int regs[10];
     char *address;
 
-    address = (char *) process + __exshift;
+    address = (char *) process + (process < __stack_limit ? __exshift : 0);
     regs[0] = (int) "UnixLib$env";
     regs[1] = (int) &address;
     regs[2] = 4;
@@ -631,7 +627,7 @@
     }
   if (__exshift)
     memcpy ((char *) __lomem + __exshift, (char *) __lomem,
-	    (char *) __break - (char *) __lomem);
+	    (char *) __stack_limit - (char *) __lomem);
 
   /* Finally call the program.  */
 #ifdef DEBUG
@@ -657,7 +653,7 @@
       if (__exshift)
 	memcpy ((char *) __lomem,
 		(char *) __lomem + __exshift,
-		(char *) __break - (char *) __lomem);
+		(char *) __stack_limit - (char *) __lomem);
       dshift (process->tty, variable, code);
       for (i = 0; i < MAXTTY; i++)
 	{
@@ -682,10 +678,10 @@
       process->argv = NULL;
     }
 
-  /* Read the current RISC OS environment handlers.  We probably don't need
-     to do this because they should be exactly the same as when we read them
-     at UnixLib initialisation time.  */
-  __env_read ();
+  /* We don't need to read the current RISC OS environment handlers because
+     they should be exactly the same as when we read them at UnixLib
+     initialisation time, other than the wimpslot/appspace/himem sizes which
+     we don't want to alter anyway.  */
 
   /* Install the UnixLib environment handlers.  */
   __env_unixlib ();
Index: unixlib/source/sys/stackalloc.c
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/sys/stackalloc.c,v
retrieving revision 1.1
diff -u -r1.1 stackalloc.c
--- unixlib/source/sys/stackalloc.c	15 Dec 2002 13:16:55 -0000	1.1
+++ unixlib/source/sys/stackalloc.c	10 Feb 2003 23:20:27 -0000
@@ -37,9 +37,13 @@
 #include <unixlib/unix.h>
 #include <unixlib/features.h>
 #include <pthread.h>
+#include <swis.h>
+
+/* #define DEBUG */
 
 #define BLOCK_FREE 0
 #define BLOCK_DATA_SIZE 4096
+#define DUMMY_BLOCK_SIZE 4
 
 /* This file should be compiled without stack checking, as it is not reentrant */
 #ifdef __CC_NORCROFT
@@ -65,13 +69,16 @@
 
 
 static struct block *freelist; /* Head of linked list of free blocks */
-static struct block *dummybottomblock; /* dummy block header at the top of the heap */
+static struct block *dummybottomblock; /* dummy block header at the bottom of the heap */
+static struct block *dummytopblock; /* dummy block header at the top of the heap */
+
+static void *__old_himem; /* Value of __himem last time the stack was increased */
 
 
 /* Remove a block from the freelist */
 #define REMOVE_FROM_FREELIST(remove) \
 { \
-  struct block *blocklist = freelist; \
+  struct block *blcklist = freelist; \
 \
   if (freelist == remove) \
     { \
@@ -79,11 +86,11 @@
     } \
   else \
     { \
-      while (blocklist && blocklist->contents.free.nextfreeblock != remove) \
-        blocklist = blocklist->contents.free.nextfreeblock; \
+      while (blcklist && blcklist->contents.free.nextfreeblock != remove) \
+        blcklist = blcklist->contents.free.nextfreeblock; \
 \
-      if (blocklist) \
-        blocklist->contents.free.nextfreeblock = remove->contents.free.nextfreeblock; \
+      if (blcklist) \
+        blcklist->contents.free.nextfreeblock = remove->contents.free.nextfreeblock; \
     } \
 }
 
@@ -99,30 +106,174 @@
    blocks higher in the heap will be found first, which should help reduce
    fragmentation in a multithreaded program */
 
-
-/* Increase the amount of memory allocated to the heap */
-/* Returns the new value of __stack, or NULL if unable to increase */
-static void *
-__stackalloc_incr (int incr)
+/* Increase __himem (and hence the wimpslot, if needed) by incr bytes
+   __real_himem contains the actual wimpslot size, which may be greater
+   than __himem to try to reduce the number of times the wimpslot has
+   to be increased */
+void *
+__stackalloc_incr_wimpslot (int incr)
 {
-  char *new__stack;
+  int regs[10];
+
+  if ((u_char *)__himem + incr < (u_char *)__real_himem)
+    {
+#ifdef DEBUG
+      __os_print ("-- __stackalloc_incr_wimpslot: no need to increase\r\n");
+#endif
+      __himem = (u_char *)__himem + incr;
+      return __himem;
+    }
+
+  /* Round the size up to reduce the number of calls needed to Wimp_SlotSize */
+  regs[0] = (int) (((u_char *)__himem - 0x8000) + incr +
+                   __DA_WIMPSLOT_ALIGNMENT) & ~__DA_WIMPSLOT_ALIGNMENT;
+  regs[1] = -1;
+#ifdef DEBUG
+  __os_print ("-- __stackalloc_incr_wimpslot: attempting to increase wimpslot to ");
+  __os_prhex(regs[0]); __os_print("\r\n");
+#endif
+  if (__os_swi (Wimp_SlotSize, regs))
+    {
+#ifdef DEBUG
+      __os_print ("-- __stackalloc_incr_wimpslot: cannot increase wimpslot\r\n");
+#endif
+      return NULL;
+    }
+#ifdef DEBUG
+  else
+    {
+      __os_print ("-- __stackalloc_incr_wimpslot: increased wimpslot to "); __os_prhex(regs[0]); __os_print("\r\n");
+    }
+#endif
 
+  __real_himem = (void *)(0x8000 + regs[0]);
+  if ((u_char *)__himem + incr > (u_char *)__real_himem)
+    {
 #ifdef DEBUG
-  __os_print ("-- __stackalloc_incr: incr = "); __os_prhex (incr); __os_print ("\r\n");
-  __os_print ("-- __stackalloc_incr: __stack = "); __os_prhex ((int)__stack); __os_print ("\r\n");
-  __os_print ("-- __stackalloc_incr: __stack_limit = "); __os_prhex ((int)__stack_limit); __os_print ("\r\n");
+      __os_print ("-- __stackalloc_incr_wimpslot: wimpslot not increased by enough\r\n");
 #endif
+      return NULL;
+    }
+
+  __himem = (u_char *)__himem + incr;
 
-  /* TODO: increase wimpslot if needed (won't be possible if we are a child process though) */
-  new__stack = (char *)__stack - incr;
-  if (new__stack < (char *)__stack_limit)
+  return __himem;
+}
+
+/* Try to increase the stack heap upwards */
+static struct block *
+__stackalloc_incr_upwards (int blocksneeded)
+{
+  int realblocksneeded = blocksneeded;
+  struct block *topblock = dummytopblock - 1;
+  int incr;
+  int foreign_incr = __himem != __old_himem;
+
+  if (foreign_incr)
+    {
+      /* Someone else has increased himem, or there is our parent in the way.
+         We need space for the new block and two dummy blocks */
+      incr = blocksneeded * sizeof (struct block) + 2 * DUMMY_BLOCK_SIZE;
+    }
+  else
+    {
+      /* Nothing has increased himem since we last increase the heap size */
+      if (topblock->startofcon != NULL)
+        {
+          /* We can use the top block to provide part of the new block */
+          topblock = topblock->startofcon;
+          realblocksneeded -= topblock->contents.free.numconsecutiveblocks;
+        }
+      else
+        {
+          topblock += 1;
+        }
+
+      incr = realblocksneeded * sizeof (struct block);
+    }
+
+  if (__stackalloc_incr_wimpslot (incr) == NULL)
     return NULL;
 
-  __stack = new__stack;
+  if (realblocksneeded != blocksneeded)
+    {
+      /* Only remove the block from the free list once we know the
+         wimpslot incr was successful */
+      REMOVE_FROM_FREELIST (topblock);
+    }
+
+  if (foreign_incr)
+    {
+      topblock = (struct block *)((u_char *)__himem - incr + DUMMY_BLOCK_SIZE);
+      /* Setup a dummy block below the new block, to prevent us trying to
+         coalesce with something that isn't in our heap */
+      (topblock - 1)->startofcon = NULL;
+    }
+
+  __old_himem = __himem;
+
+  /* Setup a new dummy block at the top of the heap */
+  dummytopblock = topblock + blocksneeded;
+  dummytopblock->size = 1;
+
+  return topblock;
+}
+
+/* Try to increase the stack heap downwards */
+static struct block *
+__stackalloc_incr_downwards (int blocksneeded)
+{
+  int realblocksneeded = blocksneeded;
+  struct block *bottomblock = dummybottomblock + 1;
+  struct block *newbottomblock;
+  void *new__stack;
+  int incr;
+
+  if (bottomblock->size == BLOCK_FREE)
+    {
+      /* We can use the bottom block to provide part of the new block */
+      realblocksneeded -= bottomblock->contents.free.numconsecutiveblocks;
+    }
+
+  newbottomblock = bottomblock - realblocksneeded;
+
+  incr = realblocksneeded * sizeof (struct block);
+  new__stack = (u_char *)__stack - incr;
+
+#ifdef DEBUG
+  __os_print ("-- __stackalloc_incr_downwards: incr = ");
+  __os_prhex (incr); __os_print ("\r\n");
+  __os_print ("-- __stackalloc_incr_downwards: __stack = ");
+  __os_prhex ((int)__stack); __os_print ("\r\n");
+  __os_print ("-- __stackalloc_incr_downwards: __stack_limit = ");
+  __os_prhex ((int)__stack_limit); __os_print ("\r\n");
+#endif
+
+  if (new__stack >= __stack_limit)
+    {
+      __stack = new__stack;
+
+      if (realblocksneeded != blocksneeded)
+        {
+          REMOVE_FROM_FREELIST (bottomblock);
+        }
+
+      /* Setup a new dummy block at the bottom of the heap */
+      dummybottomblock = newbottomblock - 1;
+      dummybottomblock->startofcon = NULL;
+    }
+  else
+    {
+#ifdef DEBUG
+      __os_print ("-- __stackalloc: no free memory below stack heap\r\n");
+#endif
+      newbottomblock = NULL;
+    }
 
-  return __stack;
+  return newbottomblock;
 }
 
+
 /* Release any free memory at the bottom of the heap */
 /* Returns non-zero if it managed to free anything */
 int
@@ -152,10 +303,11 @@
   /* Move dummy block up to where the end of the bottom block was */
   dummybottomblock = bottomblock + bottomblock->contents.free.numconsecutiveblocks - 1;
   dummybottomblock->startofcon = NULL;
-  __stack = (char *)dummybottomblock + sizeof(struct block) - 4;
+  __stack = (u_char *)dummybottomblock + sizeof(struct block) - 4;
 
 #ifdef DEBUG
-  __os_print ("-- __stackalloc_trim: __stack = "); __os_prhex ((int)__stack); __os_print ("\r\n");
+  __os_print ("-- __stackalloc_trim: __stack = ");
+  __os_prhex ((int)__stack); __os_print ("\r\n");
 #endif
 
 #if __FEATURE_PTHREADS
@@ -166,26 +318,47 @@
   return 1;
 }
 
-/* Initialise the stackalloc heap */
-/* No need for thread-safety, as only called before threads initialised */
+/* Initialise the stackalloc heap
+   No need for thread-safety, as only called before threads initialised */
 void
 __stackalloc_init (void)
 {
   struct block *initialblock;
+  int regs[10];
 
-  /* The initial stack chunk is set up in _syslib.s */
-  /* __stack points 8 bytes below the base of the initial chunk */
+  /* The initial stack chunk is set up in _syslib.s
+     __stack points 8 bytes below the base of the initial chunk
+     There are also 8 bytes spare above the initial chunk */
 
 #ifdef DEBUG
-  __os_print ("-- __stackalloc_init: __stack = "); __os_prhex ((int)__stack); __os_print ("\r\n");
-#endif
+  __os_print ("-- __stackalloc_init: __stack      = ");
+  __os_prhex ((int)__stack); __os_print ("\r\n");
+  __os_print ("-- __stackalloc_init: __himem      = ");
+  __os_prhex ((int)__himem); __os_print ("\r\n");
+  __os_print ("-- __stackalloc_init: __real_himem = ");
+  __os_prhex ((int)__real_himem); __os_print ("\r\n");
+#endif
+
+  /* Record the value of himem when the initial stack chunk was setup */
+  __old_himem = __himem;
+
+  /* Set himem to the top of the wimpslot, i.e. above any parent program */
+  regs[0] = 0;
+  regs[1] = (int)__real_himem;
+  regs[2] = 0;
+  __os_swi (OS_ChangeEnvironment, regs);
+  __himem = __real_himem;
 
-  initialblock = (struct block *)((char *)__stack + 4);
+  initialblock = (struct block *)((u_char *)__stack + 4);
   initialblock->size = 1;
+  initialblock->startofcon = NULL;
 
   dummybottomblock = initialblock - 1;
   dummybottomblock->startofcon = NULL;
 
+  dummytopblock = initialblock + 1;
+  dummytopblock->size = 1;
+
   freelist = NULL;
 }
 
@@ -243,23 +416,18 @@
 
   if (blocktoalloc == NULL)
     {
-      int realblocksneeded = blocksneeded;
-      struct block *bottomblock = dummybottomblock + 1;
-
-      /* No suitable block found, so try to increase the size of the heap */
-      if (bottomblock->size == BLOCK_FREE)
-        {
-          /* We can use the bottom block to provide part of the new block */
-          realblocksneeded -= bottomblock->contents.free.numconsecutiveblocks;
-          REMOVE_FROM_FREELIST (bottomblock);
-        }
+      /* No suitable block found, so try to increase the size of the heap.
+         Try extending the stack heap downwards if room, otherwise increase
+         the wimpslot */
+      blocktoalloc = __stackalloc_incr_downwards (blocksneeded);
 
-      blocktoalloc = bottomblock - realblocksneeded;
+      if (blocktoalloc == NULL)
+        blocktoalloc = __stackalloc_incr_upwards (blocksneeded);
 
-      if (__stackalloc_incr (realblocksneeded * sizeof(struct block)) == NULL)
+      if (blocktoalloc == NULL)
         {
 #ifdef DEBUG
-          __os_print ("-- __stackalloc: no free memory"); __os_print ("\r\n");
+          __os_print ("-- __stackalloc: no free memory\r\n");
 #endif
 #if __FEATURE_PTHREADS
           if (__pthread_system_running)
@@ -267,10 +435,6 @@
 #endif
           return NULL;
         }
-
-      /* Setup a new dummy block at the bottom of the heap */
-      dummybottomblock = blocktoalloc - 1;
-      dummybottomblock->startofcon = NULL;
     }
   else
     {
@@ -331,7 +495,7 @@
 #endif
 
   /* Find start of block this ptr refers to */
-  blocktofree = (struct block *)((char *)ptr - offsetof (struct block, contents.allocated));
+  blocktofree = (struct block *)((u_char *)ptr - offsetof (struct block, contents.allocated));
 
   prevblock = blocktofree - 1;
   startblock = prevblock->startofcon;
Index: unixlib/source/unix/unix.c
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/unix/unix.c,v
retrieving revision 1.8
diff -u -r1.8 unix.c
--- unixlib/source/unix/unix.c	5 Jan 2003 12:27:55 -0000	1.8
+++ unixlib/source/unix/unix.c	10 Feb 2003 23:20:28 -0000
@@ -361,9 +361,6 @@
 	  if (fd[i].__magic == _FDMAGIC)
 	    close (i);
 
-      /* We're going back to the RISC OS world.  */
-      __env_riscos ();
-
 #ifdef DEBUG
       __os_print ("_exit(): Setting return code = ");
       __os_prhex (return_code);
Index: unixlib/source/sys/_vfork.s
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/sys/_vfork.s,v
retrieving revision 1.5
diff -u -r1.5 _vfork.s
--- unixlib/source/sys/_vfork.s	15 Dec 2002 13:16:55 -0000	1.5
+++ unixlib/source/sys/_vfork.s	10 Feb 2003 23:33:10 -0000
@@ -114,9 +114,6 @@
 	BL	|__pthread_atfork_callparentchild|
 pthread_skip3
 	]
-	SWI	XOS_WriteS
-	DCB	"exiting to parent",10,13,0
-	ALIGN
 	stackreturn	AL, "a1,a2,a3,a4,v1,v2,v3,v4,v5,pc"
 
 return_fail


More information about the gcc mailing list