139 lines
3.3 KiB
Go
139 lines
3.3 KiB
Go
// 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.
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"unsafe"
|
|
)
|
|
|
|
type mOS struct {
|
|
initialized bool
|
|
mutex pthreadmutex
|
|
cond pthreadcond
|
|
count int
|
|
}
|
|
|
|
func unimplemented(name string) {
|
|
println(name, "not implemented")
|
|
*(*int)(unsafe.Pointer(uintptr(1231))) = 1231
|
|
}
|
|
|
|
//go:nosplit
|
|
func semacreate(mp *m) {
|
|
if mp.initialized {
|
|
return
|
|
}
|
|
mp.initialized = true
|
|
if err := pthread_mutex_init(&mp.mutex, nil); err != 0 {
|
|
throw("pthread_mutex_init")
|
|
}
|
|
if err := pthread_cond_init(&mp.cond, nil); err != 0 {
|
|
throw("pthread_cond_init")
|
|
}
|
|
}
|
|
|
|
//go:nosplit
|
|
func semasleep(ns int64) int32 {
|
|
var start int64
|
|
if ns >= 0 {
|
|
start = nanotime()
|
|
}
|
|
mp := getg().m
|
|
pthread_mutex_lock(&mp.mutex)
|
|
for {
|
|
if mp.count > 0 {
|
|
mp.count--
|
|
pthread_mutex_unlock(&mp.mutex)
|
|
return 0
|
|
}
|
|
if ns >= 0 {
|
|
spent := nanotime() - start
|
|
if spent >= ns {
|
|
pthread_mutex_unlock(&mp.mutex)
|
|
return -1
|
|
}
|
|
var t timespec
|
|
t.setNsec(ns - spent)
|
|
err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
|
|
if err == _ETIMEDOUT {
|
|
pthread_mutex_unlock(&mp.mutex)
|
|
return -1
|
|
}
|
|
} else {
|
|
pthread_cond_wait(&mp.cond, &mp.mutex)
|
|
}
|
|
}
|
|
}
|
|
|
|
//go:nosplit
|
|
func semawakeup(mp *m) {
|
|
pthread_mutex_lock(&mp.mutex)
|
|
mp.count++
|
|
if mp.count > 0 {
|
|
pthread_cond_signal(&mp.cond)
|
|
}
|
|
pthread_mutex_unlock(&mp.mutex)
|
|
}
|
|
|
|
// The read and write file descriptors used by the sigNote functions.
|
|
var sigNoteRead, sigNoteWrite int32
|
|
|
|
// sigNoteSetup initializes an async-signal-safe note.
|
|
//
|
|
// The current implementation of notes on Darwin is not async-signal-safe,
|
|
// because the functions pthread_mutex_lock, pthread_cond_signal, and
|
|
// pthread_mutex_unlock, called by semawakeup, are not async-signal-safe.
|
|
// There is only one case where we need to wake up a note from a signal
|
|
// handler: the sigsend function. The signal handler code does not require
|
|
// all the features of notes: it does not need to do a timed wait.
|
|
// This is a separate implementation of notes, based on a pipe, that does
|
|
// not support timed waits but is async-signal-safe.
|
|
func sigNoteSetup(*note) {
|
|
if sigNoteRead != 0 || sigNoteWrite != 0 {
|
|
throw("duplicate sigNoteSetup")
|
|
}
|
|
var errno int32
|
|
sigNoteRead, sigNoteWrite, errno = pipe()
|
|
if errno != 0 {
|
|
throw("pipe failed")
|
|
}
|
|
closeonexec(sigNoteRead)
|
|
closeonexec(sigNoteWrite)
|
|
|
|
// Make the write end of the pipe non-blocking, so that if the pipe
|
|
// buffer is somehow full we will not block in the signal handler.
|
|
// Leave the read end of the pipe blocking so that we will block
|
|
// in sigNoteSleep.
|
|
setNonblock(sigNoteWrite)
|
|
}
|
|
|
|
// sigNoteWakeup wakes up a thread sleeping on a note created by sigNoteSetup.
|
|
func sigNoteWakeup(*note) {
|
|
var b byte
|
|
write(uintptr(sigNoteWrite), unsafe.Pointer(&b), 1)
|
|
}
|
|
|
|
// sigNoteSleep waits for a note created by sigNoteSetup to be woken.
|
|
func sigNoteSleep(*note) {
|
|
for {
|
|
var b byte
|
|
entersyscallblock()
|
|
n := read(sigNoteRead, unsafe.Pointer(&b), 1)
|
|
exitsyscall()
|
|
if n != -_EINTR {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// BSD interface for threading.
|
|
func osinit() {
|
|
// pthread_create delayed until end of goenvs so that we
|
|
// can look at the environment first.
|
|
|
|
ncpu = getncpu()
|
|
physPageSize = getPageSize()
|
|
}
|