1// Copyright 2012 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
5//go:build race
6
7package runtime
8
9import (
10	"internal/abi"
11	"unsafe"
12)
13
14// Public race detection API, present iff build with -race.
15
16func RaceRead(addr unsafe.Pointer)
17func RaceWrite(addr unsafe.Pointer)
18func RaceReadRange(addr unsafe.Pointer, len int)
19func RaceWriteRange(addr unsafe.Pointer, len int)
20
21func RaceErrors() int {
22	var n uint64
23	racecall(&__tsan_report_count, uintptr(unsafe.Pointer(&n)), 0, 0, 0)
24	return int(n)
25}
26
27// RaceAcquire/RaceRelease/RaceReleaseMerge establish happens-before relations
28// between goroutines. These inform the race detector about actual synchronization
29// that it can't see for some reason (e.g. synchronization within RaceDisable/RaceEnable
30// sections of code).
31// RaceAcquire establishes a happens-before relation with the preceding
32// RaceReleaseMerge on addr up to and including the last RaceRelease on addr.
33// In terms of the C memory model (C11 §5.1.2.4, §7.17.3),
34// RaceAcquire is equivalent to atomic_load(memory_order_acquire).
35//
36//go:nosplit
37func RaceAcquire(addr unsafe.Pointer) {
38	raceacquire(addr)
39}
40
41// RaceRelease performs a release operation on addr that
42// can synchronize with a later RaceAcquire on addr.
43//
44// In terms of the C memory model, RaceRelease is equivalent to
45// atomic_store(memory_order_release).
46//
47//go:nosplit
48func RaceRelease(addr unsafe.Pointer) {
49	racerelease(addr)
50}
51
52// RaceReleaseMerge is like RaceRelease, but also establishes a happens-before
53// relation with the preceding RaceRelease or RaceReleaseMerge on addr.
54//
55// In terms of the C memory model, RaceReleaseMerge is equivalent to
56// atomic_exchange(memory_order_release).
57//
58//go:nosplit
59func RaceReleaseMerge(addr unsafe.Pointer) {
60	racereleasemerge(addr)
61}
62
63// RaceDisable disables handling of race synchronization events in the current goroutine.
64// Handling is re-enabled with RaceEnable. RaceDisable/RaceEnable can be nested.
65// Non-synchronization events (memory accesses, function entry/exit) still affect
66// the race detector.
67//
68//go:nosplit
69func RaceDisable() {
70	gp := getg()
71	if gp.raceignore == 0 {
72		racecall(&__tsan_go_ignore_sync_begin, gp.racectx, 0, 0, 0)
73	}
74	gp.raceignore++
75}
76
77// RaceEnable re-enables handling of race events in the current goroutine.
78//
79//go:nosplit
80func RaceEnable() {
81	gp := getg()
82	gp.raceignore--
83	if gp.raceignore == 0 {
84		racecall(&__tsan_go_ignore_sync_end, gp.racectx, 0, 0, 0)
85	}
86}
87
88// Private interface for the runtime.
89
90const raceenabled = true
91
92// For all functions accepting callerpc and pc,
93// callerpc is a return PC of the function that calls this function,
94// pc is start PC of the function that calls this function.
95func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) {
96	kind := t.Kind_ & abi.KindMask
97	if kind == abi.Array || kind == abi.Struct {
98		// for composite objects we have to read every address
99		// because a write might happen to any subobject.
100		racereadrangepc(addr, t.Size_, callerpc, pc)
101	} else {
102		// for non-composite objects we can read just the start
103		// address, as any write must write the first byte.
104		racereadpc(addr, callerpc, pc)
105	}
106}
107
108func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) {
109	kind := t.Kind_ & abi.KindMask
110	if kind == abi.Array || kind == abi.Struct {
111		// for composite objects we have to write every address
112		// because a write might happen to any subobject.
113		racewriterangepc(addr, t.Size_, callerpc, pc)
114	} else {
115		// for non-composite objects we can write just the start
116		// address, as any write must write the first byte.
117		racewritepc(addr, callerpc, pc)
118	}
119}
120
121//go:noescape
122func racereadpc(addr unsafe.Pointer, callpc, pc uintptr)
123
124//go:noescape
125func racewritepc(addr unsafe.Pointer, callpc, pc uintptr)
126
127type symbolizeCodeContext struct {
128	pc   uintptr
129	fn   *byte
130	file *byte
131	line uintptr
132	off  uintptr
133	res  uintptr
134}
135
136var qq = [...]byte{'?', '?', 0}
137var dash = [...]byte{'-', 0}
138
139const (
140	raceGetProcCmd = iota
141	raceSymbolizeCodeCmd
142	raceSymbolizeDataCmd
143)
144
145// Callback from C into Go, runs on g0.
146func racecallback(cmd uintptr, ctx unsafe.Pointer) {
147	switch cmd {
148	case raceGetProcCmd:
149		throw("should have been handled by racecallbackthunk")
150	case raceSymbolizeCodeCmd:
151		raceSymbolizeCode((*symbolizeCodeContext)(ctx))
152	case raceSymbolizeDataCmd:
153		raceSymbolizeData((*symbolizeDataContext)(ctx))
154	default:
155		throw("unknown command")
156	}
157}
158
159// raceSymbolizeCode reads ctx.pc and populates the rest of *ctx with
160// information about the code at that pc.
161//
162// The race detector has already subtracted 1 from pcs, so they point to the last
163// byte of call instructions (including calls to runtime.racewrite and friends).
164//
165// If the incoming pc is part of an inlined function, *ctx is populated
166// with information about the inlined function, and on return ctx.pc is set
167// to a pc in the logically containing function. (The race detector should call this
168// function again with that pc.)
169//
170// If the incoming pc is not part of an inlined function, the return pc is unchanged.
171func raceSymbolizeCode(ctx *symbolizeCodeContext) {
172	pc := ctx.pc
173	fi := findfunc(pc)
174	if fi.valid() {
175		u, uf := newInlineUnwinder(fi, pc)
176		for ; uf.valid(); uf = u.next(uf) {
177			sf := u.srcFunc(uf)
178			if sf.funcID == abi.FuncIDWrapper && u.isInlined(uf) {
179				// Ignore wrappers, unless we're at the outermost frame of u.
180				// A non-inlined wrapper frame always means we have a physical
181				// frame consisting entirely of wrappers, in which case we'll
182				// take an outermost wrapper over nothing.
183				continue
184			}
185
186			name := sf.name()
187			file, line := u.fileLine(uf)
188			if line == 0 {
189				// Failure to symbolize
190				continue
191			}
192			ctx.fn = &bytes(name)[0] // assume NUL-terminated
193			ctx.line = uintptr(line)
194			ctx.file = &bytes(file)[0] // assume NUL-terminated
195			ctx.off = pc - fi.entry()
196			ctx.res = 1
197			if u.isInlined(uf) {
198				// Set ctx.pc to the "caller" so the race detector calls this again
199				// to further unwind.
200				uf = u.next(uf)
201				ctx.pc = uf.pc
202			}
203			return
204		}
205	}
206	ctx.fn = &qq[0]
207	ctx.file = &dash[0]
208	ctx.line = 0
209	ctx.off = ctx.pc
210	ctx.res = 1
211}
212
213type symbolizeDataContext struct {
214	addr  uintptr
215	heap  uintptr
216	start uintptr
217	size  uintptr
218	name  *byte
219	file  *byte
220	line  uintptr
221	res   uintptr
222}
223
224func raceSymbolizeData(ctx *symbolizeDataContext) {
225	if base, span, _ := findObject(ctx.addr, 0, 0); base != 0 {
226		// TODO: Does this need to handle malloc headers?
227		ctx.heap = 1
228		ctx.start = base
229		ctx.size = span.elemsize
230		ctx.res = 1
231	}
232}
233
234// Race runtime functions called via runtime·racecall.
235//
236//go:linkname __tsan_init __tsan_init
237var __tsan_init byte
238
239//go:linkname __tsan_fini __tsan_fini
240var __tsan_fini byte
241
242//go:linkname __tsan_proc_create __tsan_proc_create
243var __tsan_proc_create byte
244
245//go:linkname __tsan_proc_destroy __tsan_proc_destroy
246var __tsan_proc_destroy byte
247
248//go:linkname __tsan_map_shadow __tsan_map_shadow
249var __tsan_map_shadow byte
250
251//go:linkname __tsan_finalizer_goroutine __tsan_finalizer_goroutine
252var __tsan_finalizer_goroutine byte
253
254//go:linkname __tsan_go_start __tsan_go_start
255var __tsan_go_start byte
256
257//go:linkname __tsan_go_end __tsan_go_end
258var __tsan_go_end byte
259
260//go:linkname __tsan_malloc __tsan_malloc
261var __tsan_malloc byte
262
263//go:linkname __tsan_free __tsan_free
264var __tsan_free byte
265
266//go:linkname __tsan_acquire __tsan_acquire
267var __tsan_acquire byte
268
269//go:linkname __tsan_release __tsan_release
270var __tsan_release byte
271
272//go:linkname __tsan_release_acquire __tsan_release_acquire
273var __tsan_release_acquire byte
274
275//go:linkname __tsan_release_merge __tsan_release_merge
276var __tsan_release_merge byte
277
278//go:linkname __tsan_go_ignore_sync_begin __tsan_go_ignore_sync_begin
279var __tsan_go_ignore_sync_begin byte
280
281//go:linkname __tsan_go_ignore_sync_end __tsan_go_ignore_sync_end
282var __tsan_go_ignore_sync_end byte
283
284//go:linkname __tsan_report_count __tsan_report_count
285var __tsan_report_count byte
286
287// Mimic what cmd/cgo would do.
288//
289//go:cgo_import_static __tsan_init
290//go:cgo_import_static __tsan_fini
291//go:cgo_import_static __tsan_proc_create
292//go:cgo_import_static __tsan_proc_destroy
293//go:cgo_import_static __tsan_map_shadow
294//go:cgo_import_static __tsan_finalizer_goroutine
295//go:cgo_import_static __tsan_go_start
296//go:cgo_import_static __tsan_go_end
297//go:cgo_import_static __tsan_malloc
298//go:cgo_import_static __tsan_free
299//go:cgo_import_static __tsan_acquire
300//go:cgo_import_static __tsan_release
301//go:cgo_import_static __tsan_release_acquire
302//go:cgo_import_static __tsan_release_merge
303//go:cgo_import_static __tsan_go_ignore_sync_begin
304//go:cgo_import_static __tsan_go_ignore_sync_end
305//go:cgo_import_static __tsan_report_count
306
307// These are called from race_amd64.s.
308//
309//go:cgo_import_static __tsan_read
310//go:cgo_import_static __tsan_read_pc
311//go:cgo_import_static __tsan_read_range
312//go:cgo_import_static __tsan_write
313//go:cgo_import_static __tsan_write_pc
314//go:cgo_import_static __tsan_write_range
315//go:cgo_import_static __tsan_func_enter
316//go:cgo_import_static __tsan_func_exit
317
318//go:cgo_import_static __tsan_go_atomic32_load
319//go:cgo_import_static __tsan_go_atomic64_load
320//go:cgo_import_static __tsan_go_atomic32_store
321//go:cgo_import_static __tsan_go_atomic64_store
322//go:cgo_import_static __tsan_go_atomic32_exchange
323//go:cgo_import_static __tsan_go_atomic64_exchange
324//go:cgo_import_static __tsan_go_atomic32_fetch_add
325//go:cgo_import_static __tsan_go_atomic64_fetch_add
326//go:cgo_import_static __tsan_go_atomic32_fetch_and
327//go:cgo_import_static __tsan_go_atomic64_fetch_and
328//go:cgo_import_static __tsan_go_atomic32_fetch_or
329//go:cgo_import_static __tsan_go_atomic64_fetch_or
330//go:cgo_import_static __tsan_go_atomic32_compare_exchange
331//go:cgo_import_static __tsan_go_atomic64_compare_exchange
332
333// start/end of global data (data+bss).
334var racedatastart uintptr
335var racedataend uintptr
336
337// start/end of heap for race_amd64.s
338var racearenastart uintptr
339var racearenaend uintptr
340
341func racefuncenter(callpc uintptr)
342func racefuncenterfp(fp uintptr)
343func racefuncexit()
344func raceread(addr uintptr)
345func racewrite(addr uintptr)
346func racereadrange(addr, size uintptr)
347func racewriterange(addr, size uintptr)
348func racereadrangepc1(addr, size, pc uintptr)
349func racewriterangepc1(addr, size, pc uintptr)
350func racecallbackthunk(uintptr)
351
352// racecall allows calling an arbitrary function fn from C race runtime
353// with up to 4 uintptr arguments.
354func racecall(fn *byte, arg0, arg1, arg2, arg3 uintptr)
355
356// checks if the address has shadow (i.e. heap or data/bss).
357//
358//go:nosplit
359func isvalidaddr(addr unsafe.Pointer) bool {
360	return racearenastart <= uintptr(addr) && uintptr(addr) < racearenaend ||
361		racedatastart <= uintptr(addr) && uintptr(addr) < racedataend
362}
363
364//go:nosplit
365func raceinit() (gctx, pctx uintptr) {
366	lockInit(&raceFiniLock, lockRankRaceFini)
367
368	// On most machines, cgo is required to initialize libc, which is used by race runtime.
369	if !iscgo && GOOS != "darwin" {
370		throw("raceinit: race build must use cgo")
371	}
372
373	racecall(&__tsan_init, uintptr(unsafe.Pointer(&gctx)), uintptr(unsafe.Pointer(&pctx)), abi.FuncPCABI0(racecallbackthunk), 0)
374
375	// Round data segment to page boundaries, because it's used in mmap().
376	start := ^uintptr(0)
377	end := uintptr(0)
378	if start > firstmoduledata.noptrdata {
379		start = firstmoduledata.noptrdata
380	}
381	if start > firstmoduledata.data {
382		start = firstmoduledata.data
383	}
384	if start > firstmoduledata.noptrbss {
385		start = firstmoduledata.noptrbss
386	}
387	if start > firstmoduledata.bss {
388		start = firstmoduledata.bss
389	}
390	if end < firstmoduledata.enoptrdata {
391		end = firstmoduledata.enoptrdata
392	}
393	if end < firstmoduledata.edata {
394		end = firstmoduledata.edata
395	}
396	if end < firstmoduledata.enoptrbss {
397		end = firstmoduledata.enoptrbss
398	}
399	if end < firstmoduledata.ebss {
400		end = firstmoduledata.ebss
401	}
402	size := alignUp(end-start, _PageSize)
403	racecall(&__tsan_map_shadow, start, size, 0, 0)
404	racedatastart = start
405	racedataend = start + size
406
407	return
408}
409
410//go:nosplit
411func racefini() {
412	// racefini() can only be called once to avoid races.
413	// This eventually (via __tsan_fini) calls C.exit which has
414	// undefined behavior if called more than once. If the lock is
415	// already held it's assumed that the first caller exits the program
416	// so other calls can hang forever without an issue.
417	lock(&raceFiniLock)
418
419	// __tsan_fini will run C atexit functions and C++ destructors,
420	// which can theoretically call back into Go.
421	// Tell the scheduler we entering external code.
422	entersyscall()
423
424	// We're entering external code that may call ExitProcess on
425	// Windows.
426	osPreemptExtEnter(getg().m)
427
428	racecall(&__tsan_fini, 0, 0, 0, 0)
429}
430
431//go:nosplit
432func raceproccreate() uintptr {
433	var ctx uintptr
434	racecall(&__tsan_proc_create, uintptr(unsafe.Pointer(&ctx)), 0, 0, 0)
435	return ctx
436}
437
438//go:nosplit
439func raceprocdestroy(ctx uintptr) {
440	racecall(&__tsan_proc_destroy, ctx, 0, 0, 0)
441}
442
443//go:nosplit
444func racemapshadow(addr unsafe.Pointer, size uintptr) {
445	if racearenastart == 0 {
446		racearenastart = uintptr(addr)
447	}
448	if racearenaend < uintptr(addr)+size {
449		racearenaend = uintptr(addr) + size
450	}
451	racecall(&__tsan_map_shadow, uintptr(addr), size, 0, 0)
452}
453
454//go:nosplit
455func racemalloc(p unsafe.Pointer, sz uintptr) {
456	racecall(&__tsan_malloc, 0, 0, uintptr(p), sz)
457}
458
459//go:nosplit
460func racefree(p unsafe.Pointer, sz uintptr) {
461	racecall(&__tsan_free, uintptr(p), sz, 0, 0)
462}
463
464//go:nosplit
465func racegostart(pc uintptr) uintptr {
466	gp := getg()
467	var spawng *g
468	if gp.m.curg != nil {
469		spawng = gp.m.curg
470	} else {
471		spawng = gp
472	}
473
474	var racectx uintptr
475	racecall(&__tsan_go_start, spawng.racectx, uintptr(unsafe.Pointer(&racectx)), pc, 0)
476	return racectx
477}
478
479//go:nosplit
480func racegoend() {
481	racecall(&__tsan_go_end, getg().racectx, 0, 0, 0)
482}
483
484//go:nosplit
485func racectxend(racectx uintptr) {
486	racecall(&__tsan_go_end, racectx, 0, 0, 0)
487}
488
489//go:nosplit
490func racewriterangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
491	gp := getg()
492	if gp != gp.m.curg {
493		// The call is coming from manual instrumentation of Go code running on g0/gsignal.
494		// Not interesting.
495		return
496	}
497	if callpc != 0 {
498		racefuncenter(callpc)
499	}
500	racewriterangepc1(uintptr(addr), sz, pc)
501	if callpc != 0 {
502		racefuncexit()
503	}
504}
505
506//go:nosplit
507func racereadrangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
508	gp := getg()
509	if gp != gp.m.curg {
510		// The call is coming from manual instrumentation of Go code running on g0/gsignal.
511		// Not interesting.
512		return
513	}
514	if callpc != 0 {
515		racefuncenter(callpc)
516	}
517	racereadrangepc1(uintptr(addr), sz, pc)
518	if callpc != 0 {
519		racefuncexit()
520	}
521}
522
523//go:nosplit
524func raceacquire(addr unsafe.Pointer) {
525	raceacquireg(getg(), addr)
526}
527
528//go:nosplit
529func raceacquireg(gp *g, addr unsafe.Pointer) {
530	if getg().raceignore != 0 || !isvalidaddr(addr) {
531		return
532	}
533	racecall(&__tsan_acquire, gp.racectx, uintptr(addr), 0, 0)
534}
535
536//go:nosplit
537func raceacquirectx(racectx uintptr, addr unsafe.Pointer) {
538	if !isvalidaddr(addr) {
539		return
540	}
541	racecall(&__tsan_acquire, racectx, uintptr(addr), 0, 0)
542}
543
544//go:nosplit
545func racerelease(addr unsafe.Pointer) {
546	racereleaseg(getg(), addr)
547}
548
549//go:nosplit
550func racereleaseg(gp *g, addr unsafe.Pointer) {
551	if getg().raceignore != 0 || !isvalidaddr(addr) {
552		return
553	}
554	racecall(&__tsan_release, gp.racectx, uintptr(addr), 0, 0)
555}
556
557//go:nosplit
558func racereleaseacquire(addr unsafe.Pointer) {
559	racereleaseacquireg(getg(), addr)
560}
561
562//go:nosplit
563func racereleaseacquireg(gp *g, addr unsafe.Pointer) {
564	if getg().raceignore != 0 || !isvalidaddr(addr) {
565		return
566	}
567	racecall(&__tsan_release_acquire, gp.racectx, uintptr(addr), 0, 0)
568}
569
570//go:nosplit
571func racereleasemerge(addr unsafe.Pointer) {
572	racereleasemergeg(getg(), addr)
573}
574
575//go:nosplit
576func racereleasemergeg(gp *g, addr unsafe.Pointer) {
577	if getg().raceignore != 0 || !isvalidaddr(addr) {
578		return
579	}
580	racecall(&__tsan_release_merge, gp.racectx, uintptr(addr), 0, 0)
581}
582
583//go:nosplit
584func racefingo() {
585	racecall(&__tsan_finalizer_goroutine, getg().racectx, 0, 0, 0)
586}
587
588// The declarations below generate ABI wrappers for functions
589// implemented in assembly in this package but declared in another
590// package.
591
592//go:linkname abigen_sync_atomic_LoadInt32 sync/atomic.LoadInt32
593func abigen_sync_atomic_LoadInt32(addr *int32) (val int32)
594
595//go:linkname abigen_sync_atomic_LoadInt64 sync/atomic.LoadInt64
596func abigen_sync_atomic_LoadInt64(addr *int64) (val int64)
597
598//go:linkname abigen_sync_atomic_LoadUint32 sync/atomic.LoadUint32
599func abigen_sync_atomic_LoadUint32(addr *uint32) (val uint32)
600
601//go:linkname abigen_sync_atomic_LoadUint64 sync/atomic.LoadUint64
602func abigen_sync_atomic_LoadUint64(addr *uint64) (val uint64)
603
604//go:linkname abigen_sync_atomic_LoadUintptr sync/atomic.LoadUintptr
605func abigen_sync_atomic_LoadUintptr(addr *uintptr) (val uintptr)
606
607//go:linkname abigen_sync_atomic_LoadPointer sync/atomic.LoadPointer
608func abigen_sync_atomic_LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
609
610//go:linkname abigen_sync_atomic_StoreInt32 sync/atomic.StoreInt32
611func abigen_sync_atomic_StoreInt32(addr *int32, val int32)
612
613//go:linkname abigen_sync_atomic_StoreInt64 sync/atomic.StoreInt64
614func abigen_sync_atomic_StoreInt64(addr *int64, val int64)
615
616//go:linkname abigen_sync_atomic_StoreUint32 sync/atomic.StoreUint32
617func abigen_sync_atomic_StoreUint32(addr *uint32, val uint32)
618
619//go:linkname abigen_sync_atomic_StoreUint64 sync/atomic.StoreUint64
620func abigen_sync_atomic_StoreUint64(addr *uint64, val uint64)
621
622//go:linkname abigen_sync_atomic_SwapInt32 sync/atomic.SwapInt32
623func abigen_sync_atomic_SwapInt32(addr *int32, new int32) (old int32)
624
625//go:linkname abigen_sync_atomic_SwapInt64 sync/atomic.SwapInt64
626func abigen_sync_atomic_SwapInt64(addr *int64, new int64) (old int64)
627
628//go:linkname abigen_sync_atomic_SwapUint32 sync/atomic.SwapUint32
629func abigen_sync_atomic_SwapUint32(addr *uint32, new uint32) (old uint32)
630
631//go:linkname abigen_sync_atomic_SwapUint64 sync/atomic.SwapUint64
632func abigen_sync_atomic_SwapUint64(addr *uint64, new uint64) (old uint64)
633
634//go:linkname abigen_sync_atomic_AddInt32 sync/atomic.AddInt32
635func abigen_sync_atomic_AddInt32(addr *int32, delta int32) (new int32)
636
637//go:linkname abigen_sync_atomic_AddUint32 sync/atomic.AddUint32
638func abigen_sync_atomic_AddUint32(addr *uint32, delta uint32) (new uint32)
639
640//go:linkname abigen_sync_atomic_AddInt64 sync/atomic.AddInt64
641func abigen_sync_atomic_AddInt64(addr *int64, delta int64) (new int64)
642
643//go:linkname abigen_sync_atomic_AddUint64 sync/atomic.AddUint64
644func abigen_sync_atomic_AddUint64(addr *uint64, delta uint64) (new uint64)
645
646//go:linkname abigen_sync_atomic_AddUintptr sync/atomic.AddUintptr
647func abigen_sync_atomic_AddUintptr(addr *uintptr, delta uintptr) (new uintptr)
648
649//go:linkname abigen_sync_atomic_AndInt32 sync/atomic.AndInt32
650func abigen_sync_atomic_AndInt32(addr *int32, mask int32) (old int32)
651
652//go:linkname abigen_sync_atomic_AndUint32 sync/atomic.AndUint32
653func abigen_sync_atomic_AndUint32(addr *uint32, mask uint32) (old uint32)
654
655//go:linkname abigen_sync_atomic_AndInt64 sync/atomic.AndInt64
656func abigen_sync_atomic_AndInt64(addr *int64, mask int64) (old int64)
657
658//go:linkname abigen_sync_atomic_AndUint64 sync/atomic.AndUint64
659func abigen_sync_atomic_AndUint64(addr *uint64, mask uint64) (old uint64)
660
661//go:linkname abigen_sync_atomic_AndUintptr sync/atomic.AndUintptr
662func abigen_sync_atomic_AndUintptr(addr *uintptr, mask uintptr) (old uintptr)
663
664//go:linkname abigen_sync_atomic_OrInt32 sync/atomic.OrInt32
665func abigen_sync_atomic_OrInt32(addr *int32, mask int32) (old int32)
666
667//go:linkname abigen_sync_atomic_OrUint32 sync/atomic.OrUint32
668func abigen_sync_atomic_OrUint32(addr *uint32, mask uint32) (old uint32)
669
670//go:linkname abigen_sync_atomic_OrInt64 sync/atomic.OrInt64
671func abigen_sync_atomic_OrInt64(addr *int64, mask int64) (old int64)
672
673//go:linkname abigen_sync_atomic_OrUint64 sync/atomic.OrUint64
674func abigen_sync_atomic_OrUint64(addr *uint64, mask uint64) (old uint64)
675
676//go:linkname abigen_sync_atomic_OrUintptr sync/atomic.OrUintptr
677func abigen_sync_atomic_OrUintptr(addr *uintptr, mask uintptr) (old uintptr)
678
679//go:linkname abigen_sync_atomic_CompareAndSwapInt32 sync/atomic.CompareAndSwapInt32
680func abigen_sync_atomic_CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
681
682//go:linkname abigen_sync_atomic_CompareAndSwapInt64 sync/atomic.CompareAndSwapInt64
683func abigen_sync_atomic_CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
684
685//go:linkname abigen_sync_atomic_CompareAndSwapUint32 sync/atomic.CompareAndSwapUint32
686func abigen_sync_atomic_CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)
687
688//go:linkname abigen_sync_atomic_CompareAndSwapUint64 sync/atomic.CompareAndSwapUint64
689func abigen_sync_atomic_CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)
690