diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-12-12 23:40:51 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-12-12 23:40:51 +0000 |
commit | ab61e9c4da707f3bc7b177c0c8f92daccdb142dc (patch) | |
tree | 0c68629fac9d7c6f103b401c9063ef00ed259f06 /libgo/runtime | |
parent | 6e456f4cf4deee3e2ccd9849286f59b90644c48b (diff) | |
download | gcc-ab61e9c4da707f3bc7b177c0c8f92daccdb142dc.zip gcc-ab61e9c4da707f3bc7b177c0c8f92daccdb142dc.tar.gz gcc-ab61e9c4da707f3bc7b177c0c8f92daccdb142dc.tar.bz2 |
libgo: Update to weekly.2011-11-18.
From-SVN: r182266
Diffstat (limited to 'libgo/runtime')
-rw-r--r-- | libgo/runtime/go-setenv.c | 4 | ||||
-rw-r--r-- | libgo/runtime/mgc0.c | 1 | ||||
-rw-r--r-- | libgo/runtime/proc.c | 18 | ||||
-rw-r--r-- | libgo/runtime/runtime.c | 12 | ||||
-rw-r--r-- | libgo/runtime/runtime.h | 38 | ||||
-rw-r--r-- | libgo/runtime/thread-linux.c | 2 | ||||
-rw-r--r-- | libgo/runtime/time.goc | 255 |
7 files changed, 312 insertions, 18 deletions
diff --git a/libgo/runtime/go-setenv.c b/libgo/runtime/go-setenv.c index 9c93f52..78717f4 100644 --- a/libgo/runtime/go-setenv.c +++ b/libgo/runtime/go-setenv.c @@ -12,10 +12,10 @@ #include "go-alloc.h" #include "go-string.h" -/* Set the C environment from Go. This is called by os.Setenv. */ +/* Set the C environment from Go. This is called by syscall.Setenv. */ void setenv_c (struct __go_string, struct __go_string) - __asm__ ("libgo_os.os.setenv_c"); + __asm__ ("libgo_syscall.syscall.setenv_c"); void setenv_c (struct __go_string k, struct __go_string v) diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c index 0f1cb49..c4ab145 100644 --- a/libgo/runtime/mgc0.c +++ b/libgo/runtime/mgc0.c @@ -741,6 +741,7 @@ mark(void (*scan)(byte*, int64)) scan((byte*)&runtime_allg, sizeof runtime_allg); scan((byte*)&runtime_allm, sizeof runtime_allm); runtime_MProf_Mark(scan); + runtime_time_scan(scan); // mark stacks for(gp=runtime_allg; gp!=nil; gp=gp->alllink) { diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index 88831d4..34566fb 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -42,7 +42,6 @@ extern void *__splitstack_find(void *, void *, size_t *, void **, void **, #endif static void schedule(G*); -static M *startm(void); typedef struct Sched Sched; @@ -128,7 +127,7 @@ struct Sched { volatile uint32 atomic; // atomic scheduling word (see below) int32 profilehz; // cpu profiling rate - + bool init; // running initialization bool lockmain; // init called runtime.LockOSThread @@ -826,7 +825,7 @@ runtime_starttheworld(bool extra) // but m is not running a specific goroutine, // so set the helpgc flag as a signal to m's // first schedule(nil) to mcpu-- and grunning--. - m = startm(); + m = runtime_newm(); m->helpgc = 1; runtime_sched.grunning++; } @@ -876,8 +875,6 @@ struct CgoThreadStart }; // Kick off new m's as needed (up to mcpumax). -// There are already `other' other cpus that will -// start looking for goroutines shortly. // Sched is locked. static void matchmg(void) @@ -895,13 +892,14 @@ matchmg(void) // Find the m that will run gp. if((mp = mget(gp)) == nil) - mp = startm(); + mp = runtime_newm(); mnextg(mp, gp); } } -static M* -startm(void) +// Create a new m. It will start off with a call to runtime_mstart. +M* +runtime_newm(void) { M *m; pthread_attr_t attr; @@ -1135,6 +1133,7 @@ runtime_exitsyscall(void) runtime_memclr(gp->gcregs, sizeof gp->gcregs); } +// Allocate a new g, with a stack big enough for stacksize bytes. G* runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize) { @@ -1283,6 +1282,7 @@ runtime_Gosched(void) runtime_gosched(); } +// Implementation of runtime.GOMAXPROCS. // delete when scheduler is stronger int32 runtime_gomaxprocsfunc(int32 n) @@ -1390,6 +1390,7 @@ static struct { uintptr pcbuf[100]; } prof; +// Called if we receive a SIGPROF signal. void runtime_sigprof(uint8 *pc __attribute__ ((unused)), uint8 *sp __attribute__ ((unused)), @@ -1412,6 +1413,7 @@ runtime_sigprof(uint8 *pc __attribute__ ((unused)), runtime_unlock(&prof); } +// Arrange to call fn with a traceback hz times a second. void runtime_setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz) { diff --git a/libgo/runtime/runtime.c b/libgo/runtime/runtime.c index 8e4433b..ec96f5b 100644 --- a/libgo/runtime/runtime.c +++ b/libgo/runtime/runtime.c @@ -87,7 +87,7 @@ static int32 argc; static byte** argv; extern Slice os_Args asm ("libgo_os.os.Args"); -extern Slice os_Envs asm ("libgo_os.os.Envs"); +extern Slice syscall_Envs asm ("libgo_syscall.syscall.Envs"); void runtime_args(int32 c, byte **v) @@ -126,9 +126,9 @@ runtime_goenvs(void) s = runtime_malloc(n*sizeof s[0]); for(i=0; i<n; i++) s[i] = runtime_gostringnocopy(argv[argc+1+i]); - os_Envs.__values = (void*)s; - os_Envs.__count = n; - os_Envs.__capacity = n; + syscall_Envs.__values = (void*)s; + syscall_Envs.__count = n; + syscall_Envs.__capacity = n; } const byte* @@ -141,8 +141,8 @@ runtime_getenv(const char *s) bs = (const byte*)s; len = runtime_findnull(bs); - envv = (String*)os_Envs.__values; - envc = os_Envs.__count; + envv = (String*)syscall_Envs.__values; + envc = syscall_Envs.__count; for(i=0; i<envc; i++){ if(envv[i].__length <= len) continue; diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 0044319..1c7ede9 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -56,6 +56,8 @@ typedef union Note Note; typedef struct MCache MCache; typedef struct FixAlloc FixAlloc; typedef struct Hchan Hchan; +typedef struct Timers Timers; +typedef struct Timer Timer; typedef struct __go_open_array Slice; typedef struct __go_string String; @@ -190,6 +192,38 @@ enum { }; #endif +struct Timers +{ + Lock; + G *timerproc; + bool sleeping; + bool rescheduling; + Note waitnote; + Timer **t; + int32 len; + int32 cap; +}; + +// Package time knows the layout of this structure. +// If this struct changes, adjust ../time/sleep.go:/runtimeTimer. +struct Timer +{ + int32 i; // heap index + + // Timer wakes up at when, and then at when+period, ... (period > 0 only) + // each time calling f(now, arg) in the timer goroutine, so f must be + // a well-behaved function and not block. + int64 when; + int64 period; + void (*f)(int64, Eface); + Eface arg; +}; + +/* + * defined macros + * you need super-gopher-guru privilege + * to add this list. + */ #define nelem(x) (sizeof(x)/sizeof((x)[0])) #define nil ((void*)0) #define USED(v) ((void) v) @@ -229,6 +263,8 @@ G* runtime_malg(int32, byte**, size_t*); void runtime_minit(void); void runtime_mallocinit(void); void runtime_gosched(void); +void runtime_tsleep(int64); +M* runtime_newm(void); void runtime_goexit(void); void runtime_entersyscall(void) __asm__("libgo_syscall.syscall.entersyscall"); void runtime_exitsyscall(void) __asm__("libgo_syscall.syscall.exitsyscall"); @@ -341,3 +377,5 @@ void reflect_call(const struct __go_func_type *, const void *, _Bool, _Bool, #ifdef __rtems__ void __wrap_rtems_task_variable_add(void **); #endif + +void runtime_time_scan(void (*)(byte*, int64)); diff --git a/libgo/runtime/thread-linux.c b/libgo/runtime/thread-linux.c index c08cc0d..a0ee360 100644 --- a/libgo/runtime/thread-linux.c +++ b/libgo/runtime/thread-linux.c @@ -30,7 +30,7 @@ runtime_futexsleep(uint32 *addr, uint32 val, int64 ns) else { ts.tv_sec = ns/1000000000LL; ts.tv_nsec = ns%1000000000LL; - // Avoid overflowdefs + // Avoid overflow if(ts.tv_sec > 1<<30) ts.tv_sec = 1<<30; tsp = &ts; diff --git a/libgo/runtime/time.goc b/libgo/runtime/time.goc index f5a412a..93b896e 100644 --- a/libgo/runtime/time.goc +++ b/libgo/runtime/time.goc @@ -2,12 +2,265 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Runtime implementations to help package time. +// Time-related runtime and pieces of package time. package time #include "runtime.h" +#include "defs.h" +#include "arch.h" +#include "malloc.h" +static Timers timers; +static void addtimer(Timer*); +static bool deltimer(Timer*); + +// Package time APIs. +// Godoc uses the comments in package time, not these. + +// Nanoseconds returns the current time in nanoseconds. func Nanoseconds() (ret int64) { ret = runtime_nanotime(); } + +// Sleep puts the current goroutine to sleep for at least ns nanoseconds. +func Sleep(ns int64) { + G *g; + + g = runtime_g(); + g->status = Gwaiting; + g->waitreason = "sleep"; + runtime_tsleep(ns); +} + +// startTimer adds t to the timer heap. +func startTimer(t *Timer) { + addtimer(t); +} + +// stopTimer removes t from the timer heap if it is there. +// It returns true if t was removed, false if t wasn't even there. +func stopTimer(t *Timer) (stopped bool) { + stopped = deltimer(t); +} + +// C runtime. + +static void timerproc(void*); +static void siftup(int32); +static void siftdown(int32); + +// Ready the goroutine e.data. +static void +ready(int64 now, Eface e) +{ + USED(now); + + runtime_ready(e.__object); +} + +// Put the current goroutine to sleep for ns nanoseconds. +// The caller must have set g->status and g->waitreason. +void +runtime_tsleep(int64 ns) +{ + Timer t; + + if(ns <= 0) + return; + + t.when = runtime_nanotime() + ns; + t.period = 0; + t.f = ready; + t.arg.__object = runtime_g(); + addtimer(&t); + runtime_gosched(); +} + +// Add a timer to the heap and start or kick the timer proc +// if the new timer is earlier than any of the others. +static void +addtimer(Timer *t) +{ + int32 n; + Timer **nt; + + runtime_lock(&timers); + if(timers.len >= timers.cap) { + // Grow slice. + n = 16; + if(n <= timers.cap) + n = timers.cap*3 / 2; + nt = runtime_malloc(n*sizeof nt[0]); + runtime_memmove(nt, timers.t, timers.len*sizeof nt[0]); + runtime_free(timers.t); + timers.t = nt; + timers.cap = n; + } + t->i = timers.len++; + timers.t[t->i] = t; + siftup(t->i); + if(t->i == 0) { + // siftup moved to top: new earliest deadline. + if(timers.sleeping) { + timers.sleeping = false; + runtime_notewakeup(&timers.waitnote); + } + if(timers.rescheduling) { + timers.rescheduling = false; + runtime_ready(timers.timerproc); + } + } + if(timers.timerproc == nil) + timers.timerproc = __go_go(timerproc, nil); + runtime_unlock(&timers); +} + +// Delete timer t from the heap. +// Do not need to update the timerproc: +// if it wakes up early, no big deal. +static bool +deltimer(Timer *t) +{ + int32 i; + + runtime_lock(&timers); + + // t may not be registered anymore and may have + // a bogus i (typically 0, if generated by Go). + // Verify it before proceeding. + i = t->i; + if(i < 0 || i >= timers.len || timers.t[i] != t) { + runtime_unlock(&timers); + return false; + } + + timers.len--; + if(i == timers.len) { + timers.t[i] = nil; + } else { + timers.t[i] = timers.t[timers.len]; + timers.t[timers.len] = nil; + timers.t[i]->i = i; + siftup(i); + siftdown(i); + } + runtime_unlock(&timers); + return true; +} + +// Timerproc runs the time-driven events. +// It sleeps until the next event in the timers heap. +// If addtimer inserts a new earlier event, addtimer +// wakes timerproc early. +static void +timerproc(void* dummy __attribute__ ((unused))) +{ + G *g; + int64 delta, now; + Timer *t; + void (*f)(int64, Eface); + Eface arg; + + g = runtime_g(); + for(;;) { + runtime_lock(&timers); + now = runtime_nanotime(); + for(;;) { + if(timers.len == 0) { + delta = -1; + break; + } + t = timers.t[0]; + delta = t->when - now; + if(delta > 0) + break; + if(t->period > 0) { + // leave in heap but adjust next time to fire + t->when += t->period * (1 + -delta/t->period); + siftdown(0); + } else { + // remove from heap + timers.t[0] = timers.t[--timers.len]; + timers.t[0]->i = 0; + siftdown(0); + t->i = -1; // mark as removed + } + f = t->f; + arg = t->arg; + runtime_unlock(&timers); + f(now, arg); + runtime_lock(&timers); + } + if(delta < 0) { + // No timers left - put goroutine to sleep. + timers.rescheduling = true; + g->status = Gwaiting; + g->waitreason = "timer goroutine (idle)"; + runtime_unlock(&timers); + runtime_gosched(); + continue; + } + // At least one timer pending. Sleep until then. + timers.sleeping = true; + runtime_noteclear(&timers.waitnote); + runtime_unlock(&timers); + runtime_entersyscall(); + runtime_notetsleep(&timers.waitnote, delta); + runtime_exitsyscall(); + } +} + +// heap maintenance algorithms. + +static void +siftup(int32 i) +{ + int32 p; + Timer **t, *tmp; + + t = timers.t; + while(i > 0) { + p = (i-1)/2; // parent + if(t[i]->when >= t[p]->when) + break; + tmp = t[i]; + t[i] = t[p]; + t[p] = tmp; + t[i]->i = i; + t[p]->i = p; + i = p; + } +} + +static void +siftdown(int32 i) +{ + int32 c, len; + Timer **t, *tmp; + + t = timers.t; + len = timers.len; + for(;;) { + c = i*2 + 1; // left child + if(c >= len) { + break; + } + if(c+1 < len && t[c+1]->when < t[c]->when) + c++; + if(t[c]->when >= t[i]->when) + break; + tmp = t[i]; + t[i] = t[c]; + t[c] = tmp; + t[i]->i = i; + t[c]->i = c; + i = c; + } +} + +void +runtime_time_scan(void (*scan)(byte*, int64)) +{ + scan((byte*)&timers, sizeof timers); +} |