1// Copyright 2016 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 windows && race
6
7package race_test
8
9import (
10	"sync/atomic"
11	"syscall"
12	"testing"
13	"unsafe"
14)
15
16func TestAtomicMmap(t *testing.T) {
17	// Test that atomic operations work on "external" memory. Previously they crashed (#16206).
18	// Also do a sanity correctness check: under race detector atomic operations
19	// are implemented inside of race runtime.
20	kernel32 := syscall.NewLazyDLL("kernel32.dll")
21	VirtualAlloc := kernel32.NewProc("VirtualAlloc")
22	VirtualFree := kernel32.NewProc("VirtualFree")
23	const (
24		MEM_COMMIT     = 0x00001000
25		MEM_RESERVE    = 0x00002000
26		MEM_RELEASE    = 0x8000
27		PAGE_READWRITE = 0x04
28	)
29	mem, _, err := syscall.Syscall6(VirtualAlloc.Addr(), 4, 0, 1<<20, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE, 0, 0)
30	if err != 0 {
31		t.Fatalf("VirtualAlloc failed: %v", err)
32	}
33	defer syscall.Syscall(VirtualFree.Addr(), 3, mem, 1<<20, MEM_RELEASE)
34	a := (*uint64)(unsafe.Pointer(mem))
35	if *a != 0 {
36		t.Fatalf("bad atomic value: %v, want 0", *a)
37	}
38	atomic.AddUint64(a, 1)
39	if *a != 1 {
40		t.Fatalf("bad atomic value: %v, want 1", *a)
41	}
42	atomic.AddUint64(a, 1)
43	if *a != 2 {
44		t.Fatalf("bad atomic value: %v, want 2", *a)
45	}
46}
47