| // Copyright 2009 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.h" |
| #include "os.h" |
| |
| int8 *goos = "nacl"; |
| |
| // Thread-safe allocation of a mutex. |
| // (The name sema is left over from the Darwin implementation. |
| // Native Client implements semaphores too, but it is just a shim |
| // over the host implementation, which on some hosts imposes a very |
| // low limit on how many semaphores can be created.) |
| // |
| // Psema points at a mutex descriptor. |
| // It starts out zero, meaning no mutex. |
| // Fill it in, being careful of others calling initsema |
| // simultaneously. |
| static void |
| initsema(uint32 *psema) |
| { |
| uint32 sema; |
| |
| if(*psema != 0) // already have one |
| return; |
| |
| sema = runtime·mutex_create(); |
| if((int32)sema < 0) { |
| runtime·printf("mutex_create failed\n"); |
| runtime·breakpoint(); |
| } |
| // mutex_create returns a file descriptor; |
| // shift it up and add the 1 bit so that can |
| // distinguish unintialized from fd 0. |
| sema = (sema<<1) | 1; |
| if(!cas(psema, 0, sema)){ |
| // Someone else filled it in. Use theirs. |
| runtime·close(sema); |
| return; |
| } |
| } |
| |
| // Lock and unlock. |
| // Defer entirely to Native Client. |
| // The expense of a call into Native Client is more like |
| // a function call than a system call, so as long as the |
| // Native Client lock implementation is good, we can't |
| // do better ourselves. |
| |
| static void |
| xlock(int32 fd) |
| { |
| if(mutex_lock(fd) < 0) { |
| runtime·printf("mutex_lock failed\n"); |
| runtime·breakpoint(); |
| } |
| } |
| |
| static void |
| xunlock(int32 fd) |
| { |
| if(mutex_unlock(fd) < 0) { |
| runtime·printf("mutex_lock failed\n"); |
| runtime·breakpoint(); |
| } |
| } |
| |
| void |
| runtime·lock(Lock *l) |
| { |
| if(m->locks < 0) |
| runtime·throw("lock count"); |
| m->locks++; |
| if(l->sema == 0) |
| runtime·initsema(&l->sema); |
| runtime·xlock(l->sema>>1); |
| } |
| |
| void |
| runtime·unlock(Lock *l) |
| { |
| m->locks--; |
| if(m->locks < 0) |
| runtime·throw("lock count"); |
| runtime·xunlock(l->sema>>1); |
| } |
| |
| void |
| runtime·destroylock(Lock*) |
| { |
| } |
| |
| // One-time notifications. |
| // |
| // Since the lock/unlock implementation already |
| // takes care of sleeping in the kernel, we just reuse it. |
| // (But it's a weird use, so it gets its own interface.) |
| // |
| // We use a lock to represent the event: |
| // unlocked == event has happened. |
| // Thus the lock starts out locked, and to wait for the |
| // event you try to lock the lock. To signal the event, |
| // you unlock the lock. |
| // |
| // Native Client does not require that the thread acquiring |
| // a lock be the thread that releases the lock, so this is safe. |
| |
| void |
| runtime·noteclear(Note *n) |
| { |
| if(n->lock.sema == 0) |
| runtime·initsema(&n->lock.sema); |
| runtime·xlock(n->lock.sema>>1); |
| } |
| |
| void |
| runtime·notewakeup(Note *n) |
| { |
| if(n->lock.sema == 0) { |
| runtime·printf("notewakeup without noteclear"); |
| runtime·breakpoint(); |
| } |
| runtime·xunlock(n->lock.sema>>1); |
| } |
| |
| void |
| runtime·notesleep(Note *n) |
| { |
| if(n->lock.sema == 0) { |
| runtime·printf("notesleep without noteclear"); |
| runtime·breakpoint(); |
| } |
| runtime·xlock(n->lock.sema>>1); |
| runtime·xunlock(n->lock.sema>>1); // Let other sleepers find out too. |
| } |
| |
| void |
| runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) |
| { |
| void **vstk; |
| |
| // I wish every OS made thread creation this easy. |
| m->tls[0] = (uint32)g; |
| m->tls[1] = (uint32)m; |
| vstk = stk; |
| *--vstk = nil; |
| if(thread_create(fn, vstk, m->tls, sizeof m->tls) < 0) { |
| runtime·printf("thread_create failed\n"); |
| runtime·breakpoint(); |
| } |
| } |
| |
| void |
| runtime·osinit(void) |
| { |
| } |
| |
| // Called to initialize a new m (including the bootstrap m). |
| void |
| runtime·minit(void) |
| { |
| } |