Skip to content

Commit d079739

Browse files
authored
Define custom memory allocation definitions (#193)
* Define custom memory allocation definitions What my aim here is to expose the amount of memory being utilized by an erlang process that is currently running. * Get the malloc configuration before setting it to restore later * Fix NDEBUG from being set when DEBUG env variable is set * Compile environment with debug enabled
1 parent ed06682 commit d079739

File tree

3 files changed

+113
-16
lines changed

3 files changed

+113
-16
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ jobs:
3737
runs-on: ${{ matrix.os }}
3838
env:
3939
MIX_ENV: test
40+
DEBUG: "1"
4041

4142
name: Test Elixir ${{ matrix.elixir }}, OTP ${{ matrix.otp }}, OS ${{ matrix.os }}
4243
strategy:

Makefile

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ endif
4040
CFLAGS ?= -O2 -Wall
4141
ifneq ($(DEBUG),)
4242
CFLAGS += -g
43+
else
44+
CFLAGS += -DNDEBUG=1
4345
endif
4446
CFLAGS += -I"$(ERTS_INCLUDE_DIR)"
4547

@@ -114,9 +116,6 @@ ifneq ($(STATIC_ERLANG_NIF),)
114116
CFLAGS += -DSTATIC_ERLANG_NIF=1
115117
endif
116118

117-
# TODO: We should allow the person building to be able to specify this
118-
CFLAGS += -DNDEBUG=1
119-
120119
ifeq ($(STATIC_ERLANG_NIF),)
121120
all: $(PREFIX) $(BUILD) $(LIB_NAME)
122121
else

c_src/sqlite3_nif.c

Lines changed: 110 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
static ErlNifResourceType* connection_type = NULL;
1414
static ErlNifResourceType* statement_type = NULL;
15+
static sqlite3_mem_methods default_alloc_methods = {0};
1516

1617
typedef struct connection
1718
{
@@ -23,6 +24,83 @@ typedef struct statement
2324
sqlite3_stmt* statement;
2425
} statement_t;
2526

27+
static void*
28+
exqlite_malloc(int bytes)
29+
{
30+
assert(bytes > 0);
31+
32+
int* p = enif_alloc(bytes + sizeof(int));
33+
if (p) {
34+
p[0] = bytes;
35+
p++;
36+
}
37+
38+
return p;
39+
}
40+
41+
static void
42+
exqlite_free(void* prior)
43+
{
44+
if (!prior) {
45+
return;
46+
}
47+
48+
int* p = prior;
49+
50+
// Shift the pointer back to free the proper block of data
51+
p--;
52+
53+
return enif_free(p);
54+
}
55+
56+
static void*
57+
exqlite_realloc(void* prior, int bytes)
58+
{
59+
assert(prior);
60+
assert(bytes > 0);
61+
62+
int* p = prior;
63+
p--;
64+
65+
p = enif_realloc(p, bytes + sizeof(int));
66+
if (p) {
67+
p[0] = bytes;
68+
p++;
69+
}
70+
71+
return p;
72+
}
73+
74+
static int
75+
exqlite_mem_size(void* prior)
76+
{
77+
if (!prior) {
78+
return 0;
79+
}
80+
81+
int* p = prior;
82+
p--;
83+
84+
return p[0];
85+
}
86+
87+
static int
88+
exqlite_mem_round_up(int bytes)
89+
{
90+
return (bytes + 7) & ~7;
91+
}
92+
93+
static int
94+
exqlite_mem_init(void* ptr)
95+
{
96+
return SQLITE_OK;
97+
}
98+
99+
static void
100+
exqlite_mem_shutdown(void* ptr)
101+
{
102+
}
103+
26104
static const char*
27105
get_sqlite3_error_msg(int rc, sqlite3* db)
28106
{
@@ -496,7 +574,7 @@ exqlite_multi_step(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
496574
return enif_make_tuple2(env, make_atom(env, "done"), rows);
497575

498576
case SQLITE_ROW:
499-
row = make_row(env, statement->statement);
577+
row = make_row(env, statement->statement);
500578
rows = enif_make_list_cell(env, row, rows);
501579
break;
502580

@@ -533,10 +611,9 @@ exqlite_step(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
533611
switch (rc) {
534612
case SQLITE_ROW:
535613
return enif_make_tuple2(
536-
env,
537-
make_atom(env, "row"),
538-
make_row(env, statement->statement)
539-
);
614+
env,
615+
make_atom(env, "row"),
616+
make_row(env, statement->statement));
540617
case SQLITE_BUSY:
541618
return make_atom(env, "busy");
542619
case SQLITE_DONE:
@@ -651,8 +728,8 @@ exqlite_serialize(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
651728

652729
connection_t* conn = NULL;
653730
ErlNifBinary database_name;
654-
ERL_NIF_TERM eos = enif_make_int(env, 0);
655-
unsigned char* buffer = NULL;
731+
ERL_NIF_TERM eos = enif_make_int(env, 0);
732+
unsigned char* buffer = NULL;
656733
sqlite3_int64 buffer_size = 0;
657734
ERL_NIF_TERM serialized;
658735

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

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

687-
connection_t* conn = NULL;
764+
connection_t* conn = NULL;
688765
unsigned char* buffer = NULL;
689766
ErlNifBinary database_name;
690767
ERL_NIF_TERM eos = enif_make_int(env, 0);
691768
ErlNifBinary serialized;
692-
int size = 0;
693-
int rc = 0;
769+
int size = 0;
770+
int rc = 0;
694771
int flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE;
695772

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

712-
size = serialized.size;
789+
size = serialized.size;
713790
buffer = sqlite3_malloc(size);
714791
if (!buffer) {
715792
return make_error_tuple(env, "deserialization_failed");
@@ -785,6 +862,19 @@ on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
785862
{
786863
assert(env);
787864

865+
static const sqlite3_mem_methods methods = {
866+
exqlite_malloc,
867+
exqlite_free,
868+
exqlite_realloc,
869+
exqlite_mem_size,
870+
exqlite_mem_round_up,
871+
exqlite_mem_init,
872+
exqlite_mem_shutdown,
873+
0};
874+
875+
sqlite3_config(SQLITE_CONFIG_GETMALLOC, &default_alloc_methods);
876+
sqlite3_config(SQLITE_CONFIG_MALLOC, &methods);
877+
788878
connection_type = enif_open_resource_type(
789879
env,
790880
"exqlite",
@@ -810,6 +900,13 @@ on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
810900
return 0;
811901
}
812902

903+
static void
904+
on_unload(ErlNifEnv* caller_env, void* priv_data)
905+
{
906+
assert(caller_env);
907+
908+
sqlite3_config(SQLITE_CONFIG_MALLOC, &default_alloc_methods);
909+
}
813910

814911
//
815912
// Enable extension loading
@@ -870,4 +967,4 @@ static ErlNifFunc nif_funcs[] = {
870967
#define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* sqlite3_nif_nif_init(ERL_NIF_INIT_ARGS)
871968
#endif
872969

873-
ERL_NIF_INIT(Elixir.Exqlite.Sqlite3NIF, nif_funcs, on_load, NULL, NULL, NULL)
970+
ERL_NIF_INIT(Elixir.Exqlite.Sqlite3NIF, nif_funcs, on_load, NULL, NULL, on_unload)

0 commit comments

Comments
 (0)