1 /* 2 * falloc.h 3 * nyquist memory allocation data structures and macros 4 * 5 * there is an falloc and ffree for each major type of data structure 6 * there is an falloc and ffree for generic (not so common) structures 7 * there is an frelease for some structures. this reduces the 8 * reference count for the particular structure by 1; it 9 * does not continue recursively. 10 */ 11 12 /* Debugging support: 13 * When DEBUG_MEM is set, each piece of allocated storage will contain 14 * a pointer to a string naming the caller or other allocation info, 15 * and a sequence number. (8 extra bytes are allocated for this info). 16 * 17 * When storage is freed, the ID is set to NULL, and the routine 18 * dbg_mem_check(ptr) will abort if ID is NULL. Call this routine to 19 * avoid following a pointer to data that was previously freed. 20 * 21 * The goal of this support is to allow you to "go back" to the point 22 * where memory is corrupted; specifically where a memory block is freed 23 * too early. 24 * 25 * When a memory-related bug is crashing the system: 26 * (1) Recompile with DEBUG_MEM on. 27 * (2) Develop some Nyquist code that will predictably crash the system. 28 * (3) When Nyquist crashes, use a debugger to find where the bad 29 * pointer came from. See if the source of the pointer was freed. 30 * (4) If the source of the pointer was freed, then notice the sequence 31 * number. 32 * (5) Rerun with dbg_mem_seq_num set to the number noted in (4). 33 * (6) Nyquist will print when the storage in question was allocated and 34 * freed. Use the debugger to find out why the storage is 35 * freed too early and who did it. 36 * (7) If the source of the pointer in (3) was not freed, you're on your 37 * own. 38 * 39 * The DEBUG_MEM related routines are: 40 * dbg_mem_allocated: called when memory is allocated 41 * dbg_mem_freed: called when memory is freed 42 * dbg_mem_released: called when memory is released 43 * dbg_mem_check: called to check memory 44 * 45 * see also xldmem.c: 46 * by setting xldmem_trace to a pointer, you can trace when the 47 * pointer is referenced by anything in the heap 48 */ 49 50 51 /* to get size_t on pmax: */ 52 #ifdef pmax 53 #include "sys/types.h" 54 #endif 55 56 #include "cque.h" 57 #include "debug.h" 58 59 #define DEBUG_MEM 0 60 #define DEBUG_MEM_INFO_SIZE (sizeof(long) + sizeof(char *)) 61 62 /* special free lists */ 63 extern CQUE *sample_block_free; /* really a sample_block_type */ 64 65 /* special counts */ 66 extern int sample_block_total; 67 extern int sample_block_used; 68 extern int snd_list_used; 69 extern int sound_used; 70 extern long table_memory; 71 72 /* generic free lists */ 73 #define MAXLISTS 128 74 extern CQUE *generic_free[MAXLISTS]; 75 76 /* general memory pool */ 77 #define MAXPOOLSIZE 1000000 78 extern char *poolp; 79 extern char *poolend; 80 81 /* sample block memory pool */ 82 #define MAXSPOOLSIZE (256 * round_size(sizeof(sample_block_node))) 83 extern char *spoolp; 84 extern char *spoolend; 85 86 extern int npools; 87 extern int sample_blocks_since_gc; 88 89 #if !defined(TRACK_POOLS) 90 #define TRACK_POOLS 1 91 #endif 92 93 #if defined(TRACK_POOLS) && TRACK_POOLS 94 // extern CQUE *pools; 95 void falloc_gc(void); 96 #endif 97 98 void falloc_init(void); 99 void new_pool(void); 100 void new_spool(void); 101 void find_sample_block(sample_block_type *sp); 102 103 char *get_from_pool(size_t siz); 104 105 #define round_size(n) (((n) + 7) & ~7) 106 107 /* check_pool -- returns true if enough bytes are available */ 108 #if DEBUG_MEM 109 #define check_pool(size) (poolp + (size) + DEBUG_MEM_INFO_SIZE <= poolend) 110 #define check_spool(size) (spoolp + (size) + DEBUG_MEM_INFO_SIZE <= spoolend) 111 #define DBG_MEM_ALLOCATED(p, who) dbg_mem_allocated(p, who) 112 #define DBG_MEM_FREED(p, who) dbg_mem_freed(p, who) 113 #define DBG_MEM_RELEASED(p, who) dbg_mem_released(p, who) 114 #else 115 #define check_pool(size) (poolp + (size) <= poolend) 116 #define check_spool(size) (spoolp + (size) <= spoolend) 117 #define DBG_MEM_ALLOCATED(p, who) 118 #define DBG_MEM_FREED(p, who) 119 #define DBG_MEM_RELEASED(p, who) 120 #endif 121 122 #define BLOCKS_PER_GC 100 123 124 /* There used to be a lot of code in this macro. I moved it to 125 * find_sample_block, but kept the macro mainly in order to pass sp 126 * by reference. 127 */ 128 #define falloc_sample_block(sp, who) { \ 129 find_sample_block(&sp); \ 130 DBG_MEM_ALLOCATED(sp, who); } 131 132 133 #define ffree_sample_block(sp, who) { \ 134 /* printf("freeing sample_block@%x\n", sp); */ \ 135 DBG_MEM_FREED(sp, who); \ 136 Qenter(sample_block_free, sp); \ 137 sample_block_used--; \ 138 } 139 140 #define frelease_sample_block(sp, who) { \ 141 sp->refcnt--; \ 142 DBG_MEM_RELEASED(sp, who); \ 143 if (sp->refcnt <= 0) { \ 144 ffree_sample_block(sp); \ 145 } \ 146 } 147 148 149 /* NOTE: This must not cause garbage collection. 150 * LVAL parameters to snd_make_? functions are not 151 * protected and falloc_sound is invoked there. 152 */ 153 #define snd_list_free (generic_free[round_size(sizeof(snd_list_node)) >> 3]) 154 155 #define falloc_snd_list(sp, who) { \ 156 if (!Qempty(snd_list_free)) \ 157 Qget(snd_list_free, snd_list_type, sp) \ 158 else \ 159 sp = (snd_list_type)get_from_pool(round_size(sizeof(snd_list_node)));\ 160 snd_list_used++; \ 161 DBG_MEM_ALLOCATED(sp, who); \ 162 } 163 164 165 #define ffree_snd_list(sp, who) { \ 166 DBG_MEM_FREED(sp, who); \ 167 Qenter(snd_list_free, sp); \ 168 snd_list_used--; \ 169 } 170 171 172 #define frelease_snd_list(sp, who) { \ 173 sp->refcnt--; \ 174 DBG_MEM_RELEASED(sp, who); \ 175 if (sp->refcnt <= 0) { \ 176 ffree_snd_list(sp, who); \ 177 } \ 178 } 179 180 181 #define sound_free (generic_free[round_size(sizeof(sound_node)) >> 3]) 182 183 #define NORMALSOUNDALLOC 184 #ifdef NORMALSOUNDALLOC 185 #define falloc_sound(sp, who) { \ 186 if (!Qempty(sound_free)) { \ 187 Qget(sound_free, sound_type, sp); \ 188 } else { \ 189 sp = (sound_type) get_from_pool(round_size(sizeof(sound_node))); \ 190 } \ 191 sound_used++; \ 192 DBG_MEM_ALLOCATED(sp, who); \ 193 } 194 #else 195 #define falloc_sound(sp) \ 196 sp =(sound_type) \ 197 get_from_pool(round_size(sizeof(sound_node))) 198 #endif 199 200 /* note: usually you call sound_unref, not this macro */ 201 #define ffree_sound(sp, who) { \ 202 /* sound_already_free_test(); */ \ 203 DBG_MEM_FREED(sp, who); \ 204 Qenter(sound_free, sp); \ 205 sound_used--; \ 206 } 207 208 209 /* falloc_generic -- sp gets new node of type sptype */ 210 /**/ 211 #define falloc_generic(sp, sptype, who) { \ 212 int size = round_size(sizeof(sptype)); \ 213 falloc_generic_bytes(sp, sptype, size, who) } 214 215 /* falloc_generic_n -- sp gets new array of n sptype's */ 216 /**/ 217 #define falloc_generic_n(sp, sptype, n, who) { \ 218 int min_size = sizeof(sptype) * (n); \ 219 int size = round_size(min_size); \ 220 falloc_generic_bytes(sp, sptype, size, who) } 221 222 #define falloc_generic_bytes(sp, sptype, size, who) \ 223 if ((size >> 3) >= MAXLISTS) { \ 224 stdputstr("falloc_generic problem\n"); \ 225 sp = (sptype *) malloc(size); \ 226 } else if (!Qempty(generic_free[size >> 3])) { \ 227 Qget(generic_free[size >> 3], sptype *, sp); \ 228 } else { \ 229 sp = (sptype *) get_from_pool(size); \ 230 } \ 231 DBG_MEM_ALLOCATED(sp, who); \ 232 /* printf("GENERIC ALLOC %x\n", sp); */ 233 234 235 /* ffree_generic puts an item back on proper freelist */ 236 /* NOTE: sIzE is capitalized funny so that it will not 237 * match an actual parameter, e.g. if the caller writes 238 * ffree_generic(ptr, size), we don't want the expanded 239 * code to include: "int size = round_size(size) >> 3"! 240 */ 241 #define ffree_generic(sp, nn, who) { \ 242 int sIzE = round_size(nn) >> 3; \ 243 DBG_MEM_FREED(sp, who); \ 244 /* printf("GENERIC FREE %x SIZE %d\n", sp, nnn); */ \ 245 if ((sIzE) >= MAXLISTS) { \ 246 free(sp); \ 247 } else { \ 248 Qenter(generic_free[sIzE], sp); \ 249 } \ 250 } 251