1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package runtime
6
7import (
8	"unsafe"
9)
10
11type mOS struct {
12	initialized bool
13	mutex       pthreadmutex
14	cond        pthreadcond
15	count       int
16}
17
18func unimplemented(name string) {
19	println(name, "not implemented")
20	*(*int)(unsafe.Pointer(uintptr(1231))) = 1231
21}
22
23//go:nosplit
24func semacreate(mp *m) {
25	if mp.initialized {
26		return
27	}
28	mp.initialized = true
29	if err := pthread_mutex_init(&mp.mutex, nil); err != 0 {
30		throw("pthread_mutex_init")
31	}
32	if err := pthread_cond_init(&mp.cond, nil); err != 0 {
33		throw("pthread_cond_init")
34	}
35}
36
37//go:nosplit
38func semasleep(ns int64) int32 {
39	var start int64
40	if ns >= 0 {
41		start = nanotime()
42	}
43	mp := getg().m
44	pthread_mutex_lock(&mp.mutex)
45	for {
46		if mp.count > 0 {
47			mp.count--
48			pthread_mutex_unlock(&mp.mutex)
49			return 0
50		}
51		if ns >= 0 {
52			spent := nanotime() - start
53			if spent >= ns {
54				pthread_mutex_unlock(&mp.mutex)
55				return -1
56			}
57			var t timespec
58			t.setNsec(ns - spent)
59			err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
60			if err == _ETIMEDOUT {
61				pthread_mutex_unlock(&mp.mutex)
62				return -1
63			}
64		} else {
65			pthread_cond_wait(&mp.cond, &mp.mutex)
66		}
67	}
68}
69
70//go:nosplit
71func semawakeup(mp *m) {
72	pthread_mutex_lock(&mp.mutex)
73	mp.count++
74	if mp.count > 0 {
75		pthread_cond_signal(&mp.cond)
76	}
77	pthread_mutex_unlock(&mp.mutex)
78}
79
80// The read and write file descriptors used by the sigNote functions.
81var sigNoteRead, sigNoteWrite int32
82
83// sigNoteSetup initializes an async-signal-safe note.
84//
85// The current implementation of notes on Darwin is not async-signal-safe,
86// because the functions pthread_mutex_lock, pthread_cond_signal, and
87// pthread_mutex_unlock, called by semawakeup, are not async-signal-safe.
88// There is only one case where we need to wake up a note from a signal
89// handler: the sigsend function. The signal handler code does not require
90// all the features of notes: it does not need to do a timed wait.
91// This is a separate implementation of notes, based on a pipe, that does
92// not support timed waits but is async-signal-safe.
93func sigNoteSetup(*note) {
94	if sigNoteRead != 0 || sigNoteWrite != 0 {
95		throw("duplicate sigNoteSetup")
96	}
97	var errno int32
98	sigNoteRead, sigNoteWrite, errno = pipe()
99	if errno != 0 {
100		throw("pipe failed")
101	}
102	closeonexec(sigNoteRead)
103	closeonexec(sigNoteWrite)
104
105	// Make the write end of the pipe non-blocking, so that if the pipe
106	// buffer is somehow full we will not block in the signal handler.
107	// Leave the read end of the pipe blocking so that we will block
108	// in sigNoteSleep.
109	setNonblock(sigNoteWrite)
110}
111
112// sigNoteWakeup wakes up a thread sleeping on a note created by sigNoteSetup.
113func sigNoteWakeup(*note) {
114	var b byte
115	write(uintptr(sigNoteWrite), unsafe.Pointer(&b), 1)
116}
117
118// sigNoteSleep waits for a note created by sigNoteSetup to be woken.
119func sigNoteSleep(*note) {
120	for {
121		var b byte
122		entersyscallblock()
123		n := read(sigNoteRead, unsafe.Pointer(&b), 1)
124		exitsyscall()
125		if n != -_EINTR {
126			return
127		}
128	}
129}
130
131// BSD interface for threading.
132func osinit() {
133	// pthread_create delayed until end of goenvs so that we
134	// can look at the environment first.
135
136	ncpu = getncpu()
137	physPageSize = getPageSize()
138}
139