da/src1 has accounting and da code together, compiles, have yet to copy in matrix...
authorglenrendes <glenda@reasoningtechnology.com>
Thu, 9 May 2019 17:01:32 +0000 (19:01 +0200)
committerglenrendes <glenda@reasoningtechnology.com>
Thu, 9 May 2019 17:01:32 +0000 (19:01 +0200)
module/da/src1/acc_doc.txt [new file with mode: 0644]
module/da/src1/da.lib.c
module/da/src1/da.lib.h
module/da/src1/da.lib.o [new file with mode: 0644]

diff --git a/module/da/src1/acc_doc.txt b/module/da/src1/acc_doc.txt
new file mode 100644 (file)
index 0000000..f19c8ff
--- /dev/null
@@ -0,0 +1,20 @@
+Explanation of process for using accounting code.
+
+  First, acc_open(&acc_live_channels, mode); ---acc_NULL or acc_SELF only, decide whether to track memory allocation for channels themselves
+  
+  Declare an Acc_channel and pass its address (via reference or pointer) to acc_open to begin an accounting channel. You will also need to pass in a Mode. 
+
+-acc_NULL does not track
+-acc_BALANCE will give you a count of outstanding mallocs and spurious frees when reported
+-acc_FULL will give you a robust accounting with a list of up to 10 outstanding/spurious pointers, then it will default to a count instead and just give the first 10 addresses.
+-acc_SELF is solely for the accounting software to account for its own memory allocation, therefore listing outstanding/spurious pointers to Acc_channels in the same format as acc_FULL.
+
+  When initializing a Da, you must pass in a pointer to the Da, its element size, and a pointer to the (already initialized) Acc_channel on which it will be stored into da_init. Among its other initialization tasks, this function will call acc_malloc for the base pointer of the Da with the appropriate channel.
+  When allocating memory for anything else in the program, you must pass the size of the memory to be allocated as well as the channel on which it is to be tracked to acc_malloc.
+
+  To free a Da, pass a pointer to the Da into da_free. It will automatically call acc_free for the base pointer, set the size to 0 and set the channel to NULL.
+  To free anything other else in the program, simply call acc_free, passing in the pointer and the channel the pointer is being tracked in. This will zero it out from the channel, call da_pts_nullify to clean up any zeroes at the end of the channel, and then free the pointer. 
+
+  To find out if there are any memory leaks in a particular channel, call acc_report with a pointer to the Acc_channel as the argument. Depending on the channel's mode, it will pretty print a current report of memory allocation and frees. If it is acc_live_channels set to Mode acc_SELF, it will report on the memory currently in use for the accounting system itself.
+
+  When finished with a channel, call acc_close and pass in the channel pointer. This will free up the memory used by it and remove it from the acc_live_channels outstanding_malloc list if there is SELF tracking on. Any allocation information being tracked by this channel will be lost, so it is advised to call acc_report before deciding whether to free the channel.
index 96596d6..12d7166 100644 (file)
 /*
-Dynamic Array
+  Dynamic Array
 
-Cannot expand an empty array.
+  Cannot expand an empty array.
 
-Accounting built into code. Alternative version of malloc and free that will invoke accounting for pointers that are allocated
-but not freed, or freed but not allocated.
+  Accounting built into code. Alternative version of malloc and free that will invoke accounting for pointers that are allocated
+  but not freed, or freed but not allocated.
 
 */
 
 #include "da.lib.h"
 
+//-----------------------------------------------------------------
 //function definitions for accounting
-  Acc_channel *acc_open(Acc_channel channel, int mode){}
-  void *acc_malloc(size_t size, Acc_channel channel){}
-  void acc_free(void *pt, Acc_channel channel){}
-  Acc_channel *acc_report(Acc_channel channel){}
-  void acc_close(Acc_channel channel){}
 
