| // 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) { |
| entersyscallblock() |
| var b byte |
| read(sigNoteRead, unsafe.Pointer(&b), 1) |
| exitsyscall() |
| } |
| |
| // 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() |
| } |