[ffi] Reland the iNativeCallable.listener example test.

The documentation changes already relanded. This is just relanding the
example.

Patchset 1 is a pure reland. Other patchsets are fixes.

Original CL:
https://dart-review.googlesource.com/c/sdk/+/326580

Change-Id: I04d24d63f08a351db7a6e43f331904274e28e2d5
Bug: https://github.com/dart-lang/sdk/issues/53435
TEST=samples/ffi/http/test/http_test.dart
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/328681
Commit-Queue: Liam Appelbe <liama@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index d6647ee..60545ce 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -48,6 +48,7 @@
     "runtime/bin:process_test",
     "runtime/bin:run_vm_tests",
     "runtime/vm:kernel_platform_files($host_toolchain)",
+    "samples/ffi/http:fake_http",
     "utils/dartdev:dartdev",
     "utils/dds:dds",
     "utils/kernel-service:kernel-service",
diff --git a/samples/ffi/http/.gitignore b/samples/ffi/http/.gitignore
new file mode 100644
index 0000000..a18c42e
--- /dev/null
+++ b/samples/ffi/http/.gitignore
@@ -0,0 +1,6 @@
+.dart_tool
+.packages
+pubspec.lock
+lib/libfake_http.so
+lib/libfake_http.dylib
+lib/fake_http.dll
diff --git a/samples/ffi/http/BUILD.gn b/samples/ffi/http/BUILD.gn
new file mode 100644
index 0000000..b8b98e6
--- /dev/null
+++ b/samples/ffi/http/BUILD.gn
@@ -0,0 +1,9 @@
+# Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+# 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.
+
+shared_library("fake_http") {
+  sources = [ "lib/fake_http.cc" ]
+  include_dirs = [ "." ]
+  ldflags = [ "-rdynamic" ]
+}
diff --git a/samples/ffi/http/README.md b/samples/ffi/http/README.md
new file mode 100644
index 0000000..023a324
--- /dev/null
+++ b/samples/ffi/http/README.md
@@ -0,0 +1,12 @@
+This is an example that shows how to use `NativeCallable.listener` to interact
+with a multi threaded native API.
+
+The native API is a fake HTTP library with some hard coded requests and
+responses. To build the dynamic library, run this command:
+
+```bash
+c++ -shared -fpic lib/fake_http.cc -lstdc++ -o lib/libfake_http.so
+```
+
+On Windows the output library should be `lib/fake_http.dll` and on Mac it should
+be `lib/libfake_http.dylib`.
diff --git a/samples/ffi/http/lib/dylib_utils.dart b/samples/ffi/http/lib/dylib_utils.dart
new file mode 100644
index 0000000..0425d78
--- /dev/null
+++ b/samples/ffi/http/lib/dylib_utils.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// 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.
+
+import 'dart:ffi';
+import 'dart:io' show File, Platform;
+
+Uri dylibPath(String name, Uri path) {
+  if (Platform.isLinux || Platform.isAndroid || Platform.isFuchsia) {
+    return path.resolve("lib$name.so");
+  }
+  if (Platform.isMacOS) return path.resolve("lib$name.dylib");
+  if (Platform.isWindows) return path.resolve("$name.dll");
+  throw Exception("Platform not implemented");
+}
+
+DynamicLibrary dlopenPlatformSpecific(String name, {List<Uri>? paths}) =>
+    DynamicLibrary.open((paths ?? [Uri()])
+        .map((path) => dylibPath(name, path).toFilePath())
+        .firstWhere((lib) => File(lib).existsSync()));
diff --git a/samples/ffi/http/lib/fake_http.cc b/samples/ffi/http/lib/fake_http.cc
new file mode 100644
index 0000000..21a2987
--- /dev/null
+++ b/samples/ffi/http/lib/fake_http.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// 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.
+
+#include <atomic>
+#include <chrono>
+#include <cstring>
+#include <thread>
+
+#if defined(_WIN32)
+#define DART_EXPORT extern "C" __declspec(dllexport)
+#else
+#define DART_EXPORT                                                            \
+  extern "C" __attribute__((visibility("default"))) __attribute((used))
+#endif
+
+constexpr char kExampleRequest[] = R"(
+GET / HTTP/1.1
+Host: www.example.com
+)";
+
+constexpr char kExampleResponse[] = R"(
+HTTP/1.1 200 OK
+Content-Length: 54
+Content-Type: text/html; charset=UTF-8
+
+<html>
+  <body>
+    Hello world!
+  </body>
+</html>
+)";
+
+DART_EXPORT void http_get(const char* uri, void (*onResponse)(const char*)) {
+  std::thread([onResponse]() {
+    std::this_thread::sleep_for(std::chrono::seconds(3));
+    onResponse(strdup(kExampleResponse));
+  }).detach();
+}
+
+DART_EXPORT void http_serve(void (*onRequest)(const char*)) {
+  std::thread([onRequest]() {
+    while (true) {
+      std::this_thread::sleep_for(std::chrono::seconds(1));
+      onRequest(strdup(kExampleRequest));
+    }
+  }).detach();
+}
diff --git a/samples/ffi/http/lib/http.dart b/samples/ffi/http/lib/http.dart
new file mode 100644
index 0000000..1fde486
--- /dev/null
+++ b/samples/ffi/http/lib/http.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// 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.
+
+import 'dart:async';
+import 'dart:ffi';
+import 'dart:io';
+
+import 'package:ffi/ffi.dart';
+
+import 'dylib_utils.dart';
+
+// Runs a simple HTTP GET request using a native HTTP library that runs
+// the request on a background thread.
+Future<String> httpGet(String uri) async {
+  // Create the NativeCallable.listener.
+  final completer = Completer<String>();
+  void onResponse(Pointer<Utf8> responsePointer) {
+    completer.complete(responsePointer.toDartString());
+    calloc.free(responsePointer);
+  }
+
+  final callback = NativeCallable<HttpCallback>.listener(onResponse);
+
+  // Invoke the native HTTP API. Our example HTTP library runs our GET
+  // request on a background thread, and calls the callback on that same
+  // thread when it receives the response.
+  final uriPointer = uri.toNativeUtf8();
+  nativeHttpGet(uriPointer, callback.nativeFunction);
+  calloc.free(uriPointer);
+
+  // Wait for the response.
+  final response = await completer.future;
+
+  // Remember to close the NativeCallable once the native API is finished
+  // with it, otherwise this isolate will stay alive indefinitely.
+  callback.close();
+
+  return response;
+}
+
+// Start a HTTP server on a background thread.
+void httpServe(void Function(String) onRequest) {
+  // Create the NativeCallable.listener.
+  void onNativeRequest(Pointer<Utf8> requestPointer) {
+    onRequest(requestPointer.toDartString());
+    calloc.free(requestPointer);
+  }
+
+  final callback = NativeCallable<HttpCallback>.listener(onNativeRequest);
+
+  // 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);
+
+  // 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;
+}
+
+// Load the native functions from a DynamicLibrary.
+late final DynamicLibrary dylib = dlopenPlatformSpecific('fake_http', paths: [
+  Platform.script.resolve('../lib/'),
+  Uri.file(Platform.resolvedExecutable),
+]);
+typedef HttpCallback = Void Function(Pointer<Utf8>);
+
+typedef HttpGetFunction = void Function(
+    Pointer<Utf8>, Pointer<NativeFunction<HttpCallback>>);
+typedef HttpGetNativeFunction = Void Function(
+    Pointer<Utf8>, Pointer<NativeFunction<HttpCallback>>);
+final nativeHttpGet =
+    dylib.lookupFunction<HttpGetNativeFunction, HttpGetFunction>('http_get');
+
+typedef HttpServeFunction = void Function(
+    Pointer<NativeFunction<HttpCallback>>);
+typedef HttpServeNativeFunction = Void Function(
+    Pointer<NativeFunction<HttpCallback>>);
+final nativeHttpServe = dylib
+    .lookupFunction<HttpServeNativeFunction, HttpServeFunction>('http_serve');
+
+Future<void> main() async {
+  print('Sending GET request...');
+  final response = await httpGet('http://example.com');
+  print('Received a response: $response');
+
+  print('Starting HTTP server...');
+  httpServe((String request) {
+    print('Received a request: $request');
+  });
+
+  await Future.delayed(Duration(seconds: 10));
+  print('All done');
+}
diff --git a/samples/ffi/http/pubspec.yaml b/samples/ffi/http/pubspec.yaml
new file mode 100644
index 0000000..2798023
--- /dev/null
+++ b/samples/ffi/http/pubspec.yaml
@@ -0,0 +1,12 @@
+name: http
+version: 0.0.1
+publish_to: none
+
+environment:
+  sdk: '>=3.0.0 <4.0.0'
+
+dependencies:
+  ffi: ^2.1.0
+
+dev_dependencies:
+  test: ^1.21.1
diff --git a/samples/ffi/http/test/http_test.dart b/samples/ffi/http/test/http_test.dart
new file mode 100644
index 0000000..509d8dd
--- /dev/null
+++ b/samples/ffi/http/test/http_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// 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.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:ffi/ffi.dart';
+import 'package:test/test.dart';
+
+import '../lib/http.dart';
+
+Future<void> main() async {
+  test('httpGet', () async {
+    final response = await httpGet('http://example.com');
+    expect(response, contains('Hello world!'));
+  });
+
+  test('httpServe', () async {
+    final completer = Completer<String>();
+    httpServe((request) => completer.complete(request));
+    final request = await completer.future;
+    expect(request, contains('www.example.com'));
+  });
+}
diff --git a/tools/linux_dist_support/create_tarball.py b/tools/linux_dist_support/create_tarball.py
index b519c43..059aecb 100755
--- a/tools/linux_dist_support/create_tarball.py
+++ b/tools/linux_dist_support/create_tarball.py
@@ -42,7 +42,6 @@
 ignoredPaths = [
     'buildtools/linux-x64/go',
     'buildtools/linux-x64/rust',
-    'samples',
     'third_party/7zip',
     'third_party/android_tools',
     'third_party/clang',