Commit 751ce3a7 authored by Ken Thompson's avatar Ken Thompson

segmented stacks AND goroutines

SVN=126929
parent ae905980
......@@ -28,7 +28,7 @@ if(newproc == N) {
newproc = nod(ONAME, N, N);
memset(newproc, 0, sizeof(*newproc));
newproc->op = ONAME;
newproc->sym = pkglookup("_newproc", "sys");
newproc->sym = pkglookup("newproc", "sys");
newproc->class = PEXTERN;
newproc->addable = 1;
newproc->ullman = 0;
......@@ -603,10 +603,12 @@ ginscall(Node *f, int proc)
if(proc) {
nodreg(&reg, types[TINT64], D_AX);
gins(ALEAQ, f, &reg);
nodreg(&reg, types[TINT64], D_BX);
gins(APUSHQ, &reg, N);
nodconst(&con, types[TINT32], argsize(f->type));
gins(AMOVL, &con, &reg);
gins(APUSHQ, &con, N);
gins(ACALL, N, newproc);
gins(APOPQ, N, &reg);
gins(APOPQ, N, &reg);
return;
}
gins(ACALL, N, f);
......
......@@ -572,19 +572,20 @@ dostkoff(void)
Sym *symmorestack;
pmorestack = P;
symmorestack = lookup("_morestack", 0);
symmorestack = lookup("sys·morestack", 0);
if(symmorestack->type == STEXT)
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT) {
if(p->from.sym == symmorestack) {
pmorestack = p;
p->from.scale |= NOSPLIT;
break;
}
}
}
if(pmorestack == P)
diag("_morestack not defined");
diag("sys·morestack not defined");
curframe = 0;
curbecome = 0;
......@@ -693,7 +694,7 @@ dostkoff(void)
p = appendp(p);
p->as = AJHI;
p->to.type = D_BRANCH;
p->to.offset = 3;
p->to.offset = 4;
q = p;
p = appendp(p);
......@@ -707,6 +708,12 @@ dostkoff(void)
p->from.offset = (autoffset+160) & ~7LL;
p->from.offset |= textarg<<32;
p = appendp(p);
p->as = AMOVQ;
p->from.type = D_AX;
p->to.type = D_INDIR+D_R14;
p->to.offset = 8;
p = appendp(p);
p->as = ACALL;
p->to.type = D_BRANCH;
......
......@@ -44,6 +44,9 @@ func mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
func mapassign1(hmap *map[any]any, key any, val any);
func mapassign2(hmap *map[any]any, key any, val any, pres bool);
func gosched();
func goexit();
func readfile(string) (string, bool); // read file into string; boolean status
func bytestorune(*byte, int32, int32) (int32, int32); // convert bytes to runes
func stringtorune(string, int32, int32) (int32, int32); // convert bytes to runes
......@@ -93,6 +96,10 @@ export
mapassign1
mapassign2
// go routines
gosched
goexit
// files
readfile
......
......@@ -183,25 +183,35 @@ char* sysimport =
"type sys._esys_089 (sys._esys_090 sys._esys_091 sys._isys_489)\n"
"var !sys.mapassign2 sys._esys_089\n"
"type sys._esys_095 {}\n"
"type sys._osys_499 {_esys_496 sys.string _esys_497 sys.bool}\n"
"type sys._isys_501 {_esys_498 sys.string}\n"
"type sys._esys_094 (sys._esys_095 sys._osys_499 sys._isys_501)\n"
"var !sys.readfile sys._esys_094\n"
"type sys._esys_096 {}\n"
"type sys._esys_097 {}\n"
"type sys._osys_510 {_esys_505 sys.int32 _esys_506 sys.int32}\n"
"type sys._esys_098 *sys.uint8\n"
"type sys._isys_512 {_esys_507 sys._esys_098 _esys_508 sys.int32 _esys_509 sys.int32}\n"
"type sys._esys_096 (sys._esys_097 sys._osys_510 sys._isys_512)\n"
"var !sys.bytestorune sys._esys_096\n"
"type sys._esys_094 (sys._esys_095 sys._esys_096 sys._esys_097)\n"
"var !sys.gosched sys._esys_094\n"
"type sys._esys_099 {}\n"
"type sys._esys_100 {}\n"
"type sys._osys_523 {_esys_518 sys.int32 _esys_519 sys.int32}\n"
"type sys._isys_525 {_esys_520 sys.string _esys_521 sys.int32 _esys_522 sys.int32}\n"
"type sys._esys_099 (sys._esys_100 sys._osys_523 sys._isys_525)\n"
"var !sys.stringtorune sys._esys_099\n"
"type sys._esys_102 {}\n"
"type sys._esys_101 {}\n"
"type sys._esys_098 (sys._esys_099 sys._esys_100 sys._esys_101)\n"
"var !sys.goexit sys._esys_098\n"
"type sys._esys_103 {}\n"
"type sys._isys_532 {_esys_531 sys.int32}\n"
"type sys._esys_101 (sys._esys_102 sys._esys_103 sys._isys_532)\n"
"var !sys.exit sys._esys_101\n"
"type sys._osys_501 {_esys_498 sys.string _esys_499 sys.bool}\n"
"type sys._isys_503 {_esys_500 sys.string}\n"
"type sys._esys_102 (sys._esys_103 sys._osys_501 sys._isys_503)\n"
"var !sys.readfile sys._esys_102\n"
"type sys._esys_105 {}\n"
"type sys._osys_512 {_esys_507 sys.int32 _esys_508 sys.int32}\n"
"type sys._esys_106 *sys.uint8\n"
"type sys._isys_514 {_esys_509 sys._esys_106 _esys_510 sys.int32 _esys_511 sys.int32}\n"
"type sys._esys_104 (sys._esys_105 sys._osys_512 sys._isys_514)\n"
"var !sys.bytestorune sys._esys_104\n"
"type sys._esys_108 {}\n"
"type sys._osys_525 {_esys_520 sys.int32 _esys_521 sys.int32}\n"
"type sys._isys_527 {_esys_522 sys.string _esys_523 sys.int32 _esys_524 sys.int32}\n"
"type sys._esys_107 (sys._esys_108 sys._osys_525 sys._isys_527)\n"
"var !sys.stringtorune sys._esys_107\n"
"type sys._esys_110 {}\n"
"type sys._esys_111 {}\n"
"type sys._isys_534 {_esys_533 sys.int32}\n"
"type sys._esys_109 (sys._esys_110 sys._esys_111 sys._isys_534)\n"
"var !sys.exit sys._esys_109\n"
"))\n"
;
......@@ -16,206 +16,78 @@ TEXT _rt0_amd64(SB),7,$-8
// allocate the per-user and per-mach blocks
LEAQ peruser<>(SB), R15 // dedicated u. register
LEAQ permach<>(SB), R14 // dedicated m. register
LEAQ m0<>(SB), R14 // dedicated m. register
LEAQ g0(SB), R15 // dedicated g. register
MOVQ R15, 0(R14) // m has pointer to its g0
LEAQ (-4096+104+4*8)(SP), AX
MOVQ AX, 0(R15) // 0(R15) is stack limit (w 104b guard)
MOVL $1024, AX
MOVL AX, 0(SP)
CALL mal(SB)
LEAQ 104(AX), BX
MOVQ BX, 0(R14) // 0(R14) is limit of istack (w 104b guard)
// create istack out of the given (operating system) stack
ADDQ 0(SP), AX
LEAQ (-4*8)(AX), BX
MOVQ BX, 8(R14) // 8(R14) is base of istack (w auto*4)
LEAQ (-1024+104)(SP), AX
MOVQ AX, 0(R15) // 0(R15) is stack limit (w 104b guard)
MOVQ SP, 8(R15) // 8(R15) is base
CALL check(SB)
// process the arguments
MOVL 16(SP), AX // copy argc
MOVL AX, 0(SP)
MOVQ 24(SP), AX // copy argv
MOVQ AX, 8(SP)
CALL args(SB)
CALL main·main(SB)
// create a new goroutine to start program
MOVQ $0, AX
MOVQ AX, 0(SP) // exit status
CALL sys·exit(SB)
PUSHQ $main·main(SB) // entry
PUSHQ $16 // arg size
CALL sys·newproc(SB)
CALL gom0init(SB)
POPQ AX
POPQ AX
CALL notok(SB) // fault
CALL notok(SB) // never returns
RET
//
// the calling sequence for a routine that
// needs N bytes stack, A args.
//
// N1 = (N+160 > 4096)? N+160: 0
// A1 = A
//
// if N <= 75
// CMPQ SP, 0(R15)
// JHI 3(PC)
// MOVQ $(N1<<0) | (A1<<32)), AX
// CALL _morestack
//
// if N > 75
// LEAQ (-N-75)(SP), AX
// CMPQ AX, 0(R15)
// JHI 3(PC)
// MOVQ $(N1<<0) | (A1<<32)), AX
// CALL _morestack
//
TEXT _morestack(SB), 7, $0
// save stuff on interrupt stack
MOVQ 8(R14), BX // istack
MOVQ SP, 8(BX) // old SP
MOVQ AX, 16(BX) // magic number
MOVQ 0(R15), AX // old limit
MOVQ AX, 24(BX)
// switch and set up new limit
MOVQ BX, SP
MOVQ 0(R14), AX // istack limit
MOVQ AX, 0(R15)
// allocate a new stack max of request and 4k
MOVL 16(SP), AX // magic number
CMPL AX, $4096
JHI 2(PC)
MOVL $4096, AX
MOVL AX, 0(SP)
CALL mal(SB)
// switch to new stack
MOVQ SP, BX // istack
ADDQ $104, AX // new stack limit
MOVQ AX, 0(R15)
ADDQ 0(SP), AX
LEAQ (-104-4*8)(AX), SP // new SP
MOVQ 8(R15), AX
MOVQ AX, 0(SP) // old base
MOVQ SP, 8(R15) // new base
// copy needed stuff from istack to new stack
MOVQ 16(BX), AX // magic number
MOVQ AX, 16(SP)
MOVQ 24(BX), AX // old limit
MOVQ AX, 24(SP)
MOVQ 8(BX), AX // old SP
MOVQ AX, 8(SP)
// are there parameters
MOVL 20(SP), CX // copy count
CMPL CX, $0
JEQ easy
// copy in
LEAQ 16(AX), SI
SUBQ CX, SP
MOVQ SP, DI
SHRL $3, CX
CLD
REP
MOVSQ
// call the intended
CALL 0(AX)
// copy out
MOVQ SP, SI
MOVQ 8(R15), BX // new base
MOVQ 8(BX), AX // old SP
LEAQ 16(AX), DI
MOVL 20(BX), CX // copy count
SHRL $3, CX
CLD
REP
MOVSQ
// restore old SP and limit
MOVQ 8(R15), SP // new base
MOVQ 24(SP), AX // old limit
MOVQ AX, 0(R15)
MOVQ 0(SP), AX
MOVQ AX, 8(R15) // old base
MOVQ 8(SP), AX // old SP
MOVQ AX, SP
// and return to the call behind mine
ADDQ $8, SP
TEXT sys·breakpoint(SB),7,$-8
BYTE $0xcc
RET
easy:
CALL 0(AX)
// restore old SP and limit
MOVQ 24(SP), AX // old limit
MOVQ AX, 0(R15)
MOVQ 0(SP), AX
MOVQ AX, 8(R15) // old base
MOVQ 8(SP), AX // old SP
MOVQ AX, SP
// and return to the call behind mine
ADDQ $8, SP
TEXT _morestack(SB), 7, $-8
BYTE $0xcc
RET
// marker. must be here; used by traceback() to discover calls to _morestack
TEXT _endmorestack(SB), 7, $-8
RET
// call a subroutine in a new coroutine
// argument list is on the stack
// addr of fn is in AX
TEXT sys·_newproc(SB), 7, $0
// save stuff on interrupt stack
MOVQ 8(R14), CX // istack
MOVQ AX, 0(CX) // fn pointer
MOVQ BX, 8(CX) // arg size
MOVQ SP, 16(CX) // old SP
MOVQ 0(R15), AX // old limit
MOVQ AX, 24(CX)
// switch and set up new limit
MOVQ CX, SP
MOVQ 0(R14), AX // istack limit
MOVQ AX, 0(R15)
CALL _newproc(SB)
// restore old SP and limit
MOVQ 24(SP), AX // old limit
MOVQ AX, 0(R15)
MOVQ 16(SP), AX // old SP
MOVQ AX, SP
TEXT FLUSH(SB),7,$-8
RET
/*
* go-routine
*/
TEXT gogo(SB), 7, $0
MOVQ 8(SP), AX // gobuf
MOVQ 0(AX), SP // restore SP
MOVQ 8(AX), AX
MOVQ AX, 0(SP) // put PC on the stack
MOVL $1, AX // return 1
RET
TEXT FLUSH(SB),7,$-8
TEXT gosave(SB), 7, $0
MOVQ 8(SP), AX // gobuf
MOVQ SP, 0(AX) // save SP
MOVQ 0(SP), BX
MOVQ BX, 8(AX) // save PC
MOVL $0, AX // return 0
RET
TEXT getu(SB),7,$-8
MOVQ R15, AX
TEXT setspgoto(SB), 7, $0
MOVQ 8(SP), AX // SP
MOVQ 16(SP), BX // fn to call
MOVQ 24(SP), CX // fn to return
MOVQ AX, SP
PUSHQ CX
JMP BX
POPQ AX
RET
GLOBL permach<>(SB),$64
GLOBL peruser<>(SB),$64
GLOBL m0<>(SB),$64
......@@ -8,22 +8,6 @@ extern int32 debug;
static int8 spmark[] = "\xa7\xf1\xd9\x2a\x82\xc8\xd8\xfe";
//typedef struct U U;
//struct U {
// uint8* stackguard;
// uint8* stackbase;
// uint8* istackguard;
// uint8* istackbase;
//};
typedef struct Stktop Stktop;
struct Stktop {
uint8* oldbase;
uint8* oldsp;
uint8* magic;
uint8* oldguard;
};
extern void _morestack();
extern void _endmorestack();
......
......@@ -4,9 +4,9 @@
#include "runtime.h"
G g0; // idle goroutine
int32 debug = 0;
/*BUG: move traceback code to architecture-dependent runtime */
void
sys·panicl(int32 lno)
{
......@@ -18,7 +18,7 @@ sys·panicl(int32 lno)
sys·printpc(&lno);
prints("\n");
sp = (uint8*)&lno;
traceback(sys·getcallerpc(&lno), sp, getu());
traceback(sys·getcallerpc(&lno), sp, g);
sys·breakpoint();
sys·exit(2);
}
......@@ -571,20 +571,229 @@ check(void)
initsig();
}
extern register u;
uint32 a;
void
sys·goexit(void)
{
//prints("goexit goid=");
//sys·printint(g->goid);
//prints("\n");
g->status = Gdead;
sys·gosched();
}
void
_newproc(byte* fn, int32 siz, byte* args)
sys·newproc(int32 siz, byte* fn, byte* arg0)
{
a = u;
byte *stk, *sp;
G *newg;
prints("_newproc fn=");
sys·printpointer(fn);
prints("; siz=");
sys·printint(siz);
prints("; args=");
sys·printpointer(args);
prints("\n");
dump(args, 32);
//prints("newproc siz=");
//sys·printint(siz);
//prints(" fn=");
//sys·printpointer(fn);
siz = (siz+7) & ~7;
if(siz > 1024) {
prints("sys·newproc: too many args: ");
sys·printint(siz);
prints("\n");
sys·panicl(123);
}
newg = mal(sizeof(G));
stk = mal(4096);
newg->stackguard = stk+160;
sp = stk + 4096 - 4*8;
newg->stackbase = sp;
sp -= siz;
mcpy(sp, (byte*)&arg0, siz);
sp -= 8;
*(byte**)sp = (byte*)sys·goexit;
sp -= 8; // retpc used by gogo
newg->sched.SP = sp;
newg->sched.PC = fn;
goidgen++;
newg->goid = goidgen;
newg->status = Grunnable;
newg->link = allg;
allg = newg;
//prints(" goid=");
//sys·printint(newg->goid);
//prints("\n");
}
G*
select(void)
{
G *gp, *bestg;
bestg = nil;
for(gp=allg; gp!=nil; gp=gp->link) {
if(gp->status != Grunnable)
continue;
if(bestg == nil || gp->pri < bestg->pri)
bestg = gp;
}
if(bestg != nil)
bestg->pri++;
return bestg;
}
void
gom0init(void)
{
gosave(&m->sched);
sys·gosched();
}
void
sys·gosched(void)
{
G* gp;
if(g != m->g0) {
if(gosave(&g->sched))
return;
g = m->g0;
gogo(&m->sched);
}
gp = select();
if(gp == nil) {
// prints("sched: no more work\n");
sys·exit(0);
}
m->curg = gp;
g = gp;
gogo(&gp->sched);
}
//
// the calling sequence for a routine that
// needs N bytes stack, A args.
//
// N1 = (N+160 > 4096)? N+160: 0
// A1 = A
//
// if N <= 75
// CMPQ SP, 0(R15)
// JHI 4(PC)
// MOVQ $(N1<<0) | (A1<<32)), AX
// MOVQ AX, 0(R14)
// CALL sys·morestack(SB)
//
// if N > 75
// LEAQ (-N-75)(SP), AX
// CMPQ AX, 0(R15)
// JHI 4(PC)
// MOVQ $(N1<<0) | (A1<<32)), AX
// MOVQ AX, 0(R14)
// CALL sys·morestack(SB)
//
int32 debug = 0;
void
morestack2(void)
{
Stktop *top;
uint32 siz2;
byte *sp;
if(debug) prints("morestack2\n");
top = (Stktop*)m->curg->stackbase;
m->curg->stackbase = top->oldbase;
m->curg->stackguard = top->oldguard;
siz2 = (top->magic>>32) & 0xffffLL;
sp = (byte*)top;
if(siz2 > 0) {
siz2 = (siz2+7) & ~7;
sp -= siz2;
mcpy(top->oldsp+16, sp, siz2);
}
m->morestack.SP = top->oldsp+8;
m->morestack.PC = (byte*)(*(uint64*)(top->oldsp+8));
if(debug) prints("morestack2 sp=");
if(debug) sys·printpointer(m->morestack.SP);
if(debug) prints(" pc=");
if(debug) sys·printpointer(m->morestack.PC);
if(debug) prints("\n");
gogo(&m->morestack);
}
void
morestack1(void)
{
int32 siz1, siz2;
Stktop *top;
byte *stk, *sp;
void (*fn)(void);
siz1 = m->morearg & 0xffffffffLL;
siz2 = (m->morearg>>32) & 0xffffLL;
if(debug) prints("morestack1 siz1=");
if(debug) sys·printint(siz1);
if(debug) prints(" siz2=");
if(debug) sys·printint(siz2);
if(debug) prints(" moresp=");
if(debug) sys·printpointer(m->moresp);
if(debug) prints("\n");
if(siz1 < 4096)
siz1 = 4096;
stk = mal(siz1 + 1024);
stk += 512;
top = (Stktop*)(stk+siz1-sizeof(*top));
top->oldbase = m->curg->stackbase;
top->oldguard = m->curg->stackguard;
top->oldsp = m->moresp;
top->magic = m->morearg;
m->curg->stackbase = (byte*)top;
m->curg->stackguard = stk + 160;
sp = (byte*)top;
if(siz2 > 0) {
siz2 = (siz2+7) & ~7;
sp -= siz2;
mcpy(sp, m->moresp+16, siz2);
}
g = m->curg;
fn = (void(*)(void))(*(uint64*)m->moresp);
if(debug) prints("fn=");
if(debug) sys·printpointer(fn);
if(debug) prints("\n");
setspgoto(sp, fn, morestack2);
*(int32*)345 = 123;
}
void
sys·morestack(uint64 u)
{
while(g == m->g0) {
// very bad news
*(int32*)123 = 123;
}
g = m->g0;
m->moresp = (byte*)(&u-1);
setspgoto(m->sched.SP, morestack1, nil);
*(int32*)234 = 123;
}
......@@ -60,31 +60,59 @@ struct Map
int32 unused;
void (*fun[])(void);
};
typedef struct Gobuf Gobuf;
struct Gobuf
{
byte* SP;
byte* PC;
};
typedef struct G G;
struct G
{
byte* stackguard; // must not move
byte* stackbase; // must not move
G* ufor; // dbl ll of all u
G* ubak;
G* runqfor; // dbl ll of runnable
G* runqbak;
Gobuf sched;
G* link;
int32 status;
int32 pri;
int32 goid;
};
typedef struct M M;
struct M
{
byte* istackguard; // must not move
byte* istackbase; // must not move
G* g0; // g0 w interrupt stack - must not move
uint64 morearg; // arg to morestack - must not move
G* curg; // current running goroutine
Gobuf sched;
Gobuf morestack;
byte* moresp;
int32 siz1;
int32 siz2;
};
typedef struct Stktop Stktop;
struct Stktop {
uint8* oldbase;
uint8* oldsp;
uint64 magic;
uint8* oldguard;
};
extern register G* g; // R15
extern register M* m; // R14
enum
{
// G status
Gidle,
Grunnable,
Gdead,
};
/*
* global variables
*/
M* allm;
G* allu;
G* runq;
G* allg;
int32 goidgen;
/*
* defined constants
......@@ -106,18 +134,21 @@ enum
/*
* common functions and data
*/
int32 strcmp(byte*, byte*);
int32 findnull(int8*);
int32 strcmp(byte*, byte*);
int32 findnull(int8*);
void dump(byte*, int32);
int32 runetochar(byte*, int32);
int32 chartorune(uint32*, byte*);
int32 runetochar(byte*, int32);
int32 chartorune(uint32*, byte*);
extern string emptystring;
extern int32 debug;
extern int32 debug;
/*
* very low level c-called
*/
int32 gogo(Gobuf*);
int32 gosave(Gobuf*);
void setspgoto(byte*, void(*)(void), void(*)(void));
void FLUSH(void*);
void* getu(void);
void throw(int8*);
......@@ -126,7 +157,7 @@ void mcpy(byte*, byte*, uint32);
void* mal(uint32);
uint32 cmpstring(string, string);
void initsig(void);
void traceback(uint8 *pc, uint8 *sp, void* up);
void traceback(uint8 *pc, uint8 *sp, G* gp);
int32 open(byte*, int32);
int32 read(int32, void*, int32);
void close(int32);
......@@ -140,6 +171,8 @@ struct SigTab
/*
* low level go -called
*/
void sys·goexit(void);
void sys·gosched(void);
void sys·exit(int32);
void sys·write(int32, void*, int32);
void sys·breakpoint(void);
......
......@@ -71,10 +71,6 @@ TEXT sigtramp(SB),1,$24
CALL sighandler(SB)
RET
TEXT sys·breakpoint(SB),1,$-8
BYTE $0xcc
RET
TEXT sys·mmap(SB),1,$-8
MOVQ 8(SP), DI // arg 1 addr
MOVL 16(SP), SI // arg 2 len
......
......@@ -65,10 +65,6 @@ TEXT sigtramp(SB),1,$24
CALL sighandler(SB)
RET
TEXT sys·breakpoint(SB),1,$-8
BYTE $0xcc
RET
TEXT sys·mmap(SB),1,$-8
MOVQ 8(SP), DI
MOVL 16(SP), SI
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment