[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: MiNT 1.10 re-sync



Kay Roemer writes:

> > Upon reflection, it would probably be easier to load shared text regions at the
> > top of memory, and continue creating the TPA from lower memory. That way you
> > don't have to worry about artificially limiting the amount of memory you give
> > to a newly spawned process. (I wonder how topdown solved this problem...)
> 
> This sounds like a possible solution.

 hmm i don't know, doesn't falcons need free space at top when changing
screen size (s_realloc)?

>  TPA doesn't matter in this case, because
> it is freed when the process (running a shared text) exits. Fragmentation seems
> to occur, when
> 
> 1) running shared text
> 2) last process running shared text exits, shared text still hangs around.
> 3) allocating memory in eg, a device driver or fs or running TSR or daemon.

 and when MiNT needs a new nalloc arena...

> 4) goto 1
> 
> After a few iterations the stuff allocated in 3) prevents the free shared
> text regions from beeing joined together to one large hunk.
> 
> Sigh! Thats a real problem when physical address space == virtual address
> space.

 yes :-(
> 
> Kay.

 ok here is what i've been testing the last few weeks.  works for me
although there could still be bugs that only show up on 68030, etc.
but first a few other fixes to add to Michaels collection. :)

0. this was missing:  use new value for TIOCSETP and keep old for
TIOCSETN, other way around can hang old binaries...

Index: file.h
@@ -340,7 +341,7 @@
 #define FIONREAD	(('F'<< 8) | 1)
 #define FIONWRITE	(('F'<< 8) | 2)
 #define TIOCGETP	(('T'<< 8) | 0)
-#define TIOCSETP	(('T'<< 8) | 1)
+#define TIOCSETN	(('T'<< 8) | 1)
 #define TIOCGETC	(('T'<< 8) | 2)
 #define TIOCSETC	(('T'<< 8) | 3)
 #define TIOCGLTC	(('T'<< 8) | 4)
@@ -361,7 +362,7 @@
 #define TIOCGFLAGS	(('T'<< 8) | 22)
 #define TIOCSFLAGS	(('T'<< 8) | 23)
 #define TIOCOUTQ	(('T'<< 8) | 24)
-#define TIOCSETN	(('T'<< 8) | 25)
+#define TIOCSETP	(('T'<< 8) | 25)
 
 /* cursor control Fcntls:
  * NOTE THAT THESE MUST BE TOGETHER

1. getcwd crashed when called from `unmounted' (Dlock) fs...

Index: unifs.c
@@ -379,6 +379,10 @@
 		return EINTRN;
 	}
 
+	if (!fs) {
+		*pathname = 0;
+		return 0;
+	}
 	if (!(fs->fsflags & FS_LONGPATH)) {
 		r = (*fs->getname)(&curproc->root[dir->dev], dir, tmppath, PATH_MAX);
 		if (r) return r;

2. ls -l /pipe: fix pty modes (S_IFCHR) and 14-char names

Index: pipefs.c
@@ -477,11 +477,12 @@
 		outp->readers = 1; outp->writers = selfread ? 1 : VIRGIN_PIPE;
 		outp->wsel = outp->rsel = 0;
 	}
+	b->name[NAME_MAX] = '\0';
 	strncpy(b->name, name, NAME_MAX);
 	b->time = timestamp;
 	b->date = datestamp;
 	b->dosflags = attrib;
-	b->mode = ((attrib & FA_SYSTEM) ? S_IFCHR : S_IFIFO) | mode;
+	b->mode = ((attrib & FA_SYSTEM) ? S_IFCHR : S_IFIFO) | (mode & ~S_IFMT);
 	b->uid = curproc->ruid;
 	b->gid = curproc->rgid;
 
3. make echo >pipe/pty work when other end already open, only fail if
O_EXCL or Fcreate attr != 0. (shells often creat() output redirection...)

Index: dosfile.c
@@ -34,7 +35,7 @@
 	unsigned perm;
 	int creating;
 	char temp1[PATH_MAX];
-	extern FILESYS proc_filesys;
+	extern FILESYS proc_filesys, pipe_filesys;
 
 /* for special BIOS "fake" devices */
 	extern DEVDRV fakedev;
@@ -59,9 +60,12 @@
 
 /*
  * file found: this is an error if (O_CREAT|O_EXCL) are set
+ *	...or if this is Fcreate with nonzero attr on the pipe filesystem
  */
 
