xref: /haiku/src/system/kernel/messaging/MessagingService.cpp (revision a8f9741c8c2815234e87b78167738057b976b537)
12d690920SAxel Dörfler /*
21462a082SIngo Weinhold  * Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
32d690920SAxel Dörfler  * Distributed under the terms of the MIT License.
42d690920SAxel Dörfler  */
52d690920SAxel Dörfler 
62d690920SAxel Dörfler // kernel-side implementation of the messaging service
72d690920SAxel Dörfler 
82d690920SAxel Dörfler #include <new>
92d690920SAxel Dörfler 
102d690920SAxel Dörfler #include <AutoDeleter.h>
112d690920SAxel Dörfler #include <KernelExport.h>
122d690920SAxel Dörfler #include <KMessage.h>
132d690920SAxel Dörfler #include <messaging.h>
142d690920SAxel Dörfler #include <MessagingServiceDefs.h>
152d690920SAxel Dörfler 
162d690920SAxel Dörfler #include "MessagingService.h"
172d690920SAxel Dörfler 
182d690920SAxel Dörfler //#define TRACE_MESSAGING_SERVICE
192d690920SAxel Dörfler #ifdef TRACE_MESSAGING_SERVICE
202d690920SAxel Dörfler #	define PRINT(x) dprintf x
212d690920SAxel Dörfler #else
222d690920SAxel Dörfler #	define PRINT(x) ;
232d690920SAxel Dörfler #endif
242d690920SAxel Dörfler 
251462a082SIngo Weinhold 
262d690920SAxel Dörfler using namespace std;
272d690920SAxel Dörfler 
282d690920SAxel Dörfler static MessagingService *sMessagingService = NULL;
292d690920SAxel Dörfler 
302d690920SAxel Dörfler static const int32 kMessagingAreaSize = B_PAGE_SIZE * 4;
312d690920SAxel Dörfler 
322d690920SAxel Dörfler 
331462a082SIngo Weinhold // #pragma mark - MessagingArea
342d690920SAxel Dörfler 
352d690920SAxel Dörfler 
362d690920SAxel Dörfler // constructor
372d690920SAxel Dörfler MessagingArea::MessagingArea()
382d690920SAxel Dörfler {
392d690920SAxel Dörfler }
402d690920SAxel Dörfler 
411462a082SIngo Weinhold 
422d690920SAxel Dörfler // destructor
432d690920SAxel Dörfler MessagingArea::~MessagingArea()
442d690920SAxel Dörfler {
452d690920SAxel Dörfler 	if (fID >= 0)
462d690920SAxel Dörfler 		delete_area(fID);
472d690920SAxel Dörfler }
482d690920SAxel Dörfler 
491462a082SIngo Weinhold 
502d690920SAxel Dörfler // Create
512d690920SAxel Dörfler MessagingArea *
522d690920SAxel Dörfler MessagingArea::Create(sem_id lockSem, sem_id counterSem)
532d690920SAxel Dörfler {
542d690920SAxel Dörfler 	// allocate the object on the heap
552d690920SAxel Dörfler 	MessagingArea *area = new(nothrow) MessagingArea;
562d690920SAxel Dörfler 	if (!area)
572d690920SAxel Dörfler 		return NULL;
582d690920SAxel Dörfler 
592d690920SAxel Dörfler 	// create the area
602d690920SAxel Dörfler 	area->fID = create_area("messaging", (void**)&area->fHeader,
612d690920SAxel Dörfler 		B_ANY_KERNEL_ADDRESS, kMessagingAreaSize, B_FULL_LOCK,
622d690920SAxel Dörfler 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA);
632d690920SAxel Dörfler 	if (area->fID < 0) {
642d690920SAxel Dörfler 		delete area;
652d690920SAxel Dörfler 		return NULL;
662d690920SAxel Dörfler 	}
672d690920SAxel Dörfler 
682d690920SAxel Dörfler 	// finish the initialization of the object
692d690920SAxel Dörfler 	area->fSize = kMessagingAreaSize;
702d690920SAxel Dörfler 	area->fLockSem = lockSem;
712d690920SAxel Dörfler 	area->fCounterSem = counterSem;
722d690920SAxel Dörfler 	area->fNextArea = NULL;
732d690920SAxel Dörfler 	area->InitHeader();
742d690920SAxel Dörfler 
752d690920SAxel Dörfler 	return area;
762d690920SAxel Dörfler }
772d690920SAxel Dörfler 
781462a082SIngo Weinhold 
792d690920SAxel Dörfler // InitHeader
802d690920SAxel Dörfler void
812d690920SAxel Dörfler MessagingArea::InitHeader()
822d690920SAxel Dörfler {
832d690920SAxel Dörfler 	fHeader->lock_counter = 1;			// create locked
842d690920SAxel Dörfler 	fHeader->size = fSize;
852d690920SAxel Dörfler 	fHeader->kernel_area = fID;
862d690920SAxel Dörfler 	fHeader->next_kernel_area = (fNextArea ? fNextArea->ID() : -1);
872d690920SAxel Dörfler 	fHeader->command_count = 0;
882d690920SAxel Dörfler 	fHeader->first_command = 0;
892d690920SAxel Dörfler 	fHeader->last_command = 0;
902d690920SAxel Dörfler }
912d690920SAxel Dörfler 
921462a082SIngo Weinhold 
932d690920SAxel Dörfler // CheckCommandSize
942d690920SAxel Dörfler bool
952d690920SAxel Dörfler MessagingArea::CheckCommandSize(int32 dataSize)
962d690920SAxel Dörfler {
972d690920SAxel Dörfler 	int32 size = sizeof(messaging_command) + dataSize;
982d690920SAxel Dörfler 
992d690920SAxel Dörfler 	return (dataSize >= 0
1002d690920SAxel Dörfler 		&& size <= kMessagingAreaSize - (int32)sizeof(messaging_area_header));
1012d690920SAxel Dörfler }
1022d690920SAxel Dörfler 
1031462a082SIngo Weinhold 
1042d690920SAxel Dörfler // Lock
1052d690920SAxel Dörfler bool
1062d690920SAxel Dörfler MessagingArea::Lock()
1072d690920SAxel Dörfler {
1082d690920SAxel Dörfler 	// benaphore-like locking
1092d690920SAxel Dörfler 	if (atomic_add(&fHeader->lock_counter, 1) == 0)
1102d690920SAxel Dörfler 		return true;
1112d690920SAxel Dörfler 
1122d690920SAxel Dörfler 	return (acquire_sem(fLockSem) == B_OK);
1132d690920SAxel Dörfler }
1142d690920SAxel Dörfler 
1151462a082SIngo Weinhold 
1162d690920SAxel Dörfler // Unlock
1172d690920SAxel Dörfler void
1182d690920SAxel Dörfler MessagingArea::Unlock()
1192d690920SAxel Dörfler {
1202d690920SAxel Dörfler 	if (atomic_add(&fHeader->lock_counter, -1) > 1)
1212d690920SAxel Dörfler 		release_sem(fLockSem);
1222d690920SAxel Dörfler }
1232d690920SAxel Dörfler 
1241462a082SIngo Weinhold 
1252d690920SAxel Dörfler // ID
1262d690920SAxel Dörfler area_id
1272d690920SAxel Dörfler MessagingArea::ID() const
1282d690920SAxel Dörfler {
1292d690920SAxel Dörfler 	return fID;
1302d690920SAxel Dörfler }
1312d690920SAxel Dörfler 
1321462a082SIngo Weinhold 
1332d690920SAxel Dörfler // Size
1342d690920SAxel Dörfler int32
1352d690920SAxel Dörfler MessagingArea::Size() const
1362d690920SAxel Dörfler {
1372d690920SAxel Dörfler 	return fSize;
1382d690920SAxel Dörfler }
1392d690920SAxel Dörfler 
1401462a082SIngo Weinhold 
1412d690920SAxel Dörfler // AllocateCommand
1422d690920SAxel Dörfler void *
1432d690920SAxel Dörfler MessagingArea::AllocateCommand(uint32 commandWhat, int32 dataSize,
1442d690920SAxel Dörfler 	bool &wasEmpty)
1452d690920SAxel Dörfler {
1462d690920SAxel Dörfler 	int32 size = sizeof(messaging_command) + dataSize;
1472d690920SAxel Dörfler 
1482d690920SAxel Dörfler 	if (dataSize < 0 || size > fSize - (int32)sizeof(messaging_area_header))
1492d690920SAxel Dörfler 		return NULL;
1502d690920SAxel Dörfler 
1512d690920SAxel Dörfler 	// the area is used as a ring buffer
1522d690920SAxel Dörfler 	int32 startOffset = sizeof(messaging_area_header);
1532d690920SAxel Dörfler 
1542d690920SAxel Dörfler 	// the simple case first: the area is empty
1552d690920SAxel Dörfler 	int32 commandOffset;
1562d690920SAxel Dörfler 	wasEmpty = (fHeader->command_count == 0);
1572d690920SAxel Dörfler 	if (wasEmpty) {
1582d690920SAxel Dörfler 		commandOffset = startOffset;
1592d690920SAxel Dörfler 
1602d690920SAxel Dörfler 		// update the header
1612d690920SAxel Dörfler 		fHeader->command_count++;
1622d690920SAxel Dörfler 		fHeader->first_command = fHeader->last_command = commandOffset;
1632d690920SAxel Dörfler 	} else {
1642d690920SAxel Dörfler 		int32 firstCommandOffset = fHeader->first_command;
1652d690920SAxel Dörfler 		int32 lastCommandOffset = fHeader->last_command;
1662d690920SAxel Dörfler 		int32 firstCommandSize;
1672d690920SAxel Dörfler 		int32 lastCommandSize;
1682d690920SAxel Dörfler 		messaging_command *firstCommand = _CheckCommand(firstCommandOffset,
1692d690920SAxel Dörfler 			firstCommandSize);
1702d690920SAxel Dörfler 		messaging_command *lastCommand = _CheckCommand(lastCommandOffset,
1712d690920SAxel Dörfler 			lastCommandSize);
1722d690920SAxel Dörfler 		if (!firstCommand || !lastCommand) {
1732d690920SAxel Dörfler 			// something has been screwed up
1742d690920SAxel Dörfler 			return NULL;
1752d690920SAxel Dörfler 		}
1762d690920SAxel Dörfler 
1772d690920SAxel Dörfler 		// find space for the command
1782d690920SAxel Dörfler 		if (firstCommandOffset < lastCommandOffset) {
1792d690920SAxel Dörfler 			// not wrapped
1802d690920SAxel Dörfler 			// try to allocate after the last command
1812d690920SAxel Dörfler 			if (size <= fSize - (lastCommandOffset + lastCommandSize)) {
1822d690920SAxel Dörfler 				commandOffset = (lastCommandOffset + lastCommandSize);
1832d690920SAxel Dörfler 			} else {
1842d690920SAxel Dörfler 				// is there enough space before the first command?
1852d690920SAxel Dörfler 				if (size > firstCommandOffset - startOffset)
1862d690920SAxel Dörfler 					return NULL;
1872d690920SAxel Dörfler 				commandOffset = startOffset;
1882d690920SAxel Dörfler 			}
1892d690920SAxel Dörfler 		} else {
1902d690920SAxel Dörfler 			// wrapped: we can only allocate between the last and the first
1912d690920SAxel Dörfler 			// command
1922d690920SAxel Dörfler 			commandOffset = lastCommandOffset + lastCommandSize;
1932d690920SAxel Dörfler 			if (size > firstCommandOffset - commandOffset)
1942d690920SAxel Dörfler 				return NULL;
1952d690920SAxel Dörfler 		}
1962d690920SAxel Dörfler 
1972d690920SAxel Dörfler 		// update the header and the last command
1982d690920SAxel Dörfler 		fHeader->command_count++;
1992d690920SAxel Dörfler 		lastCommand->next_command = fHeader->last_command = commandOffset;
2002d690920SAxel Dörfler 	}
2012d690920SAxel Dörfler 
2022d690920SAxel Dörfler 	// init the command
2032d690920SAxel Dörfler 	messaging_command *command
2042d690920SAxel Dörfler 		= (messaging_command*)((char*)fHeader + commandOffset);
2052d690920SAxel Dörfler 	command->next_command = 0;
2062d690920SAxel Dörfler 	command->command = commandWhat;
2072d690920SAxel Dörfler 	command->size = size;
2082d690920SAxel Dörfler 
2092d690920SAxel Dörfler 	return command->data;
2102d690920SAxel Dörfler }
2112d690920SAxel Dörfler 
2121462a082SIngo Weinhold 
2132d690920SAxel Dörfler // CommitCommand
2142d690920SAxel Dörfler void
2152d690920SAxel Dörfler MessagingArea::CommitCommand()
2162d690920SAxel Dörfler {
2172d690920SAxel Dörfler 	// TODO: If invoked while locked, we should supply B_DO_NOT_RESCHEDULE.
2182d690920SAxel Dörfler 	release_sem(fCounterSem);
2192d690920SAxel Dörfler }
2202d690920SAxel Dörfler 
2211462a082SIngo Weinhold 
2222d690920SAxel Dörfler // SetNextArea
2232d690920SAxel Dörfler void
2242d690920SAxel Dörfler MessagingArea::SetNextArea(MessagingArea *area)
2252d690920SAxel Dörfler {
2262d690920SAxel Dörfler 	fNextArea = area;
2272d690920SAxel Dörfler 	fHeader->next_kernel_area = (fNextArea ? fNextArea->ID() : -1);
2282d690920SAxel Dörfler }
2292d690920SAxel Dörfler 
2301462a082SIngo Weinhold 
2312d690920SAxel Dörfler // NextArea
2322d690920SAxel Dörfler MessagingArea *
2332d690920SAxel Dörfler MessagingArea::NextArea() const
2342d690920SAxel Dörfler {
2352d690920SAxel Dörfler 	return fNextArea;
2362d690920SAxel Dörfler }
2372d690920SAxel Dörfler 
2381462a082SIngo Weinhold 
2392d690920SAxel Dörfler // _CheckCommand
2402d690920SAxel Dörfler messaging_command *
2412d690920SAxel Dörfler MessagingArea::_CheckCommand(int32 offset, int32 &size)
2422d690920SAxel Dörfler {
2432d690920SAxel Dörfler 	// check offset
2442d690920SAxel Dörfler 	if (offset < (int32)sizeof(messaging_area_header)
2452d690920SAxel Dörfler 		|| offset + (int32)sizeof(messaging_command) > fSize
2462d690920SAxel Dörfler 		|| (offset & 0x3)) {
2472d690920SAxel Dörfler 		return NULL;
2482d690920SAxel Dörfler 	}
2492d690920SAxel Dörfler 
2502d690920SAxel Dörfler 	// get and check size
2512d690920SAxel Dörfler 	messaging_command *command = (messaging_command*)((char*)fHeader + offset);
2522d690920SAxel Dörfler 	size = command->size;
2532d690920SAxel Dörfler 	if (size < (int32)sizeof(messaging_command))
2542d690920SAxel Dörfler 		return NULL;
2552d690920SAxel Dörfler 	size = (size + 3) & 0x3;	// align
2562d690920SAxel Dörfler 	if (offset + size > fSize)
2572d690920SAxel Dörfler 		return NULL;
2582d690920SAxel Dörfler 
2592d690920SAxel Dörfler 	return command;
2602d690920SAxel Dörfler }
2612d690920SAxel Dörfler 
2622d690920SAxel Dörfler 
2631462a082SIngo Weinhold // #pragma mark - MessagingService
2641462a082SIngo Weinhold 
2652d690920SAxel Dörfler 
2662d690920SAxel Dörfler // constructor
2672d690920SAxel Dörfler MessagingService::MessagingService()
2682d690920SAxel Dörfler 	: fLock("messaging service"),
2692d690920SAxel Dörfler 	  fFirstArea(NULL),
2702d690920SAxel Dörfler 	  fLastArea(NULL)
2712d690920SAxel Dörfler {
2722d690920SAxel Dörfler }
2732d690920SAxel Dörfler 
2741462a082SIngo Weinhold 
2752d690920SAxel Dörfler // destructor
2762d690920SAxel Dörfler MessagingService::~MessagingService()
2772d690920SAxel Dörfler {
2782d690920SAxel Dörfler 	// Should actually never be called. Once created the service stays till the
2792d690920SAxel Dörfler 	// bitter end.
2802d690920SAxel Dörfler }
2812d690920SAxel Dörfler 
2821462a082SIngo Weinhold 
2832d690920SAxel Dörfler // InitCheck
2842d690920SAxel Dörfler status_t
2852d690920SAxel Dörfler MessagingService::InitCheck() const
2862d690920SAxel Dörfler {
2872d690920SAxel Dörfler 	if (fLock.Sem() < 0)
2882d690920SAxel Dörfler 		return fLock.Sem();
2892d690920SAxel Dörfler 	return B_OK;
2902d690920SAxel Dörfler }
2912d690920SAxel Dörfler 
2921462a082SIngo Weinhold 
2932d690920SAxel Dörfler // Lock
2942d690920SAxel Dörfler bool
2952d690920SAxel Dörfler MessagingService::Lock()
2962d690920SAxel Dörfler {
2972d690920SAxel Dörfler 	return fLock.Lock();
2982d690920SAxel Dörfler }
2992d690920SAxel Dörfler 
3001462a082SIngo Weinhold 
3012d690920SAxel Dörfler // Unlock
3022d690920SAxel Dörfler void
3032d690920SAxel Dörfler MessagingService::Unlock()
3042d690920SAxel Dörfler {
3052d690920SAxel Dörfler 	fLock.Unlock();
3062d690920SAxel Dörfler }
3072d690920SAxel Dörfler 
3081462a082SIngo Weinhold 
3092d690920SAxel Dörfler // RegisterService
3102d690920SAxel Dörfler status_t
3112d690920SAxel Dörfler MessagingService::RegisterService(sem_id lockSem, sem_id counterSem,
3122d690920SAxel Dörfler 	area_id &areaID)
3132d690920SAxel Dörfler {
3142d690920SAxel Dörfler 	// check, if a service is already registered
3152d690920SAxel Dörfler 	if (fFirstArea)
3162d690920SAxel Dörfler 		return B_BAD_VALUE;
3172d690920SAxel Dörfler 
3182d690920SAxel Dörfler 	status_t error = B_OK;
3192d690920SAxel Dörfler 
3202d690920SAxel Dörfler 	// check, if the semaphores are valid and belong to the calling team
3212d690920SAxel Dörfler 	thread_info threadInfo;
3222d690920SAxel Dörfler 	error = get_thread_info(find_thread(NULL), &threadInfo);
3232d690920SAxel Dörfler 
3242d690920SAxel Dörfler 	sem_info lockSemInfo;
3252d690920SAxel Dörfler 	if (error == B_OK)
3262d690920SAxel Dörfler 		error = get_sem_info(lockSem, &lockSemInfo);
3272d690920SAxel Dörfler 
3282d690920SAxel Dörfler 	sem_info counterSemInfo;
3292d690920SAxel Dörfler 	if (error == B_OK)
3302d690920SAxel Dörfler 		error = get_sem_info(counterSem, &counterSemInfo);
3312d690920SAxel Dörfler 
3322d690920SAxel Dörfler 	if (error != B_OK)
3332d690920SAxel Dörfler 		return error;
3342d690920SAxel Dörfler 
3352d690920SAxel Dörfler 	if (threadInfo.team != lockSemInfo.team
3362d690920SAxel Dörfler 		|| threadInfo.team != counterSemInfo.team) {
3372d690920SAxel Dörfler 		return B_BAD_VALUE;
3382d690920SAxel Dörfler 	}
3392d690920SAxel Dörfler 
3402d690920SAxel Dörfler 	// create an area
3412d690920SAxel Dörfler 	fFirstArea = fLastArea = MessagingArea::Create(lockSem, counterSem);
3422d690920SAxel Dörfler 	if (!fFirstArea)
3432d690920SAxel Dörfler 		return B_NO_MEMORY;
3442d690920SAxel Dörfler 
3452d690920SAxel Dörfler 	areaID = fFirstArea->ID();
3462d690920SAxel Dörfler 	fFirstArea->Unlock();
3472d690920SAxel Dörfler 
3482d690920SAxel Dörfler 	// store the server team and the semaphores
3492d690920SAxel Dörfler 	fServerTeam = threadInfo.team;
3502d690920SAxel Dörfler 	fLockSem = lockSem;
3512d690920SAxel Dörfler 	fCounterSem = counterSem;
3522d690920SAxel Dörfler 
3532d690920SAxel Dörfler 	return B_OK;
3542d690920SAxel Dörfler }
3552d690920SAxel Dörfler 
3561462a082SIngo Weinhold 
3572d690920SAxel Dörfler // UnregisterService
3582d690920SAxel Dörfler status_t
3592d690920SAxel Dörfler MessagingService::UnregisterService()
3602d690920SAxel Dörfler {
3612d690920SAxel Dörfler 	// check, if the team calling this function is indeed the server team
3622d690920SAxel Dörfler 	thread_info threadInfo;
3632d690920SAxel Dörfler 	status_t error = get_thread_info(find_thread(NULL), &threadInfo);
3642d690920SAxel Dörfler 	if (error != B_OK)
3652d690920SAxel Dörfler 		return error;
3662d690920SAxel Dörfler 
3672d690920SAxel Dörfler 	if (threadInfo.team != fServerTeam)
3682d690920SAxel Dörfler 		return B_BAD_VALUE;
3692d690920SAxel Dörfler 
3702d690920SAxel Dörfler 	// delete all areas
3712d690920SAxel Dörfler 	while (fFirstArea) {
3722d690920SAxel Dörfler 		MessagingArea *area = fFirstArea;
3732d690920SAxel Dörfler 		fFirstArea = area->NextArea();
3742d690920SAxel Dörfler 		delete area;
3752d690920SAxel Dörfler 	}
3762d690920SAxel Dörfler 	fLastArea = NULL;
3772d690920SAxel Dörfler 
3782d690920SAxel Dörfler 	// unset the other members
3792d690920SAxel Dörfler 	fLockSem = -1;
380*a8f9741cSMichael Lotz 	fCounterSem = -1;
3812d690920SAxel Dörfler 	fServerTeam = -1;
3822d690920SAxel Dörfler 
3832d690920SAxel Dörfler 	return B_OK;
3842d690920SAxel Dörfler }
3852d690920SAxel Dörfler 
3861462a082SIngo Weinhold 
3872d690920SAxel Dörfler // SendMessage
3882d690920SAxel Dörfler status_t
3892d690920SAxel Dörfler MessagingService::SendMessage(const void *message, int32 messageSize,
3902d690920SAxel Dörfler 	const messaging_target *targets, int32 targetCount)
3912d690920SAxel Dörfler {
3922d690920SAxel Dörfler PRINT(("MessagingService::SendMessage(%p, %ld, %p, %ld)\n", message,
3932d690920SAxel Dörfler messageSize, targets, targetCount));
3942d690920SAxel Dörfler 	if (!message || messageSize <= 0 || !targets || targetCount <= 0)
3952d690920SAxel Dörfler 		return B_BAD_VALUE;
3962d690920SAxel Dörfler 
3972d690920SAxel Dörfler 	int32 dataSize = sizeof(messaging_command_send_message)
3982d690920SAxel Dörfler 		+ targetCount * sizeof(messaging_target) + messageSize;
3992d690920SAxel Dörfler 
4002d690920SAxel Dörfler 	// allocate space for the command
4012d690920SAxel Dörfler 	MessagingArea *area;
4022d690920SAxel Dörfler 	void *data;
4032d690920SAxel Dörfler 	bool wasEmpty;
4042d690920SAxel Dörfler 	status_t error = _AllocateCommand(MESSAGING_COMMAND_SEND_MESSAGE, dataSize,
4052d690920SAxel Dörfler 		area, data, wasEmpty);
4062d690920SAxel Dörfler 	if (error != B_OK) {
4072d690920SAxel Dörfler 		PRINT(("MessagingService::SendMessage(): Failed to allocate space for "
4082d690920SAxel Dörfler 			"send message command.\n"));
4092d690920SAxel Dörfler 		return error;
4102d690920SAxel Dörfler 	}
4112d690920SAxel Dörfler PRINT(("  Allocated space for send message command: area: %p, data: %p, "
4122d690920SAxel Dörfler "wasEmpty: %d\n", area, data, wasEmpty));
4132d690920SAxel Dörfler 
4142d690920SAxel Dörfler 	// prepare the command
4152d690920SAxel Dörfler 	messaging_command_send_message *command
4162d690920SAxel Dörfler 		= (messaging_command_send_message*)data;
4172d690920SAxel Dörfler 	command->message_size = messageSize;
4182d690920SAxel Dörfler 	command->target_count = targetCount;
4192d690920SAxel Dörfler 	memcpy(command->targets, targets, sizeof(messaging_target) * targetCount);
4202d690920SAxel Dörfler 	memcpy((char*)command + (dataSize - messageSize), message, messageSize);
4212d690920SAxel Dörfler 
4222d690920SAxel Dörfler 	// shoot
4232d690920SAxel Dörfler 	area->Unlock();
4242d690920SAxel Dörfler 	if (wasEmpty)
4252d690920SAxel Dörfler 		area->CommitCommand();
4262d690920SAxel Dörfler 
4272d690920SAxel Dörfler 	return B_OK;
4282d690920SAxel Dörfler }
4292d690920SAxel Dörfler 
4301462a082SIngo Weinhold 
4312d690920SAxel Dörfler // _AllocateCommand
4322d690920SAxel Dörfler status_t
4332d690920SAxel Dörfler MessagingService::_AllocateCommand(int32 commandWhat, int32 size,
4342d690920SAxel Dörfler 	MessagingArea *&area, void *&data, bool &wasEmpty)
4352d690920SAxel Dörfler {
4362d690920SAxel Dörfler 	if (!fFirstArea)
4372d690920SAxel Dörfler 		return B_NO_INIT;
4382d690920SAxel Dörfler 
4392d690920SAxel Dörfler 	if (!MessagingArea::CheckCommandSize(size))
4402d690920SAxel Dörfler 		return B_BAD_VALUE;
4412d690920SAxel Dörfler 
4422d690920SAxel Dörfler 	// delete the discarded areas (save one)
4432d690920SAxel Dörfler 	ObjectDeleter<MessagingArea> discardedAreaDeleter;
4442d690920SAxel Dörfler 	MessagingArea *discardedArea = NULL;
4452d690920SAxel Dörfler 	while (fFirstArea != fLastArea) {
4462d690920SAxel Dörfler 		area = fFirstArea;
4472d690920SAxel Dörfler 		area->Lock();
4482d690920SAxel Dörfler 		if (area->Size() != 0) {
4492d690920SAxel Dörfler 			area->Unlock();
4502d690920SAxel Dörfler 			break;
4512d690920SAxel Dörfler 		}
4522d690920SAxel Dörfler 
4532d690920SAxel Dörfler 		PRINT(("MessagingService::_AllocateCommand(): Discarding area: %p\n",
4542d690920SAxel Dörfler 			area));
4552d690920SAxel Dörfler 
4562d690920SAxel Dörfler 		fFirstArea = area->NextArea();
4572d690920SAxel Dörfler 		area->SetNextArea(NULL);
4582d690920SAxel Dörfler 		discardedArea = area;
4592d690920SAxel Dörfler 		discardedAreaDeleter.SetTo(area);
4602d690920SAxel Dörfler 	}
4612d690920SAxel Dörfler 
4622d690920SAxel Dörfler 	// allocate space for the command in the last area
4632d690920SAxel Dörfler 	area = fLastArea;
4642d690920SAxel Dörfler 	area->Lock();
4652d690920SAxel Dörfler 	data = area->AllocateCommand(commandWhat, size, wasEmpty);
4662d690920SAxel Dörfler 
4672d690920SAxel Dörfler 	if (!data) {
4682d690920SAxel Dörfler 		// not enough space in the last area: create a new area or reuse a
4692d690920SAxel Dörfler 		// discarded one
4702d690920SAxel Dörfler 		if (discardedArea) {
4712d690920SAxel Dörfler 			area = discardedAreaDeleter.Detach();
4722d690920SAxel Dörfler 			area->InitHeader();
4732d690920SAxel Dörfler 			PRINT(("MessagingService::_AllocateCommand(): Not enough space "
4742d690920SAxel Dörfler 				"left in current area. Recycling discarded one: %p\n", area));
4752d690920SAxel Dörfler 		} else {
4762d690920SAxel Dörfler 			area = MessagingArea::Create(fLockSem, fCounterSem);
4772d690920SAxel Dörfler 			PRINT(("MessagingService::_AllocateCommand(): Not enough space "
4782d690920SAxel Dörfler 				"left in current area. Allocated new one: %p\n", area));
4792d690920SAxel Dörfler 		}
4802d690920SAxel Dörfler 		if (!area) {
4812d690920SAxel Dörfler 			fLastArea->Unlock();
4822d690920SAxel Dörfler 			return B_NO_MEMORY;
4832d690920SAxel Dörfler 		}
4842d690920SAxel Dörfler 
4852d690920SAxel Dörfler 		// add the new area
4862d690920SAxel Dörfler 		fLastArea->SetNextArea(area);
4872d690920SAxel Dörfler 		fLastArea->Unlock();
4882d690920SAxel Dörfler 		fLastArea = area;
4892d690920SAxel Dörfler 
4902d690920SAxel Dörfler 		// allocate space for the command
4912d690920SAxel Dörfler 		data = area->AllocateCommand(commandWhat, size, wasEmpty);
4922d690920SAxel Dörfler 
4932d690920SAxel Dörfler 		if (!data) {
4942d690920SAxel Dörfler 			// that should never happen
4952d690920SAxel Dörfler 			area->Unlock();
4962d690920SAxel Dörfler 			return B_NO_MEMORY;
4972d690920SAxel Dörfler 		}
4982d690920SAxel Dörfler 	}
4992d690920SAxel Dörfler 
5002d690920SAxel Dörfler 	return B_OK;
5012d690920SAxel Dörfler }
5022d690920SAxel Dörfler 
5031462a082SIngo Weinhold 
5041462a082SIngo Weinhold // #pragma mark - kernel private
5051462a082SIngo Weinhold 
5061462a082SIngo Weinhold 
5071462a082SIngo Weinhold // send_message
5081462a082SIngo Weinhold status_t
5091462a082SIngo Weinhold send_message(const void *message, int32 messageSize,
5101462a082SIngo Weinhold 	const messaging_target *targets, int32 targetCount)
5111462a082SIngo Weinhold {
5121462a082SIngo Weinhold 	// check, if init_messaging_service() has been called yet
5131462a082SIngo Weinhold 	if (!sMessagingService)
5141462a082SIngo Weinhold 		return B_NO_INIT;
5151462a082SIngo Weinhold 
5161462a082SIngo Weinhold 	if (!sMessagingService->Lock())
5171462a082SIngo Weinhold 		return B_BAD_VALUE;
5181462a082SIngo Weinhold 
5191462a082SIngo Weinhold 	status_t error = sMessagingService->SendMessage(message, messageSize,
5201462a082SIngo Weinhold 		targets, targetCount);
5211462a082SIngo Weinhold 
5221462a082SIngo Weinhold 	sMessagingService->Unlock();
5231462a082SIngo Weinhold 
5241462a082SIngo Weinhold 	return error;
5251462a082SIngo Weinhold }
5261462a082SIngo Weinhold 
5271462a082SIngo Weinhold 
5281462a082SIngo Weinhold // send_message
5291462a082SIngo Weinhold status_t
5301462a082SIngo Weinhold send_message(const KMessage *message, const messaging_target *targets,
5311462a082SIngo Weinhold 	int32 targetCount)
5321462a082SIngo Weinhold {
5331462a082SIngo Weinhold 	if (!message)
5341462a082SIngo Weinhold 		return B_BAD_VALUE;
5351462a082SIngo Weinhold 
5361462a082SIngo Weinhold 	return send_message(message->Buffer(), message->ContentSize(), targets,
5371462a082SIngo Weinhold 		targetCount);
5381462a082SIngo Weinhold }
5391462a082SIngo Weinhold 
5401462a082SIngo Weinhold 
5411462a082SIngo Weinhold // init_messaging_service
5421462a082SIngo Weinhold status_t
5431462a082SIngo Weinhold init_messaging_service()
5441462a082SIngo Weinhold {
5451462a082SIngo Weinhold 	static char buffer[sizeof(MessagingService)];
5461462a082SIngo Weinhold 
5471462a082SIngo Weinhold 	if (!sMessagingService)
5481462a082SIngo Weinhold 		sMessagingService = new(buffer) MessagingService;
5491462a082SIngo Weinhold 
5501462a082SIngo Weinhold 	status_t error = sMessagingService->InitCheck();
5511462a082SIngo Weinhold 
5521462a082SIngo Weinhold 	// cleanup on error
5531462a082SIngo Weinhold 	if (error != B_OK) {
5541462a082SIngo Weinhold 		dprintf("ERROR: Failed to init messaging service: %s\n",
5551462a082SIngo Weinhold 			strerror(error));
5561462a082SIngo Weinhold 		sMessagingService->~MessagingService();
5571462a082SIngo Weinhold 		sMessagingService = NULL;
5581462a082SIngo Weinhold 	}
5591462a082SIngo Weinhold 
5601462a082SIngo Weinhold 	return error;
5611462a082SIngo Weinhold }
5621462a082SIngo Weinhold 
5631462a082SIngo Weinhold 
5641462a082SIngo Weinhold // #pragma mark - syscalls
5651462a082SIngo Weinhold 
5661462a082SIngo Weinhold 
5671462a082SIngo Weinhold // _user_register_messaging_service
5681462a082SIngo Weinhold /** \brief Called by the userland server to register itself as a messaging
5691462a082SIngo Weinhold 		   service for the kernel.
5701462a082SIngo Weinhold 	\param lockingSem A semaphore used for locking the shared data. Semaphore
5711462a082SIngo Weinhold 		   counter must be initialized to 0.
5721462a082SIngo Weinhold 	\param counterSem A semaphore released every time the kernel pushes a
5731462a082SIngo Weinhold 		   command into an empty area. Semaphore counter must be initialized
5741462a082SIngo Weinhold 		   to 0.
5751462a082SIngo Weinhold 	\return
5761462a082SIngo Weinhold 	- The ID of the kernel area used for communication, if everything went fine,
5771462a082SIngo Weinhold 	- an error code otherwise.
5781462a082SIngo Weinhold */
5791462a082SIngo Weinhold area_id
5801462a082SIngo Weinhold _user_register_messaging_service(sem_id lockSem, sem_id counterSem)
5811462a082SIngo Weinhold {
5821462a082SIngo Weinhold 	// check, if init_messaging_service() has been called yet
5831462a082SIngo Weinhold 	if (!sMessagingService)
5841462a082SIngo Weinhold 		return B_NO_INIT;
5851462a082SIngo Weinhold 
5861462a082SIngo Weinhold 	if (!sMessagingService->Lock())
5871462a082SIngo Weinhold 		return B_BAD_VALUE;
5881462a082SIngo Weinhold 
5891462a082SIngo Weinhold 	area_id areaID;
5901462a082SIngo Weinhold 	status_t error = sMessagingService->RegisterService(lockSem, counterSem,
5911462a082SIngo Weinhold 		areaID);
5921462a082SIngo Weinhold 
5931462a082SIngo Weinhold 	sMessagingService->Unlock();
5941462a082SIngo Weinhold 
5951462a082SIngo Weinhold 	return (error != B_OK ? error : areaID);
5961462a082SIngo Weinhold }
5971462a082SIngo Weinhold 
5981462a082SIngo Weinhold 
5991462a082SIngo Weinhold // _user_unregister_messaging_service
6001462a082SIngo Weinhold status_t
6011462a082SIngo Weinhold _user_unregister_messaging_service()
6021462a082SIngo Weinhold {
6031462a082SIngo Weinhold 	// check, if init_messaging_service() has been called yet
6041462a082SIngo Weinhold 	if (!sMessagingService)
6051462a082SIngo Weinhold 		return B_NO_INIT;
6061462a082SIngo Weinhold 
6071462a082SIngo Weinhold 	if (!sMessagingService->Lock())
6081462a082SIngo Weinhold 		return B_BAD_VALUE;
6091462a082SIngo Weinhold 
6101462a082SIngo Weinhold 	status_t error = sMessagingService->UnregisterService();
6111462a082SIngo Weinhold 
6121462a082SIngo Weinhold 	sMessagingService->Unlock();
6131462a082SIngo Weinhold 
6141462a082SIngo Weinhold 	return error;
6151462a082SIngo Weinhold }
616