// try applying sequence int try_sequence(SEQLIST *test_sequence, int mem_size) { SEQLIST *sptr; unsigned char *mblock; // reset the memory allocator being tested MEMORY_SIZE = mem_size; init_myalloc(); for (sptr = test_sequence; !seq_null(sptr); sptr = seq_next(sptr)) { if (seq_alloc(sptr)) { // allocate a block mblock = myalloc(seq_size(sptr)); if (mblock == 0) { return 0; // failed -- return indication } else { // keep track of address allocated (for later frees) seq_set_myalloc_block(sptr, mblock); // put data in the block // (so we can test that it holds data w/out corruption) fill_data(seq_ref_block(sptr), mblock, seq_size(sptr)); } } else { // dealloc myfree(seq_myalloc_block(seq_tofree(sptr))); } } return 1; // succeeded in allocating entire sequence }
/** * DESCRIPTION: deletes the back/last element * in the seq and returns its value. * If the seq is empty, the seq is unchanged and * the return value has no meaning (i.e., this is * the client's fault!) * RUNTIME REQ: O(1) */ extern ETYPE seq_del_back(Seq seq){ if( seq_size(seq) <= 0){ return (ETYPE)-1; } Node* nodehold = seq->tail; if( seq_size(seq) == 1){ seq->head = NULL; } //if the list is at least 2 big, the head will not change ETYPE holder = seq->tail->a; //even if one node, should set tail to null seq->tail = seq->tail->bw; if( seq->tail != NULL) seq->tail->fw = NULL; free(nodehold); --(seq->numN); return holder; }
/** * DESCRIPTION: deletes the front/first element * in the seq and returns its value. * If the seq is empty, the seq is unchanged and * the return value has no meaning (i.e., this is * the client's fault! * RUNTIME REQ: O(1) */ extern ETYPE seq_del_front(Seq seq){ if( seq_size(seq) <= 0){ return (ETYPE)-1; } Node* nodehold = seq->head; if( seq_size(seq) == 1){ seq->tail = NULL; } //if the list is at least 2 big, the tail will not change ETYPE holder = seq->head->a; //even if one node, should set head to null; seq->head = seq->head->fw; if( seq->head != NULL) seq->head->bw = NULL; free(nodehold); --(seq->numN); return holder; }
/** * DESCRIPTION: adds a new element with given val * to the "front" of the seq. * RUNTIME REQ: O(1) */ extern void seq_add_front(Seq seq, ETYPE val){ Node* front; front = (Node*)malloc(sizeof(Node) ); front->a = val; if( seq_size(seq) >= 1){ //at least one node (head and tail exist) front->fw = seq->head; //point the new front to the list seq->head->bw = front; //point the "old" front to the new front } else{ //the seq has 0 elems; front is both "front" and "end" seq->tail = front; front->fw = NULL; } front->bw = NULL; seq->head = front; ++(seq->numN); //reflect addition of new node }
/** * DESCRIPTION: adds a new element to the "back" of * the seq * RUNTIME REQ: O(1) */ extern void seq_add_back(Seq seq, ETYPE val){ Node* back; back = (Node*)malloc(sizeof(Node) ); back->a = val; if( seq_size(seq) >= 1){ //at least one node (head and tail exist) back->bw = seq->tail; //point the new tail to the list seq->tail->fw = back; //point the "old" tail to the new end } else{ //the seq has 0 elems; back is both "front" and "end" seq->head = back; seq->tail = back; back->bw = NULL; } back->fw = NULL; seq->tail = back; ++(seq->numN); //reflect addition of new node }
// check all still allocated blocks in a test sequence // contain the data originally placed into them // i.e. have not been corrupted int check_data(SEQLIST *test_sequence) { int result; SEQLIST *current; result = 0; // stays zero if no errors for (current = test_sequence; !seq_null(current); current = seq_next(current)) { // only check if an allocate which has not been freed if (seq_alloc(current) && !seq_freed(current)) { if (!same_data(seq_ref_block(current), seq_myalloc_block(current), seq_size(current))) { if (VERBOSE) { printf("Mismatch in sequence starting at:\n"); seq_print(current); } // returning a 1 means it failed result = 1; } } } return result; }
// create a test sequence which never uses more than max_used_memory // and allocates a total of max_used_memory*allocation_factor SEQLIST *generate_sequence(int max_used_memory, int allocation_factor) { int used_memory = 0; int total_allocated = 0; int next_block_size = 0; int allocated_blocks = 0; int actual_max_used_memory = 0; SEQLIST *test_sequence = (SEQLIST *) 0; SEQLIST *tail_sequence = (SEQLIST *) 0; SEQLIST *tofree = (SEQLIST *) 0; unsigned char *new_block_ref; while (total_allocated < allocation_factor * max_used_memory) { next_block_size = random_block_size(max_used_memory); // first see if we need to free anything in order to // accommodate the new allocation while (used_memory + next_block_size > max_used_memory) { // randomly pick a block to free SEQLIST *tofree = find_nth_allocated_block(test_sequence, random_int(allocated_blocks)); // add the free tail_sequence = seq_set_next_free(tofree, tail_sequence); // reclaim the memory used_memory -= seq_size(tofree); allocated_blocks--; // mark the old block as something that has been freed seq_free(tofree); } // allocate a reference buffer for the new block new_block_ref = allocate_and_fill(next_block_size); // now allocate that block if (seq_null(test_sequence)) { // special case for first allocation test_sequence = seq_add_front(next_block_size, new_block_ref, (SEQLIST *) 0); tail_sequence = test_sequence; } else { // typical case we add at the end tail_sequence = seq_set_next_allocate(next_block_size, new_block_ref, tail_sequence); } // debug //seq_print(tail_sequence); // just prints the new one total_allocated += next_block_size; used_memory += next_block_size; if (used_memory > actual_max_used_memory) actual_max_used_memory = used_memory; allocated_blocks++; } // just so can manually see this is doing something sensible printf("Actual maximum memory usage %d (%f)\n", actual_max_used_memory, ((double) actual_max_used_memory / (double) max_used_memory)); return test_sequence; }
/** * DESCRIPTION: returns the last/back element * of the sequence; does not modify the * sequence. If sequence is empty then * return value has no meaning (client's * fault! * RUNTIME REQ: O(1) */ extern ETYPE seq_peek_back(Seq seq){ if( seq_size(seq) <= 0){ return (ETYPE)-1; } return seq->tail->a; }
/** * DESCRIPTION: returns the front element * of the sequence; does not modify the * sequence. If sequence is empty then * return value has no meaning (client's * fault! * RUNTIME REQ: O(1) */ extern ETYPE seq_peek_front(Seq seq){ if( seq_size(seq) <= 0){ return (ETYPE)-1; } return seq->head->a; }