-  void *crash_and_burn_malloc(size_t size){}
-  void crash_and_burn_free(void *){}
+Acc_channel *acc_open(Acc_channel *channel, enum Mode mode){//acc init
+  Da os; Da sf;
+  channel->outstanding_malloc = da_init(&os, sizeof(void *), NULL);
+  channel->spurious_free = da_init(&sf, sizeof(void *), NULL);
+  channel->mode = mode;
+  if( channel == &acc_live_channels ) {//avoid pushing channel tracker onto itself
+    return channel;
+  }
+  else if( acc_live_channels.mode == acc_NULL ){//accounting NULL
+    //channel = (Acc_channel *)acc_malloc(sizeof(Acc_channel), NULL);//accounting still functions but not SELF
+    return channel;
+  }
+  else if( acc_live_channels.mode == acc_SELF ){//accounting tracks itself
+    channel = (Acc_channel *)acc_malloc(sizeof(Acc_channel), &acc_live_channels);
+    return channel;
+  }
+  else{ //cerr, optional acc_live_channels only tracks channels, not other mallocs/frees
+    return channel;
+  }
+}
+void *acc_malloc(size_t size, Acc_channel *channel){
+  void *an_allocation_pt = malloc(size);
+  if( channel ) da_push((Da *)(channel->outstanding_malloc), &an_allocation_pt);
+  return (void *)an_allocation_pt;
+}
+void acc_free(void *pt, Acc_channel *channel){
+  if( channel ){
+    void **i = (void **)(((Da *)(channel->outstanding_malloc))->base);
+    bool present = false;
+    while( i < (void **)(((Da *)(channel->outstanding_malloc))->end) ){
+      if( *i == pt ){
+        da_pts_nullify((Da *)(channel->outstanding_malloc), i);
+        present = true;
+      } 
+    i++;
+    }
+    if( present == false ) da_push((Da *)(channel->spurious_free), &pt);
+  }
+  free(pt);
+}
+static void count_balance(void *element, void *closure){
+  int *counter = (int *)closure;
+  if( (void *)element ) (*counter)++;
+}
+static void acc_rep_helper_BALANCE(Acc_channel *channel){
+  int count = 0;
+  da_foreach((Da *)channel->outstanding_malloc, count_balance, &count);
+  printf("There are %d outstanding allocations.\n", count);
+  count = 0;
+  da_foreach((Da *)channel->spurious_free, count_balance, &count);
+  printf("There are %d spurious frees.\n", count);
+}
+static void print_pointer(void *element, void *closure){
+  if( element ) printf("%d ", *(int *)element);
+}
+static void acc_rep_helper_FULL(Acc_channel *channel){
+  int count = 0;
+  da_foreach((Da *)channel->outstanding_malloc, count_balance, &count);
+  printf("There are %d outstanding mallocs.\n", count);
+  if( count < 10 ){
+    printf("The outstanding allocated pointers are: ");
+    da_foreach((Da *)channel->outstanding_malloc, print_pointer, NULL);
+    printf(".\n");
+  }
+  count = 0;
+  da_foreach((Da *)channel->spurious_free, count_balance, &count);
+  printf("There are %d spurious frees.\n", count);
+  if( count < 10 ){
+    printf("The spuriously freed pointers are: ");
+    da_foreach((Da *)channel->outstanding_malloc, print_pointer, NULL);
+    printf(".\n");
+  }
+}
+Acc_channel *acc_report(Acc_channel *channel){
+  if( channel->mode == acc_NULL ){
+    printf("Accounting mode is NULL.");
+    return channel;
+  }
+  if( channel->mode == acc_BALANCE ){
+    printf("Accounting mode is BALANCE.\n");
+    if( da_emptyq((Da *)(channel->outstanding_malloc)) && da_emptyq((Da *)(channel->spurious_free)) ){
+      printf("This channel is in balance.");
+    }
+    else{
+      printf("This channel is out of balance.\n");
+      acc_rep_helper_BALANCE(channel);
+    }
+    return channel;
+  }
+  if( channel->mode == acc_FULL ){
+    printf("Accounting mode is FULL.\n");
+    if( da_emptyq((Da *)(channel->outstanding_malloc)) && da_emptyq((Da *)(channel->spurious_free)) ){
+      printf("This channel is in balance.");
+    }
+    else{
+      printf("This channel is out of balance.\n");
+      acc_rep_helper_FULL(channel);
+    }
+    return channel;
+  }
+  if( channel->mode == acc_SELF ){
+    printf("Accounting mode is SELF.\n");
+    if( da_emptyq((Da *)(channel->outstanding_malloc)) && da_emptyq((Da *)(channel->spurious_free)) ){
+      printf("There are no open channels.");
+    }
+    else {
+      printf("The accounting code is out of balance.\n");
+      acc_rep_helper_FULL(channel);
+    }
+    return channel;
+  }
+}
+void acc_close(Acc_channel *channel){
+  da_free((Da *)(channel->outstanding_malloc));
+  da_free((Da *)(channel->spurious_free));
+  if( (channel != &acc_live_channels)
+      && (acc_live_channels.mode == acc_SELF) ){
+    acc_free(channel, &acc_live_channels);
+    return;
+  }
+  else return;
+}
 
