aboutsummaryrefslogtreecommitdiff
path: root/libgo/runtime
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2011-12-12 23:40:51 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-12-12 23:40:51 +0000
commitab61e9c4da707f3bc7b177c0c8f92daccdb142dc (patch)
tree0c68629fac9d7c6f103b401c9063ef00ed259f06 /libgo/runtime
parent6e456f4cf4deee3e2ccd9849286f59b90644c48b (diff)
downloadgcc-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.c4
-rw-r--r--libgo/runtime/mgc0.c1
-rw-r--r--libgo/runtime/proc.c18
-rw-r--r--libgo/runtime/runtime.c12
-rw-r--r--libgo/runtime/runtime.h38
-rw-r--r--libgo/runtime/thread-linux.c2
-rw-r--r--libgo/runtime/time.goc255
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);
+}