Ejemplo n.º 1
0
void CBThreadPoolQueueAdd(CBThreadPoolQueue * self, CBQueueItem * item){
	item->next = NULL;
	item->active = false;
	item->cleared = false;
	// Find worker with least items to process
	uint16_t workerI = 0;
	for (uint16_t x = 1; x < self->numThreads; x++){
		CBMutexLock(self->workers[x].queueMutex);
		if (self->workers[x].queue.itemNum < self->workers[workerI].queue.itemNum)
			workerI = x;
		CBMutexUnlock(self->workers[x].queueMutex);
		// Queue may change in the meantime but this wont cause any problems
	}
	CBWorker * worker = self->workers + workerI;
	CBMutexLock(self->finishMutex);
	self->finished = false;
	CBMutexLock(worker->queueMutex);
	worker->queue.itemNum++;
	if (!worker->queue.start) {
		worker->queue.end = worker->queue.start = item;
		// We have added the first item to the queue so wake up the thread.
		assert(worker->queue.itemNum);
		CBConditionSignal(worker->waitCond);
	}else
		worker->queue.end = worker->queue.end->next = item;
	CBMutexUnlock(worker->queueMutex);
	CBMutexUnlock(self->finishMutex);
}
Ejemplo n.º 2
0
void CBNodeProcessMessages(void * node){
	CBNode * self = node;
	CBMutexLock(self->messageProcessMutex);
	for (;;) {
		if (self->messageQueue == NULL && !self->shutDownThread){
			// Wait for more messages
			CBConditionWait(self->messageProcessWaitCond, self->messageProcessMutex);
			CBLogVerbose("Process thread as been woken");
		}
		// Check to see if the thread should terminate
		if (self->shutDownThread){
			CBMutexUnlock(self->messageProcessMutex);
			return;
		}
		// Process next message on queue
		CBMessageQueue * toProcess = self->messageQueue;
		CBMutexUnlock(self->messageProcessMutex);
		// Handle alerts
		CBOnMessageReceivedAction action;
		if (toProcess->message->type == CB_MESSAGE_TYPE_ALERT)
			// The peer sent us an alert message
			action = CBNodeProcessAlert(self, toProcess->peer, CBGetAlert(toProcess->message));
		else
			action = self->onMessageReceived(self, toProcess->peer, toProcess->message);
		if (action == CB_MESSAGE_ACTION_DISCONNECT)
			// We need to disconnect the node
			CBNodeDisconnectPeer(toProcess->peer);
		CBMutexLock(self->messageProcessMutex);
		// Remove this from queue
		CBReleaseObject(toProcess->message);
		CBReleaseObject(toProcess->peer);
		self->messageQueue = toProcess->next;
		free(toProcess);
	}
}
Ejemplo n.º 3
0
void CBThreadPoolQueueClear(CBThreadPoolQueue * self){
	CBMutexLock(self->finishMutex);
	for (uint16_t x = 0; x < self->numThreads; x++) {
		CBMutexLock(self->workers[x].queueMutex);
		// Empty queue
		CBFreeQueue(&self->workers[x].queue, self->destroy);
		self->workers[x].queue.itemNum = 0;
		CBMutexUnlock(self->workers[x].queueMutex);
	}
	self->finished = true;
	CBConditionSignal(self->finishCond);
	CBMutexUnlock(self->finishMutex);
}
Ejemplo n.º 4
0
void CBNodeOnValidatorError(void * vself){
	CBNode * self = vself;
	CBMutexUnlock(CBGetNode(self)->blockAndTxMutex);
	CBLogError("There was a validation error.");
	self->callbacks.onFatalNodeError(self, CB_ERROR_VALIDATION);
	CBReleaseObject(self);
}
Ejemplo n.º 5
0
void CBNodeOnBadTime(void * vself){
	CBNode * self = vself;
	CBMutexUnlock(CBGetNode(self)->blockAndTxMutex);
	CBLogError("The system time is potentially incorrect. It does not match with the network time.");
	self->callbacks.onFatalNodeError(self, CB_ERROR_BAD_TIME);
	CBReleaseObject(self);
}
Ejemplo n.º 6
0
void CBThreadPoolQueueThreadLoop(void * vself){
	CBWorker * self = vself;
	CBMutexLock(self->queueMutex);
	for (;;) {
		while (self->queue.itemNum == 0 && !self->threadPoolQueue->shutdown)
			// Wait for more items to process. We require a loop because when the condition is signaled, the mutex is unlocked but may not be given to this thread. Another thread may use the mutex to clear the queue again, so check in a loop.
			CBConditionWait(self->waitCond, self->queueMutex);
		assert(self->queue.itemNum || self->threadPoolQueue->shutdown);
		// Check to see if the thread should terminate
		if (self->threadPoolQueue->shutdown){
			CBMutexUnlock(self->queueMutex);
			return;
		}
		// Process the next item.
		CBQueueItem * item = self->queue.start;
		item->active = true; // Prevent deletion.
		CBMutexUnlock(self->queueMutex);
		self->threadPoolQueue->process(self->threadPoolQueue, item);
		// Now we have finished with the item, remove it from the queue
		CBMutexLock(self->queueMutex);
		// Maybe we cleared the queue. Check that it hasn't been.
		if (!item->cleared) {
			self->queue.start = item->next;
			if (--self->queue.itemNum == 0){
				// Look for complete emptiness
				CBMutexLock(self->threadPoolQueue->finishMutex);
				bool empty = true;
				for (uint16_t x = 0; x < self->threadPoolQueue->numThreads; x++)
					if (self->threadPoolQueue->workers[x].queue.itemNum) {
						empty = false;
						break;
					}
				if (empty){
					self->threadPoolQueue->finished = true;
					CBConditionSignal(self->threadPoolQueue->finishCond);
				}
				CBMutexUnlock(self->threadPoolQueue->finishMutex);
			}
		}
		// Now we can destroy the item.
		self->threadPoolQueue->destroy(item);
		free(item);
	}
}
Ejemplo n.º 7
0
void CBDestroyNode(void * vself){
	CBNode * self = vself;
	// Exit thread.
	self->shutDownThread = true;
	CBMutexLock(self->messageProcessMutex);
	if (self->messageQueue == NULL)
		// The thread is waiting for messages so wake it.
		CBConditionSignal(self->messageProcessWaitCond);
	CBMutexUnlock(self->messageProcessMutex);
	CBThreadJoin(self->messageProcessThread);
	CBFreeBlockChainStorage(self->blockChainStorage);
	CBFreeAccounterStorage(self->accounterStorage);
	CBReleaseObject(self->validator);
	CBFreeMutex(self->blockAndTxMutex);
	CBFreeMutex(self->messageProcessMutex);
	CBFreeCondition(self->messageProcessWaitCond);
	CBFreeThread(self->messageProcessThread);
	CBDestroyNetworkCommunicator(vself);
}
Ejemplo n.º 8
0
void CBDestroyThreadPoolQueue(CBThreadPoolQueue * self){
	self->shutdown = true;
	for (uint16_t x = 0; x < self->numThreads; x++) {
		CBMutexLock(self->workers[x].queueMutex);
		if (self->workers[x].queue.itemNum == 0)
			// The thread is waiting for items, so wake it.
			CBConditionSignal(self->workers[x].waitCond);
		CBMutexUnlock(self->workers[x].queueMutex);
		CBThreadJoin(self->workers[x].thread);
		CBFreeThread(self->workers[x].thread);
		CBFreeCondition(self->workers[x].waitCond);
		CBFreeMutex(self->workers[x].queueMutex);
		// Free queue
		CBFreeQueue(&self->workers[x].queue, self->destroy);
	}
	CBFreeCondition(self->finishCond);
	CBFreeMutex(self->finishMutex);
	free(self->workers);
}
Ejemplo n.º 9
0
CBOnMessageReceivedAction CBNodeOnMessageReceived(CBNetworkCommunicator * comm, CBPeer * peer, CBMessage * message){
	CBNode * self = CBGetNode(comm);
	// Add message to queue
	CBRetainObject(message);
	CBRetainObject(peer);
	CBMutexLock(self->messageProcessMutex);
	if (self->messageQueue == NULL)
		self->messageQueue = self->messageQueueBack = malloc(sizeof(*self->messageQueueBack));
	else{
		self->messageQueueBack->next = malloc(sizeof(*self->messageQueueBack));
		self->messageQueueBack = self->messageQueueBack->next;
	}
	self->messageQueueBack->peer = peer;
	self->messageQueueBack->message = message;
	self->messageQueueBack->next = NULL;
	// Wakeup thread if this is the first in the queue
	if (self->messageQueue == self->messageQueueBack)
		// We have just added a block to the queue when there was not one before so wake-up the processing thread.
		CBConditionSignal(self->messageProcessWaitCond);
	CBMutexUnlock(self->messageProcessMutex);
	return CB_MESSAGE_ACTION_CONTINUE;
}
Ejemplo n.º 10
0
CBOnMessageReceivedAction CBNodeSendBlocksInvOrHeaders(CBNode * self, CBPeer * peer, CBGetBlocks * getBlocks, bool full){
	CBChainDescriptor * chainDesc = getBlocks->chainDescriptor;
	if (chainDesc->hashNum == 0)
		// Why do this?
		return CB_MESSAGE_ACTION_DISCONNECT;
	uint8_t branch;
	uint32_t blockIndex;
	// Go though the chain descriptor until a hash is found that we own
	bool found = false;
	// Lock block mutex for block chain access
	CBMutexLock(self->blockAndTxMutex);
	for (uint16_t x = 0; x < chainDesc->hashNum; x++) {
		CBErrBool exists = CBBlockChainStorageGetBlockLocation(CBGetNode(self)->validator, CBByteArrayGetData(chainDesc->hashes[x]), &branch, &blockIndex);
		if (exists == CB_ERROR) {
			CBMutexUnlock(self->blockAndTxMutex);
			return CBNodeReturnError(self, "Could not look for block with chain descriptor hash.");
		}
		if (exists == CB_TRUE) {
			// We have a block that we own.
			found = true;
			break;
		}
	}
	// Get the chain path for the main chain
	CBChainPath mainChainPath = CBValidatorGetMainChainPath(self->validator);
	CBChainPathPoint intersection;
	if (found){
		// Get the chain path for the block header we have found
		CBChainPath peerChainPath = CBValidatorGetChainPath(self->validator, branch, blockIndex);
		// Determine where the intersection is on the main chain
		intersection = CBValidatorGetChainIntersection(&mainChainPath, &peerChainPath);
	}else{
		// Bad chain?
		CBMutexUnlock(self->blockAndTxMutex);
		return CB_MESSAGE_ACTION_DISCONNECT;
	}
	CBMessage * message;
	// Now provide headers from this intersection up to 2000 blocks or block inventory items up to 500, the last one we have or the stopAtHash.
	for (uint16_t x = 0; x < (full ? 500 : 2000); x++) {
		// Check to see if we reached the last block in the main chain.
		if (intersection.chainPathIndex == 0
			&& intersection.blockIndex == mainChainPath.points[0].blockIndex) {
			if (x == 0){
				// The intersection is at the last block. The peer is up-to-date with us
				peer->upload = false;
				peer->upToDate = true;
				CBMutexUnlock(self->blockAndTxMutex);
				return CB_MESSAGE_ACTION_CONTINUE;
			}
			break;
		}
		// Move to the next block
		if (intersection.blockIndex == mainChainPath.points[intersection.chainPathIndex].blockIndex) {
			// Move to next branch
			intersection.chainPathIndex--;
			intersection.blockIndex = 0;
		}else
			// Move to the next block
			intersection.blockIndex++;
		// Get the hash
		uint8_t hash[32];
		if (! CBBlockChainStorageGetBlockHash(self->validator, mainChainPath.points[intersection.chainPathIndex].branch, intersection.blockIndex, hash)) {
			if (x != 0) CBReleaseObject(message);
			CBMutexUnlock(self->blockAndTxMutex);
			return CBNodeReturnError(self, "Could not obtain a hash for a block.");
		}
		// Check to see if we are at stopAtHash
		if (getBlocks->stopAtHash && memcmp(hash, CBByteArrayGetData(getBlocks->stopAtHash), 32) == 0){
			if (x == 0) {
				CBMutexUnlock(self->blockAndTxMutex);
				return CB_MESSAGE_ACTION_CONTINUE;
			}
			break;
		}
		if (x == 0){
			// Create inventory or block headers object to send to peer.
			if (full) {
				message = CBGetMessage(CBNewInventory());
				message->type = CB_MESSAGE_TYPE_INV;
			}else{
				message = CBGetMessage(CBNewBlockHeaders());
				message->type = CB_MESSAGE_TYPE_HEADERS;
			}
		}
		// Add block header or add inventory item
		if (full) {
			CBByteArray * hashObj = CBNewByteArrayWithDataCopy(hash, 32);
			char blkStr[CB_BLOCK_HASH_STR_SIZE];
			CBByteArrayToString(hashObj, 0, CB_BLOCK_HASH_STR_BYTES, blkStr, true);
			CBInventoryTakeInventoryItem(CBGetInventory(message), CBNewInventoryItem(CB_INVENTORY_ITEM_BLOCK, hashObj));
			CBReleaseObject(hashObj);
		}else
			CBBlockHeadersTakeBlockHeader(CBGetBlockHeaders(message), CBBlockChainStorageGetBlockHeader(self->validator, mainChainPath.points[intersection.chainPathIndex].branch, intersection.blockIndex));
	}
	CBMutexUnlock(self->blockAndTxMutex);
	// Send the message
	CBNodeSendMessageOnNetworkThread(CBGetNetworkCommunicator(self), peer, message, NULL);
	CBReleaseObject(message);
	// We are uploading to the peer
	peer->upload = true;
	return CB_MESSAGE_ACTION_CONTINUE;
}
Ejemplo n.º 11
0
void CBThreadPoolQueueWaitUntilFinished(CBThreadPoolQueue * self) {
	CBMutexLock(self->finishMutex);
	if (!self->finished) // Do not check in loop as no threads ought to add to the queue whilst waiting to finish.
		CBConditionWait(self->finishCond, self->finishMutex);
	CBMutexUnlock(self->finishMutex);
}