[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