# Collect safe foreign procedure in another OS thread

**URL:** <https://racket.discourse.group/t/collect-safe-foreign-procedure-in-another-os-thread/2889>\
**Category:** Questions & Answers\
**Tags:** question, ffi\
**Created:** [April 27, 2024, 4:26pm UTC](https://racket.discourse.group/t/collect-safe-foreign-procedure-in-another-os-thread/2889 "2024-04-27T16:26:41Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![amirouche](https://avatars.discourse-cdn.com/v4/letter/a/f475e1/32.png) [@amirouche](https://racket.discourse.group/u/amirouche)\
**Post date:** [April 27, 2024, 4:26pm UTC](https://racket.discourse.group/t/collect-safe-foreign-procedure-in-another-os-thread/2889/1 "2024-04-27T16:26:42Z")

</div>

I struggle to create a Racket wrapper for FoundationDB C client. The Chez code rely on `foreign-procedure`'s `__collect_safe` is there an equivalent available in Racket?

---

<div class="post-metadata">

**Author:** ![mflatt](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/mflatt/32/6_2.png) [@mflatt](https://racket.discourse.group/u/mflatt)\
**Post date:** [May 20, 2024, 6:14pm UTC](https://racket.discourse.group/t/collect-safe-foreign-procedure-in-another-os-thread/2889/2 "2024-05-20T18:14:08Z")

</div>

I overlooked this question originally, but just to record an answer here that was given in Discord: `#:blocking? #t` for `_fun` or `_cprocedure` is the same functionality as `__collect_safe` in the caller direction.

---

<div class="post-metadata">

**Author:** ![amirouche](https://avatars.discourse-cdn.com/v4/letter/a/f475e1/32.png) [@amirouche](https://racket.discourse.group/u/amirouche)\
**Post date:** [May 21, 2024, 12:38pm UTC](https://racket.discourse.group/t/collect-safe-foreign-procedure-in-another-os-thread/2889/3 "2024-05-21T12:38:58Z")

</div>

Thanks for the reply.

`#blocking: #t` is useful in cases where the C procedure does not return, or returns after a long while. With cisco chez, running the code without it, crashed chez.

Ref: [3.6&nbsp;Function Types](https://docs.racket-lang.org/foreign/foreign_procedures.html#(part._foreign~3aprocedures))

To expand a bit about my use case:

FoundationDB C library, every word from the documentation of `#:blocking` is useful. The blocking procedure must be run in its own OS thread, called the network thread, that is in that thread that the heavy client logic happens. Indeed, the network thread is a thick client, it does more than serializing a remote procedure call (RPC) to a server process inside the distributed database, and more than keeping up with transaction states, and cache. I can't develop the details because I do not know them, the network protocol, and wire format are not documented, and rewriting the bits of the C library is not recommended by the maintainers. I started this paragraph, to explain that I investigated that, and I think it would be better for clients to have only racket code, and avoid `#:blocking #t` but so far, I did not start that work because it is a lot of work that is not recommended. An alternative to `#:blocking #t`, and the low-level drivers is to wrap the C library using a dedicated event loop in its own thread, and then pass the event loop `fd` to racket's event loop, but that looks like a maintenance burden, and operational burden.

---

<div class="post-metadata">

**Author:** ![LiberalArtist](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/liberalartist/32/151_2.png) [@LiberalArtist](https://racket.discourse.group/u/LiberalArtist)\
**Post date:** [May 30, 2024, 6:39am UTC](https://racket.discourse.group/t/collect-safe-foreign-procedure-in-another-os-thread/2889/4 "2024-05-30T06:39:14Z")

</div>

You might want to look at how the `db` library handles this for `sqlite3-connect` and `odbc-connect`/`odbc-driver-connect` with `#:use-place` as `'place`, `'thread`, or `#t`. As [the docs](https://docs.racket-lang.org/db/notes.html#%28part._ffi-concurrency%29) explain:

> [Wire-based connections](https://docs.racket-lang.org/db/connect.html#%28tech._wire._based._connection%29) communicate using [ports](https://docs.racket-lang.org/reference/ports.html#%28tech._port%29), which do not cause other Racket threads to block. In contrast, an FFI call causes all Racket threads to block until it completes, so [FFI-based connections](https://docs.racket-lang.org/db/connect.html#%28tech._ffi._based._connection%29) can degrade the interactivity of a Racket program, particularly if long-running queries are performed using the connection.
> 
> This problem can be avoided by creating the FFI-based connection in a separate [place](https://docs.racket-lang.org/reference/places.html#%28tech._place%29) using the `#:use-place` keyword argument. Such a connection will not block all Racket threads during queries; the disadvantage is the cost of creating and communicating with a separate [place](https://docs.racket-lang.org/reference/places.html#%28tech._place%29). On Racket CS, another solution is to execute queries in a [separate OS thread](https://docs.racket-lang.org/foreign/Operating_System_Threads.html); this solution may have lower time and memory overhead than the separate place.

The core of the implementation is in [`db/private/generic/ffi-common`](https://github.com/racket/racket/blob/master/racket/collects/db/private/generic/ffi-common.rkt) for OS threads and [`db/private-generic/place-client`](https://github.com/racket/db/blob/master/db-lib/db/private/generic/place-client.rkt) and [`db/private-generic/place-server`](https://github.com/racket/db/blob/master/db-lib/db/private/generic/place-server.rkt) for places.