-	if ( (r == 0) && ( (rwmode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) ) ) {
+	if ( (r == 0) && ( (rwmode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) ||
+			(attr && fc.fs == &pipe_filesys &&
+			(rwmode & (O_CREAT|O_TRUNC)) == (O_CREAT|O_TRUNC)))) {
 		DEBUG(("do_open(%s): file already exists",name));
 		mint_errno = EACCDN;
 		release_cookie(&fc);
Index: pipefs.c
@@ -544,10 +545,12 @@
 		}
 		p->flags &= ~O_HEAD;
 	} else {
+#if 0
 		if (f->flags & O_TRUNC) {
 			DEBUG(("pipe_open: fifo already exists"));
 			return EACCDN;
 		}
+#endif
 	}
 /*
  * check for file sharing compatibility. note that O_COMPAT gets mutated

4. save a long read

Index: intr.spp
@@ -42,7 +42,7 @@
 _mint_5ms:
 	move.l	a0,-(sp)
 	lea	_uptimetick,a0
-	tst.l	_uptimetick
+	tst.l	(a0)
 	bne.s	L_no_uptime
 	move.l	#200,(a0)
 L_no_uptime:

5. fork() doesn't copy shared text regions so why allocate memory
to save them :)

Index: dosmem.c
@@ -1283,6 +1294,15 @@
 	if (save) {
 		TRACE(("do_vfork: saving parent"));
 		savesize = memused(curproc) - txtsize;
+		if (!txtsize && (p->base->p_flags & F_SHTEXT)) {
+			for (i = 0; i < curproc->num_reg; i++) {
+				m = curproc->mem[i];
+				if (m && (m->mflags & M_SHTEXT)) {
+					savesize -= m->len;
+					break;
+				}
+			}
+		}
 		assert(savesize >= 0);
 
 		saveplace = (char *)alloc_region(alt, savesize, PROT_P);

6. and now the sticky text/fragmentation megapatch...  does a few things:

. if F_ALTLOAD|F_SHTEXT look at F_MINALT bits to see how much memory
the new process needs and free sticky text regions if necessary, all
F_MINALT bits set (0xf0000000) means `as much as you can get'
. execv..() frees the old process memory before allocating the new ones,
and so no longer leaves holes in your memory map.  this took a few
ugly hacks but i think its worth it :)  the only visible change should
be when exec'ing a damaged binary the process gets killed, fixing that
would require reading executables twice.
. check the sticky bit, just making everything sharable sticky still got
me too much `out of memory's...  and free sticky text regions after disk
changes or if open() would otherwise fail.
. also free no more sticky text regions then necessary in alloc, and
some other small changes.

 oh and if you need something to adjust the F_MINALT bits...

#! /usr/bin/perl
# xsetf [-xhex] files ... -- print/set executable flags
#
$aexec = 's L L L L L L S';
#	 short	a_magic;	/* magic number */
#unsigned long	a_text;		/* size of text segment */
#unsigned long	a_data;		/* size of initialized data */
#unsigned long	a_bss;		/* size of uninitialized data */
#unsigned long	a_syms;		/* size of symbol table */
#unsigned long	a_AZero1;	/* always zero */
#unsigned long	a_ldflgs;	/* program load flags */
#unsigned short	a_isreloc;	/* is reloc info present */

while ($_ = $ARGV[0], /^-/) {
	shift;
	last if /^--$/;
	if (/^-x(.*)/) {
		if ($1) {
			$x = $1;
		} else {
			$x = shift;
			next;
		}
	}
}
foreach (@ARGV) {
	print $_, ":\t";
	open (F, "+< $_") || die "Can't open";
	sysread (F, $head, length (pack ($aexec, 0))) || die "Can't read header";
	($a_magic, $a_text, $a_data, $a_bss, $a_syms,
		$a_AZero1, $a_ldflgs, $a_isreloc) = unpack ($aexec, $head);
	die "not executable/corrupted header" unless $a_magic == 0x601a;
	seek (F, 0, 0) || die "Can't seek back";
	print "\n text ", $a_text, " data ", $a_data, " bss ", $a_bss, " symbols ",
			$a_syms, " zero1 ", $a_AZero1, " isreloc ", $a_isreloc, "\n";
	printf "\tldflags\t\t0x%08lx\n", $a_ldflgs;

	printf "\t &fload\t\t0x%08lx\n", 1	if ($a_ldflgs&1);
	printf "\t &altload\t0x%08lx\n", 2	if ($a_ldflgs&2);
	printf "\t &altalloc\t0x%08lx\n",4	if ($a_ldflgs&4);
	printf "\t &prot_p\t0x%08lx = 0x%08lx\n",	0xf0,  0
						if (!($a_ldflgs&0xf0));
	printf "\t &prot_g\t0x%08lx = 0x%08lx\n",	0xf0,  0x10
						if (($a_ldflgs&0xf0) == 0x10);
	printf "\t &prot_s\t0x%08lx = 0x%08lx\n",	0xf0,  0x20
						if (($a_ldflgs&0xf0) == 0x20);
	printf "\t &prot_pr\t0x%08lx = 0x%08lx\n",	0xf0,  0x30
						if (($a_ldflgs&0xf0) == 0x30);
	printf "\t &prot_i\t0x%08lx = 0x%08lx\n",	0xf0,  0x40
						if (($a_ldflgs&0xf0) == 0x40);
	printf "\t &prot_??\t0x%08lx = 0x%08lx\n",	0xf0, $a_ldflgs&0xf0
						if (($a_ldflgs&0xf0) > 0x40);
	printf "\t &shtext\t0x%08lx\n",  0x800 if ($a_ldflgs&0x800);
	printf "\t &minalt\t0x%08lx = 0x%08lx\n",	0xf0000000,
			$a_ldflgs&0xf0000000	if ($a_ldflgs&0xf0000802);
	if (defined ($x)) {
		$x = oct ($x) if $x =~ /^0/;
		$a_ldflgs = $x;
	}
	$newhead = pack ($aexec, $a_magic, $a_text, $a_data, $a_bss, $a_syms,
		$a_AZero1, $a_ldflgs, $a_isreloc);
	if ($newhead ne $head) {
		syswrite (F, $newhead, length ($newhead)) == length ($newhead)
			|| die "Can't write back header";
	}
	close F || die "Can't close";
}
-------cut----

 the sticky bit is of course chmod +t.  (if your /bin/sh still is on
GEMDOS change it now... :)  and then see you no longer need _shell_p.)

