diff options
Diffstat (limited to 'erts/emulator/test/dirty_nif_SUITE_data')
-rw-r--r-- | erts/emulator/test/dirty_nif_SUITE_data/Makefile.src | 2 | ||||
-rw-r--r-- | erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c | 176 | ||||
-rw-r--r-- | erts/emulator/test/dirty_nif_SUITE_data/echo_drv.c | 62 |
3 files changed, 236 insertions, 4 deletions
diff --git a/erts/emulator/test/dirty_nif_SUITE_data/Makefile.src b/erts/emulator/test/dirty_nif_SUITE_data/Makefile.src index e9301753b0..4462afd815 100644 --- a/erts/emulator/test/dirty_nif_SUITE_data/Makefile.src +++ b/erts/emulator/test/dirty_nif_SUITE_data/Makefile.src @@ -1,6 +1,6 @@ NIF_LIBS = dirty_nif_SUITE@dll@ -all: $(NIF_LIBS) +all: $(NIF_LIBS) echo_drv@dll@ @SHLIB_RULES@ diff --git a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c index 08efa23c81..0321b9898f 100644 --- a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c +++ b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2009-2016. All Rights Reserved. + * Copyright Ericsson AB 2009-2017. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ * * %CopyrightEnd% */ -#include "erl_nif.h" +#include <erl_nif.h> #include <assert.h> #ifdef __WIN32__ #include <windows.h> @@ -25,8 +25,35 @@ #include <unistd.h> #endif +/* + * Hack to get around this function missing from the NIF API. + * TODO: Add this function/macro in the appropriate place, probably with + * enif_make_pid() in erl_nif_api_funcs.h + */ +#ifndef enif_make_port +#define enif_make_port(ENV, PORT) ((void)(ENV),(const ERL_NIF_TERM)((PORT)->port_id)) +#endif + +static ERL_NIF_TERM atom_badarg; +static ERL_NIF_TERM atom_error; +static ERL_NIF_TERM atom_false; +static ERL_NIF_TERM atom_lookup; +static ERL_NIF_TERM atom_ok; +static ERL_NIF_TERM atom_pid; +static ERL_NIF_TERM atom_port; +static ERL_NIF_TERM atom_send; + static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { + atom_badarg = enif_make_atom(env, "badarg"); + atom_error = enif_make_atom(env, "error"); + atom_false = enif_make_atom(env,"false"); + atom_lookup = enif_make_atom(env, "lookup"); + atom_ok = enif_make_atom(env,"ok"); + atom_pid = enif_make_atom(env, "pid"); + atom_port = enif_make_atom(env, "port"); + atom_send = enif_make_atom(env, "send"); + return 0; } @@ -257,6 +284,147 @@ static ERL_NIF_TERM dirty_heap_access_nif(ErlNifEnv* env, int argc, const ERL_NI return res; } +/* + * enif_whereis_... tests + * subset of the functions in nif_SUITE.c + */ + +enum { + /* results */ + WHEREIS_SUCCESS, + WHEREIS_ERROR_TYPE, + WHEREIS_ERROR_LOOKUP, + WHEREIS_ERROR_SEND, + /* types */ + WHEREIS_LOOKUP_PID, /* enif_whereis_pid() */ + WHEREIS_LOOKUP_PORT /* enif_whereis_port() */ +}; + +typedef union { + ErlNifPid pid; + ErlNifPort port; +} whereis_term_data_t; + +static int whereis_type(ERL_NIF_TERM type) +{ + if (enif_is_identical(type, atom_pid)) + return WHEREIS_LOOKUP_PID; + + if (enif_is_identical(type, atom_port)) + return WHEREIS_LOOKUP_PORT; + + return WHEREIS_ERROR_TYPE; +} + +static int whereis_lookup_internal( + ErlNifEnv* env, int type, ERL_NIF_TERM name, whereis_term_data_t* out) +{ + if (type == WHEREIS_LOOKUP_PID) + return enif_whereis_pid(env, name, & out->pid) + ? WHEREIS_SUCCESS : WHEREIS_ERROR_LOOKUP; + + if (type == WHEREIS_LOOKUP_PORT) + return enif_whereis_port(env, name, & out->port) + ? WHEREIS_SUCCESS : WHEREIS_ERROR_LOOKUP; + + return WHEREIS_ERROR_TYPE; +} + +static int whereis_send_internal( + ErlNifEnv* env, int type, whereis_term_data_t* to, ERL_NIF_TERM msg) +{ + if (type == WHEREIS_LOOKUP_PID) + return enif_send(env, & to->pid, NULL, msg) + ? WHEREIS_SUCCESS : WHEREIS_ERROR_SEND; + + if (type == WHEREIS_LOOKUP_PORT) + return enif_port_command(env, & to->port, NULL, msg) + ? WHEREIS_SUCCESS : WHEREIS_ERROR_SEND; + + return WHEREIS_ERROR_TYPE; +} + +static int whereis_lookup_term( + ErlNifEnv* env, int type, ERL_NIF_TERM name, ERL_NIF_TERM* out) +{ + whereis_term_data_t res; + int rc = whereis_lookup_internal(env, type, name, &res); + if (rc == WHEREIS_SUCCESS) { + switch (type) { + case WHEREIS_LOOKUP_PID: + *out = enif_make_pid(env, & res.pid); + break; + case WHEREIS_LOOKUP_PORT: + *out = enif_make_port(env, & res.port); + break; + default: + rc = WHEREIS_ERROR_TYPE; + break; + } + } + return rc; +} + +static ERL_NIF_TERM whereis_result_term(ErlNifEnv* env, int result) +{ + ERL_NIF_TERM err; + switch (result) + { + case WHEREIS_SUCCESS: + return atom_ok; + case WHEREIS_ERROR_LOOKUP: + err = atom_lookup; + break; + case WHEREIS_ERROR_SEND: + err = atom_send; + break; + case WHEREIS_ERROR_TYPE: + err = atom_badarg; + break; + default: + err = enif_make_int(env, -result); + break; + } + return enif_make_tuple2(env, atom_error, err); +} + +/* whereis_term(Type, Name) -> pid() | port() | false */ +static ERL_NIF_TERM +whereis_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM ret; + int type, rc; + + if (argc != 2) /* allow non-atom name for testing */ + return enif_make_badarg(env); + + if ((type = whereis_type(argv[0])) == WHEREIS_ERROR_TYPE) + return enif_make_badarg(env); + + rc = whereis_lookup_term(env, type, argv[1], &ret); + return (rc == WHEREIS_SUCCESS) ? ret : atom_false; +} + +/* whereis_send(Type, Name, Message) -> ok | {error, Reason} */ +static ERL_NIF_TERM +whereis_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + whereis_term_data_t to; + int type, rc; + + if (argc != 3 || !enif_is_atom(env, argv[1])) + return enif_make_badarg(env); + + if ((type = whereis_type(argv[0])) == WHEREIS_ERROR_TYPE) + return enif_make_badarg(env); + + rc = whereis_lookup_internal(env, type, argv[1], & to); + if (rc == WHEREIS_SUCCESS) + rc = whereis_send_internal(env, type, & to, argv[2]); + + return whereis_result_term(env, rc); +} + static ErlNifFunc nif_funcs[] = { @@ -269,7 +437,9 @@ static ErlNifFunc nif_funcs[] = {"dirty_sleeper", 0, dirty_sleeper, ERL_NIF_DIRTY_JOB_IO_BOUND}, {"dirty_sleeper", 1, dirty_sleeper, ERL_NIF_DIRTY_JOB_CPU_BOUND}, {"dirty_call_while_terminated_nif", 1, dirty_call_while_terminated_nif, ERL_NIF_DIRTY_JOB_CPU_BOUND}, - {"dirty_heap_access_nif", 1, dirty_heap_access_nif, ERL_NIF_DIRTY_JOB_CPU_BOUND} + {"dirty_heap_access_nif", 1, dirty_heap_access_nif, ERL_NIF_DIRTY_JOB_CPU_BOUND}, + {"whereis_send", 3, whereis_send, ERL_NIF_DIRTY_JOB_IO_BOUND}, + {"whereis_term", 2, whereis_term, ERL_NIF_DIRTY_JOB_CPU_BOUND} }; ERL_NIF_INIT(dirty_nif_SUITE,nif_funcs,load,NULL,NULL,NULL) diff --git a/erts/emulator/test/dirty_nif_SUITE_data/echo_drv.c b/erts/emulator/test/dirty_nif_SUITE_data/echo_drv.c new file mode 100644 index 0000000000..2b3510c641 --- /dev/null +++ b/erts/emulator/test/dirty_nif_SUITE_data/echo_drv.c @@ -0,0 +1,62 @@ +#include <stdio.h> +#include "erl_driver.h" + +static ErlDrvPort erlang_port; +static ErlDrvData echo_start(ErlDrvPort, char *); +static void from_erlang(ErlDrvData, char*, ErlDrvSizeT); +static ErlDrvSSizeT echo_call(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, unsigned *ret_flags); +static ErlDrvEntry echo_driver_entry = { + NULL, /* Init */ + echo_start, + NULL, /* Stop */ + from_erlang, + NULL, /* Ready input */ + NULL, /* Ready output */ + "echo_drv", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + echo_call, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL +}; + +DRIVER_INIT(echo_drv) +{ + return &echo_driver_entry; +} + +static ErlDrvData +echo_start(ErlDrvPort port, char *buf) +{ + return (ErlDrvData) port; +} + +static void +from_erlang(ErlDrvData data, char *buf, ErlDrvSizeT count) +{ + driver_output((ErlDrvPort) data, buf, count); +} + +static ErlDrvSSizeT +echo_call(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen, + unsigned *ret_flags) +{ + *rbuf = buf; + *ret_flags |= DRIVER_CALL_KEEP_BUFFER; + return len; +} + |