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