Skip to content

Define custom memory allocation definitions #193

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

Merged
merged 4 commits into from
Feb 24, 2022
Merged
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 .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
runs-on: ${{ matrix.os }}
env:
MIX_ENV: test
DEBUG: "1"

name: Test Elixir ${{ matrix.elixir }}, OTP ${{ matrix.otp }}, OS ${{ matrix.os }}
strategy:
Expand Down
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ endif
CFLAGS ?= -O2 -Wall
ifneq ($(DEBUG),)
CFLAGS += -g
else
CFLAGS += -DNDEBUG=1
endif
CFLAGS += -I"$(ERTS_INCLUDE_DIR)"

Expand Down Expand Up @@ -114,9 +116,6 @@ ifneq ($(STATIC_ERLANG_NIF),)
CFLAGS += -DSTATIC_ERLANG_NIF=1
endif

# TODO: We should allow the person building to be able to specify this
CFLAGS += -DNDEBUG=1

ifeq ($(STATIC_ERLANG_NIF),)
all: $(PREFIX) $(BUILD) $(LIB_NAME)
else
Expand Down
123 changes: 110 additions & 13 deletions c_src/sqlite3_nif.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

static ErlNifResourceType* connection_type = NULL;
static ErlNifResourceType* statement_type = NULL;
static sqlite3_mem_methods default_alloc_methods = {0};

typedef struct connection
{
Expand All @@ -23,6 +24,83 @@ typedef struct statement
sqlite3_stmt* statement;
} statement_t;

static void*
exqlite_malloc(int bytes)
{
assert(bytes > 0);

int* p = enif_alloc(bytes + sizeof(int));
if (p) {
p[0] = bytes;
p++;
}

return p;
}

static void
exqlite_free(void* prior)
{
if (!prior) {
return;
}

int* p = prior;

// Shift the pointer back to free the proper block of data
p--;

return enif_free(p);
}

static void*
exqlite_realloc(void* prior, int bytes)
{
assert(prior);
assert(bytes > 0);

int* p = prior;
p--;

p = enif_realloc(p, bytes + sizeof(int));
if (p) {
p[0] = bytes;
p++;
}

return p;
}

static int
exqlite_mem_size(void* prior)
{
if (!prior) {
return 0;
}

int* p = prior;
p--;

return p[0];
}

static int
exqlite_mem_round_up(int bytes)
{
return (bytes + 7) & ~7;
}

static int
exqlite_mem_init(void* ptr)
{
return SQLITE_OK;
}

static void
exqlite_mem_shutdown(void* ptr)
{
}

static const char*
get_sqlite3_error_msg(int rc, sqlite3* db)
{
Expand Down Expand Up @@ -496,7 +574,7 @@ exqlite_multi_step(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return enif_make_tuple2(env, make_atom(env, "done"), rows);

case SQLITE_ROW:
row = make_row(env, statement->statement);
row = make_row(env, statement->statement);
rows = enif_make_list_cell(env, row, rows);
break;

Expand Down Expand Up @@ -533,10 +611,9 @@ exqlite_step(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
switch (rc) {
case SQLITE_ROW:
return enif_make_tuple2(
env,
make_atom(env, "row"),
make_row(env, statement->statement)
);
env,
make_atom(env, "row"),
make_row(env, statement->statement));
case SQLITE_BUSY:
return make_atom(env, "busy");
case SQLITE_DONE:
Expand Down Expand Up @@ -651,8 +728,8 @@ exqlite_serialize(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])

connection_t* conn = NULL;
ErlNifBinary database_name;
ERL_NIF_TERM eos = enif_make_int(env, 0);
unsigned char* buffer = NULL;
ERL_NIF_TERM eos = enif_make_int(env, 0);
unsigned char* buffer = NULL;
sqlite3_int64 buffer_size = 0;
ERL_NIF_TERM serialized;

Expand All @@ -668,7 +745,7 @@ exqlite_serialize(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return make_error_tuple(env, "database_name_not_iolist");
}

buffer = sqlite3_serialize(conn->db, (char*) database_name.data, &buffer_size, 0);
buffer = sqlite3_serialize(conn->db, (char*)database_name.data, &buffer_size, 0);
if (!buffer) {
return make_error_tuple(env, "serialization_failed");
}
Expand All @@ -684,13 +761,13 @@ exqlite_deserialize(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
assert(env);

connection_t* conn = NULL;
connection_t* conn = NULL;
unsigned char* buffer = NULL;
ErlNifBinary database_name;
ERL_NIF_TERM eos = enif_make_int(env, 0);
ErlNifBinary serialized;
int size = 0;
int rc = 0;
int size = 0;
int rc = 0;
int flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE;

if (argc != 3) {
Expand All @@ -709,7 +786,7 @@ exqlite_deserialize(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return enif_make_badarg(env);
}

size = serialized.size;
size = serialized.size;
buffer = sqlite3_malloc(size);
if (!buffer) {
return make_error_tuple(env, "deserialization_failed");
Expand Down Expand Up @@ -785,6 +862,19 @@ on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
{
assert(env);

static const sqlite3_mem_methods methods = {
exqlite_malloc,
exqlite_free,
exqlite_realloc,
exqlite_mem_size,
exqlite_mem_round_up,
exqlite_mem_init,
exqlite_mem_shutdown,
0};

sqlite3_config(SQLITE_CONFIG_GETMALLOC, &default_alloc_methods);
sqlite3_config(SQLITE_CONFIG_MALLOC, &methods);

connection_type = enif_open_resource_type(
env,
"exqlite",
Expand All @@ -810,6 +900,13 @@ on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
return 0;
}

static void
on_unload(ErlNifEnv* caller_env, void* priv_data)
{
assert(caller_env);

sqlite3_config(SQLITE_CONFIG_MALLOC, &default_alloc_methods);
}

//
// Enable extension loading
Expand Down Expand Up @@ -870,4 +967,4 @@ static ErlNifFunc nif_funcs[] = {
#define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* sqlite3_nif_nif_init(ERL_NIF_INIT_ARGS)
#endif

ERL_NIF_INIT(Elixir.Exqlite.Sqlite3NIF, nif_funcs, on_load, NULL, NULL, NULL)
ERL_NIF_INIT(Elixir.Exqlite.Sqlite3NIF, nif_funcs, on_load, NULL, NULL, on_unload)