summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-04-29 07:56:57 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-04-29 07:56:57 -0700
commit20d0c961509adc3a513c48461024e403bb1bc989 (patch)
tree435b26c1f09db73e6bacc1cc374036405ca9779c
parent47a170b8c143143d0eb2a0b778c583b3a370c587 (diff)
downloadtxr-20d0c961509adc3a513c48461024e403bb1bc989.tar.gz
txr-20d0c961509adc3a513c48461024e403bb1bc989.tar.bz2
txr-20d0c961509adc3a513c48461024e403bb1bc989.zip
ffi: malloc-free variants for str, dstr and buf.
The FFI types str-d, wstr-d and buf-d are like their unsuffixed counterparts, but indicate that ownership of a dynamically allocated object is being passed which the receiver is responsible for freeing. If we pass a str, wstr or buf into a foreign function, we are generally only guaranteeing the lifetime of the buffer over the function call. If we pass a str-d or buf-d, then the callee keeps the pointer indefinitely, and must free it. If we get str or buf return value from a function, it is assumed that the pointer is static or something borrowed with some limited lifetime. A copy of it is made. If we get a str-d, wstr-d or buf-d, it is assumed that the pointer has been malloc-ed for us. The object is either duplicated, and the original one immediately freed, or else the pointer is retained directly in the Lisp object and freed if that object becomes garbage. * ffi.c (str_d_s, wstr_d_s, buf_d_s): New symbol variables. (ffi_str_get): Coalesce assignment with declaration. (ffi_str_d_get, ffi_str_d_put): New static functions. (ffi_buf_d_get, ffi_buf_d_put): New static functions. (ffi_type_compile): Handle buf_d_s, str_d_s and wstr_d_s. (ffi_init): Initialize str_d_s, wstr_d_s and buf_d_s. * ffi.c (str_d_s, wstr_d_s, buf_d_s): Declared.
-rw-r--r--ffi.c75
-rw-r--r--ffi.h4
2 files changed, 71 insertions, 8 deletions
diff --git a/ffi.c b/ffi.c
index cad0376d..7af6dda7 100644
--- a/ffi.c
+++ b/ffi.c
@@ -70,7 +70,9 @@ val void_s;
val struct_s;
-val wstr_s;
+val str_d_s, wstr_s, wstr_d_s;
+
+val buf_d_s;
val ptr_in_s, ptr_out_s, ptr_in_out_s;
@@ -601,11 +603,20 @@ static val ffi_str_get(struct txr_ffi_type *tft, mem_t *src, val self)
{
(void) tft;
(void) self;
- const char *p;
- p = *coerce(const char **, src);
+ const char *p = *coerce(const char **, src);
return string_utf8(p);
}
+static val ffi_str_d_get(struct txr_ffi_type *tft, mem_t *src, val self)
+{
+ (void) tft;
+ (void) self;
+ char *p = *coerce(char **, src);
+ val ret = string_utf8(p);
+ free(p);
+ return ret;
+}
+
static void ffi_wstr_put(struct txr_ffi_type *tft, val s, mem_t *dst,
mem_t *rtvec[], val self)
{
@@ -623,6 +634,23 @@ static val ffi_wstr_get(struct txr_ffi_type *tft, mem_t *src, val self)
return string(p);
}
+static void ffi_wstr_d_put(struct txr_ffi_type *tft, val s, mem_t *dst,
+ mem_t *rtvec[], val self)
+{
+ (void) tft;
+ (void) rtvec;
+ const wchar_t *ws = c_str(s);
+ *coerce(const wchar_t **, dst) = chk_strdup(ws);
+}
+
+static val ffi_wstr_d_get(struct txr_ffi_type *tft, mem_t *src, val self)
+{
+ (void) tft;
+ (void) self;
+ wchar_t *p = *coerce(wchar_t **, src);
+ return string_own(p);
+}
+
static void ffi_buf_put(struct txr_ffi_type *tft, val buf, mem_t *dst,
mem_t *rtvec[], val self)
{
@@ -639,6 +667,22 @@ static val ffi_buf_get(struct txr_ffi_type *tft, mem_t *src, val self)
return make_duplicate_buf(num(tft->nelem), p);
}
+static void ffi_buf_d_put(struct txr_ffi_type *tft, val buf, mem_t *dst,
+ mem_t *rtvec[], val self)
+{
+ (void) rtvec;
+ mem_t *b = buf_get(buf, self);
+ *coerce(const mem_t **, dst) = chk_copy_obj(b, c_num(length(buf)));
+}
+
+static val ffi_buf_d_get(struct txr_ffi_type *tft, mem_t *src, val self)
+{
+ (void) tft;
+ (void) self;
+ mem_t *p = *coerce(mem_t **, src);
+ return make_borrowed_buf(num(tft->nelem), p);
+}
+
static mem_t *ffi_buf_alloc(struct txr_ffi_type *tft, val buf, val self)
{
(void) tft;
@@ -1115,11 +1159,14 @@ val ffi_type_compile(val syntax)
&ffi_type_pointer,
ffi_ptr_in_out_put, ffi_ptr_out_get,
ffi_ptr_out_in, target_type);
- } else if (sym == buf_s) {
+ } else if (sym == buf_s || sym == buf_d_s) {
cnum nelem = c_num(cadr(syntax));
val type = make_ffi_type_builtin(syntax, cptr_s, sizeof (mem_t *),
&ffi_type_pointer,
- ffi_buf_put, ffi_buf_get);
+ if3(sym == buf_s,
+ ffi_buf_put, ffi_buf_d_put),
+ if3(sym == buf_s,
+ ffi_buf_get, ffi_buf_d_get));
struct txr_ffi_type *tft = ffi_type_struct(type);
tft->alloc = ffi_buf_alloc;
tft->free = ffi_noop_free;
@@ -1228,14 +1275,25 @@ val ffi_type_compile(val syntax)
tft->in = ffi_freeing_in;
tft->rtsize = 1;
return type;
+ } else if (syntax == str_d_s) {
+ val type = make_ffi_type_builtin(syntax, str_s, sizeof (mem_t *),
+ &ffi_type_pointer,
+ ffi_str_put, ffi_str_d_get);
+ return type;
} else if (syntax == wstr_s) {
return make_ffi_type_builtin(syntax, str_s, sizeof (mem_t *),
&ffi_type_pointer,
ffi_wstr_put, ffi_wstr_get);
- } else if (syntax == buf_s) {
+ } else if (syntax == wstr_d_s) {
+ return make_ffi_type_builtin(syntax, str_s, sizeof (mem_t *),
+ &ffi_type_pointer,
+ ffi_wstr_d_put, ffi_wstr_d_get);
+ } else if (syntax == buf_s || syntax == buf_d_s) {
val type = make_ffi_type_builtin(syntax, buf_s, sizeof (mem_t *),
&ffi_type_pointer,
- ffi_buf_put, ffi_void_get);
+ if3(syntax == buf_s,
+ ffi_buf_put, ffi_buf_d_put),
+ ffi_void_get);
struct txr_ffi_type *tft = ffi_type_struct(type);
tft->alloc = ffi_buf_alloc;
tft->free = ffi_noop_free;
@@ -1427,7 +1485,10 @@ void ffi_init(void)
array_s = intern(lit("array"), user_package);
void_s = intern(lit("void"), user_package);
struct_s = intern(lit("struct"), user_package);
+ str_d_s = intern(lit("str-d"), user_package);
wstr_s = intern(lit("wstr"), user_package);
+ wstr_d_s = intern(lit("wstr-d"), user_package);
+ buf_d_s = intern(lit("buf-d"), user_package);
ptr_in_s = intern(lit("ptr-in"), user_package);
ptr_out_s = intern(lit("ptr-out"), user_package);
ptr_in_out_s = intern(lit("ptr-in-out"), user_package);
diff --git a/ffi.h b/ffi.h
index fafee40f..99c87a28 100644
--- a/ffi.h
+++ b/ffi.h
@@ -37,7 +37,9 @@ extern val long_s, ulong_s;
extern val double_s;
-extern val wstr_s;
+extern val str_d_s, wstr_s, wstr_d_s;
+
+extern val buf_d_s;
extern val ptr_in_s, ptr_out_s, ptr_in_out_s;