detached a52bc83

internal/fakecgo: disable race in fakecgo (#319)

Closes #318
commit
a52bc8357ac935129f101c8483804e1fc0e52161
author
TotallyGamerJet · · 2025-05-20 12:28 UTC
committer
Hajime Hoshi · · 2025-05-20 12:56 UTC
parent
1638563
signature
unsigned
refs
tag: v0.8.4
4 files · +32 -2
M .github/workflows/test.yml +8 -2
@@ -129,10 +129,16 @@ jobs:
129129 sudo apt-get install g++-multilib
130130 env CGO_ENABLED=1 GOARCH=386 go test -shuffle=on -v -count=10 ./...
131131
132- - name: go test race
132+ - name: go test race (no Cgo)
133+ if: ${{ runner.os == 'macOS' && !startsWith(matrix.go, '1.18.') && !startsWith(matrix.go, '1.19.') }}
134+ run: |
135+ # -race usually requires Cgo, but macOS is an exception. See https://go.dev/doc/articles/race_detector#Requirements
136+ env CGO_ENABLED=0 go test -race -shuffle=on -v -count=10 ./...
137+
138+ - name: go test race (Cgo)
133139 if: ${{ !startsWith(matrix.go, '1.18.') && !startsWith(matrix.go, '1.19.') }}
134140 run: |
135- go test -race -shuffle=on -v -count=10 ./...
141+ env CGO_ENABLED=1 go test -race -shuffle=on -v -count=10 ./...
136142
137143 freebsd:
138144 strategy:
@@ -129,10 +129,16 @@ jobs:
129 sudo apt-get install g++-multilib129 sudo apt-get install g++-multilib
130 env CGO_ENABLED=1 GOARCH=386 go test -shuffle=on -v -count=10 ./...130 env CGO_ENABLED=1 GOARCH=386 go test -shuffle=on -v -count=10 ./...
131 131
132- - name: go test race132+ - name: go test race (no Cgo)
133+ if: ${{ runner.os == 'macOS' && !startsWith(matrix.go, '1.18.') && !startsWith(matrix.go, '1.19.') }}
134+ run: |
135+ # -race usually requires Cgo, but macOS is an exception. See https://go.dev/doc/articles/race_detector#Requirements
136+ env CGO_ENABLED=0 go test -race -shuffle=on -v -count=10 ./...
137+
138+ - name: go test race (Cgo)
133 if: ${{ !startsWith(matrix.go, '1.18.') && !startsWith(matrix.go, '1.19.') }}139 if: ${{ !startsWith(matrix.go, '1.18.') && !startsWith(matrix.go, '1.19.') }}
134 run: |140 run: |
135- go test -race -shuffle=on -v -count=10 ./...141+ env CGO_ENABLED=1 go test -race -shuffle=on -v -count=10 ./...
136 142
137 freebsd:143 freebsd:
138 strategy:144 strategy:
M internal/fakecgo/gen.go +1 -0
@@ -37,6 +37,7 @@ func call5(fn, a1, a2, a3, a4, a5 uintptr) uintptr
3737
3838 {{ range . -}}
3939 //go:nosplit
40+//go:norace
4041 func {{.Name}}(
4142 {{- range .Args -}}
4243 {{- if .Name -}}
@@ -37,6 +37,7 @@ func call5(fn, a1, a2, a3, a4, a5 uintptr) uintptr
37 37
38 {{ range . -}}38 {{ range . -}}
39 //go:nosplit39 //go:nosplit
40+//go:norace
40 func {{.Name}}(41 func {{.Name}}(
41 {{- range .Args -}}42 {{- range .Args -}}
42 {{- if .Name -}}43 {{- if .Name -}}
M internal/fakecgo/go_libinit.go +3 -0
@@ -19,6 +19,7 @@ var (
1919 )
2020
2121 //go:nosplit
22+//go:norace
2223 func x_cgo_notify_runtime_init_done() {
2324 pthread_mutex_lock(&runtime_init_mu)
2425 runtime_init_done = 1
@@ -28,6 +29,8 @@ func x_cgo_notify_runtime_init_done() {
2829
2930 // Store the g into a thread-specific value associated with the pthread key pthread_g.
3031 // And pthread_key_destructor will dropm when the thread is exiting.
32+//
33+//go:norace
3134 func x_cgo_bindm(g unsafe.Pointer) {
3235 // We assume this will always succeed, otherwise, there might be extra M leaking,
3336 // when a C thread exits after a cgo call.
@@ -19,6 +19,7 @@ var (
19 )19 )
20 20
21 //go:nosplit21 //go:nosplit
22+//go:norace
22 func x_cgo_notify_runtime_init_done() {23 func x_cgo_notify_runtime_init_done() {
23 pthread_mutex_lock(&runtime_init_mu)24 pthread_mutex_lock(&runtime_init_mu)
24 runtime_init_done = 125 runtime_init_done = 1
@@ -28,6 +29,8 @@ func x_cgo_notify_runtime_init_done() {
28 29
29 // Store the g into a thread-specific value associated with the pthread key pthread_g.30 // Store the g into a thread-specific value associated with the pthread key pthread_g.
30 // And pthread_key_destructor will dropm when the thread is exiting.31 // And pthread_key_destructor will dropm when the thread is exiting.
32+//
33+//go:norace
31 func x_cgo_bindm(g unsafe.Pointer) {34 func x_cgo_bindm(g unsafe.Pointer) {
32 // We assume this will always succeed, otherwise, there might be extra M leaking,35 // We assume this will always succeed, otherwise, there might be extra M leaking,
33 // when a C thread exits after a cgo call.36 // when a C thread exits after a cgo call.
M internal/fakecgo/symbols.go +20 -0
@@ -19,6 +19,7 @@ func setg_trampoline(setg uintptr, G uintptr)
1919 func call5(fn, a1, a2, a3, a4, a5 uintptr) uintptr
2020
2121 //go:nosplit
22+//go:norace
2223 func malloc(size uintptr) unsafe.Pointer {
2324 ret := call5(mallocABI0, uintptr(size), 0, 0, 0, 0)
2425 // this indirection is to avoid go vet complaining about possible misuse of unsafe.Pointer
@@ -26,96 +27,115 @@ func malloc(size uintptr) unsafe.Pointer {
2627 }
2728
2829 //go:nosplit
30+//go:norace
2931 func free(ptr unsafe.Pointer) {
3032 call5(freeABI0, uintptr(ptr), 0, 0, 0, 0)
3133 }
3234
3335 //go:nosplit
36+//go:norace
3437 func setenv(name *byte, value *byte, overwrite int32) int32 {
3538 return int32(call5(setenvABI0, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), uintptr(overwrite), 0, 0))
3639 }
3740
3841 //go:nosplit
42+//go:norace
3943 func unsetenv(name *byte) int32 {
4044 return int32(call5(unsetenvABI0, uintptr(unsafe.Pointer(name)), 0, 0, 0, 0))
4145 }
4246
4347 //go:nosplit
48+//go:norace
4449 func sigfillset(set *sigset_t) int32 {
4550 return int32(call5(sigfillsetABI0, uintptr(unsafe.Pointer(set)), 0, 0, 0, 0))
4651 }
4752
4853 //go:nosplit
54+//go:norace
4955 func nanosleep(ts *syscall.Timespec, rem *syscall.Timespec) int32 {
5056 return int32(call5(nanosleepABI0, uintptr(unsafe.Pointer(ts)), uintptr(unsafe.Pointer(rem)), 0, 0, 0))
5157 }
5258
5359 //go:nosplit
60+//go:norace
5461 func abort() {
5562 call5(abortABI0, 0, 0, 0, 0, 0)
5663 }
5764
5865 //go:nosplit
66+//go:norace
5967 func pthread_attr_init(attr *pthread_attr_t) int32 {
6068 return int32(call5(pthread_attr_initABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))
6169 }
6270
6371 //go:nosplit
72+//go:norace
6473 func pthread_create(thread *pthread_t, attr *pthread_attr_t, start unsafe.Pointer, arg unsafe.Pointer) int32 {
6574 return int32(call5(pthread_createABI0, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(start), uintptr(arg), 0))
6675 }
6776
6877 //go:nosplit
78+//go:norace
6979 func pthread_detach(thread pthread_t) int32 {
7080 return int32(call5(pthread_detachABI0, uintptr(thread), 0, 0, 0, 0))
7181 }
7282
7383 //go:nosplit
84+//go:norace
7485 func pthread_sigmask(how sighow, ign *sigset_t, oset *sigset_t) int32 {
7586 return int32(call5(pthread_sigmaskABI0, uintptr(how), uintptr(unsafe.Pointer(ign)), uintptr(unsafe.Pointer(oset)), 0, 0))
7687 }
7788
7889 //go:nosplit
90+//go:norace
7991 func pthread_self() pthread_t {
8092 return pthread_t(call5(pthread_selfABI0, 0, 0, 0, 0, 0))
8193 }
8294
8395 //go:nosplit
96+//go:norace
8497 func pthread_get_stacksize_np(thread pthread_t) size_t {
8598 return size_t(call5(pthread_get_stacksize_npABI0, uintptr(thread), 0, 0, 0, 0))
8699 }
87100
88101 //go:nosplit
102+//go:norace
89103 func pthread_attr_getstacksize(attr *pthread_attr_t, stacksize *size_t) int32 {
90104 return int32(call5(pthread_attr_getstacksizeABI0, uintptr(unsafe.Pointer(attr)), uintptr(unsafe.Pointer(stacksize)), 0, 0, 0))
91105 }
92106
93107 //go:nosplit
108+//go:norace
94109 func pthread_attr_setstacksize(attr *pthread_attr_t, size size_t) int32 {
95110 return int32(call5(pthread_attr_setstacksizeABI0, uintptr(unsafe.Pointer(attr)), uintptr(size), 0, 0, 0))
96111 }
97112
98113 //go:nosplit
114+//go:norace
99115 func pthread_attr_destroy(attr *pthread_attr_t) int32 {
100116 return int32(call5(pthread_attr_destroyABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))
101117 }
102118
103119 //go:nosplit
120+//go:norace
104121 func pthread_mutex_lock(mutex *pthread_mutex_t) int32 {
105122 return int32(call5(pthread_mutex_lockABI0, uintptr(unsafe.Pointer(mutex)), 0, 0, 0, 0))
106123 }
107124
108125 //go:nosplit
126+//go:norace
109127 func pthread_mutex_unlock(mutex *pthread_mutex_t) int32 {
110128 return int32(call5(pthread_mutex_unlockABI0, uintptr(unsafe.Pointer(mutex)), 0, 0, 0, 0))
111129 }
112130
113131 //go:nosplit
132+//go:norace
114133 func pthread_cond_broadcast(cond *pthread_cond_t) int32 {
115134 return int32(call5(pthread_cond_broadcastABI0, uintptr(unsafe.Pointer(cond)), 0, 0, 0, 0))
116135 }
117136
118137 //go:nosplit
138+//go:norace
119139 func pthread_setspecific(key pthread_key_t, value unsafe.Pointer) int32 {
120140 return int32(call5(pthread_setspecificABI0, uintptr(key), uintptr(value), 0, 0, 0))
121141 }
@@ -19,6 +19,7 @@ func setg_trampoline(setg uintptr, G uintptr)
19 func call5(fn, a1, a2, a3, a4, a5 uintptr) uintptr19 func call5(fn, a1, a2, a3, a4, a5 uintptr) uintptr
20 20
21 //go:nosplit21 //go:nosplit
22+//go:norace
22 func malloc(size uintptr) unsafe.Pointer {23 func malloc(size uintptr) unsafe.Pointer {
23 ret := call5(mallocABI0, uintptr(size), 0, 0, 0, 0)24 ret := call5(mallocABI0, uintptr(size), 0, 0, 0, 0)
24 // this indirection is to avoid go vet complaining about possible misuse of unsafe.Pointer25 // this indirection is to avoid go vet complaining about possible misuse of unsafe.Pointer
@@ -26,96 +27,115 @@ func malloc(size uintptr) unsafe.Pointer {
26 }27 }
27 28
28 //go:nosplit29 //go:nosplit
30+//go:norace
29 func free(ptr unsafe.Pointer) {31 func free(ptr unsafe.Pointer) {
30 call5(freeABI0, uintptr(ptr), 0, 0, 0, 0)32 call5(freeABI0, uintptr(ptr), 0, 0, 0, 0)
31 }33 }
32 34
33 //go:nosplit35 //go:nosplit
36+//go:norace
34 func setenv(name *byte, value *byte, overwrite int32) int32 {37 func setenv(name *byte, value *byte, overwrite int32) int32 {
35 return int32(call5(setenvABI0, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), uintptr(overwrite), 0, 0))38 return int32(call5(setenvABI0, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), uintptr(overwrite), 0, 0))
36 }39 }
37 40
38 //go:nosplit41 //go:nosplit
42+//go:norace
39 func unsetenv(name *byte) int32 {43 func unsetenv(name *byte) int32 {
40 return int32(call5(unsetenvABI0, uintptr(unsafe.Pointer(name)), 0, 0, 0, 0))44 return int32(call5(unsetenvABI0, uintptr(unsafe.Pointer(name)), 0, 0, 0, 0))
41 }45 }
42 46
43 //go:nosplit47 //go:nosplit
48+//go:norace
44 func sigfillset(set *sigset_t) int32 {49 func sigfillset(set *sigset_t) int32 {
45 return int32(call5(sigfillsetABI0, uintptr(unsafe.Pointer(set)), 0, 0, 0, 0))50 return int32(call5(sigfillsetABI0, uintptr(unsafe.Pointer(set)), 0, 0, 0, 0))
46 }51 }
47 52
48 //go:nosplit53 //go:nosplit
54+//go:norace
49 func nanosleep(ts *syscall.Timespec, rem *syscall.Timespec) int32 {55 func nanosleep(ts *syscall.Timespec, rem *syscall.Timespec) int32 {
50 return int32(call5(nanosleepABI0, uintptr(unsafe.Pointer(ts)), uintptr(unsafe.Pointer(rem)), 0, 0, 0))56 return int32(call5(nanosleepABI0, uintptr(unsafe.Pointer(ts)), uintptr(unsafe.Pointer(rem)), 0, 0, 0))
51 }57 }
52 58
53 //go:nosplit59 //go:nosplit
60+//go:norace
54 func abort() {61 func abort() {
55 call5(abortABI0, 0, 0, 0, 0, 0)62 call5(abortABI0, 0, 0, 0, 0, 0)
56 }63 }
57 64
58 //go:nosplit65 //go:nosplit
66+//go:norace
59 func pthread_attr_init(attr *pthread_attr_t) int32 {67 func pthread_attr_init(attr *pthread_attr_t) int32 {
60 return int32(call5(pthread_attr_initABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))68 return int32(call5(pthread_attr_initABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))
61 }69 }
62 70
63 //go:nosplit71 //go:nosplit
72+//go:norace
64 func pthread_create(thread *pthread_t, attr *pthread_attr_t, start unsafe.Pointer, arg unsafe.Pointer) int32 {73 func pthread_create(thread *pthread_t, attr *pthread_attr_t, start unsafe.Pointer, arg unsafe.Pointer) int32 {
65 return int32(call5(pthread_createABI0, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(start), uintptr(arg), 0))74 return int32(call5(pthread_createABI0, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(start), uintptr(arg), 0))
66 }75 }
67 76
68 //go:nosplit77 //go:nosplit
78+//go:norace
69 func pthread_detach(thread pthread_t) int32 {79 func pthread_detach(thread pthread_t) int32 {
70 return int32(call5(pthread_detachABI0, uintptr(thread), 0, 0, 0, 0))80 return int32(call5(pthread_detachABI0, uintptr(thread), 0, 0, 0, 0))
71 }81 }
72 82
73 //go:nosplit83 //go:nosplit
84+//go:norace
74 func pthread_sigmask(how sighow, ign *sigset_t, oset *sigset_t) int32 {85 func pthread_sigmask(how sighow, ign *sigset_t, oset *sigset_t) int32 {
75 return int32(call5(pthread_sigmaskABI0, uintptr(how), uintptr(unsafe.Pointer(ign)), uintptr(unsafe.Pointer(oset)), 0, 0))86 return int32(call5(pthread_sigmaskABI0, uintptr(how), uintptr(unsafe.Pointer(ign)), uintptr(unsafe.Pointer(oset)), 0, 0))
76 }87 }
77 88
78 //go:nosplit89 //go:nosplit
90+//go:norace
79 func pthread_self() pthread_t {91 func pthread_self() pthread_t {
80 return pthread_t(call5(pthread_selfABI0, 0, 0, 0, 0, 0))92 return pthread_t(call5(pthread_selfABI0, 0, 0, 0, 0, 0))
81 }93 }
82 94
83 //go:nosplit95 //go:nosplit
96+//go:norace
84 func pthread_get_stacksize_np(thread pthread_t) size_t {97 func pthread_get_stacksize_np(thread pthread_t) size_t {
85 return size_t(call5(pthread_get_stacksize_npABI0, uintptr(thread), 0, 0, 0, 0))98 return size_t(call5(pthread_get_stacksize_npABI0, uintptr(thread), 0, 0, 0, 0))
86 }99 }
87 100
88 //go:nosplit101 //go:nosplit
102+//go:norace
89 func pthread_attr_getstacksize(attr *pthread_attr_t, stacksize *size_t) int32 {103 func pthread_attr_getstacksize(attr *pthread_attr_t, stacksize *size_t) int32 {
90 return int32(call5(pthread_attr_getstacksizeABI0, uintptr(unsafe.Pointer(attr)), uintptr(unsafe.Pointer(stacksize)), 0, 0, 0))104 return int32(call5(pthread_attr_getstacksizeABI0, uintptr(unsafe.Pointer(attr)), uintptr(unsafe.Pointer(stacksize)), 0, 0, 0))
91 }105 }
92 106
93 //go:nosplit107 //go:nosplit
108+//go:norace
94 func pthread_attr_setstacksize(attr *pthread_attr_t, size size_t) int32 {109 func pthread_attr_setstacksize(attr *pthread_attr_t, size size_t) int32 {
95 return int32(call5(pthread_attr_setstacksizeABI0, uintptr(unsafe.Pointer(attr)), uintptr(size), 0, 0, 0))110 return int32(call5(pthread_attr_setstacksizeABI0, uintptr(unsafe.Pointer(attr)), uintptr(size), 0, 0, 0))
96 }111 }
97 112
98 //go:nosplit113 //go:nosplit
114+//go:norace
99 func pthread_attr_destroy(attr *pthread_attr_t) int32 {115 func pthread_attr_destroy(attr *pthread_attr_t) int32 {
100 return int32(call5(pthread_attr_destroyABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))116 return int32(call5(pthread_attr_destroyABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))
101 }117 }
102 118
103 //go:nosplit119 //go:nosplit
120+//go:norace
104 func pthread_mutex_lock(mutex *pthread_mutex_t) int32 {121 func pthread_mutex_lock(mutex *pthread_mutex_t) int32 {
105 return int32(call5(pthread_mutex_lockABI0, uintptr(unsafe.Pointer(mutex)), 0, 0, 0, 0))122 return int32(call5(pthread_mutex_lockABI0, uintptr(unsafe.Pointer(mutex)), 0, 0, 0, 0))
106 }123 }
107 124
108 //go:nosplit125 //go:nosplit
126+//go:norace
109 func pthread_mutex_unlock(mutex *pthread_mutex_t) int32 {127 func pthread_mutex_unlock(mutex *pthread_mutex_t) int32 {
110 return int32(call5(pthread_mutex_unlockABI0, uintptr(unsafe.Pointer(mutex)), 0, 0, 0, 0))128 return int32(call5(pthread_mutex_unlockABI0, uintptr(unsafe.Pointer(mutex)), 0, 0, 0, 0))
111 }129 }
112 130
113 //go:nosplit131 //go:nosplit
132+//go:norace
114 func pthread_cond_broadcast(cond *pthread_cond_t) int32 {133 func pthread_cond_broadcast(cond *pthread_cond_t) int32 {
115 return int32(call5(pthread_cond_broadcastABI0, uintptr(unsafe.Pointer(cond)), 0, 0, 0, 0))134 return int32(call5(pthread_cond_broadcastABI0, uintptr(unsafe.Pointer(cond)), 0, 0, 0, 0))
116 }135 }
117 136
118 //go:nosplit137 //go:nosplit
138+//go:norace
119 func pthread_setspecific(key pthread_key_t, value unsafe.Pointer) int32 {139 func pthread_setspecific(key pthread_key_t, value unsafe.Pointer) int32 {
120 return int32(call5(pthread_setspecificABI0, uintptr(key), uintptr(value), 0, 0, 0))140 return int32(call5(pthread_setspecificABI0, uintptr(key), uintptr(value), 0, 0, 0))
121 }141 }

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close