Skip to content

Portable float NIF #63

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ rebar3.crashdump
_*
.eunit
*.o
*.so
*.beam
*.plt
*.swp
Expand Down
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
sudo: false
dist: trusty
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default travis vms are very old (

language: erlang
install: 'true'
before_script:
Expand Down
82 changes: 82 additions & 0 deletions c_src/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Based on c_src.mk from erlang.mk by Loic Hoguin <[email protected]>

CURDIR := $(shell pwd)
BASEDIR := $(abspath $(CURDIR)/..)

PROJECT := prometheus_nif

ERTS_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~s/erts-~s/include/\", [code:root_dir(), erlang:system_info(version)]).")
ERL_INTERFACE_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~s\", [code:lib_dir(erl_interface, include)]).")
ERL_INTERFACE_LIB_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~s\", [code:lib_dir(erl_interface, lib)]).")

C_SRC_DIR = $(CURDIR)
C_SRC_OUTPUT ?= $(CURDIR)/../priv/$(PROJECT).so

# System type and C compiler/flags.

UNAME_SYS := $(shell uname -s)
ifeq ($(UNAME_SYS), Darwin)
CC ?= cc
CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes
CXXFLAGS ?= -O3 -arch x86_64 -std=c++11 -finline-functions -Wall
LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress
else ifeq ($(UNAME_SYS), FreeBSD)
CC ?= clang
CXX ?= clang++
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
CXXFLAGS ?= -O3 -std=c++11 -finline-functions -Wall
else ifeq ($(UNAME_SYS), Linux)
CC ?= gcc
CXX ?= g++
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
CXXFLAGS ?= -O3 -std=c++11 -finline-functions -Wall
endif

CFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR)
CXXFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR) -std=c++11

LDLIBS += -L $(ERL_INTERFACE_LIB_DIR) -lerl_interface -lei

ifeq ($(UNAME_SYS), OpenBSD)
LDLIBS += -lestdc++
else
LDLIBS += -lstdc++
endif

LDFLAGS += -shared

# Verbosity.

c_verbose_0 = @echo " C " $(?F);
c_verbose = $(c_verbose_$(V))

cpp_verbose_0 = @echo " CPP " $(?F);
cpp_verbose = $(cpp_verbose_$(V))

link_verbose_0 = @echo " LD " $(@F);
link_verbose = $(link_verbose_$(V))

SOURCES := $(shell find $(C_SRC_DIR) -type f \( -name "*.c" -o -name "*.C" -o -name "*.cc" -o -name "*.cpp" \))
OBJECTS = $(addsuffix .o, $(basename $(SOURCES)))

COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c
COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c

$(C_SRC_OUTPUT): $(OBJECTS)
@mkdir -p $(BASEDIR)/priv/
$(link_verbose) $(CC) $(OBJECTS) $(LDFLAGS) $(LDLIBS) -o $(C_SRC_OUTPUT)

%.o: %.c
$(COMPILE_C) $(OUTPUT_OPTION) $<

%.o: %.cc
$(COMPILE_CPP) $(OUTPUT_OPTION) $<

%.o: %.C
$(COMPILE_CPP) $(OUTPUT_OPTION) $<

%.o: %.cpp
$(COMPILE_CPP) $(OUTPUT_OPTION) $<

clean:
@rm -f $(C_SRC_OUTPUT) $(OBJECTS)
19 changes: 19 additions & 0 deletions c_src/atoms.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* Copyright (c) 2017, Benoit Chesneau <[email protected]>.
*
* This file is part of instrument released under the MIT license.
* See the NOTICE for more information.
*/

#ifndef ATOMS_H
#define ATOMS_H

namespace prometheus {
extern ERL_NIF_TERM ATOM_OK;
extern ERL_NIF_TERM ATOM_ERROR;
extern ERL_NIF_TERM ATOM_EINVAL;
extern ERL_NIF_TERM ATOM_BADARG;

} // namespace prometheus


#endif // ATOMS_H
195 changes: 195 additions & 0 deletions c_src/prometheus_nif.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
/* Copyright (c) 2017, Benoit Chesneau <[email protected]>.
*
* This file is part of prometheus released under the MIT license.
* See the NOTICE for more information.
*/

#include <syslog.h>

#include <new>
#include <stdexcept>

#include "prometheus_nif.h"

#include "erl_nif.h"

#ifndef ATOMS_H
#include "atoms.h"
#endif

#include "value.h"


static ErlNifFunc nif_funcs[] =
{
{"new_value", 0, prometheus::NewValue},
{"inc_value", 1, prometheus::IncValue},
{"inc_value", 2, prometheus::IncValue},
{"dec_value", 1, prometheus::DecValue},
{"dec_value", 2, prometheus::DecValue},
{"set_value", 2, prometheus::SetValue},
{"get_value", 1, prometheus::GetValue}
};

