1// Copyright 2011 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	waitsema uintptr // semaphore for parking on locks
11}
12
13//extern malloc
14func libc_malloc(uintptr) unsafe.Pointer
15
16//go:noescape
17//extern sem_init
18func sem_init(sem *semt, pshared int32, value uint32) int32
19
20//go:noescape
21//extern sem_wait
22func sem_wait(sem *semt) int32
23
24//go:noescape
25//extern sem_post
26func sem_post(sem *semt) int32
27
28//go:noescape
29//extern sem_reltimedwait_np
30func sem_reltimedwait_np(sem *semt, timeout *timespec) int32
31
32//go:nosplit
33func semacreate(mp *m) {
34	if mp.mos.waitsema != 0 {
35		return
36	}
37
38	var sem *semt
39
40	// Call libc's malloc rather than malloc. This will
41	// allocate space on the C heap. We can't call malloc
42	// here because it could cause a deadlock.
43	sem = (*semt)(libc_malloc(unsafe.Sizeof(*sem)))
44	if sem_init(sem, 0, 0) != 0 {
45		throw("sem_init")
46	}
47	mp.mos.waitsema = uintptr(unsafe.Pointer(sem))
48}
49
50//go:nosplit
51func semasleep(ns int64) int32 {
52	_m_ := getg().m
53	if ns >= 0 {
54		var ts timespec
55		ts.set_sec(ns / 1000000000)
56		ts.set_nsec(int32(ns % 1000000000))
57
58		if sem_reltimedwait_np((*semt)(unsafe.Pointer(_m_.mos.waitsema)), &ts) != 0 {
59			err := errno()
60			if err == _ETIMEDOUT || err == _EAGAIN || err == _EINTR {
61				return -1
62			}
63			throw("sem_reltimedwait_np")
64		}
65		return 0
66	}
67	for {
68		r1 := sem_wait((*semt)(unsafe.Pointer(_m_.mos.waitsema)))
69		if r1 == 0 {
70			break
71		}
72		if errno() == _EINTR {
73			continue
74		}
75		throw("sem_wait")
76	}
77	return 0
78}
79
80//go:nosplit
81func semawakeup(mp *m) {
82	if sem_post((*semt)(unsafe.Pointer(mp.mos.waitsema))) != 0 {
83		throw("sem_post")
84	}
85}
86