// size in words. // Flag one means block is free. void initialiseFreeBlock(void* freeRegion, uint32_t size, void* prevFreeRegion, void* nextFreeRegion, bool flag, bool setHeader) { totalFreeSpace += WORDS_TO_BYTES(size); // Stats // Update largest free region. if (size > largestFreeBlock) { largestFreeBlock = WORDS_TO_BYTES(size); } if (setHeader) { struct blockHeader *header = INIT_STRUCT(blockHeader, freeRegion); header->attribute = size; // Set size. Size is max 2^30. Flag is 0 by default. if (flag) header->attribute |= MSB_TO_ONE; // Set flag to 1. } void* usableArea = ADDRESS_PLUS_OFFSET(freeRegion, blockHeader); struct freeBlockLinks *blockLinks = INIT_STRUCT(freeBlockLinks, usableArea); PREV_BLOCK(blockLinks) = prevFreeRegion; NEXT_BLOCK(blockLinks) = nextFreeRegion; // Set footer free region. uint64_t sizeOffset = WORDS_TO_BYTES(size); void* footer = ADDRESS_MINUS_OFFSET(usableArea + sizeOffset, freeBlockFooter); struct freeBlockFooter *blockFooter = INIT_STRUCT(freeBlockFooter, footer); blockFooter->size = size; }
/* And a debugging version of the above: */ void * GC_debug_gcj_fast_malloc(size_t lw, void * ptr_to_struct_containing_descr, GC_EXTRA_PARAMS) { GC_PTR result; size_t lb = WORDS_TO_BYTES(lw); /* We clone the code from GC_debug_gcj_malloc, so that we */ /* dont end up with extra frames on the stack, which could */ /* confuse the backtrace. */ LOCK(); maybe_finalize(); result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind); if (result == 0) { UNLOCK(); GC_err_printf2("GC_debug_gcj_fast_malloc(%ld, 0x%lx) returning NIL (", (unsigned long) lw, (unsigned long) ptr_to_struct_containing_descr); GC_err_puts(s); GC_err_printf1(":%ld)\n", (unsigned long)i); return GC_oom_fn(WORDS_TO_BYTES(lw)); } *((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr; UNLOCK(); if (!GC_debugging_started) { GC_start_debugging(); } ADD_CALL_CHAIN(result, ra); return (GC_store_debug_info(result, (word)lb, s, (word)i)); }
// Split a large block into two sub-blocks. // spaceLeft and size are in words void *splitFreeBlock(void* blockToSplit, uint64_t spaceLeft, uint32_t size, void* currentFreeBlock, struct freeBlockLinks *currentBlockLinks) { // Reinitialise header of first sub-block. void* block = ADDRESS_MINUS_OFFSET(blockToSplit, blockHeader); struct blockHeader *allocatedBlock = INIT_STRUCT(blockHeader, block); allocatedBlock->attribute = size; // Create and initialise new node. uint32_t sizeNewNode = spaceLeft - BYTES_TO_WORDS(sizeof(blockHeader)); uint64_t sizeOffset = WORDS_TO_BYTES(size); void* endUserRequestedBlock = blockToSplit + sizeOffset; // initialise new block. void* prevBlock = PREV_BLOCK(currentBlockLinks); totalFreeSpace -= WORDS_TO_BYTES(spaceLeft); totalFreeSpace -= WORDS_TO_BYTES(size); // Stats initialiseFreeBlock(endUserRequestedBlock, sizeNewNode, prevBlock, currentFreeBlock, false, true); insertFreeBlock(endUserRequestedBlock, currentBlockLinks); return endUserRequestedBlock; }
void coalesceWithNextBlock(void* newAddr, uint32_t newSize, struct freeBlockLinks *successorBlockLinks) { struct blockHeader *newBlock = newAddr; newBlock->attribute = newSize; // Update links to freenodes. void* blockLinks = ADDRESS_PLUS_OFFSET(newAddr, blockHeader); struct freeBlockLinks *newBlockLinks = INIT_STRUCT(freeBlockLinks, blockLinks); PREV_BLOCK(newBlockLinks) = PREV_BLOCK(successorBlockLinks); NEXT_BLOCK(newBlockLinks) = NEXT_BLOCK(successorBlockLinks); // Prev block. void* prevLinks = ADDRESS_PLUS_OFFSET(PREV_BLOCK(newBlockLinks), blockHeader); struct freeBlockLinks *prevBlockLinks = INIT_STRUCT(freeBlockLinks, prevLinks); NEXT_BLOCK(prevBlockLinks) = newAddr; // Next block. void* nextLinks = ADDRESS_PLUS_OFFSET(NEXT_BLOCK(newBlockLinks), blockHeader); struct freeBlockLinks *nextBlockLinks = INIT_STRUCT(freeBlockLinks, nextLinks); PREV_BLOCK(prevBlockLinks) = newAddr; uint64_t sizeOffset = WORDS_TO_BYTES(newSize); setFooterBlockOnCoalescing(newAddr, sizeOffset, newSize); updateNextBlockOnCoalescing(newAddr, sizeOffset); }
/* allocated as a small object. */ void * GC_gcj_fast_malloc(size_t lw, void * ptr_to_struct_containing_descr) { ptr_t op; ptr_t * opp; DCL_LOCK_STATE; opp = &(GC_gcjobjfreelist[lw]); LOCK(); op = *opp; if( EXPECT(op == 0, 0) ) { maybe_finalize(); op = (ptr_t)GC_clear_stack( GC_generic_malloc_words_small_inner(lw, GC_gcj_kind)); if (0 == op) { UNLOCK(); return GC_oom_fn(WORDS_TO_BYTES(lw)); } } else { *opp = obj_link(op); GC_words_allocd += lw; } *(void **)op = ptr_to_struct_containing_descr; UNLOCK(); return((GC_PTR) op); }
// lengthMmapRegion in bytes bool coalesceMmapRegions(void* mmapsList, void* newMmapRegion, uint64_t lengthMmapRegion) { void* currentMmapRegion = mmapsList; struct headerMmapRegion *headerMmap = INIT_STRUCT(headerMmapRegion, currentMmapRegion); do { uint64_t oldLength = WORDS_TO_BYTES(headerMmap->length); void* endMmapRegion = currentMmapRegion + oldLength; if(endMmapRegion == newMmapRegion) { // Coalesce mmap regions. uint32_t newLength = headerMmap->length + BYTES_TO_WORDS(lengthMmapRegion); // update size mmap region. headerMmap->length = newLength; // Initialize footer mmap setMmapFooter(currentMmapRegion, WORDS_TO_BYTES(newLength)); // Calculate size new free region. void* beginningFreeRegion = ADDRESS_MINUS_OFFSET(endMmapRegion, blockHeader); uint64_t newFreeSpaceSize = lengthMmapRegion - sizeof(blockHeader); // size free region. struct blockHeader *footerPrevMmapRegion = INIT_STRUCT(blockHeader, beginningFreeRegion); uint32_t flag = GET_FLAG(footerPrevMmapRegion->attribute); // Coalesce with prev block if free. if (flag == MSB_TO_ONE) { void* previous = ADDRESS_MINUS_OFFSET(beginningFreeRegion, freeBlockFooter); struct freeBlockFooter *prevUsableBlockFooter = INIT_STRUCT(freeBlockFooter, previous); uint64_t sizePrevBlock = WORDS_TO_BYTES(prevUsableBlockFooter->size); // Footer has no flag beginningFreeRegion = beginningFreeRegion - sizePrevBlock - sizeof(blockHeader); newFreeSpaceSize += sizeof(blockHeader) + sizePrevBlock; numberFreeBlocks--; totalFreeSpace += newFreeSpaceSize; // Stats uint32_t newFreeSpaceSizeInWords = BYTES_TO_WORDS(newFreeSpaceSize); coalesceWithPrevBlock(beginningFreeRegion, newFreeSpaceSizeInWords); } else { initialiseFreeMmapRegion(beginningFreeRegion, newFreeSpaceSize); } return true; // coalescing. } else { // Check next mmap region currentMmapRegion = NEXT_MMAP_ADDRESS(headerMmap); headerMmap = currentMmapRegion; } } while (headerMmap != NULL && NEXT_MMAP_ADDRESS(headerMmap) != NULL); return false; // no coalescing. }
void coalesceWithPrevBlock(void* newAddr, uint32_t newSize) { struct blockHeader *newBlock = INIT_STRUCT(blockHeader, newAddr); newBlock->attribute = newSize; uint64_t sizeOffset = WORDS_TO_BYTES(newSize); setFooterBlockOnCoalescing(newAddr, sizeOffset, newSize); updateNextBlockOnCoalescing(newAddr, sizeOffset); }
GC_API GC_descr GC_CALL GC_make_descriptor(const GC_word * bm, size_t len) { signed_word last_set_bit = len - 1; GC_descr result; DCL_LOCK_STATE; # if defined(AO_HAVE_load_acquire) && defined(AO_HAVE_store_release) if (!EXPECT(AO_load_acquire(&GC_explicit_typing_initialized), TRUE)) { LOCK(); if (!GC_explicit_typing_initialized) { GC_init_explicit_typing(); AO_store_release(&GC_explicit_typing_initialized, TRUE); } UNLOCK(); } # else LOCK(); if (!EXPECT(GC_explicit_typing_initialized, TRUE)) { GC_init_explicit_typing(); GC_explicit_typing_initialized = TRUE; } UNLOCK(); # endif while (last_set_bit >= 0 && !GC_get_bit(bm, last_set_bit)) last_set_bit--; if (last_set_bit < 0) return(0 /* no pointers */); # if ALIGNMENT == CPP_WORDSZ/8 { signed_word i; for (i = 0; i < last_set_bit; i++) { if (!GC_get_bit(bm, i)) { break; } } if (i == last_set_bit) { /* An initial section contains all pointers. Use length descriptor. */ return (WORDS_TO_BYTES(last_set_bit+1) | GC_DS_LENGTH); } } # endif if ((word)last_set_bit < BITMAP_BITS) { signed_word i; /* Hopefully the common case. */ /* Build bitmap descriptor (with bits reversed) */ result = SIGNB; for (i = last_set_bit - 1; i >= 0; i--) { result >>= 1; if (GC_get_bit(bm, i)) result |= SIGNB; } result |= GC_DS_BITMAP; } else {
void coalesceWithNeighbours(void* newAddr, uint32_t newSize, struct freeBlockLinks *successorBlockLinks) { struct blockHeader *newBlock = INIT_STRUCT(blockHeader, newAddr); newBlock->attribute = newSize; uint64_t sizeOffset = WORDS_TO_BYTES(newSize); setFooterBlockOnCoalescing(newAddr, sizeOffset, newSize); updateNextBlockOnCoalescing(newAddr, sizeOffset); // Remove successor block removeAllocatedBlock(successorBlockLinks); numberFreeBlocks--; }
void freeMemory(void *ptr) { /* Read flag for coalescing with previous block Read size to get to the next block and check if it's free (coalescing) */ void *startBlock = ADDRESS_MINUS_OFFSET(ptr, blockHeader); struct blockHeader *header = INIT_STRUCT(blockHeader, startBlock); uint32_t size = GET_SIZE(header->attribute); // in words if(!freeList) { initialiseFreeBlock(startBlock, size, startBlock, startBlock, false, false); freeList = startBlock; numberFreeBlocks++; totalFreeSpace += WORDS_TO_BYTES(size); // Stats } else { coalescingAndFree(startBlock); } currentAllocatedMemory -= WORDS_TO_BYTES(size); }
// Check if the new region is big enough to store a new free block. // if not do not split, but free list now points to next node. void allocateBlock(uint32_t size, uint32_t spaceLeft, uint32_t minFreeRegionSize, uint32_t sizeFreeRegion, void* freeBlock, void* currentFreeBlock, struct freeBlockLinks *currentBlockLinks) { if (spaceLeft > minFreeRegionSize) { if (sufficientSize(size)) { freeList = splitFreeBlock(freeBlock, spaceLeft, size, currentFreeBlock, currentBlockLinks); } else { minFreeRegionSize -= BYTES_TO_WORDS(sizeof(freeBlockFooter)); freeList = splitFreeBlock(freeBlock, spaceLeft, minFreeRegionSize, currentFreeBlock, currentBlockLinks); } numberFreeBlocks++; } else { // No split. // If successor is mmap footer, then set its flag to 0. totalFreeSpace -= WORDS_TO_BYTES(sizeFreeRegion); uint64_t sizeOffset = WORDS_TO_BYTES(sizeFreeRegion); void* next = ADDRESS_PLUS_OFFSET(currentFreeBlock + sizeOffset, blockHeader); struct blockHeader *nextBlockHeader = INIT_STRUCT(blockHeader, next); // check if last one (size = 0.) if (nextBlockHeader->attribute == MSB_TO_ONE) { // Tell next that block is not free anymore. nextBlockHeader->attribute = MSB_TO_ZERO; } else { // If next block is not last one, then just set its flag to zero and keep size. // Flag is automatically set to zero. nextBlockHeader->attribute = GET_SIZE(nextBlockHeader->attribute); } freeList = NEXT_BLOCK(currentBlockLinks); } }
void * GC_generic_malloc(size_t lb, int k) { void * result; DCL_LOCK_STATE; if (GC_have_errors) GC_print_all_errors(); GC_INVOKE_FINALIZERS(); if (SMALL_OBJ(lb)) { LOCK(); result = GC_generic_malloc_inner((word)lb, k); UNLOCK(); } else { size_t lw; size_t lb_rounded; word n_blocks; GC_bool init; lw = ROUNDED_UP_WORDS(lb); lb_rounded = WORDS_TO_BYTES(lw); n_blocks = OBJ_SZ_TO_BLOCKS(lb_rounded); init = GC_obj_kinds[k].ok_init; LOCK(); result = (ptr_t)GC_alloc_large(lb_rounded, k, 0); if (0 != result) { if (GC_debugging_started) { BZERO(result, n_blocks * HBLKSIZE); } else { # ifdef THREADS /* Clear any memory that might be used for GC descriptors */ /* before we release the lock. */ ((word *)result)[0] = 0; ((word *)result)[1] = 0; ((word *)result)[lw-1] = 0; ((word *)result)[lw-2] = 0; # endif } } GC_bytes_allocd += lb_rounded; UNLOCK(); if (init && !GC_debugging_started && 0 != result) { BZERO(result, n_blocks * HBLKSIZE); } } if (0 == result) { return((*GC_oom_fn)(lb)); } else { return(result); } }
void findAndSetLargestFreeBlock() { // traverse free list. largestFreeBlock = 0; // Reset largest free region. int numberTraversedNodes = 0; void* currentFreeBlock = freeList; do { struct blockHeader *currentFreeRegionHeader = INIT_STRUCT(blockHeader, currentFreeBlock); uint32_t sizeFreeRegion = GET_SIZE(currentFreeRegionHeader->attribute); // in words. uint64_t sizeFreeRegionInBytes = WORDS_TO_BYTES(sizeFreeRegion); if(sizeFreeRegionInBytes > largestFreeBlock) { largestFreeBlock = sizeFreeRegionInBytes; } void* freeBlock = ADDRESS_PLUS_OFFSET(currentFreeBlock, blockHeader); struct freeBlockLinks *currentBlockLinks = INIT_STRUCT(freeBlockLinks, freeBlock); numberTraversedNodes++; currentFreeBlock = NEXT_BLOCK(currentBlockLinks); } while (numberTraversedNodes < numberFreeBlocks); }
STATIC void GC_init_explicit_typing(void) { unsigned i; GC_STATIC_ASSERT(sizeof(struct LeafDescriptor) % sizeof(word) == 0); /* Set up object kind with simple indirect descriptor. */ GC_eobjfreelist = (ptr_t *)GC_new_free_list_inner(); GC_explicit_kind = GC_new_kind_inner( (void **)GC_eobjfreelist, (WORDS_TO_BYTES((word)-1) | GC_DS_PER_OBJECT), TRUE, TRUE); /* Descriptors are in the last word of the object. */ GC_typed_mark_proc_index = GC_new_proc_inner(GC_typed_mark_proc); /* Set up object kind with array descriptor. */ GC_array_mark_proc_index = GC_new_proc_inner(GC_array_mark_proc); GC_array_kind = GC_new_kind_inner(GC_new_free_list_inner(), GC_MAKE_PROC(GC_array_mark_proc_index, 0), FALSE, TRUE); GC_bm_table[0] = GC_DS_BITMAP; for (i = 1; i < WORDSZ/2; i++) { GC_bm_table[i] = (((word)-1) << (WORDSZ - i)) | GC_DS_BITMAP; } }
// size free region in bytes void initialiseFreeMmapRegion(void* beginningFreeRegion, uint64_t sizeFreeRegion) { uint32_t sizeFreeRegionInWords = BYTES_TO_WORDS(sizeFreeRegion); // headerMmapsize in words. if(!freeList) { freeList = beginningFreeRegion; // Initialise the free list. initialiseFreeBlock(beginningFreeRegion, sizeFreeRegionInWords, beginningFreeRegion, beginningFreeRegion, false, true); } else { // Add to free list. void *currentBlock = freeList; void* links = ADDRESS_PLUS_OFFSET(currentBlock, blockHeader); struct freeBlockLinks *currentBlockLinks = INIT_STRUCT(freeBlockLinks, links); void* prevBlock = PREV_BLOCK(currentBlockLinks); initialiseFreeBlock(beginningFreeRegion, sizeFreeRegionInWords, prevBlock, currentBlock, false, true); // Tell next block that its previous one is NOW free. uint64_t sizeOffset = WORDS_TO_BYTES(sizeFreeRegionInWords); updateNextBlockOnCoalescing(beginningFreeRegion, sizeFreeRegion); insertFreeBlock(beginningFreeRegion, currentBlockLinks); } }
/* Currently useless for multithreaded worlds. */ GC_API void * GC_CALL GC_is_visible(void *p) { hdr *hhdr; if ((word)p & (ALIGNMENT - 1)) goto fail; if (!GC_is_initialized) GC_init(); # ifdef THREADS hhdr = HDR((word)p); if (hhdr != 0 && GC_base(p) == 0) { goto fail; } else { /* May be inside thread stack. We can't do much. */ return(p); } # else /* Check stack first: */ if (GC_on_stack(p)) return(p); hhdr = HDR((word)p); if (hhdr == 0) { if (GC_is_static_root(p)) return(p); /* Else do it again correctly: */ # if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || \ defined(MSWINCE) || defined(PCR)) GC_register_dynamic_libraries(); if (GC_is_static_root(p)) return(p); # endif goto fail; } else { /* p points to the heap. */ word descr; ptr_t base = GC_base(p); /* Should be manually inlined? */ if (base == 0) goto fail; if (HBLKPTR(base) != HBLKPTR(p)) hhdr = HDR((word)p); descr = hhdr -> hb_descr; retry: switch(descr & GC_DS_TAGS) { case GC_DS_LENGTH: if ((word)((ptr_t)p - (ptr_t)base) > (word)descr) goto fail; break; case GC_DS_BITMAP: if ((ptr_t)p - (ptr_t)base >= WORDS_TO_BYTES(BITMAP_BITS) || ((word)p & (sizeof(word) - 1))) goto fail; if (!(((word)1 << (WORDSZ - ((ptr_t)p - (ptr_t)base) - 1)) & descr)) goto fail; break; case GC_DS_PROC: /* We could try to decipher this partially. */ /* For now we just punt. */ break; case GC_DS_PER_OBJECT: if ((signed_word)descr >= 0) { descr = *(word *)((ptr_t)base + (descr & ~GC_DS_TAGS)); } else { ptr_t type_descr = *(ptr_t *)base; descr = *(word *)(type_descr - (descr - (GC_DS_PER_OBJECT - GC_INDIR_PER_OBJ_BIAS))); } goto retry; } return(p); } # endif fail: (*GC_is_visible_print_proc)((ptr_t)p); return(p); }
void *getFreeBlock(uint64_t requestedSize) { // Transform size in bytes to size in words. uint32_t size = BYTES_TO_WORDS(requestedSize); if (!freeList) { mmapRegion(requestedSize); return getFreeBlock(requestedSize); } int numberTraversedNodes = 0; bool freeBlockFound = false; bool updateLargestFreeBlock = false; void* freeBlock; void* currentFreeBlock = freeList; /* Traverse free list (circular double linked list) Use next-fit. */ do { struct blockHeader *currentFreeRegionHeader = INIT_STRUCT(blockHeader, currentFreeBlock); uint32_t sizeFreeRegion = GET_SIZE(currentFreeRegionHeader->attribute); freeBlock = ADDRESS_PLUS_OFFSET(currentFreeBlock, blockHeader); struct freeBlockLinks *currentBlockLinks = INIT_STRUCT(freeBlockLinks, freeBlock); if (sizeFreeRegion >= size) { freeBlockFound = true; int sizeFreeRegionInBytes = WORDS_TO_BYTES(sizeFreeRegion); // Larger blocks than largestFreeBlock can exist if mmap is called again. if (sizeFreeRegionInBytes >= largestFreeBlock) { updateLargestFreeBlock = true; } uint32_t spaceLeft; // in words uint32_t minFreeRegionSize = minimumSize(); if (sufficientSize(size)) { spaceLeft = sizeFreeRegion - size; } else { spaceLeft = sizeFreeRegion - minFreeRegionSize; } allocateBlock(size, spaceLeft, minFreeRegionSize, sizeFreeRegion, freeBlock, currentFreeBlock, currentBlockLinks); // Remove allocated block. if (numberFreeBlocks == 1) { freeList = NULL; } else { removeAllocatedBlock(currentBlockLinks); } numberFreeBlocks--; // Look for new largestFreeBlock if(numberFreeBlocks && updateLargestFreeBlock) { findAndSetLargestFreeBlock(); } } // Step to the next free block in the free list. numberTraversedNodes++; currentFreeBlock = NEXT_BLOCK(currentBlockLinks); } while (numberTraversedNodes < numberFreeBlocks && !freeBlockFound); if (!freeBlockFound) { mmapRegion(requestedSize); return getFreeBlock(requestedSize); } return freeBlock; }
/*-----------------------------------------------------------------------------* * NAME * OtaHandleAccessWrite * * DESCRIPTION * Handle write-access requests from the Host where the characteristic * handle falls within the range of the OTAU Application Service. * * PARAMETERS * p_ind [in] Write request data * * RETURNS * Nothing *----------------------------------------------------------------------------*/ void OtaHandleAccessWrite(GATT_ACCESS_IND_T *p_ind) { sys_status rc = gatt_status_write_not_permitted; /* Function status */ switch (p_ind->handle) { case HANDLE_CSR_OTA_CURRENT_APP: { /* Set the index of the current application */ const uint8 app_id = p_ind->value[0]; /* New application index */ #if defined(USE_STATIC_RANDOM_ADDRESS) || defined(USE_RESOLVABLE_RANDOM_ADDRESS) BD_ADDR_T bd_addr; /* Bluetooth Device address */ GapGetRandomAddress(&bd_addr); #endif /* USE_STATIC_RANDOM_ADDRESS || USE_RESOLVABLE_RANDOM_ADDRESS */ rc = OtaWriteCurrentApp(app_id, IS_BONDED, &(CONN_HOST_ADDR), LINK_DIVERSIFIER, #if defined(USE_STATIC_RANDOM_ADDRESS) || defined(USE_RESOLVABLE_RANDOM_ADDRESS) &bd_addr, #else NULL, #endif CONNECTION_IRK, GattServiceChangedIndActive()); if (rc != sys_status_success) { /* Sanitise the result. If OtaWriteCurrentApp fails it will be * because one or more of the supplied parameters was invalid. */ rc = gatt_status_invalid_param_value; } } break; case HANDLE_CSR_OTA_READ_CS_BLOCK: /* Set the offset and length of a block of CS to read */ /* Validate input (expecting uint16[2]) */ if (p_ind->size_value == WORDS_TO_BYTES(sizeof(uint16[2]))) { const uint16 offset = BufReadUint16(&p_ind->value); data_transfer_data_length = (uint8)BufReadUint16(&p_ind->value); rc = readCsBlock(offset, data_transfer_data_length, data_transfer_memory); } else { rc = gatt_status_invalid_length; } break; case HANDLE_CSR_OTA_DATA_TRANSFER_CLIENT_CONFIG: { /* Modify the Data Transfer Client Characteristic Configuration * Descriptor */ const uint16 client_config = BufReadUint16(&p_ind->value); /* Requested descriptor value */ if((client_config == gatt_client_config_notification) || (client_config == gatt_client_config_none)) { data_transfer_configuration[0] = client_config; rc = sys_status_success; } else { /* INDICATION or RESERVED */ /* Return error as only notifications are supported */ rc = gatt_status_desc_improper_config; } } break; default: /* Writing to this characteristic is not permitted */ break; } GattAccessRsp(p_ind->cid, p_ind->handle, rc, 0, NULL); /* Perform any follow-up actions */ if (rc == sys_status_success) { switch (p_ind->handle) { case HANDLE_CSR_OTA_READ_CS_BLOCK: /* If this write action was to trigger a CS key read and * notifications have been enabled send the result now. */ if (data_transfer_configuration[0] == gatt_client_config_notification) { GattCharValueNotification(CONNECTION_CID, HANDLE_CSR_OTA_DATA_TRANSFER, data_transfer_data_length, data_transfer_memory); } break; case HANDLE_CSR_OTA_CURRENT_APP: /* If a new application index has been requested disconnect from * the Host and reset the device to run the new application. */ /* Record that the GATT database may be different after the * device has reset. */ GattOnOtaSwitch(); /* When the disconnect confirmation comes in, call OtaReset() */ g_ota_reset_required = TRUE; /* Disconnect from the Host */ GattDisconnectReq(CONNECTION_CID); break; default: /* No follow up action necessary */ break; } } }
void coalescingAndFree(void* block) { struct blockHeader *header = INIT_STRUCT(blockHeader, block); uint32_t size = GET_SIZE(header->attribute); // in words uint32_t flag = GET_FLAG(header->attribute); NEIGHBOUR_BLOCKS state = NEIGHBOUR_BLOCKS_NOT_FREE; struct freeBlockLinks *successorBlockLinks = NULL; // update only if necessary // Initialise addr and size for no change. void* newAddr = block; uint32_t newSize = size; uint64_t sizeOffset; // Is precedent block free? if (flag == MSB_TO_ONE) { state = NEIGHBOUR_BLOCKS_PRECEDENT_FREE; // In this case it's just about updating the size of the prev free block // and removing the successive one if free. void* footer = ADDRESS_MINUS_OFFSET(block, freeBlockFooter); struct freeBlockFooter *prevBlockFooter = INIT_STRUCT(freeBlockFooter, footer); sizeOffset = WORDS_TO_BYTES(prevBlockFooter->size); // Footer has no flag. newAddr = block - sizeOffset - sizeof(blockHeader); newSize = prevBlockFooter->size + BYTES_TO_WORDS(sizeof(blockHeader)) + size; } // Is successive block free? sizeOffset = WORDS_TO_BYTES(size); void* nextBlock = ADDRESS_PLUS_OFFSET(block + sizeOffset, blockHeader); struct blockHeader *nextHeader = INIT_STRUCT(blockHeader, nextBlock); if (nextHeader->attribute != MSB_TO_ZERO) { // check if next block is mmap footer or not. uint32_t nextSize = GET_SIZE(nextHeader->attribute); sizeOffset = WORDS_TO_BYTES(nextSize); void* nextNextBlock = ADDRESS_PLUS_OFFSET(nextBlock + sizeOffset, blockHeader); struct blockHeader *nextNextHeader = INIT_STRUCT(blockHeader, nextNextBlock); if (nextNextHeader->attribute != MSB_TO_ZERO) { flag = GET_FLAG(nextNextHeader->attribute); if (flag == MSB_TO_ONE) { if (!state) { state = NEIGHBOUR_BLOCKS_SUCCESSIVE_FREE; // Do not change address, but Increase size newSize = size + BYTES_TO_WORDS(sizeof(blockHeader)) + nextSize; } else { state = NEIGHBOUR_BLOCKS_BOTH_FREE; newSize = newSize + BYTES_TO_WORDS(sizeof(blockHeader)) + nextSize; } successorBlockLinks = nextBlock + sizeof(blockHeader); // IF NO PREV block is free: // Just update the pointers of the prev and next blocks // relative to this block AND the size. } } } // Otherwise it's next block is the mmap footer. switch(state) { case NEIGHBOUR_BLOCKS_NOT_FREE: { void *currentBlock = freeList; struct freeBlockLinks *currentBlockLinks = ADDRESS_PLUS_OFFSET(currentBlock, blockHeader); void* prevBlock = PREV_BLOCK(currentBlockLinks); initialiseFreeBlock(newAddr, newSize, prevBlock, currentBlock, false, false); // Tell next block that its previous one is NOW free. sizeOffset = WORDS_TO_BYTES(size); updateNextBlockOnCoalescing(newAddr, sizeOffset); insertFreeBlock(newAddr, currentBlockLinks); numberFreeBlocks++; break; } case NEIGHBOUR_BLOCKS_PRECEDENT_FREE: { coalesceWithPrevBlock(newAddr, newSize); break; } case NEIGHBOUR_BLOCKS_SUCCESSIVE_FREE: { coalesceWithNextBlock(newAddr, newSize, successorBlockLinks); break; } case NEIGHBOUR_BLOCKS_BOTH_FREE: { coalesceWithNeighbours(newAddr, newSize, successorBlockLinks); break; } default: { fprintf(stderr, "memoryManagement.coalescingAndFree - NEIGHBOUR_BLOCKS state unknown\n"); exit(-1); } } // end switch // Update total free space // When state == 0, the totalFreeSpace is updated when the block is initialised. totalFreeSpace += WORDS_TO_BYTES(size); // Stats if (state != NEIGHBOUR_BLOCKS_NOT_FREE) totalFreeSpace += sizeof(blockHeader); // Largest free region if (newSize > largestFreeBlock) largestFreeBlock = newSize; freeList = newAddr; }