private unsafe void *allocate_sma_header(sma_header **sma_ptr, int sm_index) { sma_header *old_entry = *sma_ptr; int obj_length = sm_sizes[sm_index]; int obj_count = sm_total_counts[sm_index]; chunk_header *c = allocate_chunk(sizeof(sma_header) + obj_count * 4 + obj_count * obj_length); if (c == null) { return(null); } /* Set as small object */ c->flags &= ~(1 << 4); /* Fill in the header */ sma_header *h = (sma_header *)((byte *)c + sizeof(chunk_header)); h->obj_length = obj_length; h->free_count = obj_count; h->total_count = obj_count; h->next = old_entry; h->global_free_count = get_sm_free_ptr(sm_index); /* Add our free blocks to the total free count */ *get_sm_free_ptr(sm_index) += obj_count; /* Set all memory as free */ for (int i = 0; i < obj_count; i += 8) { /* Each 32-bit test uint covers 8 entries of 4 bits */ uint *test = (uint *)((byte *)h + sizeof(sma_header) + i * 4); *test = 0; } // TODO: ?zero the returned memory block *sma_ptr = h; return(h); }
public void *Alloc(int length) { /* Wait for all other allocations and collections to complete */ var state = libsupcs.OtherOperations.EnterUninterruptibleSection(); bool can_continue = false; while (can_continue == false) { libsupcs.Monitor.Enter(collection_mutex); { if (collection_in_progress == false && alloc_in_progress == false) { alloc_in_progress = true; can_continue = true; } } libsupcs.Monitor.Exit(collection_mutex); } /* Increase the allocation counter */ allocs++; /* Decide if we want a large or small object */ if (length > hdr->lo_size) { chunk_header *c = allocate_chunk(length); alloc_in_progress = false; if (c == null) { return(null); } var ret = (void *)((byte *)c + sizeof(chunk_header)); libsupcs.OtherOperations.ExitUninterruptibleSection(state); return(ret); } else { /* Small object */ int sm_index = get_size_index(length); if (sm_index < 0) { alloc_in_progress = false; return(null); } /* Get first sma_header */ sma_header **sma_ptr = get_sma_ptr(sm_index); int * sm_free_ptr = get_sm_free_ptr(sm_index); /* Ensure there is free space of the appropriate size */ if (*sm_free_ptr == 0) { allocate_sma_header(sma_ptr, sm_index); } /* Allocate space */ void *ret = allocate_small_object(*sma_ptr, sm_index); if (ret == null) { Formatter.Write("gengc: allocate_small_object failed. sm_free_ptr = ", Program.arch.DebugOutput); Formatter.Write((ulong)*sm_free_ptr, Program.arch.DebugOutput); Formatter.Write(". Trying again... ", Program.arch.DebugOutput); allocate_sma_header(sma_ptr, sm_index); ret = allocate_small_object(*sma_ptr, sm_index); if (ret == null) { Formatter.WriteLine("failed again", Program.arch.DebugOutput); } else { Formatter.WriteLine("succeeded", Program.arch.DebugOutput); } } alloc_in_progress = false; libsupcs.OtherOperations.ExitUninterruptibleSection(state); return(ret); } }