Changeset: dce7fa42e62a for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=dce7fa42e62a
Modified Files:
sql/backends/monet5/UDF/capi/Tests/capi04.sql
sql/backends/monet5/UDF/capi/Tests/capi04.stable.out
sql/backends/monet5/UDF/capi/capi.c
Branch: jitudf
Log Message:
Automatically clean up any mallocs performed in the jitted function.
diffs (190 lines):
diff --git a/sql/backends/monet5/UDF/capi/Tests/capi04.sql
b/sql/backends/monet5/UDF/capi/Tests/capi04.sql
--- a/sql/backends/monet5/UDF/capi/Tests/capi04.sql
+++ b/sql/backends/monet5/UDF/capi/Tests/capi04.sql
@@ -10,8 +10,6 @@ CREATE FUNCTION capi04(inp STRING) RETUR
if (inp.is_null(inp.data[i])) {
result->data[i] = result->null_value;
} else {
- // the contract says we must use "malloc" to allocate
for the result strings
- // "malloc" is a function pointer that actually points
to GDKmalloc
result->data[i] = malloc(strlen(inp.data[i]) + 2);
strcpy(result->data[i] + 1, inp.data[i]);
result->data[i][0] = 'H';
@@ -35,8 +33,28 @@ CREATE FUNCTION capi04(inp STRING) RETUR
};
SELECT capi04(i) FROM strings;
+ROLLBACK;
+
+START TRANSACTION;
+# return constant strings, instead of allocated strings
+CREATE FUNCTION capi04(inp STRING) RETURNS STRING LANGUAGE C {
+#include <string.h>
+
+ result->initialize(result, inp.count);
+ for(size_t i = 0; i < inp.count; i++) {
+ if (inp.is_null(inp.data[i])) {
+ result->data[i] = result->null_value;
+ } else {
+ result->data[i] = malloc(strlen(inp.data[i]) + 2);
+ strcpy(result->data[i] + 1, inp.data[i]);
+ result->data[i] = "hello";
+ }
+ }
+};
+
+CREATE TABLE strings(i STRING);
+INSERT INTO strings VALUES ('ello'), ('ow'), (NULL), ('onestly?'), ('annes');
+
+SELECT capi04(i) FROM strings;
ROLLBACK;
-
-
-
diff --git a/sql/backends/monet5/UDF/capi/Tests/capi04.stable.out
b/sql/backends/monet5/UDF/capi/Tests/capi04.stable.out
--- a/sql/backends/monet5/UDF/capi/Tests/capi04.stable.out
+++ b/sql/backends/monet5/UDF/capi/Tests/capi04.stable.out
@@ -54,14 +54,10 @@ Ready.
# loading sql script: 90_generator.sql
# loading sql script: 90_generator_hge.sql
# loading sql script: 99_system.sql
-Hello
-How
-Honestly?
-Hannes
-# 15:50:30 >
-# 15:50:30 > "mclient" "-lsql" "-ftest" "-Eutf-8" "-i" "-e"
"--host=/var/tmp/mtest-20003" "--port=32751"
-# 15:50:30 >
+# 12:56:26 >
+# 12:56:26 > "mclient" "-lsql" "-ftest" "-Eutf-8" "-i" "-e"
"--host=/var/tmp/mtest-37150" "--port=31836"
+# 12:56:26 >
#START TRANSACTION;
#CREATE FUNCTION capi04(inp STRING) RETURNS STRING LANGUAGE C {
@@ -98,6 +94,35 @@ Hannes
# }
#};
#ROLLBACK;
+#START TRANSACTION;
+#CREATE FUNCTION capi04(inp STRING) RETURNS STRING LANGUAGE C {
+##include <string.h>
+#
+# result->initialize(result, inp.count);
+# for(size_t i = 0; i < inp.count; i++) {
+# if (inp.is_null(inp.data[i])) {
+# result->data[i] = result->null_value;
+# } else {
+# result->data[i] = malloc(strlen(inp.data[i]) + 2);
+# strcpy(result->data[i] + 1, inp.data[i]);
+# result->data[i] = "hello";
+# }
+# }
+#};
+#CREATE TABLE strings(i STRING);
+#INSERT INTO strings VALUES ('ello'), ('ow'), (NULL), ('onestly?'), ('annes');
+[ 5 ]
+#SELECT capi04(i) FROM strings;
+% sys.L2 # table_name
+% L2 # name
+% clob # type
+% 5 # length
+[ "hello" ]
+[ "hello" ]
+[ NULL ]
+[ "hello" ]
+[ "hello" ]
+#ROLLBACK;
# 15:50:31 >
# 15:50:31 > "Done."
diff --git a/sql/backends/monet5/UDF/capi/capi.c
b/sql/backends/monet5/UDF/capi/capi.c
--- a/sql/backends/monet5/UDF/capi/capi.c
+++ b/sql/backends/monet5/UDF/capi/capi.c
@@ -22,6 +22,13 @@
#include <unistd.h>
#include <string.h>
+struct _allocated_region;
+typedef struct _allocated_region {
+ struct _allocated_region* next;
+} allocated_region;
+
+
+static __thread allocated_region* allocated_regions;
static __thread jmp_buf jump_buffer;
static str
@@ -125,7 +132,7 @@ clear_mprotect(void* addr, size_t len) {
}
-static void* wrapped_GDK_malloc(size_t size) {
+static void* jump_GDK_malloc(size_t size) {
void* ptr = GDKmalloc(size);
if (!ptr) {
longjmp(jump_buffer, 2);
@@ -133,11 +140,21 @@ static void* wrapped_GDK_malloc(size_t s
return ptr;
}
+static void* wrapped_GDK_malloc(size_t size) {
+ allocated_region* region;
+ void* ptr = jump_GDK_malloc(size + sizeof(allocated_region));
+ region = (allocated_region*)ptr;
+ region->next = allocated_regions;
+ allocated_regions = region;
+
+ return ptr + sizeof(allocated_region);
+}
+
#define GENERATE_BASE_HEADERS(type, tpename) \
static int tpename##_is_null(type value); \
static void tpename##_initialize(struct cudf_data_struct_##tpename* self,
size_t count) { \
self->count = count; \
- self->data = wrapped_GDK_malloc(count * sizeof(self->null_value)); \
+ self->data = jump_GDK_malloc(count * sizeof(self->null_value)); \
}
#define GENERATE_BASE_FUNCTIONS(tpe, tpename) \
@@ -278,6 +295,8 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal
(void) cntxt;
+ allocated_regions = NULL;
+
// we need to be able to catch segfaults and bus errors
// so we can work with mprotect to prevent UDFs from changing
// the input data
@@ -781,7 +800,7 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal
goto wrapup;
} else {
// we jumped here
- msg = createException(MAL, "cudf.eval", "We longjumped
here because of an error!.");
+ msg = createException(MAL, "cudf.eval", "We longjumped
here because of an error, but we don't know which!");
goto wrapup;
}
}
@@ -903,9 +922,6 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal
msg = createException(MAL, "cudf.eval",
MAL_MALLOC_FAIL);
goto wrapup;
}
- if (ptr != str_nil) {
- GDKfree(source_base[j]);
- }
}
GDKfree(data);
} else {
@@ -940,6 +956,11 @@ wrapup:
GDKfree(regions);
regions = next;
}
+ while(allocated_regions) {
+ allocated_region* next = allocated_regions->next;
+ GDKfree(allocated_regions);
+ allocated_regions = next;
+ }
// block segfaults and bus errors again after we exit
(void) pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
// argument names (input)
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list