-//functions definitions for Das
-
-//possible helper functions
-static acc_open_NULL(){}
-static acc_open_BALANCE(){}
-static acc_open_FULL(){}
-static acc_open_SELF(){}
-
-static acc_report_NULL(){}
-static acc_report_BALANCE(){}
-static acc_report_FULL(){}
-static acc_report_SELF(){}
-
-static da_init_NULL(){}
-static da_init_BALANCE(){}
-static da_init_FULL(){}
-static da_init_SELF(){}
+void *crash_and_burn_malloc(size_t size){}
+void crash_and_burn_free(void *pt){}
 
-static da_malloc_NULL(){}
-static da_malloc_BALANCE(){}
-static da_malloc_FULL(){}
-static da_malloc_SELF(){}
-
-static da_free_NULL(){}
-static da_free_BALANCE(){}
-static da_free_FULL(){}
-static da_free_SELF(){}
 
+//-----------------------------------------------------------------
+//functions definitions for Das
 
 // constructors / destructors
-  Da *da_init(Da *dap, size_t element_size, Acc_channel channel){}
-  void da_rewind(Da *dap){}
-  void da_rebase(Da *dap, char *old_base, void *pta){}
-  char *da_expand(Da *dap){}
-  bool da_boundq(Da *dap){}
-  void da_erase(Da *dap){}
+Da *da_init(Da *dap, size_t element_size, Acc_channel *channel){
+  dap->element_size = element_size;
+  dap->size = 4 * element_size;
+  dap->base = acc_malloc(dap->size, channel);
+  dap->end = dap->base;
+  dap->channel = channel;
+  return dap;
+}
+void da_free(Da *dap){
+  acc_free(dap->base, dap->channel);
+  dap->size = 0;
+  dap->channel = NULL;
+}
+void da_rewind(Da *dap){
+  dap->end = dap->base;
+}
+void da_rebase(Da *dap, char *old_base, void *pta){
+  char **pt = (char **)pta;
+  size_t offset = *pt - old_base;
+  *pt = dap->base + offset;
+}
+char *da_expand(Da *dap){
+  char *old_base = dap->base;
+  size_t end_offset = dap->end - old_base;
+  size_t new_size = dap->size << 1;
+  char *new_base = acc_malloc(new_size, (Acc_channel *)(dap->channel));
+  memcpy( new_base, old_base, end_offset + dap->element_size);
+  acc_free(old_base, (Acc_channel *)(dap->channel));
+  dap->base = new_base;
+  dap->end = new_base + end_offset;
+  dap->size = new_size;
+  return old_base;
+}
+bool da_boundq(Da *dap){
+  return dap->end > (dap->base + dap->size);
+}
 
 // status / attributes
 //
-  bool da_empty(Da *dap){}
-  bool da_equal(Da *da_0, Da *da_1){}
-  size_t da_length(Da *dap){}
-  bool da_length_equal(Da *dap0, Da *dap1){}
+bool da_emptyq(Da *dap){
+  return dap->end == dap->base;
+}
+bool da_equal(Da *da_0, Da *da_1){
+  return !bcmp(da_0, da_1, sizeof(Da));
+}
+size_t da_length(Da *dap){
+  return (dap->end - dap->base)/dap->element_size;
+}
+bool da_length_equal(Da *dap0, Da *dap1){
+  return da_length(dap0) == da_length(dap1);
+}
 
 // accessing
 //
