| // Copyright 2010 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| #include "runtime.h" | |
| #include "os_GOOS.h" | |
| #include "arch_GOARCH.h" | |
| int8 *goos = "plan9"; | |
| int8 *runtime·exitstatus; | |
| int32 runtime·postnote(int32, int8*); | |
| void | |
| runtime·minit(void) | |
| { | |
| } | |
| static int32 | |
| getproccount(void) | |
| { | |
| int32 fd, i, n, ncpu; | |
| byte buf[2048]; | |
| fd = runtime·open((byte*)"/dev/sysstat", OREAD); | |
| if(fd < 0) | |
| return 1; | |
| ncpu = 0; | |
| for(;;) { | |
| n = runtime·read(fd, buf, sizeof buf); | |
| if(n <= 0) | |
| break; | |
| for(i = 0; i < n; i++) { | |
| if(buf[i] == '\n') | |
| ncpu++; | |
| } | |
| } | |
| runtime·close(fd); | |
| return ncpu > 0 ? ncpu : 1; | |
| } | |
| static int32 | |
| getpid(void) | |
| { | |
| byte b[20], *c; | |
| int32 fd, n; | |
| 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·gonote); | |
| } | |
| void | |
| runtime·goenvs(void) | |
| { | |
| } | |
| void | |
| runtime·initsig(void) | |
| { | |
| } | |
| void | |
| runtime·osyield(void) | |
| { | |
| runtime·sleep(0); | |
| } | |
| void | |
| runtime·usleep(uint32 µs) | |
| { | |
| uint32 ms; | |
| ms = µs/1000; | |
| if(ms == 0) | |
| ms = 1; | |
| 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) | |
| { | |
| int64 ns; | |
| ns = runtime·nanotime(); | |
| sec = ns / 1000000000LL; | |
| nsec = ns - sec * 1000000000LL; | |
| FLUSH(&sec); | |
| FLUSH(&nsec); | |
| } | |
| void | |
| runtime·itoa(int32 n, byte *p, uint32 len) | |
| { | |
| 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 | |
| goexitsall(void) | |
| { | |
| M *m; | |
| int32 pid; | |
| pid = getpid(); | |
| for(m=runtime·atomicloadp(&runtime·allm); m; m=m->alllink) | |
| if(m->procid != pid) | |
| runtime·postnote(m->procid, "gointr"); | |
| } | |
| void | |
| runtime·gonote(void*, byte *s) | |
| { | |
| uint8 buf[128]; | |
| int32 l; | |
| l = runtime·findnull(s); | |
| if(l > 4 && runtime·mcmp(s, (byte*)"sys:", 4) == 0) { | |
| runtime·memclr(buf, sizeof buf); | |
| runtime·memmove((void*)buf, (void*)s, runtime·findnull(s)); | |
| runtime·exitstatus = (int8*)buf; | |
| goexitsall(); | |
| runtime·noted(NDFLT); | |
| } | |
| if(runtime·exitstatus) | |
| runtime·exits(runtime·exitstatus); | |
| if(runtime·strcmp(s, (byte*)"gointr") == 0) | |
| runtime·noted(NCONT); | |
| runtime·noted(NDFLT); | |
| } | |
| int32 | |
| runtime·postnote(int32 pid, int8* msg) | |
| { | |
| int32 fd, len; | |
| uint8 buf[128]; | |
| uint8 tmp[16]; | |
| uint8 *p, *q; | |
| runtime·memclr(buf, sizeof buf); | |
| /* build path string /proc/pid/note */ | |
| q = tmp; | |
| p = buf; | |
| runtime·itoa(pid, tmp, sizeof tmp); | |
| runtime·memmove((void*)p, (void*)"/proc/", 6); | |
| for(p += 6; *p++ = *q++; ); | |
| p--; | |
| runtime·memmove((void*)p, (void*)"/note", 5); | |
| fd = runtime·open(buf, OWRITE); | |
| 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·exit(int32 e) | |
| { | |
| byte tmp[16]; | |
| if(e == 0) | |
| runtime·exitstatus = ""; | |
| else { | |
| /* build error string */ | |
| runtime·itoa(e, tmp, sizeof tmp); | |
| runtime·exitstatus = (int8*)tmp; | |
| } | |
| goexitsall(); | |
| runtime·exits(runtime·exitstatus); | |
| } | |
| void | |
| runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) | |
| { | |
| m->tls[0] = m->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); | |
| } | |
| if(runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, m, g, fn) < 0) | |
| runtime·throw("newosproc: rfork failed"); | |
| } | |
| uintptr | |
| runtime·semacreate(void) | |
| { | |
| return 1; | |
| } | |
| int32 | |
| runtime·semasleep(int64 ns) | |
| { | |
| int32 ret; | |
| 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) | |
| ms = 0x7fffffff; | |
| else | |
| ms = ns/1000; | |
| ret = runtime·plan9_tsemacquire(&m->waitsemacount, 1, ms); | |
| if(ret == 1) | |
| return 0; // success | |
| return -1; // timeout or interrupted | |
| */ | |
| } | |
| while(runtime·plan9_semacquire(&m->waitsemacount, 1) < 0) { | |
| /* interrupted; try again */ | |
| } | |
| return 0; // success | |
| } | |
| void | |
| runtime·semawakeup(M *mp) | |
| { | |
| runtime·plan9_semrelease(&mp->waitsemacount, 1); | |
| } | |
| void | |
| 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) | |
| { | |
| } | |
| int32 | |
| runtime·read(int32 fd, void *buf, int32 nbytes) | |
| { | |
| return runtime·pread(fd, buf, nbytes, -1LL); | |
| } | |
| int32 | |
| runtime·write(int32 fd, void *buf, int32 nbytes) | |
| { | |
| return runtime·pwrite(fd, buf, nbytes, -1LL); | |
| } | |
| uintptr | |
| runtime·memlimit(void) | |
| { | |
| return 0; | |
| } | |
| void | |
| runtime·setprof(bool on) | |
| { | |
| USED(on); | |
| } | |
| static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; | |
| // This runs on a foreign stack, without an m or a g. No stack split. | |
| #pragma textflag 7 | |
| void | |
| runtime·badcallback(void) | |
| { | |
| runtime·pwrite(2, badcallback, sizeof badcallback - 1, -1LL); | |
| } | |
| static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n"; | |
| // This runs on a foreign stack, without an m or a g. No stack split. | |
| #pragma textflag 7 | |
| void | |
| runtime·badsignal(void) | |
| { | |
| runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL); | |
| } |