aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorKen Thompson <ken@golang.org>2009-01-27 12:03:53 -0800
committerKen Thompson <ken@golang.org>2009-01-27 12:03:53 -0800
commit1e1cc4eb570aa6fec645ff4faf13431847b99db8 (patch)
treebbbf12c48e9ab2d82b89e6a0adf15f15757e57af /src/runtime
parent4a903e0b32be5a590880ceb7379e68790602c29d (diff)
downloadgo-1e1cc4eb570aa6fec645ff4faf13431847b99db8.tar.xz
defer
R=r OCL=23592 CL=23592
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/proc.c37
-rw-r--r--src/runtime/rt0_amd64.s12
-rw-r--r--src/runtime/runtime.h23
3 files changed, 66 insertions, 6 deletions
diff --git a/src/runtime/proc.c b/src/runtime/proc.c
index 7435830ff6..3fe08df94d 100644
--- a/src/runtime/proc.c
+++ b/src/runtime/proc.c
@@ -171,7 +171,7 @@ sys·newproc(int32 siz, byte* fn, byte* arg0)
if((newg = gfget()) != nil){
newg->status = Gwaiting;
- }else{
+ } else {
newg = malg(4096);
newg->status = Gwaiting;
newg->alllink = allg;
@@ -205,6 +205,41 @@ sys·newproc(int32 siz, byte* fn, byte* arg0)
}
void
+sys·deferproc(int32 siz, byte* fn, byte* arg0)
+{
+ Defer *d;
+
+ d = mal(sizeof(*d) + siz - sizeof(d->args));
+ d->fn = fn;
+ d->sp = (byte*)&arg0;
+ d->siz = siz;
+ mcpy(d->args, d->sp, d->siz);
+
+ d->link = g->defer;
+ g->defer = d;
+}
+
+void
+sys·deferreturn(int32 arg0)
+{
+ // warning: jmpdefer knows the frame size
+ // of this routine. dont change anything
+ // that might change the frame size
+ Defer *d;
+ byte *sp;
+
+ d = g->defer;
+ if(d == nil)
+ return;
+ sp = (byte*)&arg0;
+ if(d->sp != sp)
+ return;
+ mcpy(d->sp, d->args, d->siz);
+ g->defer = d->link;
+ jmpdefer(d->fn);
+}
+
+void
tracebackothers(G *me)
{
G *g;
diff --git a/src/runtime/rt0_amd64.s b/src/runtime/rt0_amd64.s
index 8588d61a4e..f8d4a381b3 100644
--- a/src/runtime/rt0_amd64.s
+++ b/src/runtime/rt0_amd64.s
@@ -120,7 +120,7 @@ TEXT setspgoto(SB), 7, $0
// if(*val == old){
// *val = new;
// return 1;
-// }else
+// } else
// return 0;
TEXT cas(SB), 7, $0
MOVQ 8(SP), BX
@@ -133,3 +133,13 @@ TEXT cas(SB), 7, $0
RET
MOVL $1, AX
RET
+
+// void jmpdefer(byte*);
+// 1. pop the caller
+// 2. sub 5 bytes from the callers return
+// 3. jmp to the argument
+TEXT jmpdefer(SB), 7, $0
+ MOVQ 8(SP), AX // function
+ ADDQ $(8+56), SP // pop saved PC and callers frame
+ SUBQ $5, (SP) // reposition his return address
+ JMP AX // and goto function
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
index 5552c9e94d..78e2affc62 100644
--- a/src/runtime/runtime.h
+++ b/src/runtime/runtime.h
@@ -52,6 +52,7 @@ typedef struct SigTab SigTab;
typedef struct MCache MCache;
typedef struct Iface Iface;
typedef struct Itype Itype;
+typedef struct Defer Defer;
/*
* per cpu declaration
@@ -128,6 +129,7 @@ struct G
{
byte* stackguard; // must not move
byte* stackbase; // must not move
+ Defer* defer; // must not move
byte* stack0; // first stack segment
Gobuf sched;
G* alllink; // on allg
@@ -136,8 +138,8 @@ struct G
int32 goid;
int32 selgen; // valid sudog pointer
G* schedlink;
- bool readyonstop;
- M* m; // for debuggers
+ bool readyonstop;
+ M* m; // for debuggers
};
struct Mem
{
@@ -151,8 +153,8 @@ struct M
G* g0; // g0 w interrupt stack - must not move
uint64 morearg; // arg to morestack - must not move
uint64 cret; // return value from C - must not move
- uint64 procid; // for debuggers - must not move
- G* gsignal; // signal-handling G - must not move
+ uint64 procid; // for debuggers - must not move
+ G* gsignal; // signal-handling G - must not move
G* curg; // current running goroutine
G* lastg; // last running goroutine - to emulate fifo
Gobuf sched;
@@ -236,6 +238,18 @@ enum
};
/*
+ * defered subroutine calls
+ */
+struct Defer
+{
+ int32 siz;
+ byte* sp;
+ byte* fn;
+ Defer* link;
+ byte args[8]; // padded to actual size
+};
+
+/*
* external data
*/
extern Alg algarray[Amax];
@@ -286,6 +300,7 @@ int32 write(int32, void*, int32);
void close(int32);
int32 fstat(int32, void*);
bool cas(uint32*, uint32, uint32);
+void jmpdefer(byte*);
void exit1(int32);
void ready(G*);
byte* getenv(int8*);