-  char *da_index(Da *dap, size_t i){}
-  char *da_push(Da *dap, void *element){}
-  bool da_pop(Da *dap, void *element){}
+char *da_index(Da *dap, size_t i){
+  size_t offset = i * dap->element_size;
+  char *pt = dap->base + offset;
+  return pt;
+}
+// allocate space for a new element at the end of the array
+static char *da_push_alloc(Da *dap){
+  size_t element_off = dap->end - dap->base;
+  dap->end += dap->element_size;
+  if( dap->end > dap->base + dap->size ) da_expand(dap);
+  return dap->base + element_off;
+}
+char *da_push(Da *dap, void *element){
+  char *element_pt = da_push_alloc(dap);
+  memcpy(element_pt, element, dap->element_size);
+  return element_pt;
+}
+bool da_pop(Da *dap, void *element){
+  bool flag = dap->end >= dap->base + dap->element_size;
+  if( flag ){
+    dap->end -= dap->element_size;
+    if(element) memcpy(element, dap->end, dap->element_size);
+  }
+  return flag;
+}
 
 // iteration, f is given a pointer to an element and a pointer to the closure
-  bool da_endq(Da *dap, void *pt){}
-  bool da_right_bound(Da *dap, void *pt){}
-  void da_foreach(Da *dap, void f(void *, void *), void *closure){}
-  bool da_exists(Da *dap, bool f(void *, void*), void *closure){}
-  bool da_all(Da *dap, bool f(void *, void*), void *closure){}
+
+// true when pt has run off the end
+bool da_endq(Da *dap, void *pt){
+  return (char *)pt >= dap->end;
+}
+// array is a row of elements, pt points at the rightmost element
+bool da_right_bound(Da *dap, void *pt){
+  return ((char *)pt + dap->element_size) >= dap->end;
+}
+// passed in f(element_pt, arg_pt)
+// We have no language support closures, so we pass in an argument for it.
+// The closure may be set to NULL if it is not needed.
+void da_foreach(Da *dap, void f(void *, void *), void *closure){
+  char *pt = dap->base;
+  while( pt != dap->end ){
+    f(pt, closure);
+    pt += dap->element_size;
+  }
+}
+//would like da_exists and da_all to return pointer to element
+//abstract helper for da_exists and da_all
+static bool da_quantifier(bool complement, Da *dap, bool pred(void *, void*), void *closure){
+  char *pt = dap->base;
+  bool result = false;
+  while( (complement? !result : result) && (pt != dap->end) ){
+    result = pred(pt, closure);
+    pt += dap->element_size;
+  }
+  return result;
+}
+//∃, OR foreach
+bool da_exists(Da *dap, bool pred(void *, void*), void *closure){
+  return da_quantifier(true, dap, pred, closure);
+}
+//∀, AND foreach
+bool da_all(Da *dap, bool pred(void *, void*), void *closure){
+  return da_quantifier(false, dap, pred, closure);
+}
 
 // elements are pointers
 //
-  void *da_pts_exists(Da *dap, void *test_element){}
-  void da_pts_free_all(Da *dap){}
-  void da_pts_nullify(Da *dap, void **ept){}
+static bool da_pts_exists_0(void *element, void *test_element){ return element == test_element; }
+void *da_pts_exists(Da *dap, void *test_element){
+  if( da_exists(dap, da_pts_exists_0, test_element) ) return test_element;
+  else return NULL;
+}
+// elements were allocated, now they will all be freed
+static void da_pts_free_all_0(void *pt, void *closure){
+  acc_free(*(char **)pt, closure);
+}
+void da_pts_free_all(Da *dap){
+  da_foreach(dap, da_pts_free_all_0, dap->channel);
+  da_rewind(dap);
+}
+// elements are pointers
+// ept points at an element, we set *ept to NULL
+// we pop all NULLs off the top of the stack
+void da_pts_nullify(Da *dap, void **ept){
+  if(ept >= (void **)(dap->base) && ept < (void **)(dap->end)){
+    *ept = NULL;
+  }
+  while(
+        dap->end > dap->base
+        &&
+        *(void **)(dap->end - dap->element_size) == NULL){
+    da_pop(dap, NULL);
+  }
+}
 
 // matrices - elements are das 
 //need to rename/sed a lot of functions before adding
