// This implementation depends on OS-specific implementations of
 //
-//     uintptr runtime·semacreate(void)
-//             Create a semaphore, which will be assigned to m->waitsema.
-//             The zero value is treated as absence of any semaphore,
-//             so be sure to return a non-zero value.
+//     func semacreate(mp *m)
+//             Create a semaphore for mp, if it does not already have one.
 //
-//     int32 runtime·semasleep(int64 ns)
-//             If ns < 0, acquire m->waitsema and return 0.
-//             If ns >= 0, try to acquire m->waitsema for at most ns nanoseconds.
+//     func semasleep(ns int64) int32
+//             If ns < 0, acquire m's semaphore and return 0.
+//             If ns >= 0, try to acquire m's semaphore for at most ns nanoseconds.
 //             Return 0 if the semaphore was acquired, -1 if interrupted or timed out.
 //
-//     int32 runtime·semawakeup(M *mp)
-//             Wake up mp, which is or will soon be sleeping on mp->waitsema.
+//     func semawakeup(mp *m)
+//             Wake up mp, which is or will soon be sleeping on its semaphore.
 //
 const (
        locked uintptr = 1
        if atomic.Casuintptr(&l.key, 0, locked) {
                return
        }
-       if gp.m.waitsema == 0 {
-               gp.m.waitsema = semacreate()
-       }
+       semacreate(gp.m)
 
        // On uniprocessor's, no point spinning.
        // On multiprocessors, spin for ACTIVE_SPIN attempts.
        if gp != gp.m.g0 {
                throw("notesleep not on g0")
        }
-       if gp.m.waitsema == 0 {
-               gp.m.waitsema = semacreate()
-       }
+       semacreate(gp.m)
        if !atomic.Casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) {
                // Must be locked (got wakeup).
                if n.key != locked {
        if gp != gp.m.g0 && gp.m.preemptoff != "" {
                throw("notetsleep not on g0")
        }
-       if gp.m.waitsema == 0 {
-               gp.m.waitsema = semacreate()
-       }
+       semacreate(gp.m)
        return notetsleep_internal(n, ns, nil, 0)
 }
 
        if gp == gp.m.g0 {
                throw("notetsleepg on g0")
        }
-       if gp.m.waitsema == 0 {
-               gp.m.waitsema = semacreate()
-       }
+       semacreate(gp.m)
        entersyscallblock(0)
        ok := notetsleep_internal(n, ns, nil, 0)
        exitsyscall(0)
 
 
 //go:nosplit
 func semawakeup(mp *m) {
-       mach_semrelease(uint32(mp.waitsema))
+       mach_semrelease(mp.waitsema)
 }
 
 //go:nosplit
-func semacreate() uintptr {
-       var x uintptr
+func semacreate(mp *m) {
+       if mp.waitsema != 0 {
+               return
+       }
        systemstack(func() {
-               x = uintptr(mach_semcreate())
+               mp.waitsema = mach_semcreate()
        })
-       return x
 }
 
 // BSD interface for threading.
        if ns >= 0 {
                var nsecs int32
                secs := timediv(ns, 1000000000, &nsecs)
-               r := mach_semaphore_timedwait(uint32(_g_.m.waitsema), uint32(secs), uint32(nsecs))
+               r := mach_semaphore_timedwait(_g_.m.waitsema, uint32(secs), uint32(nsecs))
                if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT {
                        return -1
                }
        }
 
        for {
-               r := mach_semaphore_wait(uint32(_g_.m.waitsema))
+               r := mach_semaphore_wait(_g_.m.waitsema)
                if r == 0 {
                        break
                }
 
 }
 
 //go:nosplit
-func semacreate() uintptr {
-       var cond uintptr
+func semacreate(mp *m) {
+       if mp.waitsema != 0 {
+               return
+       }
        systemstack(func() {
                mu := nacl_mutex_create(0)
                if mu < 0 {
                }
                c := nacl_cond_create(0)
                if c < 0 {
-                       print("nacl_cond_create: error ", -cond, "\n")
+                       print("nacl_cond_create: error ", -c, "\n")
                        throw("semacreate")
                }
-               cond = uintptr(c)
-               _g_ := getg()
-               _g_.m.waitsemalock = uint32(mu)
+               mp.waitsema = c
+               mp.waitsemalock = mu
        })
-       return cond
 }
 
 //go:nosplit
 
        systemstack(func() {
                _g_ := getg()
-               if nacl_mutex_lock(int32(_g_.m.waitsemalock)) < 0 {
+               if nacl_mutex_lock(_g_.m.waitsemalock) < 0 {
                        throw("semasleep")
                }
 
                for _g_.m.waitsemacount == 0 {
                        if ns < 0 {
-                               if nacl_cond_wait(int32(_g_.m.waitsema), int32(_g_.m.waitsemalock)) < 0 {
+                               if nacl_cond_wait(_g_.m.waitsema, _g_.m.waitsemalock) < 0 {
                                        throw("semasleep")
                                }
                        } else {
                                end := ns + nanotime()
                                ts.tv_sec = end / 1e9
                                ts.tv_nsec = int32(end % 1e9)
-                               r := nacl_cond_timed_wait_abs(int32(_g_.m.waitsema), int32(_g_.m.waitsemalock), &ts)
+                               r := nacl_cond_timed_wait_abs(_g_.m.waitsema, _g_.m.waitsemalock, &ts)
                                if r == -_ETIMEDOUT {
-                                       nacl_mutex_unlock(int32(_g_.m.waitsemalock))
+                                       nacl_mutex_unlock(_g_.m.waitsemalock)
                                        ret = -1
                                        return
                                }
                }
 
                _g_.m.waitsemacount = 0
-               nacl_mutex_unlock(int32(_g_.m.waitsemalock))
+               nacl_mutex_unlock(_g_.m.waitsemalock)
                ret = 0
        })
        return ret
 //go:nosplit
 func semawakeup(mp *m) {
        systemstack(func() {
-               if nacl_mutex_lock(int32(mp.waitsemalock)) < 0 {
+               if nacl_mutex_lock(mp.waitsemalock) < 0 {
                        throw("semawakeup")
                }
                if mp.waitsemacount != 0 {
                        throw("semawakeup")
                }
                mp.waitsemacount = 1
-               nacl_cond_signal(int32(mp.waitsema))
-               nacl_mutex_unlock(int32(mp.waitsemalock))
+               nacl_cond_signal(mp.waitsema)
+               nacl_mutex_unlock(mp.waitsemalock)
        })
 }
 
 
 }
 
 //go:nosplit
-func semacreate() uintptr {
-       return 1
+func semacreate(mp *m) {
 }
 
 //go:nosplit
 
 }
 
 //go:nosplit
-func semacreate() uintptr {
-       return 1
+func semacreate(mp *m) {
 }
 
 //go:nosplit
 
 }
 
 //go:nosplit
-func semacreate() uintptr {
-       return 1
+func semacreate(mp *m) {
 }
 
 //go:nosplit
 
 }
 
 //go:nosplit
-func semacreate() uintptr {
-       return stdcall4(_CreateEventA, 0, 0, 0, 0)
+func semacreate(mp *m) {
+       if mp.waitsema != 0 {
+               return
+       }
+       mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0)
 }
 
 // May run with m.p==nil, so write barriers are not allowed.
 
 }
 
 //go:nosplit
-func semacreate() uintptr {
+func semacreate(mp *m) {
+       if mp.waitsema != 0 {
+               return
+       }
+
        var sem *semt
        _g_ := getg()
 
        if sem_init(sem, 0, 0) != 0 {
                throw("sem_init")
        }
-       return uintptr(unsafe.Pointer(sem))
+       mp.waitsema = uintptr(unsafe.Pointer(sem))
 }
 
 //go:nosplit
 
 
 import "unsafe"
 
-type mOS struct{}
+type mOS struct {
+       waitsema uint32 // semaphore for parking on locks
+}
 
 func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
 func bsdthread_register() int32
 
 
 import "unsafe"
 
-type mOS struct{}
+type mOS struct {
+       waitsema      int32 // semaphore for parking on locks
+       waitsemacount int32
+       waitsemalock  int32
+}
 
 func nacl_exception_stack(p uintptr, size int32) int32
 func nacl_exception_handler(fn uintptr, arg unsafe.Pointer) int32
 
 
 import "unsafe"
 
-type mOS struct{}
+type mOS struct {
+       waitsemacount uint32
+}
 
 //go:noescape
 func setitimer(mode int32, new, old *itimerval)
 
 
 package runtime
 
-type mOS struct{}
+type mOS struct {
+       waitsemacount uint32
+}
 
 //go:noescape
 func setitimer(mode int32, new, old *itimerval)
 
 import "unsafe"
 
 type mOS struct {
-       notesig *int8
-       errstr  *byte
+       waitsemacount uint32
+       notesig       *int8
+       errstr        *byte
 }
 
 func closefd(fd int32) int32
 
 }
 
 type mOS struct {
-       perrno *int32 // pointer to tls errno
+       waitsema uintptr // semaphore for parking on locks
+       perrno   *int32  // pointer to tls errno
        // these are here because they are too large to be on the stack
        // of low-level NOSPLIT functions.
        //LibCall       libcall;
 
 
 import "unsafe"
 
-type mOS struct{}
+type mOS struct {
+       waitsema uintptr // semaphore for parking on locks
+}
 
 type stdFunction *byte
 
 
        fflag         uint32      // floating point compare flags
        locked        uint32      // tracking for lockosthread
        nextwaitm     uintptr     // next m waiting for lock
-       waitsema      uintptr     // semaphore for parking on locks
-       waitsemacount uint32
-       waitsemalock  uint32
        gcstats       gcstats
        needextram    bool
        traceback     uint8