diff --git a/c_src/eLfq/eLfq.cc b/c_src/eLfq/eLfq.cc index c5c9017..b7e3c8c 100644 --- a/c_src/eLfq/eLfq.cc +++ b/c_src/eLfq/eLfq.cc @@ -1,3 +1,242 @@ #include "erl_nif.h" +#include + #include "concurrentqueue.h" + +struct atoms { + ERL_NIF_TERM atomOk; + ERL_NIF_TERM atomError; + ERL_NIF_TERM atomTrue; + //ERL_NIF_TERM atomFalse; + //ERL_NIF_TERM atomUndefined; + ERL_NIF_TERM atomEmpty; +}; + +struct shared_data { + ErlNifResourceType *resQueueInstance; +}; + +struct q_item { + ErlNifEnv *env; + ERL_NIF_TERM term; +}; + +struct squeue { + moodycamel::ConcurrentQueue *queue; +}; + +const char kAtomOk[] = "ok"; +const char kAtomError[] = "error"; +const char kAtomTrue[] = "true"; +//const char kAtomFalse[] = "false"; +//const char kAtomUndefined[] = "undefined"; +const char kAtomEmpty[] = "empty"; + +atoms ATOMS; + +void nif_enlfq_free(ErlNifEnv *env, void *obj); + +ERL_NIF_TERM nif_enlfq_new(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); + +ERL_NIF_TERM nif_enlfq_push(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); + +ERL_NIF_TERM nif_enlfq_pop(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); + +ERL_NIF_TERM make_atom(ErlNifEnv *env, const char *name) { + ERL_NIF_TERM ret; + + if (enif_make_existing_atom(env, name, &ret, ERL_NIF_LATIN1)) + return ret; + + return enif_make_atom(env, name); +} + +ERL_NIF_TERM make_binary(ErlNifEnv *env, const char *buff, size_t length) { + ERL_NIF_TERM term; + unsigned char *destination_buffer = enif_make_new_binary(env, length, &term); + memcpy(destination_buffer, buff, length); + return term; +} + +ERL_NIF_TERM make_error(ErlNifEnv *env, const char *error) { + return enif_make_tuple2(env, ATOMS.atomError, make_binary(env, error, strlen(error))); +} + + +void open_resources(ErlNifEnv *env, shared_data *data) { + ErlNifResourceFlags flags = static_cast(ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER); + data->resQueueInstance = enif_open_resource_type(env, NULL, "enlfq_instance", nif_enlfq_free, flags, NULL); +} + +int on_nif_load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM) { + + ATOMS.atomOk = make_atom(env, kAtomOk); + ATOMS.atomError = make_atom(env, kAtomError); + ATOMS.atomTrue = make_atom(env, kAtomTrue); +// ATOMS.atomFalse = make_atom(env, kAtomFalse); +// ATOMS.atomUndefined = make_atom(env, kAtomUndefined); + ATOMS.atomEmpty = make_atom(env, kAtomEmpty); + + shared_data *data = static_cast(enif_alloc(sizeof(shared_data))); + open_resources(env, data); + + *priv_data = data; + return 0; +} + +void on_nif_unload(ErlNifEnv *, void *priv_data) { + shared_data *data = static_cast(priv_data); + enif_free(data); +} + +int on_nif_upgrade(ErlNifEnv *env, void **priv, void **, ERL_NIF_TERM) { + shared_data *data = static_cast(enif_alloc(sizeof(shared_data))); + open_resources(env, data); + + *priv = data; + return 0; +} + +void nif_enlfq_free(ErlNifEnv *, void *obj) { + squeue *inst = static_cast(obj); + + if (inst != nullptr) { + q_item item; + while (inst->queue->try_dequeue(item)) { + enif_free_env(item.env); + } + delete inst->queue; + } +} + +ERL_NIF_TERM nif_new(ErlNifEnv *env, int, const ERL_NIF_TERM *) { + shared_data *data = static_cast(enif_priv_data(env)); + + + squeue *qinst = static_cast(enif_alloc_resource(data->resQueueInstance, sizeof(squeue))); + qinst->queue = new moodycamel::ConcurrentQueue; + + if (qinst == NULL) + return make_error(env, "enif_alloc_resource failed"); + + ERL_NIF_TERM term = enif_make_resource(env, qinst); + enif_release_resource(qinst); + return enif_make_tuple2(env, ATOMS.atomOk, term); +} + +ERL_NIF_TERM nif_in2(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + shared_data *data = static_cast(enif_priv_data(env)); + + squeue *inst; + + if (!enif_get_resource(env, argv[0], data->resQueueInstance, (void **) &inst)) { + return enif_make_badarg(env); + } + + q_item item; + + item.env = enif_alloc_env(); + item.term = enif_make_copy(item.env, argv[1]); + + inst->queue->enqueue(item); + + return ATOMS.atomTrue; +} + +ERL_NIF_TERM nif_in3(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomTrue; +} + +ERL_NIF_TERM nif_ins2(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomTrue; +} + +ERL_NIF_TERM nif_ins3(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomTrue; +} + +ERL_NIF_TERM nif_tryIn2(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomTrue; +} + +ERL_NIF_TERM nif_tryIn3(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomTrue; +} + +ERL_NIF_TERM nif_tryIns2(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomTrue; +} + +ERL_NIF_TERM nif_tryIns3(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomTrue; +} + +ERL_NIF_TERM nif_tryOut1(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + shared_data *data = static_cast(enif_priv_data(env)); + squeue *inst = NULL; + + if (!enif_get_resource(env, argv[0], data->resQueueInstance, (void **) &inst)) { + return enif_make_badarg(env); + } + + ERL_NIF_TERM term; + q_item item; + + if (inst->queue->try_dequeue(item)) { + term = enif_make_copy(env, item.term); + enif_free_env(item.env); + return enif_make_tuple2(env, ATOMS.atomOk, term); + } else { + return ATOMS.atomEmpty; + } + +} + +ERL_NIF_TERM nif_tryOut2(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomEmpty; +} + +ERL_NIF_TERM nif_tryOuts2(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomEmpty; +} + +ERL_NIF_TERM nif_tryOuts3(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomEmpty; +} + +ERL_NIF_TERM nif_tryOutByProd2(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomEmpty; +} + +ERL_NIF_TERM nif_tryOutsByProd3(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomEmpty; +} + +ERL_NIF_TERM nif_size1(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) { + return ATOMS.atomEmpty; +} + + +static ErlNifFunc nif_funcs[] = + { + {"new", 0, nif_new}, + {"in", 2, nif_in2}, + {"in", 3, nif_in3}, + {"ins", 2, nif_ins2}, + {"ins", 3, nif_ins3}, + {"tryIn", 2, nif_tryIn2}, + {"tryIn", 3, nif_tryIn3}, + {"tryIns", 2, nif_tryIns2}, + {"tryIns", 3, nif_tryIns3}, + {"tryOut", 1, nif_tryOut1}, + {"tryOut", 2, nif_tryOut2}, + {"tryOuts", 2, nif_tryOuts2}, + {"tryOuts", 3, nif_tryOuts3}, + {"tryOutByProd", 2, nif_tryOutByProd2}, + {"tryOutsByProd", 3, nif_tryOutsByProd3}, + {"size", 1, nif_size1} + }; + +ERL_NIF_INIT(eLfq, nif_funcs, on_nif_load, NULL, on_nif_upgrade, on_nif_unload +) \ No newline at end of file