[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;
   }