index 6548b9f..0975274 100644 (file)
@@ -3,17 +3,25 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <stdio.h>
+#include <string.h>
 
-#define malloc crash_and_burn_malloc
-#define free crash_and_burn_free
+//#define malloc crash_and_burn_malloc
+//#define free crash_and_burn_free
+//shouldn't define these in header bc need to use malloc and free in functions, put definitions after header if going to use
+
+// See acc_doc.txt for explanation of process for using accounting code.
+
+enum Mode{acc_NULL, acc_BALANCE, acc_FULL, acc_SELF};//0,1,2,3
+
+struct Da;//forward declaration because mutually referential structs
 
 typedef struct {
-  Da outstanding_malloc;
-  Da spurious_free;
-  int mode;
+  struct Da *outstanding_malloc;
+  struct Da *spurious_free;
+  enum Mode mode;
 } Acc_channel; //name instances of channels with handles
 
-typedef struct {
+typedef struct Da {
   char *base;
   char *end; // one byte/one element off the end of the array
   size_t size; // size >= (end - base) + 1;
@@ -21,19 +29,14 @@ typedef struct {
   Acc_channel *channel;//assign during init, set to NULL during free
 } Da;
 
-enum Mode{acc_NULL, acc_BALANCE, acc_FULL, acc_SELF};//0,1,2,3
-
 extern Acc_channel acc_live_channels;//acc_NULL or acc_SELF to track acc channels or not, other options return invalid upon report
 
-/*
-  Explanation of process for using accounting code.
-*/
 //function declarations for accounting
-  Acc_channel *acc_open(Acc_channel channel, int mode);//initializes channel structs
-  void *acc_malloc(size_t size, Acc_channel channel);//works for things besides Das too
-  void acc_free(void *pt, Acc_channel channel);//works for things besides Das too
-  Acc_channel *acc_report(Acc_channel channel);//reports on channels based on mode
-  void acc_close(Acc_channel channel);//frees channel itself
+  Acc_channel *acc_open(Acc_channel *channel, enum Mode mode);//initializes channel structs
+  void *acc_malloc(size_t size, Acc_channel *channel);//works for things besides Das too
+  void acc_free(void *pt, Acc_channel *channel);//works for things besides Das too
+  Acc_channel *acc_report(Acc_channel *channel);//reports on channels based on mode
+  void acc_close(Acc_channel *channel);//frees channel itself
 
   void *crash_and_burn_malloc(size_t size);//sends error message in case of accidental regular malloc
   void crash_and_burn_free(void *);// sends error message in case of accidental regular free
@@ -41,17 +44,16 @@ extern Acc_channel acc_live_channels;//acc_NULL or acc_SELF to track acc channel
 //function declarations for Das
 
 // constructors / destructors
-  Da *da_init(Da *dap, size_t element_size, Acc_channel channel);//calls da_malloc for base pointer
-  
+  Da *da_init(Da *dap, size_t element_size, Acc_channel *channel);//calls da_malloc for base pointer
+  void da_free(Da *dap);
   void da_rewind(Da *dap);
   void da_rebase(Da *dap, char *old_base, void *pta);
   char *da_expand(Da *dap);
   bool da_boundq(Da *dap);
-  void da_erase(Da *dap);
 
 // status / attributes
 //
-  bool da_empty(Da *dap);
+  bool da_emptyq(Da *dap);
   bool da_equal(Da *da_0, Da *da_1);
   size_t da_length(Da *dap);
   bool da_length_equal(Da *dap0, Da *dap1);
@@ -78,6 +80,7 @@ extern Acc_channel acc_live_channels;//acc_NULL or acc_SELF to track acc channel
 
 // matrices - elements are das 
 //need to rename/sed a lot of functions before adding
+void da_mat_erase(Da *dap);//same as free
 
 
 
diff --git a/module/da/src1/da.lib.o b/module/da/src1/da.lib.o
new file mode 100644 (file)
index 0000000..256b449
Binary files /dev/null and b/module/da/src1/da.lib.o differ