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 <pepijnnol...@gmail.com>
Authored: Wed Jun 17 13:46:18 2015 +0200
Committer: Pepijn Noltes <pepijnnol...@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");
+    }
+}

Reply via email to