[test] Make tests more reliably detect races under TSAN.
Bug: https://github.com/dart-lang/sdk/issues/61974
Change-Id: I27ad40af61becc558a8d1650a7f45a1484aecc0b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/464600
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/tests/vm/dart/tsan/array_data_race_test.dart b/runtime/tests/vm/dart/tsan/array_data_race_test.dart
index a9cde1d2..db24255 100644
--- a/runtime/tests/vm/dart/tsan/array_data_race_test.dart
+++ b/runtime/tests/vm/dart/tsan/array_data_race_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// VMOptions=--experimental-shared-data
+// VMOptions=--experimental-shared-data --no-osr --no-background-compilation
import "dart:ffi";
import "dart:io";
@@ -16,28 +16,30 @@
List<dynamic>? box;
@pragma("vm:never-inline")
-noopt() {}
-
-@pragma("vm:never-inline")
dataRaceFromMain() {
final localBox = box!;
- for (var i = 0; i < 1000000; i++) {
- localBox[0] += 1;
- noopt();
+ for (var i = 0; i < 50000; i++) {
+ usleep(100);
+ var t = localBox[0];
+ usleep(100);
+ localBox[0] = t + 1;
}
}
@pragma("vm:never-inline")
dataRaceFromChild() {
final localBox = box!;
- for (var i = 0; i < 1000000; i++) {
- localBox[0] += 1;
- noopt();
+ for (var i = 0; i < 50000; i++) {
+ usleep(100);
+ var t = localBox[0];
+ usleep(100);
+ localBox[0] = t + 1;
}
}
-child(_) {
+child(replyPort) {
dataRaceFromChild();
+ replyPort.send(null);
}
final nativeLib = dlopenPlatformSpecific('ffi_test_functions');
@@ -53,6 +55,13 @@
@Native<IntPtr Function(Handle, Handle, Handle)>(symbol: 'UnsafeSetSharedTo')
external int unsafeSetSharedTo(Object library_name, String name, Object value);
+// Leaf: we don't want the two threads to synchronize via safepoint.
+final usleep = DynamicLibrary.process()
+ .lookupFunction<Void Function(Long), void Function(int)>(
+ 'usleep',
+ isLeaf: true,
+ );
+
main(List<String> arguments) {
if (arguments.contains("--testee")) {
setFfiNativeResolverForTest(getRootLibraryUrl());
@@ -60,8 +69,13 @@
// Still we want to use it here to test data race detection.
unsafeSetSharedTo(getRootLibraryUrl(), "box", List<dynamic>.filled(1, 0));
- print(box); // side effect initialization
- Isolate.spawn(child, null);
+ // Avoid synchronizing via lazy compilation and initialization.
+ usleep(0);
+ box![0] += 0;
+
+ var port = new RawReceivePort();
+ port.handler = (_) => port.close();
+ Isolate.spawn(child, port.sendPort);
dataRaceFromMain();
return;
}
diff --git a/runtime/tests/vm/dart/tsan/field_data_race_no_sanitize_test.dart b/runtime/tests/vm/dart/tsan/field_data_race_no_sanitize_test.dart
index c1238e4..06d7045 100644
--- a/runtime/tests/vm/dart/tsan/field_data_race_no_sanitize_test.dart
+++ b/runtime/tests/vm/dart/tsan/field_data_race_no_sanitize_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// VMOptions=--experimental-shared-data
+// VMOptions=--experimental-shared-data --no-osr --no-background-compilation
import "dart:ffi";
import "dart:io";
@@ -21,28 +21,30 @@
Box? box;
@pragma("vm:never-inline")
-noopt() {}
-
-@pragma("vm:never-inline")
dataRaceFromMain() {
final localBox = box!;
- for (var i = 0; i < 1000000; i++) {
- localBox.foo += 1;
- noopt();
+ for (var i = 0; i < 50000; i++) {
+ usleep(100);
+ var t = localBox.foo;
+ usleep(100);
+ localBox.foo = t + 1;
}
}
@pragma("vm:never-inline")
dataRaceFromChild() {
final localBox = box!;
- for (var i = 0; i < 1000000; i++) {
- localBox.foo += 1;
- noopt();
+ for (var i = 0; i < 50000; i++) {
+ usleep(100);
+ var t = localBox.foo;
+ usleep(100);
+ localBox.foo = t + 1;
}
}
-child(_) {
+child(replyPort) {
dataRaceFromChild();
+ replyPort.send(null);
}
final nativeLib = dlopenPlatformSpecific('ffi_test_functions');
@@ -58,12 +60,25 @@
@Native<IntPtr Function(Handle, Handle, Handle)>(symbol: 'UnsafeSetSharedTo')
external int unsafeSetSharedTo(Object library_name, String name, Object value);
+// Leaf: we don't want the two threads to synchronize via safepoint.
+final usleep = DynamicLibrary.process()
+ .lookupFunction<Void Function(Long), void Function(int)>(
+ 'usleep',
+ isLeaf: true,
+ );
+
main(List<String> arguments) {
if (arguments.contains("--testee")) {
setFfiNativeResolverForTest(getRootLibraryUrl());
unsafeSetSharedTo(getRootLibraryUrl(), "box", Box());
- print(box); // side effect initialization
- Isolate.spawn(child, null);
+
+ // Avoid synchronizing via lazy compilation.
+ usleep(0);
+ box!.foo += 0;
+
+ var port = new RawReceivePort();
+ port.handler = (_) => port.close();
+ Isolate.spawn(child, port.sendPort);
dataRaceFromMain();
return;
}
diff --git a/runtime/tests/vm/dart/tsan/field_data_race_test.dart b/runtime/tests/vm/dart/tsan/field_data_race_test.dart
index 9b7e7a1..0c9a745 100644
--- a/runtime/tests/vm/dart/tsan/field_data_race_test.dart
+++ b/runtime/tests/vm/dart/tsan/field_data_race_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// VMOptions=--experimental-shared-data
+// VMOptions=--experimental-shared-data --no-osr --no-background-compilation
import "dart:ffi";
import "dart:io";
@@ -20,23 +20,24 @@
Box? box;
@pragma("vm:never-inline")
-noopt() {}
-
-@pragma("vm:never-inline")
dataRaceFromMain() {
final localBox = box!;
- for (var i = 0; i < 1000000; i++) {
- localBox.foo += 1;
- noopt();
+ for (var i = 0; i < 50000; i++) {
+ usleep(100);
+ var t = localBox.foo;
+ usleep(100);
+ localBox.foo = t + 1;
}
}
@pragma("vm:never-inline")
dataRaceFromChild() {
final localBox = box!;
- for (var i = 0; i < 1000000; i++) {
- localBox.foo += 1;
- noopt();
+ for (var i = 0; i < 50000; i++) {
+ usleep(100);
+ var t = localBox.foo;
+ usleep(100);
+ localBox.foo = t + 1;
}
}
@@ -52,8 +53,9 @@
@pragma("vm:never-inline")
dataRaceFromChildCallerCaller() => dataRaceFromChildCaller();
-child(_) {
+child(replyPort) {
dataRaceFromChildCallerCaller();
+ replyPort.send(null);
}
final nativeLib = dlopenPlatformSpecific('ffi_test_functions');
@@ -69,14 +71,27 @@
@Native<IntPtr Function(Handle, Handle, Handle)>(symbol: 'UnsafeSetSharedTo')
external int unsafeSetSharedTo(Object library_name, String name, Object value);
+// Leaf: we don't want the two threads to synchronize via safepoint.
+final usleep = DynamicLibrary.process()
+ .lookupFunction<Void Function(Long), void Function(int)>(
+ 'usleep',
+ isLeaf: true,
+ );
+
main(List<String> arguments) {
if (arguments.contains("--testee")) {
setFfiNativeResolverForTest(getRootLibraryUrl());
// At this point List is not allowed to be stored in shaded fields.
// Still we want to use it here to test data race detection.
unsafeSetSharedTo(getRootLibraryUrl(), "box", Box());
- print(box); // side effect initialization
- Isolate.spawn(child, null);
+
+ // Avoid synchronizing via lazy compilation.
+ usleep(0);
+ box!.foo += 0;
+
+ var port = new RawReceivePort();
+ port.handler = (_) => port.close();
+ Isolate.spawn(child, port.sendPort);
dataRaceFromMainCallerCaller();
return;
}
diff --git a/runtime/tests/vm/dart/tsan/typed_data_race_test.dart b/runtime/tests/vm/dart/tsan/typed_data_race_test.dart
index cc174ea..0e39989 100644
--- a/runtime/tests/vm/dart/tsan/typed_data_race_test.dart
+++ b/runtime/tests/vm/dart/tsan/typed_data_race_test.dart
@@ -2,8 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// VMOptions=--experimental-shared-data
+// VMOptions=--experimental-shared-data --no-osr --no-background-compilation
+import "dart:ffi";
import "dart:io";
import "dart:isolate";
import "dart:typed_data";
@@ -13,34 +14,48 @@
Uint8List box = Uint8List(1);
@pragma("vm:never-inline")
-noopt() {}
-
-@pragma("vm:never-inline")
dataRaceFromMain() {
final localBox = box;
- for (var i = 0; i < 10000000; i++) {
- localBox[0] += 1;
- noopt();
+ for (var i = 0; i < 50000; i++) {
+ usleep(100);
+ var t = localBox[0];
+ usleep(100);
+ localBox[0] = t + 1;
}
}
@pragma("vm:never-inline")
dataRaceFromChild() {
final localBox = box;
- for (var i = 0; i < 10000000; i++) {
- localBox[0] += 1;
- noopt();
+ for (var i = 0; i < 50000; i++) {
+ usleep(100);
+ var t = localBox[0];
+ usleep(100);
+ localBox[0] = t + 1;
}
}
-child(_) {
+child(replyPort) {
dataRaceFromChild();
+ replyPort.send(null);
}
+// Leaf: we don't want the two threads to synchronize via safepoint.
+final usleep = DynamicLibrary.process()
+ .lookupFunction<Void Function(Long), void Function(int)>(
+ 'usleep',
+ isLeaf: true,
+ );
+
main(List<String> arguments) {
if (arguments.contains("--testee")) {
- print(box); // side effect initialization
- Isolate.spawn(child, null);
+ // Avoid synchronizing via lazy compilation and initialization.
+ usleep(0);
+ box![0] += 0;
+
+ var port = new RawReceivePort();
+ port.handler = (_) => port.close();
+ Isolate.spawn(child, port.sendPort);
dataRaceFromMain();
return;
}