| // 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 "defs_GOOS_GOARCH.h" |
| #include "os_GOOS.h" |
| #include "arch_GOARCH.h" |
| #include "textflag.h" |
| #include "stack.h" |
| |
| int8 *goos = "nacl"; |
| extern SigTab runtime·sigtab[]; |
| |
| void runtime·sigtramp(void); |
| |
| // 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) |
| { |
| mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K |
| mp->gsignal->m = mp; |
| } |
| |
| // Called to initialize a new m (including the bootstrap m). |
| // Called on the new thread, can not allocate memory. |
| void |
| runtime·minit(void) |
| { |
| int32 ret; |
| |
| // Initialize signal handling |
| ret = runtime·nacl_exception_stack((byte*)g->m->gsignal->stack.lo, 32*1024); |
| if(ret < 0) |
| runtime·printf("runtime: nacl_exception_stack: error %d\n", -ret); |
| |
| ret = runtime·nacl_exception_handler(runtime·sigtramp, nil); |
| if(ret < 0) |
| runtime·printf("runtime: nacl_exception_handler: error %d\n", -ret); |
| } |
| |
| // Called from dropm to undo the effect of an minit. |
| void |
| runtime·unminit(void) |
| { |
| } |
| |
| int8 runtime·sigtrampf[] = "runtime: signal at PC=%X AX=%X CX=%X DX=%X BX=%X DI=%X R15=%X *SP=%X\n"; |
| int8 runtime·sigtrampp[] = "runtime: sigtramp"; |
| |
| extern byte runtime·tls0[]; |
| |
| void |
| runtime·osinit(void) |
| { |
| runtime·ncpu = 1; |
| g->m->procid = 2; |
| //runtime·nacl_exception_handler(runtime·sigtramp, nil); |
| } |
| |
| void |
| runtime·crash(void) |
| { |
| *(int32*)0 = 0; |
| } |
| |
| #pragma textflag NOSPLIT |
| void |
| runtime·get_random_data(byte **rnd, int32 *rnd_len) |
| { |
| *rnd = nil; |
| *rnd_len = 0; |
| } |
| |
| void |
| runtime·goenvs(void) |
| { |
| runtime·goenvs_unix(); |
| } |
| |
| void |
| runtime·initsig(void) |
| { |
| } |
| |
| #pragma textflag NOSPLIT |
| void |
| runtime·usleep(uint32 us) |
| { |
| Timespec ts; |
| |
| ts.tv_sec = us/1000000; |
| ts.tv_nsec = (us%1000000)*1000; |
| runtime·nacl_nanosleep(&ts, nil); |
| } |
| |
| void runtime·mstart_nacl(void); |
| |
| void |
| runtime·newosproc(M *mp, void *stk) |
| { |
| int32 ret; |
| void **tls; |
| |
| tls = (void**)mp->tls; |
| tls[0] = mp->g0; |
| tls[1] = mp; |
| ret = runtime·nacl_thread_create(runtime·mstart_nacl, stk, tls+2, 0); |
| if(ret < 0) { |
| runtime·printf("nacl_thread_create: error %d\n", -ret); |
| runtime·throw("newosproc"); |
| } |
| } |
| |
| static void |
| semacreate(void) |
| { |
| int32 mu, cond; |
| |
| mu = runtime·nacl_mutex_create(0); |
| if(mu < 0) { |
| runtime·printf("nacl_mutex_create: error %d\n", -mu); |
| runtime·throw("semacreate"); |
| } |
| cond = runtime·nacl_cond_create(0); |
| if(cond < 0) { |
| runtime·printf("nacl_cond_create: error %d\n", -cond); |
| runtime·throw("semacreate"); |
| } |
| g->m->waitsemalock = mu; |
| g->m->scalararg[0] = cond; // assigned to m->waitsema |
| } |
| |
| #pragma textflag NOSPLIT |
| uint32 |
| runtime·semacreate(void) |
| { |
| void (*fn)(void); |
| uint32 x; |
| |
| fn = semacreate; |
| runtime·onM(&fn); |
| x = g->m->scalararg[0]; |
| g->m->scalararg[0] = 0; |
| return x; |
| } |
| |
| static void |
| semasleep(void) |
| { |
| int32 ret; |
| int64 ns; |
| |
| ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32; |
| g->m->scalararg[0] = 0; |
| g->m->scalararg[1] = 0; |
| |
| ret = runtime·nacl_mutex_lock(g->m->waitsemalock); |
| if(ret < 0) { |
| //runtime·printf("nacl_mutex_lock: error %d\n", -ret); |
| runtime·throw("semasleep"); |
| } |
| if(g->m->waitsemacount > 0) { |
| g->m->waitsemacount = 0; |
| runtime·nacl_mutex_unlock(g->m->waitsemalock); |
| g->m->scalararg[0] = 0; |
| return; |
| } |
| |
| while(g->m->waitsemacount == 0) { |
| if(ns < 0) { |
| ret = runtime·nacl_cond_wait(g->m->waitsema, g->m->waitsemalock); |
| if(ret < 0) { |
| //runtime·printf("nacl_cond_wait: error %d\n", -ret); |
| runtime·throw("semasleep"); |
| } |
| } else { |
| Timespec ts; |
| |
| ns += runtime·nanotime(); |
| ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec); |
| ret = runtime·nacl_cond_timed_wait_abs(g->m->waitsema, g->m->waitsemalock, &ts); |
| if(ret == -ETIMEDOUT) { |
| runtime·nacl_mutex_unlock(g->m->waitsemalock); |
| g->m->scalararg[0] = -1; |
| return; |
| } |
| if(ret < 0) { |
| //runtime·printf("nacl_cond_timed_wait_abs: error %d\n", -ret); |
| runtime·throw("semasleep"); |
| } |
| } |
| } |
| |
| g->m->waitsemacount = 0; |
| runtime·nacl_mutex_unlock(g->m->waitsemalock); |
| g->m->scalararg[0] = 0; |
| } |
| |
| #pragma textflag NOSPLIT |
| int32 |
| runtime·semasleep(int64 ns) |
| { |
| int32 r; |
| void (*fn)(void); |
| |
| g->m->scalararg[0] = (uint32)ns; |
| g->m->scalararg[1] = (uint32)(ns>>32); |
| fn = semasleep; |
| runtime·onM(&fn); |
| r = g->m->scalararg[0]; |
| g->m->scalararg[0] = 0; |
| return r; |
| } |
| |
| static void |
| semawakeup(void) |
| { |
| int32 ret; |
| M *mp; |
| |
| mp = g->m->ptrarg[0]; |
| g->m->ptrarg[0] = nil; |
| |
| ret = runtime·nacl_mutex_lock(mp->waitsemalock); |
| if(ret < 0) { |
| //runtime·printf("nacl_mutex_lock: error %d\n", -ret); |
| runtime·throw("semawakeup"); |
| } |
| if(mp->waitsemacount != 0) { |
| //runtime·printf("semawakeup: double wakeup\n"); |
| runtime·throw("semawakeup"); |
| } |
| mp->waitsemacount = 1; |
| runtime·nacl_cond_signal(mp->waitsema); |
| runtime·nacl_mutex_unlock(mp->waitsemalock); |
| } |
| |
| #pragma textflag NOSPLIT |
| void |
| runtime·semawakeup(M *mp) |
| { |
| void (*fn)(void); |
| |
| g->m->ptrarg[0] = mp; |
| fn = semawakeup; |
| runtime·onM(&fn); |
| } |
| |
| uintptr |
| runtime·memlimit(void) |
| { |
| runtime·printf("memlimit\n"); |
| return 0; |
| } |
| |
| #pragma dataflag NOPTR |
| 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 NOSPLIT |
| void |
| runtime·badsignal2(void) |
| { |
| runtime·write(2, badsignal, sizeof badsignal - 1); |
| runtime·exit(2); |
| } |
| |
| void runtime·madvise(byte*, uintptr, int32) { } |
| void runtime·munmap(byte*, uintptr) {} |
| |
| void |
| runtime·resetcpuprofiler(int32 hz) |
| { |
| USED(hz); |
| } |
| |
| void |
| runtime·sigdisable(uint32) |
| { |
| } |
| |
| void |
| runtime·sigenable(uint32) |
| { |
| } |
| |
| void |
| runtime·closeonexec(int32) |
| { |
| } |
| |
| uint32 runtime·writelock; // test-and-set spin lock for runtime.write |
| |
| /* |
| An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s. |
| |
| void (*runtime·nacl_irt_query)(void); |
| |
| int8 runtime·nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1"; |
| void *runtime·nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf |
| int32 runtime·nacl_irt_basic_v0_1_size = sizeof(runtime·nacl_irt_basic_v0_1); |
| |
| int8 runtime·nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3"; |
| void *runtime·nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect |
| int32 runtime·nacl_irt_memory_v0_3_size = sizeof(runtime·nacl_irt_memory_v0_3); |
| |
| int8 runtime·nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1"; |
| void *runtime·nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice |
| int32 runtime·nacl_irt_thread_v0_1_size = sizeof(runtime·nacl_irt_thread_v0_1); |
| */ |