namespace prometheus {

ERL_NIF_TERM ATOM_OK;
ERL_NIF_TERM ATOM_ERROR;
ERL_NIF_TERM ATOM_EINVAL;
ERL_NIF_TERM ATOM_BADARG;


ErlNifResourceType *m_Value_RESOURCE;

void
value_resource_cleanup(ErlNifEnv *env, void *res)
{

}

void
CreateValueType(ErlNifEnv *env)
{
ErlNifResourceFlags flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER);
m_Value_RESOURCE = enif_open_resource_type(env, NULL, "prometheus_Value", value_resource_cleanup, flags, NULL);
return;
}

ERL_NIF_TERM
NewValue(
ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[])
{
prometheus::Value * value;
void *alloc_ptr;
alloc_ptr = enif_alloc_resource(m_Value_RESOURCE, sizeof(prometheus::Value));
value = new(alloc_ptr) prometheus::Value();
ERL_NIF_TERM result = enif_make_resource(env, value);
enif_release_resource(value);
return enif_make_tuple2(env, ATOM_OK, result);
}

ERL_NIF_TERM
IncValue(
ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[])
{
prometheus::Value* value_ptr;

if(!enif_get_resource(env, argv[0], m_Value_RESOURCE, (void **) &value_ptr))
return enif_make_badarg(env);

if(argc > 1)
{
double v;
if (!enif_get_double(env, argv[1], &v))
return enif_make_badarg(env);
value_ptr->Increment(v);
}
else
{
value_ptr->Increment();
}

return ATOM_OK;
}

ERL_NIF_TERM
DecValue(
ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[])
{
prometheus::Value* value_ptr;

if(!enif_get_resource(env, argv[0], m_Value_RESOURCE, (void **) &value_ptr))
return enif_make_badarg(env);

if(argc > 1)
{
double v;
if (!enif_get_double(env, argv[1], &v))
return enif_make_badarg(env);
value_ptr->Decrement(v);
}
else
{
value_ptr->Decrement();
}

return ATOM_OK;
}

ERL_NIF_TERM
SetValue(
ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[])
{
prometheus::Value* value_ptr;

if(!enif_get_resource(env, argv[0], m_Value_RESOURCE, (void **) &value_ptr))
return enif_make_badarg(env);

double v;
if (!enif_get_double(env, argv[1], &v))
return enif_make_badarg(env);
value_ptr->Set(v);

return ATOM_OK;
}

ERL_NIF_TERM
GetValue(
ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[])
{
prometheus::Value* value_ptr;

if(!enif_get_resource(env, argv[0], m_Value_RESOURCE, (void **) &value_ptr))
return enif_make_badarg(env);

double v;
v = value_ptr->GetValue();
return enif_make_double(env, v);
}

} // namespace prometheus


/*nif initialization */

static void on_unload(ErlNifEnv *env, void *priv_data)
{
}


static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
try
{
prometheus::CreateValueType(env);

#define ATOM(Id, Value) { Id = enif_make_atom(env, Value); }
// initialize the atoms
ATOM(prometheus::ATOM_OK, "ok");
ATOM(prometheus::ATOM_ERROR, "error");
ATOM(prometheus::ATOM_EINVAL, "einval");
ATOM(prometheus::ATOM_BADARG, "badarg");
#undef ATOM

return 0;

}
catch(...)
{
return -1;
}
}

extern "C" {
ERL_NIF_INIT(prometheus_value, nif_funcs, &on_load, NULL, NULL, &on_unload);
}
31 changes: 31 additions & 0 deletions c_src/prometheus_nif.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* Copyright (c) 2017, Benoit Chesneau <[email protected]>.
*
* This file is part of instrument released under the MIT license.
* See the NOTICE for more information.
*/


#ifndef INCL_instrument_H
#define INCL_instrument_H

extern "C" {
#include "erl_nif.h"

ERL_NIF_TERM instrument_new_value(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM instrument_inc_value(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM instrument_dec_value(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM instrument_set_value(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM instrument_get_value(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
}

namespace prometheus {

ERL_NIF_TERM NewValue(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM IncValue(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM DecValue(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM SetValue(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM GetValue(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);

} // namespace instrument

#endif
42 changes: 42 additions & 0 deletions c_src/value.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* Copyright (c) 2017, Benoit Chesneau <[email protected]>.
*
* This file is part of instrument released under the MIT license.
* See the NOTICE for more information.
*/

#include "value.h"

namespace prometheus {

Value::Value() : value_{0} {}

Value::Value(double value) : value_{value} {}

void Value::Increment() { Increment(1.0); }
void Value::Increment(double value) {
if (value < 0.0) {
return;
}
Change(value);
}

void Value::Decrement() { Decrement(1.0); }

void Value::Decrement(double value) {
if (value < 0.0) {
return;
}
Change(-1.0 * value);
}

void Value::Set(double value) { value_.store(value); }

void Value::Change(double value) {
auto current = value_.load();
while (!value_.compare_exchange_weak(current, current + value))
;
}

double Value::GetValue() const { return value_; }

}
Loading