From 7ead50641b73e3fa83f7f893d8674098d8d4cb53 Mon Sep 17 00:00:00 2001 From: Joshua Suskalo Date: Sat, 25 Sep 2021 11:40:16 -0500 Subject: [PATCH] Fill in section on scopes --- README.md | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 055215e..c263887 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,44 @@ This can be used to implement out variables often seen in native code. (deserialize int-ptr [::ffi/pointer ::ffi/int]))) ``` -### TODO Scopes +### Scopes +In order to serialize any non-primitive type (such as the previous +`[::ffi/pointer ::ffi/int]`), off-heap memory needs to be allocated. When memory +is allocated inside the JVM, the memory is associated with a scope. Because none +was provided here, the scope is an implicit scope, and the memory will be freed +when the serialized object is garbage collected. + +In many cases this is not desirable, because the memory is not freed in a +deterministic manner, causing garbage collection pauses to become longer, as +well as changing allocation performance. Instead of an implicit scope, there are +other kinds of scopes as well. A `stack-scope` is a thread-local scope. Stack +scopes are `Closeable`, which means they should usually be used in a `with-open` +form. When a `stack-scope` is closed, it immediately frees all the memory +associated with it. The previous example, `out-int`, can be implemented with a +stack scope. + +```clojure +(defcfn out-int + "out_int" [::ffi/pointer] ::ffi/void + native-fn + [i] + (with-open [scope (ffi/stack-scope)] + (let [int-ptr (ffi/serialize i [::ffi/pointer ::ffi/int] scope)] + (native-fn int-ptr) + (ffi/deserialize int-ptr [::ffi/pointer ::ffi/int])))) +``` + +This will free the pointer immediately upon leaving the function. + +When memory needs to be accessible from multiple threads, there's +`shared-scope`. When using a `shared-scope`, it should be accessed inside a +`with-acquired` block. When a `shared-scope` is `.close`d, it will release all +its associated memory when every `with-acquired` block associated with it is +exited. + +In addition, two non-`Closeable` scopes are `global-scope`, which never frees +the resources associated with it, and `connected-scope`, which is a scope that +frees its resources on garbage collection, like an implicit scope. ### TODO Serialization and Deserialization