summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/thread_plan9.c
diff options
context:
space:
mode:
authorMichael Stapelberg <stapelberg@debian.org>2013-03-04 21:27:36 +0100
committerMichael Stapelberg <michael@stapelberg.de>2013-03-04 21:27:36 +0100
commit04b08da9af0c450d645ab7389d1467308cfc2db8 (patch)
treedb247935fa4f2f94408edc3acd5d0d4f997aa0d8 /src/pkg/runtime/thread_plan9.c
parent917c5fb8ec48e22459d77e3849e6d388f93d3260 (diff)
downloadgolang-upstream/1.1_hg20130304.tar.gz
Imported Upstream version 1.1~hg20130304upstream/1.1_hg20130304
Diffstat (limited to 'src/pkg/runtime/thread_plan9.c')
-rw-r--r--src/pkg/runtime/thread_plan9.c222
1 files changed, 143 insertions, 79 deletions
diff --git a/src/pkg/runtime/thread_plan9.c b/src/pkg/runtime/thread_plan9.c
index 3b0dca69f..7f94623e7 100644
--- a/src/pkg/runtime/thread_plan9.c
+++ b/src/pkg/runtime/thread_plan9.c
@@ -7,12 +7,37 @@
#include "arch_GOARCH.h"
int8 *goos = "plan9";
+extern SigTab runtime·sigtab[];
+int32 runtime·postnote(int32, int8*);
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+void
+runtime·mpreinit(M *mp)
+{
+ // Initialize stack and goroutine for note handling.
+ mp->gsignal = runtime·malg(32*1024);
+ mp->notesig = (int8*)runtime·malloc(ERRMAX*sizeof(int8));
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
void
runtime·minit(void)
{
+ // Mask all SSE floating-point exceptions
+ // when running on the 64-bit kernel.
+ runtime·setfpmasks();
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
}
+
static int32
getproccount(void)
{
@@ -36,10 +61,30 @@ getproccount(void)
return ncpu > 0 ? ncpu : 1;
}
+static int32
+getpid(void)
+{
+ byte b[20], *c;
+ int32 fd;
+
+ runtime·memclr(b, sizeof(b));
+ fd = runtime·open((byte*)"#c/pid", 0);
+ if(fd >= 0) {
+ runtime·read(fd, b, sizeof(b));
+ runtime·close(fd);
+ }
+ c = b;
+ while(*c == ' ' || *c == '\t')
+ c++;
+ return runtime·atoi(c);
+}
+
void
runtime·osinit(void)
{
runtime·ncpu = getproccount();
+ m->procid = getpid();
+ runtime·notify(runtime·sigtramp);
}
void
@@ -52,6 +97,7 @@ runtime·initsig(void)
{
}
+#pragma textflag 7
void
runtime·osyield(void)
{
@@ -69,34 +115,6 @@ runtime·usleep(uint32 µs)
runtime·sleep(ms);
}
-int64
-runtime·nanotime(void)
-{
- static int32 fd = -1;
- byte b[8];
- uint32 hi, lo;
-
- // As long as all goroutines share the same file
- // descriptor table we can get away with using
- // just a static fd. Without a lock the file can
- // be opened twice but that's okay.
- //
- // Using /dev/bintime gives us a latency on the
- // order of ten microseconds between two calls.
- //
- // The naïve implementation (without the cached
- // file descriptor) is roughly four times slower
- // in 9vx on a 2.16 GHz Intel Core 2 Duo.
-
- if(fd < 0 && (fd = runtime·open((byte*)"/dev/bintime", OREAD|OCEXEC)) < 0)
- return 0;
- if(runtime·pread(fd, b, sizeof b, 0) != sizeof b)
- return 0;
- hi = b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3];
- lo = b[4]<<24 | b[5]<<16 | b[6]<<8 | b[7];
- return (int64)hi<<32 | (int64)lo;
-}
-
void
time·now(int64 sec, int32 nsec)
{
@@ -109,48 +127,111 @@ time·now(int64 sec, int32 nsec)
FLUSH(&nsec);
}
-extern Tos *_tos;
void
-runtime·exit(int32)
+runtime·itoa(int32 n, byte *p, uint32 len)
{
- int32 fd;
+ byte *q, c;
+ uint32 i;
+
+ if(len <= 1)
+ return;
+
+ runtime·memclr(p, len);
+ q = p;
+
+ if(n==0) {
+ *q++ = '0';
+ USED(q);
+ return;
+ }
+ if(n < 0) {
+ *q++ = '-';
+ p++;
+ n = -n;
+ }
+ for(i=0; n > 0 && i < len; i++) {
+ *q++ = '0' + (n%10);
+ n = n/10;
+ }
+ for(q--; q >= p; ) {
+ c = *p;
+ *p++ = *q;
+ *q-- = c;
+ }
+}
+
+void
+runtime·goexitsall(int8 *status)
+{
+ M *mp;
+ int32 pid;
+
+ pid = getpid();
+ for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
+ if(mp->procid != pid)
+ runtime·postnote(mp->procid, status);
+}
+
+int32
+runtime·postnote(int32 pid, int8* msg)
+{
+ int32 fd, len;
uint8 buf[128];
uint8 tmp[16];
uint8 *p, *q;
- int32 pid;
runtime·memclr(buf, sizeof buf);
- runtime·memclr(tmp, sizeof tmp);
- pid = _tos->pid;
- /* build path string /proc/pid/notepg */
- for(q=tmp; pid > 0;) {
- *q++ = '0' + (pid%10);
- pid = pid/10;
- }
+ /* build path string /proc/pid/note */
+ q = tmp;
p = buf;
+ runtime·itoa(pid, tmp, sizeof tmp);
runtime·memmove((void*)p, (void*)"/proc/", 6);
- p += 6;
- for(q--; q >= tmp;)
- *p++ = *q--;
- runtime·memmove((void*)p, (void*)"/notepg", 7);
+ for(p += 6; *p++ = *q++; );
+ p--;
+ runtime·memmove((void*)p, (void*)"/note", 5);
- /* post interrupt note */
fd = runtime·open(buf, OWRITE);
- runtime·write(fd, "interrupt", 9);
- runtime·exits(nil);
+ if(fd < 0)
+ return -1;
+
+ len = runtime·findnull((byte*)msg);
+ if(runtime·write(fd, msg, len) != len) {
+ runtime·close(fd);
+ return -1;
+ }
+ runtime·close(fd);
+ return 0;
}
void
-runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+runtime·exit(int32 e)
{
- m->tls[0] = m->id; // so 386 asm can find it
+ byte tmp[16];
+ int8 *status;
+
+ if(e == 0)
+ status = "";
+ else {
+ /* build error string */
+ runtime·itoa(e, tmp, sizeof tmp);
+ status = (int8*)tmp;
+ }
+
+ runtime·goexitsall(status);
+ runtime·exits(status);
+}
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+ mp->tls[0] = mp->id; // so 386 asm can find it
if(0){
- runtime·printf("newosproc stk=%p m=%p g=%p fn=%p rfork=%p id=%d/%d ostk=%p\n",
- stk, m, g, fn, runtime·rfork, m->id, m->tls[0], &m);
+ runtime·printf("newosproc stk=%p m=%p g=%p rfork=%p id=%d/%d ostk=%p\n",
+ stk, mp, mp->g0, runtime·rfork, mp->id, (int32)mp->tls[0], &mp);
}
- if(runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, m, g, fn) < 0)
+ if(runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, mp, mp->g0, runtime·mstart) < 0)
runtime·throw("newosproc: rfork failed");
}
@@ -167,36 +248,18 @@ runtime·semasleep(int64 ns)
int32 ms;
if(ns >= 0) {
- // TODO: Plan 9 needs a new system call, tsemacquire.
- // The kernel implementation is the same as semacquire
- // except with a tsleep and check for timeout.
- // It would be great if the implementation returned the
- // value that was added to the semaphore, so that on
- // timeout the return value would be 0, on success 1.
- // Then the error string does not have to be parsed
- // to detect timeout.
- //
- // If a negative time indicates no timeout, then
- // semacquire can be implemented (in the kernel)
- // as tsemacquire(p, v, -1).
- runtime·throw("semasleep: timed sleep not implemented on Plan 9");
-
- /*
- if(ns < 0)
- ms = -1;
- else if(ns/1000 > 0x7fffffffll)
+ if(ns/1000000 > 0x7fffffffll)
ms = 0x7fffffff;
else
- ms = ns/1000;
- ret = runtime·plan9_tsemacquire(&m->waitsemacount, 1, ms);
+ ms = ns/1000000;
+ ret = runtime·plan9_tsemacquire(&m->waitsemacount, ms);
if(ret == 1)
return 0; // success
return -1; // timeout or interrupted
- */
}
while(runtime·plan9_semacquire(&m->waitsemacount, 1) < 0) {
- /* interrupted; try again */
+ /* interrupted; try again (c.f. lock_sema.c) */
}
return 0; // success
}
@@ -213,15 +276,15 @@ os·sigpipe(void)
runtime·throw("too many writes on closed pipe");
}
-/*
- * placeholder - once notes are implemented,
- * a signal generating a panic must appear as
- * a call to this function for correct handling by
- * traceback.
- */
void
runtime·sigpanic(void)
{
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring(m->notesig);
+
+ if(g->sig == 1 || g->sig == 2)
+ runtime·throw("fault");
}
int32
@@ -266,4 +329,5 @@ void
runtime·badsignal(void)
{
runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL);
+ runtime·exits(badsignal);
}