MessagingArea *
MessagingArea::Create(sem_id lockSem, sem_id counterSem)
{
	// allocate the object on the heap
	MessagingArea *area = new(nothrow) MessagingArea;
	if (!area)
		return NULL;

	// create the area
	area->fID = create_area("messaging", (void**)&area->fHeader,
		B_ANY_KERNEL_ADDRESS, kMessagingAreaSize, B_FULL_LOCK,
		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA);
	if (area->fID < 0) {
		delete area;
		return NULL;
	}

	// finish the initialization of the object
	area->fSize = kMessagingAreaSize;
	area->fLockSem = lockSem;
	area->fCounterSem = counterSem;
	area->fNextArea = NULL;
	area->InitHeader();

	return area;
}
status_t
MessagingService::UnregisterService()
{
	// check, if the team calling this function is indeed the server team
	thread_info threadInfo;
	status_t error = get_thread_info(find_thread(NULL), &threadInfo);
	if (error != B_OK)
		return error;

	if (threadInfo.team != fServerTeam)
		return B_BAD_VALUE;

	// delete all areas
	while (fFirstArea) {
		MessagingArea *area = fFirstArea;
		fFirstArea = area->NextArea();
		delete area;
	}
	fLastArea = NULL;

	// unset the other members
	fLockSem = -1;
	fCounterSem = -1;
	fServerTeam = -1;

	return B_OK;
}
status_t
MessagingService::SendMessage(const void *message, int32 messageSize,
	const messaging_target *targets, int32 targetCount)
{
PRINT(("MessagingService::SendMessage(%p, %ld, %p, %ld)\n", message,
messageSize, targets, targetCount));
	if (!message || messageSize <= 0 || !targets || targetCount <= 0)
		return B_BAD_VALUE;

	int32 dataSize = sizeof(messaging_command_send_message)
		+ targetCount * sizeof(messaging_target) + messageSize;

	// allocate space for the command
	MessagingArea *area;
	void *data;
	bool wasEmpty;
	status_t error = _AllocateCommand(MESSAGING_COMMAND_SEND_MESSAGE, dataSize,
		area, data, wasEmpty);
	if (error != B_OK) {
		PRINT(("MessagingService::SendMessage(): Failed to allocate space for "
			"send message command.\n"));
		return error;
	}
PRINT(("  Allocated space for send message command: area: %p, data: %p, "
"wasEmpty: %d\n", area, data, wasEmpty));

	// prepare the command
	messaging_command_send_message *command
		= (messaging_command_send_message*)data;
	command->message_size = messageSize;
	command->target_count = targetCount;
	memcpy(command->targets, targets, sizeof(messaging_target) * targetCount);
	memcpy((char*)command + (dataSize - messageSize), message, messageSize);

	// shoot
	area->Unlock();
	if (wasEmpty)
		area->CommitCommand();

	return B_OK;
}
// _CommandProcessor
int32
MessagingService::_CommandProcessor()
{
	bool commandWaiting = false;
	while (!fTerminating) {
		// wait for the next command
		if (!commandWaiting) {
			status_t error = acquire_sem(fCounterSem);
			if (error != B_OK)
				continue;
		} else
			commandWaiting = false;

		// get it from the first area
		MessagingArea *area = fFirstArea;
		area->Lock();
		while (area->CountCommands() > 0) {
			const messaging_command *command = area->PopCommand();
			if (!command) {
				// something's seriously wrong
				ERROR("MessagingService::_CommandProcessor(): area %p (%"
					B_PRId32 ") has command count %" B_PRId32 ", but doesn't "
					"return any more commands.", area, area->ID(),
					area->CountCommands());
				break;
			}
PRINT("MessagingService::_CommandProcessor(): got command %" B_PRIu32 "\n",
command->command);

			// dispatch the command
			MessagingCommandHandler *handler
				= _GetCommandHandler(command->command);
			if (handler) {
				handler->HandleMessagingCommand(command->command, command->data,
					command->size - sizeof(messaging_command));
			} else {
				WARNING("MessagingService::_CommandProcessor(): No handler "
					"found for command %" B_PRIu32 "\n", command->command);
			}
		}

		// there is a new area we don't know yet
		if (!area->NextArea() && area->NextKernelAreaID() >= 0) {
			// create it
			MessagingArea *nextArea;
			status_t error = MessagingArea::Create(area->NextKernelAreaID(),
				fLockSem, fCounterSem, nextArea);
			if (error == B_OK) {
				area->SetNextArea(nextArea);
				commandWaiting = true;
			} else {
				// Bad, but what can we do?
				ERROR("MessagingService::_CommandProcessor(): Failed to clone "
					"kernel area %" B_PRId32 ": %s\n", area->NextKernelAreaID(),
					strerror(error));
			}

		}

		// if the current area is empty and there is a next one, we discard the
		// current one
		if (area->NextArea() && area->CountCommands() == 0) {
			fFirstArea = area->NextArea();
			area->Discard();
			area->Unlock();
			delete area;
		} else {
			area->Unlock();
		}
	}

	return 0;
}