00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #include "soarkernel.h"
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 void *allocate_memory(unsigned long size, int usage_code)
00061 {
00062 char *p;
00063
00064 current_agent(memory_for_usage)[usage_code] += size;
00065 size += sizeof(char *);
00066 current_agent(memory_for_usage)[STATS_OVERHEAD_MEM_USAGE] += sizeof(char *);
00067
00068 p = (char *) malloc(size);
00069 if (p == NULL) {
00070 char msg[MESSAGE_SIZE];
00071 snprintf(msg, MESSAGE_SIZE, "\nmem.c: Error: Tried but failed to allocate %lu bytes of memory.\n", size);
00072 msg[MESSAGE_SIZE - 1] = 0;
00073 abort_with_fatal_error(msg);
00074 }
00075 if (((unsigned long) p) & 3) {
00076 char msg[MESSAGE_SIZE];
00077 strncpy(msg, "\nmem.c: Error: Memory allocator returned an address that's not a multiple of 4.\n",
00078 MESSAGE_SIZE);
00079 msg[MESSAGE_SIZE - 1] = 0;
00080 abort_with_fatal_error(msg);
00081 }
00082
00083 fill_with_garbage(p, size);
00084
00085 *((unsigned long *) p) = size;
00086 p += sizeof(char *);
00087
00088 return (void *) p;
00089 }
00090
00091 void *allocate_memory_and_zerofill(unsigned long size, int usage_code)
00092 {
00093 void *p;
00094
00095 p = allocate_memory(size, usage_code);
00096 memset(p, 0, size);
00097 return p;
00098 }
00099
00100 void free_memory(void *mem, int usage_code)
00101 {
00102 unsigned long size;
00103
00104 mem = ((char *) mem) - sizeof(char *);
00105 size = *((unsigned long *) mem);
00106 fill_with_garbage(mem, size);
00107
00108 current_agent(memory_for_usage)[STATS_OVERHEAD_MEM_USAGE] -= sizeof(char *);
00109 current_agent(memory_for_usage)[usage_code] -= (size - sizeof(char *));
00110
00111 free(mem);
00112 }
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 char *make_memory_block_for_string(const char *s)
00141 {
00142 char *p;
00143 unsigned long size;
00144
00145 size = strlen(s) + 1;
00146 p = allocate_memory(size, STRING_MEM_USAGE);
00147 strncpy(p, s, size);
00148 p[size - 1] = 0;
00149 return p;
00150 }
00151
00152 void free_memory_block_for_string(char *p)
00153 {
00154 free_memory(p, STRING_MEM_USAGE);
00155 }
00156
00157 #define INITIAL_GROWABLE_STRING_SIZE 100
00158
00159 growable_string make_blank_growable_string(void)
00160 {
00161 growable_string gs;
00162
00163 gs = allocate_memory(2 * sizeof(int *) + INITIAL_GROWABLE_STRING_SIZE, STRING_MEM_USAGE);
00164 memsize_of_growable_string(gs) = INITIAL_GROWABLE_STRING_SIZE;
00165 length_of_growable_string(gs) = 0;
00166 *(text_of_growable_string(gs)) = 0;
00167 return gs;
00168 }
00169
00170 void add_to_growable_string(growable_string * gs, char *string_to_add)
00171 {
00172 int current_length, length_to_add, new_length, new_memsize;
00173 growable_string new;
00174
00175 current_length = length_of_growable_string(*gs);
00176 length_to_add = strlen(string_to_add);
00177 new_length = current_length + length_to_add;
00178 if (new_length + 1 > memsize_of_growable_string(*gs)) {
00179 new_memsize = memsize_of_growable_string(*gs);
00180 while (new_length + 1 > new_memsize)
00181 new_memsize = new_memsize * 2;
00182 new = allocate_memory(new_memsize + 2 * sizeof(int *), STRING_MEM_USAGE);
00183 memsize_of_growable_string(new) = new_memsize;
00184 strcpy(text_of_growable_string(new), text_of_growable_string(*gs));
00185 free_memory(*gs, STRING_MEM_USAGE);
00186 *gs = new;
00187 }
00188 strcpy(text_of_growable_string(*gs) + current_length, string_to_add);
00189 length_of_growable_string(*gs) = new_length;
00190 }
00191
00192 void free_growable_string(growable_string gs)
00193 {
00194 free_memory(gs, STRING_MEM_USAGE);
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 #define DEFAULT_INTERLEAVE_FACTOR 1
00221
00222
00223
00224 #define DEFAULT_BLOCK_SIZE 0x7FF0
00225
00226 void add_block_to_memory_pool(memory_pool * p)
00227 {
00228 char *new_block;
00229 unsigned long size, i, item_num, interleave_factor;
00230 char *item, *prev_item;
00231
00232
00233 size = p->item_size * p->items_per_block + sizeof(char *);
00234 new_block = allocate_memory(size, POOL_MEM_USAGE);
00235 *(char **) new_block = p->first_block;
00236 p->first_block = new_block;
00237 p->num_blocks++;
00238
00239
00240 interleave_factor = DEFAULT_INTERLEAVE_FACTOR;
00241 if (interleave_factor >= (unsigned) (p->items_per_block))
00242 interleave_factor = 1;
00243
00244 item_num = interleave_factor;
00245 prev_item = new_block + sizeof(char *);
00246 for (i = 0; i < (unsigned) (p->items_per_block) - 1; i++) {
00247 item = new_block + sizeof(char *) + item_num * p->item_size;
00248 *(char **) prev_item = item;
00249 prev_item = item;
00250 item_num = item_num + interleave_factor;
00251 if (item_num >= (unsigned) (p->items_per_block))
00252 item_num -= p->items_per_block;
00253 }
00254 *(char **) prev_item = p->free_list;
00255 p->free_list = new_block + sizeof(char *);
00256 }
00257
00258 void init_memory_pool(memory_pool * p, long item_size, char *name)
00259 {
00260 if (item_size < sizeof(char *))
00261 item_size = sizeof(char *);
00262 while (item_size & 3)
00263 item_size++;
00264 p->item_size = item_size;
00265 p->items_per_block = DEFAULT_BLOCK_SIZE / item_size;
00266 p->num_blocks = 0;
00267 p->first_block = NIL;
00268 p->free_list = NIL;
00269 #ifdef MEMORY_POOL_STATS
00270 p->used_count = 0;
00271 #endif
00272 p->next = current_agent(memory_pools_in_use);
00273 current_agent(memory_pools_in_use) = p;
00274 if (strlen(name) > MAX_POOL_NAME_LENGTH) {
00275 char msg[2 * MAX_POOL_NAME_LENGTH];
00276 snprintf(msg, 2 * MAX_POOL_NAME_LENGTH, "mem.c: Internal error: memory pool name too long: %s\n", name);
00277 msg[2 * MAX_POOL_NAME_LENGTH - 1] = 0;
00278 abort_with_fatal_error(msg);
00279 }
00280 strncpy(p->name, name, MAX_POOL_NAME_LENGTH);
00281 p->name[MAX_POOL_NAME_LENGTH - 1] = 0;
00282
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315 cons *destructively_reverse_list(cons * c)
00316 {
00317 cons *prev, *current, *next;
00318
00319 prev = NIL;
00320 current = c;
00321 while (current) {
00322 next = current->rest;
00323 current->rest = prev;
00324 prev = current;
00325 current = next;
00326 }
00327 return prev;
00328 }
00329
00330 bool member_of_list(void *item, list * the_list)
00331 {
00332 while (the_list) {
00333 if (the_list->first == item)
00334 return TRUE;
00335 the_list = the_list->rest;
00336 }
00337 return FALSE;
00338 }
00339
00340 list *add_if_not_member(void *item, list * old_list)
00341 {
00342 cons *c;
00343
00344 for (c = old_list; c != NIL; c = c->rest)
00345 if (c->first == item)
00346 return old_list;
00347 allocate_cons(&c);
00348 c->first = item;
00349 c->rest = old_list;
00350 return c;
00351 }
00352
00353 void free_list(list * the_list)
00354 {
00355 cons *c;
00356
00357 while (the_list) {
00358 c = the_list;
00359 the_list = the_list->rest;
00360 free_cons(c);
00361 }
00362 }
00363
00364 list *extract_list_elements(list ** header, cons_test_fn f)
00365 {
00366 cons *first_extracted_element, *tail_of_extracted_elements;
00367 cons *c, *prev_c, *next_c;
00368
00369 first_extracted_element = NIL;
00370 tail_of_extracted_elements = NIL;
00371
00372 prev_c = NIL;
00373 for (c = (*header); c != NIL; c = next_c) {
00374 next_c = c->rest;
00375 if (!f(c)) {
00376 prev_c = c;
00377 continue;
00378 }
00379 if (prev_c)
00380 prev_c->rest = next_c;
00381 else
00382 *header = next_c;
00383 if (first_extracted_element)
00384 tail_of_extracted_elements->rest = c;
00385 else
00386 first_extracted_element = c;
00387 tail_of_extracted_elements = c;
00388 }
00389 if (first_extracted_element)
00390 tail_of_extracted_elements->rest = NIL;
00391 return first_extracted_element;
00392 }
00393
00394 dl_list *extract_dl_list_elements(dl_list ** header, dl_cons_test_fn f)
00395 {
00396 dl_cons *first_extracted_element, *tail_of_extracted_elements;
00397 dl_cons *dc, *next_dc;
00398
00399 first_extracted_element = NIL;
00400 tail_of_extracted_elements = NIL;
00401
00402 for (dc = (*header); dc != NIL; dc = next_dc) {
00403 next_dc = dc->next;
00404 if (!f(dc))
00405 continue;
00406 remove_from_dll((*header), dc, next, prev);
00407 if (first_extracted_element)
00408 tail_of_extracted_elements->next = dc;
00409 else
00410 first_extracted_element = dc;
00411 dc->prev = tail_of_extracted_elements;
00412 tail_of_extracted_elements = dc;
00413 }
00414 if (first_extracted_element)
00415 tail_of_extracted_elements->next = NIL;
00416 return first_extracted_element;
00417 }
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453 unsigned long masks_for_n_low_order_bits[33] = { 0x00000000,
00454 0x00000001, 0x00000003, 0x00000007, 0x0000000F,
00455 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
00456 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
00457 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
00458 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
00459 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
00460 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
00461 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
00462 };
00463
00464 struct hash_table_struct *make_hash_table(short minimum_log2size, hash_function h)
00465 {
00466 hash_table *ht;
00467
00468 ht = allocate_memory(sizeof(hash_table), HASH_TABLE_MEM_USAGE);
00469 ht->count = 0;
00470 if (minimum_log2size < 1)
00471 minimum_log2size = 1;
00472 ht->size = (((unsigned long) 1) << minimum_log2size);
00473 ht->log2size = minimum_log2size;
00474 ht->minimum_log2size = minimum_log2size;
00475 ht->buckets = allocate_memory_and_zerofill(ht->size * sizeof(char *), HASH_TABLE_MEM_USAGE);
00476 ht->h = h;
00477 return ht;
00478 }
00479
00480 void resize_hash_table(hash_table * ht, short new_log2size)
00481 {
00482 unsigned long i;
00483 bucket_array *new_buckets;
00484 item_in_hash_table *item, *next;
00485 unsigned long hash_value;
00486 unsigned long new_size;
00487
00488 new_size = (((unsigned long) 1) << new_log2size);
00489 new_buckets = (bucket_array *) allocate_memory_and_zerofill(new_size * sizeof(char *), HASH_TABLE_MEM_USAGE);
00490
00491 for (i = 0; i < ht->size; i++) {
00492 for (item = *(ht->buckets + i); item != NIL; item = next) {
00493 next = item->next;
00494
00495 hash_value = (*(ht->h)) (item, new_log2size);
00496 item->next = *(new_buckets + hash_value);
00497 *(new_buckets + hash_value) = item;
00498 }
00499 }
00500
00501 free_memory(ht->buckets, HASH_TABLE_MEM_USAGE);
00502 ht->buckets = new_buckets;
00503 ht->size = new_size;
00504 ht->log2size = new_log2size;
00505 }
00506
00507 void remove_from_hash_table(struct hash_table_struct *ht, void *item)
00508 {
00509 unsigned long hash_value;
00510 item_in_hash_table *this_one, *prev;
00511
00512 this_one = item;
00513 hash_value = (*(ht->h)) (item, ht->log2size);
00514 if (*(ht->buckets + hash_value) == this_one) {
00515
00516 *(ht->buckets + hash_value) = this_one->next;
00517 } else {
00518
00519 prev = *(ht->buckets + hash_value);
00520 while (prev->next != this_one)
00521 prev = prev->next;
00522 prev->next = this_one->next;
00523 }
00524 this_one->next = NIL;
00525
00526 ht->count--;
00527 if ((ht->count < ht->size / 2) && (ht->log2size > ht->minimum_log2size))
00528 resize_hash_table(ht, (short) (ht->log2size - 1));
00529 }
00530
00531 void add_to_hash_table(struct hash_table_struct *ht, void *item)
00532 {
00533 unsigned long hash_value;
00534 item_in_hash_table *this_one;
00535
00536 this_one = item;
00537 ht->count++;
00538 if (ht->count >= ht->size * 2)
00539 resize_hash_table(ht, (short) (ht->log2size + 1));
00540 hash_value = (*(ht->h)) (item, ht->log2size);
00541 this_one->next = *(ht->buckets + hash_value);
00542 *(ht->buckets + hash_value) = this_one;
00543 }
00544
00545 void do_for_all_items_in_hash_table(struct hash_table_struct *ht, hash_table_callback_fn f)
00546 {
00547 unsigned long hash_value;
00548 item_in_hash_table *item;
00549
00550 for (hash_value = 0; hash_value < ht->size; hash_value++) {
00551 item = (item_in_hash_table *) (*(ht->buckets + hash_value));
00552 for (; item != NIL; item = item->next)
00553 if ((*f) (item))
00554 return;
00555 }
00556 }
00557
00558 void do_for_all_items_in_hash_bucket(struct hash_table_struct *ht, hash_table_callback_fn f, unsigned long hash_value)
00559 {
00560 item_in_hash_table *item;
00561
00562 hash_value = hash_value & masks_for_n_low_order_bits[ht->log2size];
00563 item = (item_in_hash_table *) (*(ht->buckets + hash_value));
00564 for (; item != NIL; item = item->next)
00565 if ((*f) (item))
00566 return;
00567 }
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 void init_memory_utilities(void)
00578 {
00579 int i;
00580
00581 init_memory_pool(¤t_agent(cons_cell_pool), sizeof(cons), "cons cell");
00582 init_memory_pool(¤t_agent(dl_cons_pool), sizeof(dl_cons), "dl cons");
00583 for (i = 0; i < NUM_MEM_USAGE_CODES; i++)
00584 current_agent(memory_for_usage)[i] = 0;
00585 }