mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-06-21 00:40:16 +00:00
61 lines
2.1 KiB
Nim
61 lines
2.1 KiB
Nim
import std/atomics
|
|
import results
|
|
import ./ffi_context, ./ffi_types
|
|
|
|
const MaxFFIContexts* = 32
|
|
## Maximum number of concurrently live FFI contexts when using FFIContextPool.
|
|
|
|
type FFIContextPool*[T] = object
|
|
contexts: array[MaxFFIContexts, FFIContext[T]]
|
|
initialized: array[MaxFFIContexts, Atomic[bool]]
|
|
|
|
proc createFFIContext*[T](
|
|
pool: var FFIContextPool[T]
|
|
): Result[ptr FFIContext[T], string] =
|
|
## Acquires a context from the fixed pool. The context's worker is built once on
|
|
## first use and reused on every later acquisition.
|
|
|
|
for i in 0 ..< MaxFFIContexts:
|
|
let ctx = pool.contexts[i].addr
|
|
if not ctx.tryClaim():
|
|
continue
|
|
if pool.initialized[i].load():
|
|
## Reused context: a prior destroy drained and released it, worker still alive.
|
|
ctx.markAsActive()
|
|
return ok(ctx)
|
|
initContextResources(ctx).isOkOr:
|
|
ctx.release()
|
|
return err("createFFIContext: initContextResources failed: " & $error)
|
|
pool.initialized[i].store(true)
|
|
return ok(ctx)
|
|
return err("FFI context pool exhausted (max " & $MaxFFIContexts & " contexts)")
|
|
|
|
proc releaseFFIContext*[T](
|
|
ctx: ptr FFIContext[T], callback: FFICallBack, userData: pointer
|
|
): Result[void, string] =
|
|
return ctx.requestRecycle(callback, userData)
|
|
|
|
proc destroyFFIContext*[T](
|
|
pool: var FFIContextPool[T], ctx: ptr FFIContext[T]
|
|
): Result[void, string] =
|
|
## Full teardown: stops/joins the worker threads and returns the context to the
|
|
## pool, marking it uninitialised so a later createFFIContext rebuilds it.
|
|
ctx.stopAndJoinThreads().isOkOr:
|
|
return err("destroyFFIContext(pool): " & $error)
|
|
for i in 0 ..< MaxFFIContexts:
|
|
if pool.contexts[i].addr == ctx:
|
|
pool.initialized[i].store(false)
|
|
break
|
|
ctx.release()
|
|
return ok()
|
|
|
|
proc isValidCtx*[T](pool: var FFIContextPool[T], ctx: pointer): bool =
|
|
## Returns true only if ctx points to one of the pool's contexts that is
|
|
## currently in use.
|
|
if ctx.isNil():
|
|
return false
|
|
for i in 0 ..< MaxFFIContexts:
|
|
if cast[pointer](pool.contexts[i].addr) == ctx:
|
|
return cast[ptr FFIContext[T]](ctx).isInUse()
|
|
return false
|