You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2015/06/17 13:47:50 UTC
celix git commit: CELIX-237: Added dyn_function.c for dynamically
calling function and dynamically creating closure using a schema
Repository: celix
Updated Branches:
refs/heads/feature/CELIX-237_rsa-ffi 387f7792d -> 7f3383247
CELIX-237: Added dyn_function.c for dynamically calling function and dynamically creating closure using a schema
Project: http://git-wip-us.apache.org/repos/asf/celix/repo
Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/7f338324
Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/7f338324
Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/7f338324
Branch: refs/heads/feature/CELIX-237_rsa-ffi
Commit: 7f338324707f1100f25f7b1f3ca82f01e56663fc
Parents: 387f779
Author: Pepijn Noltes <pe...@gmail.com>
Authored: Wed Jun 17 13:46:18 2015 +0200
Committer: Pepijn Noltes <pe...@gmail.com>
Committed: Wed Jun 17 13:46:18 2015 +0200
----------------------------------------------------------------------
remote_services/dyn_type/CMakeLists.txt | 14 ++
remote_services/dyn_type/closure_tests.c | 98 ++++++++++++
remote_services/dyn_type/dyn_function.c | 209 ++++++++++++++++++++++++++
remote_services/dyn_type/dyn_function.h | 24 +++
remote_services/dyn_type/dyn_type.c | 26 +---
remote_services/dyn_type/dyn_type.h | 28 +++-
remote_services/dyn_type/func_tests.c | 66 ++++++++
7 files changed, 443 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/celix/blob/7f338324/remote_services/dyn_type/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/remote_services/dyn_type/CMakeLists.txt b/remote_services/dyn_type/CMakeLists.txt
index 8b5b78f..351bb7c 100644
--- a/remote_services/dyn_type/CMakeLists.txt
+++ b/remote_services/dyn_type/CMakeLists.txt
@@ -6,4 +6,18 @@ add_executable(struct_tests
json_serializer.c
)
+add_executable(func_tests
+ func_tests.c
+ dyn_type.c
+ dyn_function.c
+)
+
+add_executable(closure_tests
+ closure_tests.c
+ dyn_type.c
+ dyn_function.c
+)
+
target_link_libraries(struct_tests ${JANSSON_LIBRARIES} /lib64/libffi.so )
+target_link_libraries(func_tests ${JANSSON_LIBRARIES} /lib64/libffi.so )
+target_link_libraries(closure_tests ${JANSSON_LIBRARIES} /lib64/libffi.so )
http://git-wip-us.apache.org/repos/asf/celix/blob/7f338324/remote_services/dyn_type/closure_tests.c
----------------------------------------------------------------------
diff --git a/remote_services/dyn_type/closure_tests.c b/remote_services/dyn_type/closure_tests.c
new file mode 100644
index 0000000..39e4ca5
--- /dev/null
+++ b/remote_services/dyn_type/closure_tests.c
@@ -0,0 +1,98 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "dyn_function.h"
+
+#define EXAMPLE1_SCHEMA "example(III)I"
+void example1_binding(void *userData, void* args[], void *out) {
+ printf("example1 closure called\n");
+ int32_t a = *((int32_t *)args[0]);
+ int32_t b = *((int32_t *)args[1]);
+ int32_t c = *((int32_t *)args[2]);
+ int32_t *ret = out;
+ *ret = a + b + c;
+}
+
+#define EXAMPLE2_SCHEMA "example(I{DDD val1 val2 val3}I)D"
+struct example2_arg2 {
+ double val1;
+ double val2;
+ double val3;
+};
+void example2_binding(void *userData, void* args[], void *out) {
+ printf("example2 closure called\n");
+ int32_t a = *((int32_t *)args[0]);
+ struct example2_arg2 *b = *((struct example2_arg2 **)args[1]);
+ int32_t c = *((int32_t *)args[2]);
+ int32_t *ret = out;
+ *ret = a + b->val1 + b->val2 + b->val3 + c;
+}
+
+
+#define EXAMPLE3_SCHEMA "example(III){III sum max min}"
+struct example3_ret {
+ int32_t sum;
+ int32_t max;
+ int32_t min;
+};
+
+void example3_binding(void *userData, void* args[], void *out) {
+ printf("exampleelosure called\n");
+ int32_t a = *((int32_t *)args[0]);
+ int32_t b = *((int32_t *)args[1]);
+ int32_t c = *((int32_t *)args[2]);
+ struct example3_ret *result = calloc(1,sizeof(*result));
+ result->sum = a + b + c;
+ result->min = a <= b ? a : b;
+ result->max = a >= b ? a : b;
+ result->min = result->min <= c ? result->min : c;
+ result->max = result->max >= c ? result->max : c;
+
+ struct example3_ret **ret = out;
+ (*ret) = result;
+}
+
+int main() {
+ dyn_closure_type *dynClosure = NULL;
+ int rc;
+
+ rc = dynClosure_create(EXAMPLE1_SCHEMA, example1_binding, NULL, &dynClosure);
+ if (rc == 0) {
+ int32_t (*func)(int32_t a, int32_t b, int32_t c) = NULL;
+ dynClosure_getFnPointer(dynClosure, (void *)&func);
+ int32_t ret = func(2,3,4);
+ printf("Return value for example1 is %i\n", ret);
+ dynClosure_destroy(dynClosure);
+ } else {
+ printf("example1 failed\n");
+ }
+
+ dynClosure = NULL;
+ rc = dynClosure_create(EXAMPLE2_SCHEMA, example2_binding, NULL, &dynClosure);
+ if (rc == 0) {
+ double (*func)(int32_t a, struct example2_arg2 *b, int32_t c) = NULL;
+ dynClosure_getFnPointer(dynClosure, (void *)&func);
+ struct example2_arg2 b = { .val1 = 1.0, .val2 = 1.5, .val3 = 2.0 };
+ double ret = func(2,&b,4);
+ printf("Return value for example2 is %f\n", ret);
+ dynClosure_destroy(dynClosure);
+ } else {
+ printf("example2 failed\n");
+ }
+
+ dynClosure = NULL;
+ rc = dynClosure_create(EXAMPLE3_SCHEMA, example3_binding, NULL, &dynClosure);
+ if (rc == 0) {
+ struct example3_ret * (*func)(int32_t a, int32_t b, int32_t c) = NULL;
+ dynClosure_getFnPointer(dynClosure, (void *)&func);
+ struct example3_ret *ret = func(2,8,4);
+ printf("Return value for example3 is {sum:%i, max:%i, min:%i}\n", ret->sum, ret->max, ret->min);
+ dynClosure_destroy(dynClosure);
+ free(ret);
+ } else {
+ printf("example2 failed\n");
+ }
+}
http://git-wip-us.apache.org/repos/asf/celix/blob/7f338324/remote_services/dyn_type/dyn_function.c
----------------------------------------------------------------------
diff --git a/remote_services/dyn_type/dyn_function.c b/remote_services/dyn_type/dyn_function.c
new file mode 100644
index 0000000..a90bc64
--- /dev/null
+++ b/remote_services/dyn_type/dyn_function.c
@@ -0,0 +1,209 @@
+#include "dyn_function.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <strings.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <ffi.h>
+
+#include "dyn_type.h"
+
+struct _dyn_function_type {
+ dyn_type *arguments;
+ dyn_type *funcReturn;
+ void (*fn)(void);
+ ffi_cif cif;
+};
+
+struct _dyn_closure_type {
+ dyn_type *arguments;
+ dyn_type *funcReturn;
+ ffi_cif cif;
+ ffi_closure *ffiClosure;
+ void (*fn)(void);
+ void (*bind)(void *userData, void *args[], void *ret);
+ void *userData;
+};
+
+
+static int dynFunction_initCif(ffi_cif *cif, dyn_type *arguments, dyn_type *funcReturn);
+static int dynFunction_parseSchema(const char *schema, dyn_type **arguments, dyn_type **funcReturn);
+static void dynClosure_ffiBind(ffi_cif *cif, void *ret, void *args[], void *userData);
+
+int dynFunction_create(const char *schema, void (*fn)(void), dyn_function_type **out) {
+ int status = 0;
+ dyn_function_type *dynFunc = NULL;
+
+ dynFunc = calloc(1, sizeof(*dynFunc));
+
+ if (dynFunc != NULL) {
+ dynFunc->fn = fn;
+ status = dynFunction_parseSchema(schema, &dynFunc->arguments, &dynFunc->funcReturn);
+ if (status == 0) {
+ status = dynFunction_initCif(&dynFunc->cif, dynFunc->arguments, dynFunc->funcReturn);
+ }
+ } else {
+ status = 2;
+ }
+
+ if (status == 0) {
+ *out = dynFunc;
+ } else {
+ if (status == 1) {
+ printf("Cannot parse func schema '%s'\n", schema);
+ } else {
+ printf("Cannot allocate memory for dyn function\n");
+ }
+ }
+ return status;
+}
+
+static int dynFunction_parseSchema(const char *schema, dyn_type **arguments, dyn_type **funcReturn) {
+ int status = 0;
+ //FIXME white space parsing is missing. Note move parsing to lex/bison?
+ //TODO move to parse schema function
+ char *startPos = index(schema, '(');
+ char *endPos = index(schema, ')');
+
+ if (startPos != NULL && endPos != NULL) {
+ int nrOfArgs = 0;
+ int len = endPos - startPos - 1;
+
+ char *pos = startPos + 1;
+ while (*pos != ')') {
+ nrOfArgs += 1;
+ if (*pos == '{') { //embedded struct
+ while (*pos != '}' && *pos != '\0') {
+ pos += 1;
+ }
+ }
+ pos += 1;
+ }
+
+ printf("nrOfAgrs is %i\n", nrOfArgs);
+
+ //length needed is len args +2 -> {DD}
+ //+ 7 per arg e.g. {DD arg001 arg002}
+ //+ 1 x \0
+ //--> len args + 3 + 7 * nrArgs
+ int argLength = 3 + len + 7 * nrOfArgs;
+
+ char argSchema[argLength];
+ argSchema[0] = '{';
+ memcpy(argSchema + 1, startPos + 1, len);
+ pos += len + 1;
+ int i;
+ for (i = 0 ; i < nrOfArgs; i += 1) {
+ sprintf(argSchema + 1 + len + 7 * i, " arg%03d", i);
+ pos += 7;
+ }
+ argSchema[argLength -2] = '}';
+ argSchema[argLength -1] = '\0';
+ printf("arg schema is '%s'\n", argSchema);
+
+ size_t returnLen = strlen(endPos + 1);
+ char returnSchema[returnLen + 1];
+ memcpy(returnSchema, endPos +1, returnLen);
+ returnSchema[returnLen] = '\0';
+ printf("return schema is '%s'\n", returnSchema);
+
+ status = dynType_create(argSchema, arguments);
+ if (status == 0) {
+ status = dynType_create(returnSchema, funcReturn);
+ }
+ } else {
+ status = 1;
+ }
+
+ return status;
+}
+
+static int dynFunction_initCif(ffi_cif *cif, dyn_type *arguments, dyn_type *returnValue) {
+ int result = 0;
+
+ int count = 0;
+ int i;
+ for (i = 0; arguments->complex.ffiType.elements[i] != NULL; i += 1) {
+ count += 1;
+ }
+
+ ffi_type **args = arguments->complex.ffiType.elements;
+ ffi_type *returnType = &ffi_type_pointer;
+ if (returnType->type == DYN_TYPE_SIMPLE) {
+ returnType = returnValue->simple.ffiType;
+ }
+
+
+ int ffiResult = ffi_prep_cif(cif, FFI_DEFAULT_ABI, count, returnType, args);
+ if (ffiResult != FFI_OK) {
+ result = 1;
+ }
+
+ return result;
+}
+
+int dynFunction_destroy(dyn_function_type *dynFunc) {
+ int result = 0;
+ printf("TODO destroy dyn dync\n");
+ return result;
+}
+
+int dynFunction_call(dyn_function_type *dynFunc, void *returnValue, void **argValues) {
+ ffi_call(&dynFunc->cif, dynFunc->fn, returnValue, argValues);
+ return 0;
+}
+
+static void dynClosure_ffiBind(ffi_cif *cif, void *ret, void *args[], void *userData) {
+ dyn_closure_type *dynClosure = userData;
+ dynClosure->bind(dynClosure->userData, args, ret);
+}
+
+int dynClosure_create(const char *schema, void (*bind)(void *, void **, void*), void *userData, dyn_closure_type **out) {
+ int status = 0;
+ dyn_closure_type *dynClosure = calloc(1, sizeof(*dynClosure));
+ if (dynClosure != NULL) {
+ dynClosure->bind = bind;
+ dynClosure->userData = userData;
+ status = dynFunction_parseSchema(schema, &dynClosure->arguments, &dynClosure->funcReturn);
+ if (status == 0) {
+ status = dynFunction_initCif(&dynClosure->cif, dynClosure->arguments, dynClosure->funcReturn);
+ if (status == 0) {
+ dynClosure->ffiClosure = ffi_closure_alloc(sizeof(ffi_closure), (void **)&dynClosure->fn);
+ if (dynClosure->ffiClosure != NULL) {
+ int rc = ffi_prep_closure_loc(dynClosure->ffiClosure, &dynClosure->cif, dynClosure_ffiBind, dynClosure, dynClosure->fn);
+ if (rc != FFI_OK) {
+ status = 1;
+ }
+ } else {
+ status = 2;
+ }
+ }
+ }
+ } else {
+ status = 2;
+ }
+
+ if (status == 0) {
+ *out = dynClosure;
+ }
+ return status;
+}
+
+int dynClosure_getFnPointer(dyn_closure_type *dynClosure, void (**fn)(void)) {
+ int status = 0;
+ if (dynClosure != NULL) {
+ (*fn) = dynClosure->fn;
+ } else {
+ status = 1;
+ }
+ return status;
+}
+
+
+int dynClosure_destroy(dyn_closure_type *dynClosure) {
+ int result = 0;
+ printf("TODO destroy closure\n");
+ return result;
+}
http://git-wip-us.apache.org/repos/asf/celix/blob/7f338324/remote_services/dyn_type/dyn_function.h
----------------------------------------------------------------------
diff --git a/remote_services/dyn_type/dyn_function.h b/remote_services/dyn_type/dyn_function.h
new file mode 100644
index 0000000..21a5e0d
--- /dev/null
+++ b/remote_services/dyn_type/dyn_function.h
@@ -0,0 +1,24 @@
+#ifndef __DYN_FUNCTION_H_
+#define __DYN_FUNCTION_H_
+
+#include <ffi.h>
+#include "dyn_type.h"
+
+/**
+ * Uses the following schema
+ * (Name)([Type]*)Type
+ * e.g add(DD)D or sum({[D[D setA setB})D
+ */
+
+typedef struct _dyn_function_type dyn_function_type;
+typedef struct _dyn_closure_type dyn_closure_type;
+
+int dynFunction_create(const char *schema, void (*fn)(void), dyn_function_type **dynFunc);
+int dynFunction_destroy(dyn_function_type *dynFunc);
+int dynFunction_call(dyn_function_type *dynFunc, void *returnValue, void **argValues);
+
+int dynClosure_create(const char *schema, void (*bind)(void *, void **, void*), void *userData, dyn_closure_type **out);
+int dynClosure_getFnPointer(dyn_closure_type *dynClosure, void(**fn)(void));
+int dynClosure_destroy(dyn_closure_type *dynClosure);
+
+#endif
http://git-wip-us.apache.org/repos/asf/celix/blob/7f338324/remote_services/dyn_type/dyn_type.c
----------------------------------------------------------------------
diff --git a/remote_services/dyn_type/dyn_type.c b/remote_services/dyn_type/dyn_type.c
index fe4c9bc..e7a2645 100644
--- a/remote_services/dyn_type/dyn_type.c
+++ b/remote_services/dyn_type/dyn_type.c
@@ -16,26 +16,6 @@ struct generic_sequence {
void *buf;
};
-struct _dyn_type {
- int type;
- union {
- struct {
- ffi_type *ffiType;
- } simple;
-
- struct {
- ffi_type ffiType;
- char **names;
- dyn_type **nested_types;
- } complex;
-
- struct {
- ffi_type seqStruct;
- dyn_type *dynType; //set if sequence is of a complex type
- ffi_type *simpleType; //set if sequence is of a simple type
- } sequence;
- };
-};
static char dynType_schemaType(dyn_type *dynType, ffi_type *ffiType);
@@ -105,12 +85,15 @@ static int dynType_simple_create(char t, dyn_type **result) {
ffi_type *ffiType = dynType_ffiType_for(t);
dyn_type *simple = NULL;
if (ffiType != NULL) {
- dyn_type *simple = calloc(1,sizeof(*simple));
+ simple = calloc(1,sizeof(*simple));
simple->type = DYN_TYPE_SIMPLE;
simple->simple.ffiType = ffiType;
}
if (ffiType != NULL && simple != NULL) {
*result = simple;
+ } else {
+ printf("Error creating simple dyn type for '%c'\n", t);
+ status = 1;
}
return status;
}
@@ -203,6 +186,7 @@ static int dynType_complex_create(char *schema, dyn_type **result) {
memcpy(nested, schema + start + 1, len);
nested[len] = '\0';
dyn_type *nestedType = NULL;
+ //TODO catch nested problem
dynType_complex_create(nested, &nestedType); //TODO use status result
type->complex.nested_types[index] = nestedType;
type->complex.ffiType.elements[index] = &ffi_type_pointer;
http://git-wip-us.apache.org/repos/asf/celix/blob/7f338324/remote_services/dyn_type/dyn_type.h
----------------------------------------------------------------------
diff --git a/remote_services/dyn_type/dyn_type.h b/remote_services/dyn_type/dyn_type.h
index 5877fdf..c7fabc5 100644
--- a/remote_services/dyn_type/dyn_type.h
+++ b/remote_services/dyn_type/dyn_type.h
@@ -31,7 +31,10 @@
*
*
* ComplexTypes
- * {[Type]+} [(Name)(SPACE)]+
+ * {[Type]+ [(Name)(SPACE)]+}
+ *
+ * NOTE MAYBE SUPPORT STRUCT BY VALUE ->
+ * <[Type]+ [(Name)(SPACE)]+>
*
* SequenceType
* [(Type)
@@ -49,6 +52,29 @@
typedef struct _dyn_type dyn_type;
+/* TODO MOVE TO PRIVATE HEADER */
+struct _dyn_type {
+ int type;
+ union {
+ struct {
+ ffi_type *ffiType;
+ } simple;
+
+ struct {
+ ffi_type ffiType;
+ char **names;
+ dyn_type **nested_types;
+ } complex;
+
+ struct {
+ ffi_type seqStruct;
+ dyn_type *dynType; //set if sequence is of a complex type
+ ffi_type *simpleType; //set if sequence is of a simple type
+ } sequence;
+ };
+};
+
+
int dynType_create(const char *schema, dyn_type **type);
int dynType_destroy(dyn_type *type);
http://git-wip-us.apache.org/repos/asf/celix/blob/7f338324/remote_services/dyn_type/func_tests.c
----------------------------------------------------------------------
diff --git a/remote_services/dyn_type/func_tests.c b/remote_services/dyn_type/func_tests.c
new file mode 100644
index 0000000..95811d7
--- /dev/null
+++ b/remote_services/dyn_type/func_tests.c
@@ -0,0 +1,66 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "dyn_function.h"
+
+#define EXAMPLE1_SCHEMA "example(III)I"
+int32_t example1(int32_t a, int32_t b, int32_t c) {
+ printf("example1 called with a:%i, b:%i, c:%i\n", a, b, c);
+ return 1;
+}
+
+#define EXAMPLE2_SCHEMA "example(I{IID val1 val2 val3}D)D"
+struct example2_arg {
+ int32_t val1;
+ int32_t val2;
+ double val3;
+};
+
+double example2(int32_t arg1, struct example2_arg *arg2, double arg3) {
+ printf("example2 called with arg1:%i, arg2:{val1:%i, val2:%i, val3:%f}, arg3:%f\n", arg1, arg2->val1, arg2->val2, arg2->val3, arg3);
+ return 2.2;
+}
+
+
+int main() {
+ dyn_function_type *dynFunc = NULL;
+ int rc;
+
+ rc = dynFunction_create(EXAMPLE1_SCHEMA, (void *)example1, &dynFunc);
+ if (rc == 0 ) {
+ int32_t a = 2;
+ int32_t b = 4;
+ int32_t c = 8;
+ void *values[3];
+ int32_t rVal = 0;
+ values[0] = &a;
+ values[1] = &b;
+ values[2] = &c;
+ dynFunction_call(dynFunc, &rVal, values);
+ dynFunction_destroy(dynFunc);
+ dynFunc = NULL;
+ } else {
+ printf("Example 1 failed\n");
+ }
+
+ rc = dynFunction_create(EXAMPLE2_SCHEMA, (void *)example2, &dynFunc);
+ if (rc == 0 ) {
+ int32_t arg1 = 2;
+ struct example2_arg complexVal = { .val1 = 2, .val2 = 3, .val3 = 4.1 };
+ struct example2_arg *arg2 = &complexVal;
+ double arg3 = 8.1;
+ double returnVal = 0;
+ void *values[3];
+ values[0] = &arg1;
+ values[1] = &arg2;
+ values[2] = &arg3;
+ dynFunction_call(dynFunc, &returnVal, values);
+ dynFunction_destroy(dynFunc);
+ dynFunc = NULL;
+ } else {
+ printf("Example 3 failed\n");
+ }
+}