mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-07-17 21:39:28 +00:00
59 lines
1.7 KiB
Nim
59 lines
1.7 KiB
Nim
## Cross-thread allocation helpers backed by libc `malloc`/`free`.
|
|
## Avoids Nim `allocShared` whose TLS-owned MemRegion segfaults when freed from a
|
|
## thread other than the one that allocated (and may have since exited); libc is process-global.
|
|
|
|
import system/ansi_c
|
|
|
|
type SharedSeq*[T] = tuple[data: ptr UncheckedArray[T], len: int]
|
|
|
|
proc alloc*(str: cstring): cstring =
|
|
## Fresh null-terminated `c_malloc` copy of `str`; free with `dealloc(cstring)`.
|
|
if str.isNil():
|
|
var ret = cast[cstring](c_malloc(1))
|
|
ret[0] = '\0'
|
|
return ret
|
|
|
|
let ret = cast[cstring](c_malloc(csize_t(len(str) + 1)))
|
|
copyMem(ret, str, len(str) + 1)
|
|
return ret
|
|
|
|
proc alloc*(str: string): cstring =
|
|
var ret = cast[cstring](c_malloc(csize_t(str.len + 1)))
|
|
let s = cast[seq[char]](str)
|
|
for i in 0 ..< str.len:
|
|
ret[i] = s[i]
|
|
ret[str.len] = '\0'
|
|
return ret
|
|
|
|
proc dealloc*(p: cstring) {.inline.} =
|
|
## Frees an `alloc(...)` buffer. Nil-safe.
|
|
if not p.isNil():
|
|
c_free(cast[pointer](p))
|
|
|
|
proc allocBox*(size: int): pointer =
|
|
## `c_malloc` block for a cross-thread callback box; free with `freeBox`.
|
|
c_malloc(csize_t(size))
|
|
|
|
proc freeBox*(p: pointer) =
|
|
if not p.isNil():
|
|
c_free(p)
|
|
|
|
proc allocSharedSeq*[T](s: seq[T]): SharedSeq[T] =
|
|
if s.len == 0:
|
|
return (cast[ptr UncheckedArray[T]](nil), 0)
|
|
|
|
let data = c_malloc(csize_t(sizeof(T) * s.len))
|
|
copyMem(data, unsafeAddr s[0], sizeof(T) * s.len)
|
|
return (cast[ptr UncheckedArray[T]](data), s.len)
|
|
|
|
proc deallocSharedSeq*[T](s: var SharedSeq[T]) =
|
|
if not s.data.isNil():
|
|
c_free(s.data)
|
|
s.len = 0
|
|
|
|
proc toSeq*[T](s: SharedSeq[T]): seq[T] =
|
|
var ret = newSeq[T]()
|
|
for i in 0 ..< s.len:
|
|
ret.add(s.data[i])
|
|
return ret
|