[ffi/samples] Fix samples/ffi/http so it passes under tsan.
Before this fix running under tsan produces following warning:
```
00:00 +0: httpGet
00:03 +1: httpServe
00:04 +2: All tests passed!
/usr/bin/addr2line: DWARF error: mangled line number section (bad file number)
/usr/bin/addr2line: DWARF error: mangled line number section (bad file number)
/usr/bin/addr2line: DWARF error: mangled line number section (bad file number)
/usr/bin/addr2line: DWARF error: mangled line number section (bad file number)
/usr/bin/addr2line: DWARF error: mangled line number section (bad file number)
==================
WARNING: ThreadSanitizer: signal-unsafe call inside of a signal (pid=145964)
#0 malloc ../../../../../../llvm-llvm-project/../../../../../../llvm-llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:676 (dartvm+0x21c9330) (BuildId: d195bc5e9885ab144039c676e433289217750aec)
#1 __dcigettext intl/./intl/dcigettext.c:621 (libc.so.6+0x39f23) (BuildId: 4a95b54430cb5a2c68c1812f1738222660dec6d1)
#2 __tsan::CallUserSignalHandler(__tsan::ThreadState*, bool, bool, int, __sanitizer::__sanitizer_siginfo*, void*) ../../../../../../llvm-llvm-project/../../../../../../llvm-llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:2149 (dartvm+0x21d34af) (BuildId: d195bc5e9885ab144039c676e433289217750aec)
SUMMARY: ThreadSanitizer: signal-unsafe call inside of a signal intl/./intl/dcigettext.c:621 in __dcigettext
==================
ThreadSanitizer: reported 1 warnings
```
TEST=samples/ffi/http
Change-Id: I4cd1b62d30cde3ff0d4cd5f6a23c33e36491884a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/445284
Commit-Queue: Alexander Aprelev <aam@google.com>
Reviewed-by: Liam Appelbe <liama@google.com>
diff --git a/samples/ffi/http/lib/fake_http.cc b/samples/ffi/http/lib/fake_http.cc
index 63b4f1d..4420e5e 100644
--- a/samples/ffi/http/lib/fake_http.cc
+++ b/samples/ffi/http/lib/fake_http.cc
@@ -38,11 +38,23 @@
}).detach();
}
-DART_EXPORT void http_serve(void (*onRequest)(const char*)) {
- std::thread([onRequest]() {
- while (true) {
+std::atomic<bool> stop_requested = false;
+std::thread* server = nullptr;
+
+DART_EXPORT void http_start_serving(void (*onRequest)(const char*)) {
+ server = new std::thread([onRequest]() {
+ while (!stop_requested) {
std::this_thread::sleep_for(std::chrono::seconds(1));
onRequest(kExampleRequest);
}
- }).detach();
+ });
}
+
+DART_EXPORT void http_stop_serving() {
+ if (server != nullptr) {
+ stop_requested = true;
+ server->join();
+ delete server;
+ server = nullptr;
+ }
+}
\ No newline at end of file
diff --git a/samples/ffi/http/lib/http.dart b/samples/ffi/http/lib/http.dart
index 0ce55c2..850d80d 100644
--- a/samples/ffi/http/lib/http.dart
+++ b/samples/ffi/http/lib/http.dart
@@ -39,7 +39,8 @@
}
// Start a HTTP server on a background thread.
-void httpServe(void Function(String) onRequest) {
+// Returns a function that should be called to stop the server.
+Function httpServe(void Function(String) onRequest) {
// Create the NativeCallable.listener.
void onNativeRequest(Pointer<Utf8> requestPointer) {
onRequest(requestPointer.toDartString());
@@ -50,13 +51,12 @@
// Invoke the native function to start the HTTP server. Our example
// HTTP library will start a server on a background thread, and pass
// any requests it receives to out callback.
- nativeHttpServe(callback.nativeFunction);
+ nativeHttpStartServing(callback.nativeFunction);
- // The server will run indefinitely, and the callback needs to stay
- // alive for that whole time, so we can't close the callback here.
- // But we also don't want the callback to keep the isolate alive
- // forever, so we set keepIsolateAlive to false.
- callback.keepIsolateAlive = false;
+ return () {
+ nativeHttpStopServing();
+ callback.close();
+ };
}
// Load the native functions from a DynamicLibrary.
@@ -73,12 +73,21 @@
final nativeHttpGet =
dylib.lookupFunction<HttpGetNativeFunction, HttpGetFunction>('http_get');
-typedef HttpServeFunction = void Function(
+typedef HttpStartServingFunction = bool Function(
Pointer<NativeFunction<HttpCallback>>);
-typedef HttpServeNativeFunction = Void Function(
+typedef HttpStartServingNativeFunction = Bool Function(
Pointer<NativeFunction<HttpCallback>>);
-final nativeHttpServe = dylib
- .lookupFunction<HttpServeNativeFunction, HttpServeFunction>('http_serve');
+final nativeHttpStartServing = dylib
+ .lookupFunction<HttpStartServingNativeFunction, HttpStartServingFunction>(
+ 'http_start_serving',
+);
+
+typedef HttpStopServingFunction = void Function();
+typedef HttpStopServingNativeFunction = Void Function();
+final nativeHttpStopServing = dylib
+ .lookupFunction<HttpStopServingNativeFunction, HttpStopServingFunction>(
+ 'http_stop_serving',
+);
Future<void> main() async {
print('Sending GET request...');
diff --git a/samples/ffi/http/test/http_test.dart b/samples/ffi/http/test/http_test.dart
index 56b092b..c43ab99 100644
--- a/samples/ffi/http/test/http_test.dart
+++ b/samples/ffi/http/test/http_test.dart
@@ -16,12 +16,13 @@
test('httpServe', () async {
final completer = Completer<String>();
- httpServe((request) {
+ final callWhenDone = httpServe((request) {
if (!completer.isCompleted) {
completer.complete(request);
}
});
final request = await completer.future;
expect(request, contains('www.example.com'));
+ callWhenDone();
});
}