[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>
This commit is contained in:
Alexander Aprelev
2025-08-14 19:22:50 -07:00
committed by Commit Queue
parent aa4d2350c9
commit 11399713c5
3 changed files with 38 additions and 16 deletions
+16 -4
View File
@@ -38,11 +38,23 @@ DART_EXPORT void http_get(const char* uri, void (*onResponse)(const char*)) {
}).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;
}
}
+20 -11
View File
@@ -39,7 +39,8 @@ Future<String> httpGet(String uri) async {
}
// 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 @@ void httpServe(void Function(String) onRequest) {
// 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 @@ typedef HttpGetNativeFunction = Void Function(
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...');
+2 -1
View File
@@ -16,12 +16,13 @@ Future<void> main() async {
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();
});
}