int _createBlock(const size_t blockSize) { TRACE_FLOW("(%lu)", blockSize); if (_hasAvailableBlock(blockSize)) { return 0; } if (blockSize > READ_FROM_HEAP(lookupTableOffset, Address)) { assert(0); } // all right, block of this size does not exist - we need to // split a bigger block int parentOkay = _createBlock(blockSize + 1); if (parentOkay != 0) { return parentOkay; } // ========= // we can now safely assume that there is a block of // blockSize+1 size that we can split // get the first from the list Address parentBlockAddress = GET_FIRST_BLOCK_ADDRESS(blockSize + 1); // remove it from the list _removeBlockFromList(parentBlockAddress, blockSize + 1); // and split it // as we know that there is no other block available, we can write // it's address to look-up table WRITE_FIRST_BLOCK_ADDRESS(blockSize, parentBlockAddress); // let's find the center of the block (there we split) Address blockHalfAddress = parentBlockAddress + UNIT * ((Address)1 << (blockSize-1)); Address leftBlockAddress = parentBlockAddress; Address rightBlockAddress = blockHalfAddress; TRACE_DUMP("left block starts at %lu, right at %lu (parent starts at %lu)", leftBlockAddress, rightBlockAddress, parentBlockAddress); // set addresses and size on the left half... WRITE_ON_HEAP(leftBlockAddress, Address, blockSize); MARK_BLOCK_FREE(leftBlockAddress); SET_ADDRESS_OF_PREVIOUS_SIBLING(leftBlockAddress, 0); SET_ADDRESS_OF_FOLLOWING_SIBLING(leftBlockAddress, rightBlockAddress); // ... as well as on the right one WRITE_ON_HEAP(rightBlockAddress, Address, blockSize); MARK_BLOCK_FREE(rightBlockAddress); SET_ADDRESS_OF_PREVIOUS_SIBLING(rightBlockAddress, leftBlockAddress); SET_ADDRESS_OF_FOLLOWING_SIBLING(rightBlockAddress, 0); buddyDump(); // and that's it! return 0; }
Address _allocateBlock(const size_t blockSize) { TRACE_FLOW("(%lu)", blockSize); int createOkay = _createBlock(blockSize); if (createOkay != 0) { return 0; } // we will get the first one Address firstBlockAddress = GET_FIRST_BLOCK_ADDRESS(blockSize); Address nextBlockAddress = GET_ADDRESS_OF_FOLLOWING_SIBLING(firstBlockAddress); // remove it from the list _removeBlockFromList(firstBlockAddress, blockSize); // set new first block WRITE_FIRST_BLOCK_ADDRESS(nextBlockAddress, blockSize); // mark it as used MARK_BLOCK_USED(firstBlockAddress); // and return it return firstBlockAddress; }
/** * @brief Daemon thread routine * @details This function is passed as start_routine to daemon thread, * it waits for new requests to come, and when _pendingCV is fired: * - daemon takes the request from _pending queue and hashes its data * - when hashing finished, it adds the block to chain * * @param chain_ptr pointer to chain * @return NULL */ void* Chain::daemonRoutine(void *pChain) { (void) pChain; int blockId; _daemonWorkFlag = true; while (s_initiated) { // Lock _pendingBlocks LOCK(_pendingMutex) // No requests to process if (_pending.empty()) { if (_isClosing) { UNLOCK(_pendingMutex) _daemonWorkFlag = false; return NULL; } // Wait for "hey! someone pending" signal if (pthread_cond_wait(&_pendingCV, &_pendingMutex)) { exit(FAIL); } } if (_isClosing) { UNLOCK(_pendingMutex) _daemonWorkFlag = false; return NULL; } if (_pending.size()) { // Get new request Request *newReq = _pending.front(); _pending.pop_front(); // Release the queue UNLOCK(_pendingMutex) // Hash and attach blockId = _createBlock(newReq); // Delete processed request delete newReq; // Update status LOCK(_statusMutex) _status[blockId] = ATTACHED; UNLOCK(_statusMutex) // Send signal to anyone waiting for attaching if (pthread_cond_signal(&_attachedCV)) { exit(FAIL); } } else // No requests to process {