aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bp.c4
-rw-r--r--types.h5
-rw-r--r--vm.c48
-rw-r--r--vm.h4
4 files changed, 47 insertions, 14 deletions
diff --git a/bp.c b/bp.c
index 51d34ca..3257d0f 100644
--- a/bp.c
+++ b/bp.c
@@ -120,7 +120,9 @@ static int process_file(def_t *defs, const char *filename, vm_op_t *pattern, uns
}
recycle_if_unused(&m);
+#ifdef DEBUG_HEAP
check(recycle_all_matches() == 0, "Memory leak: there should no longer be any matches in use at this point.");
+#endif
destroy_file(&f);
return success;
@@ -300,7 +302,7 @@ int main(int argc, char *argv[])
}
if (flags & BP_JSON) printf("]\n");
-#ifdef FREE_ON_EXIT
+#ifdef DEBUG_HEAP
// This code frees up all residual heap-allocated memory. Since the program
// is about to exit, this step is unnecessary. However, it is useful for
// tracking down memory leaks.
diff --git a/types.h b/types.h
index 30a0e9e..65dcb5a 100644
--- a/types.h
+++ b/types.h
@@ -94,7 +94,10 @@ typedef struct match_s {
struct match_s *child, *nextsibling;
vm_op_t *op;
// Intrusive linked list nodes for garbage collection:
- struct match_s **atme, *next;
+ struct match_s *next;
+#ifdef DEBUG_HEAP
+ struct match_s **atme;
+#endif
int refcount;
} match_t;
diff --git a/vm.c b/vm.c
index ff62b4d..b0bc267 100644
--- a/vm.c
+++ b/vm.c
@@ -12,9 +12,11 @@
#include "utils.h"
#include "vm.h"
-// Linked list operations:
-#define LL_PREPEND(head, node) do { (node)->atme = &(head); (node)->next = head; if (head) (head)->atme = &(node)->next; head = node; } while(0)
-#define LL_REMOVE(node) do { *(node)->atme = (node)->next; if ((node)->next) (node)->next->atme = (node)->atme; } while(0)
+#ifdef DEBUG_HEAP
+// Doubly-linked list operations:
+#define DLL_PREPEND(head, node) do { (node)->atme = &(head); (node)->next = head; if (head) (head)->atme = &(node)->next; head = node; } while(0)
+#define DLL_REMOVE(node) do { *(node)->atme = (node)->next; if ((node)->next) (node)->next->atme = (node)->atme; } while(0)
+#endif
// Refcounting ownership-setting macros:
#define ADD_OWNER(owner, m) do { owner = m; ++(m)->refcount; } while(0)
@@ -26,7 +28,10 @@
// the `unused_matches` linked list so it can be reused without the need for
// additional calls to malloc/free. Thus, it is an invariant that every match
// object is in one of these two lists:
-static match_t *in_use_matches = NULL, *unused_matches = NULL;
+static match_t *unused_matches = NULL;
+#ifdef DEBUG_HEAP
+static match_t *in_use_matches = NULL;
+#endif
__attribute__((nonnull, pure))
static inline const char *next_char(file_t *f, const char *str);
@@ -552,15 +557,27 @@ match_t *get_capture(match_t *m, const char **id)
match_t *new_match(void)
{
match_t *m;
+
+#ifdef DEBUG_HEAP
if (unused_matches) {
m = unused_matches;
- LL_REMOVE(m);
+ DLL_REMOVE(m);
memset(m, 0, sizeof(match_t));
} else {
m = new(match_t);
}
// Keep track of the object:
- LL_PREPEND(in_use_matches, m);
+ DLL_PREPEND(in_use_matches, m);
+#else
+ if (unused_matches) {
+ m = unused_matches;
+ unused_matches = unused_matches->next;
+ memset(m, 0, sizeof(match_t));
+ } else {
+ m = new(match_t);
+ }
+#endif
+
return m;
}
@@ -580,12 +597,20 @@ void recycle_if_unused(match_t **at_m)
REMOVE_OWNERSHIP(m->child);
REMOVE_OWNERSHIP(m->nextsibling);
- LL_REMOVE(m);
+#ifdef DEBUG_HEAP
+ DLL_REMOVE(m); // Remove from in_use_matches
memset(m, 0, sizeof(match_t));
- LL_PREPEND(unused_matches, m);
+ DLL_PREPEND(unused_matches, m);
+#else
+ memset(m, 0, sizeof(match_t));
+ m->next = unused_matches;
+ unused_matches = m;
+#endif
+
*at_m = NULL;
}
+#ifdef DEBUG_HEAP
//
// Force all match objects into the pool of unused match objects.
//
@@ -594,8 +619,8 @@ size_t recycle_all_matches(void)
size_t count = 0;
while (in_use_matches) {
match_t *m = in_use_matches;
- LL_REMOVE(m);
- LL_PREPEND(unused_matches, m);
+ DLL_REMOVE(m);
+ DLL_PREPEND(unused_matches, m);
++count;
}
return count;
@@ -610,12 +635,13 @@ size_t free_all_matches(void)
recycle_all_matches();
while (unused_matches) {
match_t *m = unused_matches;
- LL_REMOVE(m);
+ DLL_REMOVE(m);
free(m);
++count;
}
return count;
}
+#endif
//
// Deallocate memory associated with an op
diff --git a/vm.h b/vm.h
index 3e7526b..3777492 100644
--- a/vm.h
+++ b/vm.h
@@ -15,10 +15,12 @@ match_t *get_capture(match_t *m, const char **id);
__attribute__((nonnull))
void destroy_op(vm_op_t *op);
match_t *new_match(void);
-size_t free_all_matches(void);
__attribute__((nonnull))
void recycle_if_unused(match_t **at_m);
+#ifdef DEBUG_HEAP
+size_t free_all_matches(void);
size_t recycle_all_matches(void);
+#endif
#endif
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1