Added NIF -> FFI bridge

This commit is contained in:
Josh Nussbaum
2015-09-21 18:50:41 -04:00
parent 6ffa064069
commit ecfb01a3fe
3 changed files with 154 additions and 0 deletions

18
Makefile Normal file
View File

@@ -0,0 +1,18 @@
CC=gcc
CFLAGS=
OBJ = ffi_nif.o
TARGET = ffi_nif.so
LIBS += -ldl -lffi
ERTS_INCLUDE_PATH=/home/josh/Playground/erlangs/erts-6.0/include
DIR=c_src
$(DIR)/%.o: $(DIR)/%.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS) -I$(ERTS_INCLUDE_PATH)
$(TARGET): $(DIR)/$(OBJ)
$(CC) -shared -o $@ $^ $(CFLAGS) $(LIBS)
.PHONY : $(TARGET)
clean :
$(RM) $(DIR)/*.o *.so

136
c_src/ffi_nif.c Normal file
View File

@@ -0,0 +1,136 @@
#include <sys/types.h>
#include <stdio.h>
#include <erl_nif.h>
#include <ffi.h>
#define MAXLEN 1024
enum {
VOID = 0,
STRING,
INT
} TYPE;
static void call(int argc, ffi_type **args, void **values, ffi_type* returnType) {
ffi_cif cif;
int returnValue;
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, argc, returnType, args) == FFI_OK) {
ffi_call(&cif, (void*)puts, &returnValue, values);
}
}
static ERL_NIF_TERM nif_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
char library[MAXLEN],
function[MAXLEN];
int argumentsLength, valuesLength, returnType, returnValue, i;
ErlNifCharEncoding encoding = ERL_NIF_LATIN1;
if (!enif_get_atom(env, argv[0], library, MAXLEN, encoding)) {
return enif_make_badarg(env);
}
if (!enif_get_atom(env, argv[1], function, MAXLEN, encoding)) {
return enif_make_badarg(env);
}
if (!enif_get_list_length(env, argv[2], &argumentsLength)) {
return enif_make_badarg(env);
}
if (!enif_get_int(env, argv[3], &returnType)) {
return enif_make_badarg(env);
}
if (!enif_get_list_length(env, argv[4], &valuesLength)) {
return enif_make_badarg(env);
}
if (valuesLength != argumentsLength) {
return enif_make_badarg(env);
}
ffi_type *ffiArgs[argumentsLength], *ffiReturnType = &ffi_type_sint;
int args[argumentsLength];
void *ffiValues[valuesLength];
ERL_NIF_TERM head, tail = argv[2];
uint type;
for (i=0;enif_get_list_cell(env, tail, &head, &tail);i++) {
ffi_type *ffiType;
enif_get_uint(env, head, &type);
args[i] = type;
switch (type) {
case VOID:
ffiType = &ffi_type_void;
break;
case STRING:
ffiType = &ffi_type_pointer;
break;
case INT:
ffiType = &ffi_type_sint;
break;
}
ffiArgs[i] = ffiType;
}
tail = argv[4];
int intData;
char charData[MAXLEN];
char *s = charData;
for (i=0;enif_get_list_cell(env, tail, &head, &tail);i++) {
type = args[i];
switch (type) {
case VOID:
break;
case STRING:
enif_get_string(env, head, charData, MAXLEN, encoding);
ffiValues[i] = &s;
break;
case INT:
enif_get_int(env, head, &intData);
ffiValues[i] = &intData;
break;
}
}
switch (returnType) {
case VOID:
ffiReturnType = &ffi_type_void;
break;
case STRING:
ffiReturnType = &ffi_type_pointer;
break;
case INT:
ffiReturnType = &ffi_type_sint;
break;
}
printf("%s.%s() %d %d\n", library, function, argumentsLength, returnType);
call(argumentsLength, ffiArgs, ffiValues, ffiReturnType);
returnValue = 100;
return enif_make_int(env, returnValue);
}
static ErlNifFunc nif_funcs[] = {
{"nif_call", 5, nif_call}
};
ERL_NIF_INIT(Elixir.FFI, nif_funcs, NULL, NULL, NULL, NULL)

BIN
c_src/ffi_nif.o Normal file

Binary file not shown.