Index: dosfile.c
@@ -9,6 +9,7 @@
 #include "mint.h"
 
 extern char vt52xkey[];
+MEMREGION *tofreed;	/* to-be-freed shared text region (set in denyshare) */
 
 static long do_dup P_((int,int));
 static void unselectme P_((PROC *));
@@ -232,6 +236,12 @@
 		dispose_fileptr(f);
 		return NULL;
 	}
+
+	if (tofreed) {
+		tofreed->links = 0;
+		free_region(tofreed);
+		tofreed = 0;
+	}
 
 /* special code for opening a tty */
 	if (is_terminal(f)) {
Index: dosmem.c
@@ -53,7 +53,7 @@
 	long maxsize, mleft;
 
 	if (size == -1L) {
-		maxsize = max_rsize(map);
+		maxsize = max_rsize(map, 0L);
 		if (curproc->maxmem) {
 			mleft = curproc->maxmem - memused(curproc);
 			if (maxsize > mleft)
@@ -420,6 +420,33 @@
 		}
 	}
 
+/* make a local copy of the name, in case we are overlaying the current
+ * process
+ */
+	if (mkname) {
+		lastslash = 0;
+		newname = ptr1;
+		while (*newname) {
+			if (*newname == '\\' || *newname == '/')
+				lastslash = newname;
+			++newname;
+		}
+		if (!lastslash)
+			lastslash = ptr1;
+		else
+			lastslash++;
+
+		i = 0; newname = localname;
+		while (i++ < PNAMSIZ) {
+			if (*lastslash == '.' || *lastslash == 0) {
+				*newname = 0; break;
+			}
+			else
+				*newname++ = *lastslash++;
+		}
+		*newname = 0;
+	}
+
 TRACE(("creating environment"));
 
 	if (mkload || mkbase) {
@@ -434,7 +461,7 @@
 TRACE(("creating base page"));
 
 	if (mkbase) {
-		base = create_base((char *)ptr2, env, flags, 0L);
+		base = create_base((char *)ptr2, env, flags, 0L, 0L, 0L, 0L, 0L, 0L);
 		if (!base) {
 			DEBUG(("Pexec: unable to create basepage"));
 			detach_region(curproc, env);
@@ -444,8 +471,19 @@
 TRACELOW(("Pexec: basepage region(%lx) is %ld bytes at %lx", base, base->len, base->loc));
 	}
 	else if (mkload) {
-		base = load_region((char *)ptr1, env, (char *)ptr2,
-			&xattr, &text, &flags);
+		char cbuf[128], *tail = ptr2;
+		if (overlay) {
+			static char fbuf[PATH_MAX];
+			ptr1 = strncpy (fbuf, ptr1, PATH_MAX-2);
+			tail = strncpy (cbuf, ptr2, 127);
+		}
+#if 0
+		base = load_region((char *)ptr1, env, (char *)tail,
+			&xattr, &text, &flags, 0);
+#else
+		base = load_region((char *)ptr1, env, (char *)tail,
+			&xattr, &text, &flags, overlay);
+#endif
 		if (!base) {
 			DEBUG(("Pexec: load_region failed"));
 			detach_region(curproc, env);
@@ -480,33 +518,6 @@
 #endif
 	}
 
-/* make a local copy of the name, in case we are overlaying the current
- * process
- */
-	if (mkname) {
-		lastslash = 0;
-		newname = ptr1;
-		while (*newname) {
-			if (*newname == '\\' || *newname == '/')
-				lastslash = newname;
-			++newname;
-		}
-		if (!lastslash)
-			lastslash = ptr1;
-		else
-			lastslash++;
-
-		i = 0; newname = localname;
-		while (i++ < PNAMSIZ) {
-			if (*lastslash == '.' || *lastslash == 0) {
-				*newname = 0; break;
-			}
-			else
-				*newname++ = *lastslash++;
-		}
-		*newname = 0;
-	}
-
 	if (mkload || mkbase) {
 	    /*
 	     * Now that the file's loaded, flags is set to the prgflags
@@ -846,7 +857,7 @@
    memory runs low. Assume that we will never have 65535 processes
    using a particular memory region. */
 				if (m->links == 0) {
-					if (m->mflags & M_SHTEXT)
+					if (m->mflags & M_SHTEXT_T)
 						m->links = 0xffff;
 					else
 						free_region(m);
@@ -1307,9 +1327,10 @@
 		}
 		savemem = addr2mem((virtaddr)saveplace);
 		assert(savemem);
+		savemem->mflags |= M_FSAVED;
 		for (i = 0; i < curproc->num_reg; i++) {
 			m = curproc->mem[i];
-			if (m && m != savemem && !(m->mflags & M_SHTEXT)) {
+			if (m && !(m->mflags & (M_FSAVED|M_SHTEXT))) {
 				if (i != 1 || txtsize == 0) {
 				    quickmove(saveplace, (char *)m->loc, m->len);
 				    saveplace += m->len;
@@ -1354,23 +1375,7 @@
 	TRACE(("do_vfork: parent waking up"));
 
 	if (save) {
-		TRACE(("do_vfork: parent restoring memory"));
-		saveplace = (char *)savemem->loc;
-		for (i = 0; i < curproc->num_reg; i++) {
-			m = curproc->mem[i];
-			if (m && (m != savemem) && !(m->mflags & M_SHTEXT)) {
-				if (i != 1 || txtsize == 0) {
-				    quickmove((char *)m->loc, saveplace, m->len);
-				    saveplace += m->len;
-				}
-				else {
-				    quickmove((char *)m->loc+txtsize, saveplace,
-					m->len - txtsize);
-				    saveplace += m->len - txtsize;
-				}
-			}
-		}
-		detach_region(curproc, savemem);
+		fork_restore(curproc, 0L);
 	}
 	curproc->sigmask = sigmask;
 /* note that the PROC structure pointed to by p may be freed during
@@ -1380,6 +1385,50 @@
 	check_sigs();	/* did we get any signals while sleeping? */
 	return newpid;
 }
+
+/*
+ * fork_restore(p): restore process memory after a blocking fork
+ */
+
+void fork_restore(p, savemem)
+PROC *p;
+MEMREGION *savemem;
+{
+	MEMREGION *m;
+	long txtsize = p->txtsize;
+	char *saveplace;
+	int i;
+
+	if (!savemem) {
+		for (i = 0; i < p->num_reg; i++) {
+			m = p->mem[i];
+			if (m && (m->mflags & M_FSAVED)) {
+				savemem = m;
+				break;
+			}
+		}
+		if (!savemem)
+			return;
+	}
+	saveplace = (char *)savemem->loc;
+
+	TRACE(("do_vfork: parent restoring memory"));
+	for (i = 0; i < p->num_reg; i++) {
+		m = p->mem[i];
+		if (m && !(m->mflags & (M_FSAVED|M_SHTEXT))) {
+			if (i != 1 || txtsize == 0) {
+			    quickmove((char *)m->loc, saveplace, m->len);
+			    saveplace += m->len;
+			}
+			else {
+			    quickmove((char *)m->loc+txtsize, saveplace,
+				m->len - txtsize);
+			    saveplace += m->len - txtsize;
+			}
+		}
+	}
+	detach_region(p, savemem);
+}
 
 /*
  * here are the interfaces that the user sees. Pvfork() doesn't save
Index: filesys.c
@@ -367,7 +367,7 @@
 	int i;
 	FILEPTR *f;
 	FILESYS *fs;
-	SHTEXT *stext;
+	SHTEXT *stext, **old;
 	extern SHTEXT *text_reg;	/* in mem.c */
 	DIR *dirh;
 	fcookie dir;
@@ -461,13 +461,25 @@
 	}
 
 /* free any file descriptors associated with shared text regions */
-	for (stext = text_reg; stext; stext = stext->next) {
+	for (old = &text_reg; (stext = *old);) {
 		f = stext->f;
 		if (f->fc.dev == d) {
 			f->dev = NULL;
 			do_pclose(rootproc, f);
 			stext->f = 0;
+/* free region if unattached */
+			if (stext->text->links == 0xffff) {
+				stext->text->links = 0;
+				stext->text->mflags &= ~(M_SHTEXT|M_SHTEXT_T);
+				free_region(stext->text);
+				*old = stext->next;
+				kfree(stext);
+				continue;
+			}
+/* else clear `sticky bit' */
+			stext->text->mflags &= ~M_SHTEXT_T;
 		}
+		old = &stext->next;
 	}
 }
 
@@ -979,6 +991,8 @@
 {
 	int newrm, newsm;	/* new read and sharing mode */
 	int oldrm, oldsm;	/* read and sharing mode of already opened file */
+	extern MEMREGION *tofreed;
+	MEMREGION *m = tofreed;
 	int i;
 
 	newrm = f->flags & O_RWMODE;
@@ -999,6 +1013,12 @@
 		oldsm = list->flags & O_SHMODE;
 		if (oldsm == O_DENYW || oldsm == O_DENYRW) {
 		 	if (newrm != O_RDONLY) {
+/* conflict because of unattached shared text region? */
+				if (!m && (m = find_text_seg(list))) {
+					if (m->links == 0xffff)
+						continue;
+					m = 0;
+				}
 				DEBUG(("write access denied"));
 				return 1;
 			}
@@ -1040,6 +1060,9 @@
 			;	/* everything is OK */
 		}
 	}
+/* cannot close shared text regions file here... have open do it. */
+	if (m)
+		tofreed = m;
 	return 0;
 }
 
Index: mem.c
@@ -576,7 +576,7 @@
 	ulong size;
 	int mode;
 {
-	MEMREGION *m, *n, *s;
+	MEMREGION *m, *n, *nlast, *nfirstp, *s;
 
 	TRACELOW(("get_region(%s,%lx,%x)",
 		(map == ker ? "ker" : (map == core ? "core" : "alt")),
@@ -601,10 +601,12 @@
 /* We come back and try again if we found and freed any unattached shared
  * text regions.
  */
+	nfirstp = NULL;
 retry:
-	s = NULL;
-
 	n = *map;
+retry2:
+	s = nlast = NULL;
+
 	while (n) {
 		if (ISFREE(n)) {
 			if (n->len == size) {
@@ -628,10 +630,13 @@
 				    return 0;
 				}
 			}
+			nlast = n;
 /* If this is an unattached shared text region, leave it as a last resort */
 		} else if (n->links == 0xffff && (n->mflags & M_SHTEXT)) {
-			if (!s)
+			if (!s) {
 				s = n;
+				nfirstp = nlast;
+			}
 		}
 		n = n->next;
 	}
@@ -639,11 +644,60 @@
 /* Looks like we're out of free memory. Try freeing an unattached shared text
  * region, and then try again to fill this request.
  */
+#if 1
+	if (s && s->len < size) {
+		long lastsize = 0, end = 0;
+
+		n = nlast = nfirstp;
+		if (!n || n->next != s)
+			n = s;
+		for (; n; n = n->next) {
+			if (ISFREE(n)) {
+				if (end == n->loc) {
+					lastsize += n->len;
+				} else {
+					s = NULL;
+					nfirstp = nlast;
+					lastsize = n->len;
+				}
+				nlast = n;
+				end = n->loc + n->len;
+				if (lastsize >= size) {
+					break;
+				}
+			} else if (n->links == 0xffff && (n->mflags & M_SHTEXT)) {
+				if (end == n->loc) {
+					if (!s)
+						s = n;
+					lastsize += n->len;
+				} else {
+					s = n;
+					nfirstp = nlast;
+					lastsize = n->len;
+				}
+				end = n->loc + n->len;
+				if (lastsize >= size) {
+					break;
+				}
+			}
+		}
+		if (!n)
+			s = NULL;
+	}
+	if (s) {
+		s->links = 0;
+		free_region(s);
+		if (!(n = nfirstp))
+			n = *map;
+		goto retry2;
+	}
+#else
 	if (s) {
 		s->links = 0;
 		free_region(s);
 		goto retry;
 	}
+#endif
 		
 	if (m)
 		dispose_region(m);
@@ -836,6 +890,7 @@
 	return 0;
 }
 
+#if 0
 /*
  * max_rsize(map): return the length of the biggest free region
  * in the given memory map, or 0 if no regions remain.
@@ -879,6 +934,84 @@
 	}
 	return size;
 }
+#else
+/*
+ * max_rsize(map, needed): return the length of the biggest free region
+ * in the given memory map, or 0 if no regions remain.
+ * needed is minimun amount needed, if != 0 try to keep unattached
+ * shared text regions, else count them all as free.
+ */
+
+long
+max_rsize(map, needed)
+	MMAP map;
+	long needed;
+{
+	MEMREGION *m;
+	long size = 0, lastsize = 0, end = 0;
+
+	if (needed) {
+		for (m = *map; m; m = m->next) {
+			if (ISFREE(m) ||
+			    (m->links == 0xfffe && !(m->mflags & M_SHTEXT))) {
+				if (end == m->loc) {
+					lastsize += m->len;
+				} else {
+					lastsize = m->len;
+				}
+				end = m->loc + m->len;
+				if (lastsize > size) {
+					size = lastsize;
+				}
+			}
+		}
+		if (size >= needed)
+			return size;
+
+		lastsize = end = 0;
+	}
+	for (m = *map; m; m = m->next) {
+		if (ISFREE(m) || m->links == 0xfffe ||
+		    (m->links == 0xffff && (m->mflags & M_SHTEXT))) {
+			if (end == m->loc) {
+				lastsize += m->len;
+			} else {
+				lastsize = m->len;
+			}
+			end = m->loc + m->len;
+			if (lastsize > size) {
+				if (needed && lastsize >= needed)
+					return lastsize;
+				size = lastsize;
+			}
+		}
+	}
+	return size;
+}
+
+/*
+ * tot_rsize(map, flag): if flag == 1, return the total number of bytes in
+ * the given memory map; if flag == 0, return only the number of free
+ * bytes
+ */
+
+long
+tot_rsize(map, flag)
+	MMAP map;
+	int flag;
+{
+	MEMREGION *m;
+	long size = 0;
+
+	for (m = *map; m; m = m->next) {
+		if (flag || ISFREE(m) ||
+		    (m->links == 0xffff && (m->mflags & M_SHTEXT))) {
+			size += m->len;
+		}
+	}
+	return size;
+}
+#endif
 
 /*
  * alloc_region(MMAP map, ulong size, int mode): allocate a new region and
@@ -979,61 +1112,195 @@
 	return m;
 }
 
+static void terminateme(code)
+	int code;
+{
+	Pterm (code);
+}
+
 MEMREGION *
-create_base(cmd, env, flags, prgsize)
+create_base(cmd, env, flags, prgsize, execproc, s, f, fh, xp)
 	const char *cmd;
 	MEMREGION *env;
 	ulong flags, prgsize;
+	PROC *execproc;
+	SHTEXT *s;
+	FILEPTR *f;
+	FILEHEAD *fh;
+	XATTR *xp;
 {
-	long len, coresize, altsize;
+	long len = 0, minalt = 0, coresize, altsize;
 	MMAP map;
-	MEMREGION *m;
+	MEMREGION *m, *savemem = 0;
 	BASEPAGE *b;
+	PROC *parent = 0;	/* keep compiler happy... */
 	short protmode;
+	int i;
+
+/* if we're about to do an exec tell max_rsize which of the exec'ing
+   process regions will be freed, but don't free them yet so the process
+   can still get an ENOMEM...
+*/
+	if (execproc) {
+		for (i = 0; i < execproc->num_reg; i++) {
+			m = execproc->mem[i];
+			if (m && m->links == 1)
+				m->links = 0xfffe;
+		}
+
+/* if parents mem saved because of a blocking fork that can be restored too
+*/
+		if ((parent = pid2proc(execproc->ppid)) &&
+		    parent->wait_q == WAIT_Q && 
+		    parent->wait_cond == (long)execproc) {
+			for (i = 0; i < parent->num_reg; i++) {
+				m = parent->mem[i];
+				if (m && (m->mflags & M_FSAVED)) {
+					m->links = 0xfffe;
+					savemem = m;
+					break;
+				}
+			}
+		}
+	}
 
 /* if flags & F_ALTLOAD == 1, then we might decide to load in alternate
    RAM if enough is available. "enough" is: if more alt ram than ST ram,
    load there; otherwise, if more than (minalt+1)*128K alt ram available
    for heap space, load in alt ram ("minalt" is the high byte of flags)
  */
+	if (flags & (F_ALTLOAD|F_SHTEXT)) {
+		minalt = (flags & F_MINALT) >> 28L;
+		minalt = len = (minalt+1)*128*1024L + prgsize + 256;
+		if ((flags & F_MINALT) == F_MINALT)
+			len = 0;
+	}
 	if (flags & F_ALTLOAD) {
-		coresize = max_rsize(core);
-		altsize = max_rsize(alt);
-		if (altsize >= coresize)
+		coresize = max_rsize(core, len);
+		altsize = max_rsize(alt, len);
+		if (altsize >= coresize) {
 			map = alt;
-		else {
-			len = (flags & F_MINALT) >> 28L;
-			len = (len+1)*128*1024L + prgsize + 256;
-			if (altsize >= len)
+			len = altsize;
+		} else {
+			if (altsize >= minalt) {
 				map = alt;
-			else
+				len = altsize;
+			} else {
 				map = core;
+				len = coresize;
+			}
 		}
 	}
 	else
-		map = core;
+		len = max_rsize((map = core), len);
 
-	len = max_rsize(map);
+	if (savemem)
+		savemem->links = 1;
 	if (curproc->maxmem && len > curproc->maxmem) {
 		len = curproc->maxmem;
 	}
 
-	if (len < prgsize) {
-	    /* can't possibly load this file in its eligible regions */
-	    DEBUG(("create_base: max_rsize smaller than prgsize"));
-	    return 0;
-	}
-
 /* make sure that a little bit of memory is left over */
 	if (len > 2*KEEP_MEM) {
 		len -= KEEP_MEM;
 	}
-
+	if (s && !s->text &&
+	    (!(flags & F_ALTLOAD) || map == alt || altsize < fh->ftext ||
+	     !(s->text = addr2mem(alloc_region(alt, fh->ftext, PROT_P))))) {
+		if (len > fh->ftext + KERNEL_MEM)
+			len -= fh->ftext + KERNEL_MEM;
+		else
+			len = 0;
+	}
+
+	if (prgsize && len < prgsize + 0x400) {
+		/* can't possibly load this file in its eligible regions */
+		DEBUG(("create_base: max_rsize smaller than prgsize"));
+
+		if (execproc) {
+/* error, undo the above */
+			for (i = 0; i < execproc->num_reg; i++) {
+				m = execproc->mem[i];
+				if (m && m->links == 0xfffe)
+					m->links = 1;
+			}
+		}
+		if (s && !s->text) {
+			kfree (s);
+		}
+		mint_errno = ENSMEM;
+		return 0;
+	}
+	if (execproc) {
+/* free exec'ing process memory... if the exec returns after this make it
+   _exit (SIGKILL << 8);
+*/
+		*((short *) (execproc->stack + ISTKSIZE + sizeof (void (*)()))) =
+			(SIGKILL << 8);
+		execproc->ctxt[SYSCALL].term_vec = (long)rts;
+		execproc->ctxt[SYSCALL].pc = (long)terminateme;
+		execproc->ctxt[SYSCALL].sr |= 0x2000;
+		execproc->ctxt[SYSCALL].ssp = (long)(execproc->stack + ISTKSIZE);
+
+		if (savemem)
+			fork_restore(parent, savemem);
+		for (i = 0; i < execproc->num_reg; i++) {
+			m = execproc->mem[i];
+			if (m && m->links == 0xfffe) {
+				if (m->mflags & M_SHTEXT_T) {
+					m->links = 0xffff;
+				} else {
+					m->links = 0;
+					free_region(m);
+				}
+				execproc->mem[i] = 0;
+				execproc->addr[i] = 0;
+			}
+		}
+	}
 	protmode = (flags & F_PROTMODE) >> F_PROTSHIFT;
 
-	m = addr2mem(alloc_region(map, len, protmode));
+	m = 0;
+	if (s && !s->f) {
+		if (!s->text) {
+			m = addr2mem(alloc_region(map, len + fh->ftext + KERNEL_MEM, protmode));
+			if (!m ||
+			    (((len > minalt &&
+				((flags & F_MINALT) < F_MINALT) &&
+				max_rsize (map, -1) < fh->ftext) ||
+			      !(s->text = addr2mem(alloc_region(map, fh->ftext, PROT_P))) ||
+			      (m->next == s->text &&
+				!(detach_region (curproc, s->text), s->text = 0))) &&
+			     shrink_region(m, fh->ftext))) {
+				if (m)
+					detach_region(curproc, m);
+				kfree (s);
+				mint_errno = ENSMEM;
+				return 0;
+			}
+			if (!s->text) {
+				s->text = m;
+				if (protmode != PROT_P)
+					change_prot_status (curproc, m->loc, PROT_P);
+				m = 0;
+			}
+		}
+		s = get_text_seg(f, fh, xp, s, 0);
+		if (!s) {
+			if (m)
+				detach_region(curproc, m);
+			DEBUG(("create_base: unable to load shared text segment"));
+/* mint_errno set in get_text_seg */
+			return 0;
+		}
+	}
+
+	if (!m) {
+		m = addr2mem(alloc_region(map, len, protmode));
+	}
 	if (!m) {
 		DEBUG(("create_base: alloc_region failed"));
+		mint_errno = ENSMEM;
 		return 0;
 	}
 	b = (BASEPAGE *)(m->loc);
@@ -1062,7 +1329,7 @@
  */
 
 MEMREGION *
-load_region(filename, env, cmdlin, xp, text, fp)
+load_region(filename, env, cmdlin, xp, text, fp, isexec)
 	const char *filename;
 	MEMREGION *env;
 	const char *cmdlin;
@@ -1070,6 +1337,7 @@
 	MEMREGION **text;	/* set to point to shared text region,
 				   if any */
 	long *fp;		/* prgflags for this file */
+	int isexec;		/* this is an exec*() (overlay) */
 {
 	FILEPTR *f;
 	DEVDRV *dev;
@@ -1077,6 +1345,7 @@
 	BASEPAGE *b;
 	long size, start;
 	FILEHEAD fh;
+	SHTEXT *s;
 
 /* bug: this should be O_DENYW mode, not O_DENYNONE */
 /* we must use O_DENYNONE because of the desktop and because of the
@@ -1105,30 +1374,45 @@
 
 	if (fh.flag & F_SHTEXT) {
 		TRACE(("loading shared text segment"));
-		shtext = get_text_seg(f, &fh, xp);
-		if (!shtext) {
+		s = get_text_seg(f, &fh, xp, 0L, isexec);
+		if (!s) {
 			DEBUG(("load_region: unable to get shared text segment"));
 /* mint_errno set in get_text_seg */
 			goto failed;
 		}
 		size = fh.fdata + fh.fbss;
+		shtext = s->text;
 	} else {
 		size = fh.ftext + fh.fdata + fh.fbss;
 		shtext = 0;
+		s = 0;
 	}
 
-	reg = create_base(cmdlin, env, fh.flag, size);
+	env->links++;
+	if (s && !shtext) {
+		reg = create_base(cmdlin, env, fh.flag, size,
+			isexec ? curproc : 0L, s, f, &fh, xp);
+		shtext = s->text;
+	} else {
+		if (shtext)
+			shtext->links++;
+		reg = create_base(cmdlin, env, fh.flag, size,
+			isexec ? curproc : 0L, 0L, 0L, 0L, 0L);
+		if (shtext)
+			shtext->links--;
+	}
+	env->links--;
 	if (reg && size+1024L > reg->len) {
 		DEBUG(("load_region: insufficient memory to load"));
 		detach_region(curproc, reg);
 		reg = 0;
+		mint_errno = ENSMEM;
 	}
 
 	if (reg == 0) {
 		if (shtext) {
 			detach_region(curproc, shtext);
 		}
-		mint_errno = ENSMEM;
 		goto failed;
 	}
 
@@ -1294,58 +1578,70 @@
  * process
  */
 
-MEMREGION *
-get_text_seg(f, fh, xp)
+SHTEXT *
+get_text_seg(f, fh, xp, s, noalloc)
 	FILEPTR *f;
 	FILEHEAD *fh;
 	XATTR *xp;
-{
 	SHTEXT *s;
+	int noalloc;
+{
 	MEMREGION *m;
 	long r;
 	BASEPAGE b;
 
-	s = text_reg;
+	if (s) {
+		m = s->text;
+	} else {
+		s = text_reg;
 
-	while(s) {
-		if (s->f && samefile(&f->fc, &s->f->fc) &&
-		    xp->mtime == s->mtime &&
-		    xp->mdate == s->mdate)
-		{
-			m = s->text;
+		while(s) {
+			if (s->f && samefile(&f->fc, &s->f->fc) &&
+			    xp->mtime == s->mtime &&
+			    xp->mdate == s->mdate)
+			{
+				m = s->text;
 /* Kludge for unattached shared region */
-			if (m->links == 0xffff)
-				m->links = 0;
+				if (m->links == 0xffff)
+					m->links = 0;
 
-			if (attach_region(curproc, m)) {
+				if (attach_region(curproc, m)) {
 TRACE(("re-using shared text region %lx", m));
-				return m;
-			}
-			else {
-				mint_errno = ENSMEM;
-				return 0;
+					return s;
+				}
+				else {
+					mint_errno = ENSMEM;
+					return 0;
+				}
 			}
+			s = s->next;
 		}
-		s = s->next;
-	}
 
 /* hmmm, not found; OK, we'll have to create a new text region */
 
-	s = kmalloc(SIZEOF(SHTEXT));
-	if (!s) {
-		mint_errno = ENSMEM;
-		return 0;
+		s = kmalloc(SIZEOF(SHTEXT));
+		if (!s) {
+			mint_errno = ENSMEM;
+			return 0;
+		}
+		if (noalloc) {
+			s->f = 0;
+			s->text = 0;
+			return s;
+		}
+		m = 0;
 	}
-	m = 0;
+	if (!m) {
 /* actually, I can't see why loading in TT RAM is ever undesireable,
  * since shared text programs should be very clean (and since only
  * the text segment is going in there). But better safe than sorry.
  */
-	if (fh->flag & F_ALTLOAD) {
-		m = addr2mem(alloc_region(alt, fh->ftext, PROT_P));
+		if (fh->flag & F_ALTLOAD) {
+			m = addr2mem(alloc_region(alt, fh->ftext, PROT_P));
+		}
+		if (!m)
+			m = addr2mem(alloc_region(core, fh->ftext, PROT_P));
 	}
-	if (!m)
-		m = addr2mem(alloc_region(core, fh->ftext, PROT_P));
 
 	if (!m) {
 		kfree(s);
@@ -1375,6 +1671,11 @@
 
 /* region has valid shared text data */
 	m->mflags |= M_SHTEXT;
+#if 1
+	if (xp->mode & 01000)
+#endif
+/* make it sticky (this should depend on the files mode!?) */
+	m->mflags |= M_SHTEXT_T;
 
 /*
  * KLUDGE: to make sure we always have up to date shared text
@@ -1395,7 +1696,25 @@
 	s->mdate = xp->mdate;
 	text_reg = s;
 TRACE(("shared text region %lx created", m));
-	return m;
+	return s;
+}
+
+/*
+ * function to just check for existence of a shared text region
+ * corresponding to file "f"
+ */
+
+MEMREGION *
+find_text_seg(f)
+	FILEPTR *f;
+{
+	SHTEXT *s;
+
+	for (s = text_reg; s; s = s->next) {
+		if (s->f && samefile(&f->fc, &s->f->fc))
+			return s->text;
+	}
+	return 0;
 }
 
 /*
Index: mem.h
@@ -25,6 +25,8 @@
 #define M_MAP		0x0f	/* and with this to pick out map */
 
 #define M_SHTEXT	0x10	/* region is a shared text region */
+#define M_SHTEXT_T	0x20	/* `sticky bit' for shared text regions */
+#define M_FSAVED	0x40	/* region is saved memory of a forked process */
 #define M_KEEP		0x0100	/* don't free on process termination */
 
 /* dummy type for virtual addresses */
Index: proto.h
@@ -154,6 +154,7 @@
 long ARGS_ON_STACK p_waitpid P_((int pid, int nohang, long *rusage));
 long ARGS_ON_STACK p_wait3 P_((int nohang, long *rusage));
 long ARGS_ON_STACK p_wait P_((void));
+void ARGS_ON_STACK fork_restore P_((PROC *p, MEMREGION *savemem));
 long ARGS_ON_STACK p_vfork P_((void));
 long ARGS_ON_STACK p_fork P_((void));
 
@@ -217,14 +218,16 @@
 MEMREGION *get_region P_((MMAP map, ulong size, int mode));
 void free_region P_((MEMREGION *reg));
 long shrink_region P_((MEMREGION *reg, ulong newsize));
-long max_rsize P_((MMAP map));
+long max_rsize P_((MMAP map, long needed));
 long tot_rsize P_((MMAP map, int flag));
 virtaddr alloc_region P_((MMAP map, ulong size, int mode));
 MEMREGION *create_env P_((const char *env, ulong flags));
-MEMREGION *create_base P_((const char *cmd, MEMREGION *env, ulong flags, ulong prgsize));
+MEMREGION *create_base P_((const char *cmd, MEMREGION *env, ulong flags, ulong prgsize,
+			PROC *execproc, SHTEXT *s, FILEPTR *f, FILEHEAD *fh, XATTR *xp));
 MEMREGION *load_region P_((const char *name, MEMREGION *env, const char *cmdlin, XATTR *x,
-			MEMREGION **text, long *fp));
-MEMREGION *get_text_seg P_((FILEPTR *f, FILEHEAD *fh, XATTR *xp));
+			MEMREGION **text, long *fp, int isexec));
+SHTEXT *get_text_seg P_((FILEPTR *f, FILEHEAD *fh, XATTR *xp, SHTEXT *s, int noalloc));
+MEMREGION *find_text_seg P_((FILEPTR *f));
 long load_and_reloc P_((FILEPTR *f, FILEHEAD *fh, char *where, long start,
 			long nbytes, BASEPAGE *base));
 void rts P_((void));
-- 
J"urgen Lock / nox@jelal.north.de / UUCP: ..!uunet!unido!uniol!jelal!nox
								...ohne Gewehr
PGP public key fingerprint =  8A 18 58 54 03 7B FC 12  1F 8B 63 C7 19 27 CF DA