mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
work much harder to reclaim stacks
This commit is contained in:
parent
ceecb31310
commit
ca9b36624f
1 changed files with 130 additions and 9 deletions
|
@ -1,38 +1,147 @@
|
||||||
|
/*
|
||||||
|
* Is nothing simple?
|
||||||
|
*
|
||||||
|
* We can't free the stack until we've finished executing,
|
||||||
|
* but once we've finished executing, we can't do anything
|
||||||
|
* at all, including call free. So instead we keep a linked list
|
||||||
|
* of all stacks for all processes, and every few times we try
|
||||||
|
* to allocate a new stack we scan the current stack list for
|
||||||
|
* dead processes and reclaim those stacks.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include "9proc.h"
|
#include "9proc.h"
|
||||||
|
|
||||||
int fforkstacksize = 16384;
|
int fforkstacksize = 16384;
|
||||||
|
|
||||||
|
typedef struct Stack Stack;
|
||||||
|
struct Stack
|
||||||
|
{
|
||||||
|
Stack *next;
|
||||||
|
Stack *fnext;
|
||||||
|
int pid;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Lock stacklock;
|
||||||
|
static Stack *freestacks;
|
||||||
|
static Stack *allstacks;
|
||||||
|
static int stackmallocs;
|
||||||
|
static void gc(void);
|
||||||
|
|
||||||
|
static void*
|
||||||
|
mallocstack(void)
|
||||||
|
{
|
||||||
|
Stack *p;
|
||||||
|
|
||||||
|
lock(&stacklock);
|
||||||
|
top:
|
||||||
|
p = freestacks;
|
||||||
|
if(p)
|
||||||
|
freestacks = p->fnext;
|
||||||
|
else{
|
||||||
|
if(stackmallocs++%1 == 0)
|
||||||
|
gc();
|
||||||
|
if(freestacks)
|
||||||
|
goto top;
|
||||||
|
p = malloc(fforkstacksize);
|
||||||
|
p->next = allstacks;
|
||||||
|
allstacks = p;
|
||||||
|
}
|
||||||
|
if(p)
|
||||||
|
p->pid = 1;
|
||||||
|
unlock(&stacklock);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gc(void)
|
||||||
|
{
|
||||||
|
Stack *p;
|
||||||
|
|
||||||
|
for(p=allstacks; p; p=p->next){
|
||||||
|
if(p->pid > 1)
|
||||||
|
if(kill(p->pid, 0) < 0 && errno == ESRCH){
|
||||||
|
if(0) fprint(2, "reclaim stack from %d\n", p->pid);
|
||||||
|
p->pid = 0;
|
||||||
|
}
|
||||||
|
if(p->pid == 0){
|
||||||
|
p->fnext = freestacks;
|
||||||
|
freestacks = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
freestack(void *v)
|
||||||
|
{
|
||||||
|
Stack *p;
|
||||||
|
|
||||||
|
p = v;
|
||||||
|
if(p == nil)
|
||||||
|
return;
|
||||||
|
lock(&stacklock);
|
||||||
|
p->fnext = freestacks;
|
||||||
|
p->pid = 0;
|
||||||
|
freestacks = p;
|
||||||
|
unlock(&stacklock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
tramp(void *v)
|
tramp(void *v)
|
||||||
{
|
{
|
||||||
void (*fn)(void*), *arg;
|
void (*fn)(void*), *arg;
|
||||||
void **v2;
|
void **v2;
|
||||||
|
void *p;
|
||||||
|
|
||||||
_p9uproc(0);
|
_p9uproc(0);
|
||||||
v2 = v;
|
v2 = v;
|
||||||
fn = v2[0];
|
fn = v2[0];
|
||||||
arg = v2[1];
|
arg = v2[1];
|
||||||
|
p = v2[2];
|
||||||
free(v2);
|
free(v2);
|
||||||
fn(arg);
|
fn(arg);
|
||||||
|
_exit(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
trampnowait(void *v)
|
||||||
|
{
|
||||||
|
int pid;
|
||||||
|
int cloneflag;
|
||||||
|
void **v2;
|
||||||
|
int *pidp;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
v2 = v;
|
||||||
|
cloneflag = (int)v2[4];
|
||||||
|
pidp = v2[3];
|
||||||
|
p = v2[2];
|
||||||
|
pid = clone(tramp, p+fforkstacksize-512, cloneflag, v);
|
||||||
|
*pidp = pid;
|
||||||
|
_exit(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ffork(int flags, void (*fn)(void*), void *arg)
|
ffork(int flags, void (*fn)(void*), void *arg)
|
||||||
{
|
{
|
||||||
void **v;
|
void **v;
|
||||||
char *p;
|
char *p;
|
||||||
int cloneflag, pid;
|
int cloneflag, pid, thepid, status, nowait;
|
||||||
|
|
||||||
_p9uproc(0);
|
_p9uproc(0);
|
||||||
p = malloc(fforkstacksize);
|
p = mallocstack();
|
||||||
v = malloc(sizeof(void*)*2);
|
v = malloc(sizeof(void*)*5);
|
||||||
if(p==nil || v==nil){
|
if(p==nil || v==nil){
|
||||||
free(p);
|
freestack(p);
|
||||||
free(v);
|
free(v);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -46,22 +155,34 @@ ffork(int flags, void (*fn)(void*), void *arg)
|
||||||
cloneflag |= CLONE_FILES;
|
cloneflag |= CLONE_FILES;
|
||||||
else
|
else
|
||||||
flags &= ~RFFDG;
|
flags &= ~RFFDG;
|
||||||
|
nowait = flags&RFNOWAIT;
|
||||||
if(!(flags&RFNOWAIT))
|
if(!(flags&RFNOWAIT))
|
||||||
cloneflag |= SIGCHLD;
|
cloneflag |= SIGCHLD;
|
||||||
else
|
else
|
||||||
flags &= ~RFNOWAIT;
|
flags &= ~RFNOWAIT;
|
||||||
if(flags){
|
if(flags){
|
||||||
fprint(2, "unknown rfork flags %x\n", flags);
|
fprint(2, "unknown rfork flags %x\n", flags);
|
||||||
free(p);
|
freestack(p);
|
||||||
free(v);
|
free(v);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
v[0] = fn;
|
v[0] = fn;
|
||||||
v[1] = arg;
|
v[1] = arg;
|
||||||
pid = clone(tramp, p+fforkstacksize-16, cloneflag, v);
|
v[2] = p;
|
||||||
if(pid < 0)
|
v[3] = &thepid;
|
||||||
free(p);
|
v[4] = (void*)cloneflag;
|
||||||
return pid;
|
thepid = -1;
|
||||||
|
pid = clone(nowait ? trampnowait : tramp, p+fforkstacksize-16, cloneflag, v);
|
||||||
|
if(pid > 0 && nowait){
|
||||||
|
if(wait4(pid, &status, __WALL, 0) < 0)
|
||||||
|
fprint(2, "ffork wait4: %r\n");
|
||||||
|
}else
|
||||||
|
thepid = pid;
|
||||||
|
if(thepid == -1)
|
||||||
|
freestack(p);
|
||||||
|
else
|
||||||
|
((Stack*)p)->pid = thepid;
|
||||||
|
return thepid;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
Loading…
Reference in a new issue