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
6b74a0983SAxel Dörfler
7b74a0983SAxel Dörfler //! kernel-side implementation of the messaging service
8b74a0983SAxel Dörfler
92d690920SAxel Dörfler
102d690920SAxel Dörfler #include <new>
112d690920SAxel Dörfler
122d690920SAxel Dörfler #include <AutoDeleter.h>
13995aabb0SPulkoMandy #include <BytePointer.h>
142d690920SAxel Dörfler #include <KernelExport.h>
152d690920SAxel Dörfler #include <KMessage.h>
162d690920SAxel Dörfler #include <messaging.h>
172d690920SAxel Dörfler #include <MessagingServiceDefs.h>
182d690920SAxel Dörfler
192d690920SAxel Dörfler #include "MessagingService.h"
202d690920SAxel Dörfler
212d690920SAxel Dörfler //#define TRACE_MESSAGING_SERVICE
222d690920SAxel Dörfler #ifdef TRACE_MESSAGING_SERVICE
232d690920SAxel Dörfler # define PRINT(x) dprintf x
242d690920SAxel Dörfler #else
252d690920SAxel Dörfler # define PRINT(x) ;
262d690920SAxel Dörfler #endif
272d690920SAxel Dörfler
281462a082SIngo Weinhold
292d690920SAxel Dörfler using namespace std;
302d690920SAxel Dörfler
312d690920SAxel Dörfler static MessagingService *sMessagingService = NULL;
322d690920SAxel Dörfler
332d690920SAxel Dörfler static const int32 kMessagingAreaSize = B_PAGE_SIZE * 4;
342d690920SAxel Dörfler
352d690920SAxel Dörfler
361462a082SIngo Weinhold // #pragma mark - MessagingArea
372d690920SAxel Dörfler
382d690920SAxel Dörfler
MessagingArea()392d690920SAxel Dörfler MessagingArea::MessagingArea()
402d690920SAxel Dörfler {
412d690920SAxel Dörfler }
422d690920SAxel Dörfler
431462a082SIngo Weinhold
~MessagingArea()442d690920SAxel Dörfler MessagingArea::~MessagingArea()
452d690920SAxel Dörfler {
462d690920SAxel Dörfler if (fID >= 0)
472d690920SAxel Dörfler delete_area(fID);
482d690920SAxel Dörfler }
492d690920SAxel Dörfler
501462a082SIngo Weinhold
512d690920SAxel Dörfler MessagingArea *
Create(sem_id lockSem,sem_id counterSem)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,
62*8a0c9d52SAugustin Cavalier B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_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 void
InitHeader()802d690920SAxel Dörfler MessagingArea::InitHeader()
812d690920SAxel Dörfler {
822d690920SAxel Dörfler fHeader->lock_counter = 1; // create locked
832d690920SAxel Dörfler fHeader->size = fSize;
842d690920SAxel Dörfler fHeader->kernel_area = fID;
852d690920SAxel Dörfler fHeader->next_kernel_area = (fNextArea ? fNextArea->ID() : -1);
862d690920SAxel Dörfler fHeader->command_count = 0;
872d690920SAxel Dörfler fHeader->first_command = 0;
882d690920SAxel Dörfler fHeader->last_command = 0;
892d690920SAxel Dörfler }
902d690920SAxel Dörfler
911462a082SIngo Weinhold
922d690920SAxel Dörfler bool
CheckCommandSize(int32 dataSize)932d690920SAxel Dörfler MessagingArea::CheckCommandSize(int32 dataSize)
942d690920SAxel Dörfler {
952d690920SAxel Dörfler int32 size = sizeof(messaging_command) + dataSize;
962d690920SAxel Dörfler
972d690920SAxel Dörfler return (dataSize >= 0
982d690920SAxel Dörfler && size <= kMessagingAreaSize - (int32)sizeof(messaging_area_header));
992d690920SAxel Dörfler }
1002d690920SAxel Dörfler
1011462a082SIngo Weinhold
1022d690920SAxel Dörfler bool
Lock()1032d690920SAxel Dörfler MessagingArea::Lock()
1042d690920SAxel Dörfler {
1052d690920SAxel Dörfler // benaphore-like locking
1062d690920SAxel Dörfler if (atomic_add(&fHeader->lock_counter, 1) == 0)
1072d690920SAxel Dörfler return true;
1082d690920SAxel Dörfler
1092d690920SAxel Dörfler return (acquire_sem(fLockSem) == B_OK);
1102d690920SAxel Dörfler }
1112d690920SAxel Dörfler
1121462a082SIngo Weinhold
1132d690920SAxel Dörfler void
Unlock()1142d690920SAxel Dörfler MessagingArea::Unlock()
1152d690920SAxel Dörfler {
1162d690920SAxel Dörfler if (atomic_add(&fHeader->lock_counter, -1) > 1)
1172d690920SAxel Dörfler release_sem(fLockSem);
1182d690920SAxel Dörfler }
1192d690920SAxel Dörfler
1201462a082SIngo Weinhold
1212d690920SAxel Dörfler area_id
ID() const1222d690920SAxel Dörfler MessagingArea::ID() const
1232d690920SAxel Dörfler {
1242d690920SAxel Dörfler return fID;
1252d690920SAxel Dörfler }
1262d690920SAxel Dörfler
1271462a082SIngo Weinhold
1282d690920SAxel Dörfler int32
Size() const1292d690920SAxel Dörfler MessagingArea::Size() const
1302d690920SAxel Dörfler {
1312d690920SAxel Dörfler return fSize;
1322d690920SAxel Dörfler }
1332d690920SAxel Dörfler
1341462a082SIngo Weinhold
13575d1cb28SRene Gollent bool
IsEmpty() const13675d1cb28SRene Gollent MessagingArea::IsEmpty() const
13775d1cb28SRene Gollent {
13875d1cb28SRene Gollent return fHeader->command_count == 0;
13975d1cb28SRene Gollent }
14075d1cb28SRene Gollent
14175d1cb28SRene Gollent
1422d690920SAxel Dörfler void *
AllocateCommand(uint32 commandWhat,int32 dataSize,bool & wasEmpty)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
178f528e1adSRene Gollent 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
20381007175SAdrien Destugues BytePointer<messaging_command> command(fHeader);
20481007175SAdrien Destugues command += 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 void
CommitCommand()2142d690920SAxel Dörfler MessagingArea::CommitCommand()
2152d690920SAxel Dörfler {
2162d690920SAxel Dörfler // TODO: If invoked while locked, we should supply B_DO_NOT_RESCHEDULE.
2172d690920SAxel Dörfler release_sem(fCounterSem);
2182d690920SAxel Dörfler }
2192d690920SAxel Dörfler
2201462a082SIngo Weinhold
2212d690920SAxel Dörfler void
SetNextArea(MessagingArea * area)2222d690920SAxel Dörfler MessagingArea::SetNextArea(MessagingArea *area)
2232d690920SAxel Dörfler {
2242d690920SAxel Dörfler fNextArea = area;
2252d690920SAxel Dörfler fHeader->next_kernel_area = (fNextArea ? fNextArea->ID() : -1);
2262d690920SAxel Dörfler }
2272d690920SAxel Dörfler
2281462a082SIngo Weinhold
2292d690920SAxel Dörfler MessagingArea *
NextArea() const2302d690920SAxel Dörfler MessagingArea::NextArea() const
2312d690920SAxel Dörfler {
2322d690920SAxel Dörfler return fNextArea;
2332d690920SAxel Dörfler }
2342d690920SAxel Dörfler
2351462a082SIngo Weinhold
2362d690920SAxel Dörfler messaging_command *
_CheckCommand(int32 offset,int32 & size)2372d690920SAxel Dörfler MessagingArea::_CheckCommand(int32 offset, int32 &size)
2382d690920SAxel Dörfler {
2392d690920SAxel Dörfler // check offset
2402d690920SAxel Dörfler if (offset < (int32)sizeof(messaging_area_header)
2412d690920SAxel Dörfler || offset + (int32)sizeof(messaging_command) > fSize
2422d690920SAxel Dörfler || (offset & 0x3)) {
2432d690920SAxel Dörfler return NULL;
2442d690920SAxel Dörfler }
2452d690920SAxel Dörfler
2462d690920SAxel Dörfler // get and check size
24781007175SAdrien Destugues BytePointer<messaging_command> command(fHeader);
24881007175SAdrien Destugues command += offset;
2492d690920SAxel Dörfler size = command->size;
2502d690920SAxel Dörfler if (size < (int32)sizeof(messaging_command))
2512d690920SAxel Dörfler return NULL;
252f528e1adSRene Gollent size = (size + 3) & ~0x3; // align
2532d690920SAxel Dörfler if (offset + size > fSize)
2542d690920SAxel Dörfler return NULL;
2552d690920SAxel Dörfler
256995aabb0SPulkoMandy return &command;
2572d690920SAxel Dörfler }
2582d690920SAxel Dörfler
2592d690920SAxel Dörfler
2601462a082SIngo Weinhold // #pragma mark - MessagingService
2611462a082SIngo Weinhold
2622d690920SAxel Dörfler
MessagingService()2632d690920SAxel Dörfler MessagingService::MessagingService()
264b74a0983SAxel Dörfler :
2652d690920SAxel Dörfler fFirstArea(NULL),
2662d690920SAxel Dörfler fLastArea(NULL)
2672d690920SAxel Dörfler {
2683066f3dbSAxel Dörfler recursive_lock_init(&fLock, "messaging service");
2692d690920SAxel Dörfler }
2702d690920SAxel Dörfler
2711462a082SIngo Weinhold
~MessagingService()2722d690920SAxel Dörfler MessagingService::~MessagingService()
2732d690920SAxel Dörfler {
2742d690920SAxel Dörfler // Should actually never be called. Once created the service stays till the
2752d690920SAxel Dörfler // bitter end.
2762d690920SAxel Dörfler }
2772d690920SAxel Dörfler
2781462a082SIngo Weinhold
2792d690920SAxel Dörfler status_t
InitCheck() const2802d690920SAxel Dörfler MessagingService::InitCheck() const
2812d690920SAxel Dörfler {
2822d690920SAxel Dörfler return B_OK;
2832d690920SAxel Dörfler }
2842d690920SAxel Dörfler
2851462a082SIngo Weinhold
2862d690920SAxel Dörfler bool
Lock()2872d690920SAxel Dörfler MessagingService::Lock()
2882d690920SAxel Dörfler {
289b74a0983SAxel Dörfler return recursive_lock_lock(&fLock) == B_OK;
2902d690920SAxel Dörfler }
2912d690920SAxel Dörfler
2921462a082SIngo Weinhold
2932d690920SAxel Dörfler void
Unlock()2942d690920SAxel Dörfler MessagingService::Unlock()
2952d690920SAxel Dörfler {
296b74a0983SAxel Dörfler recursive_lock_unlock(&fLock);
2972d690920SAxel Dörfler }
2982d690920SAxel Dörfler
2991462a082SIngo Weinhold
3002d690920SAxel Dörfler status_t
RegisterService(sem_id lockSem,sem_id counterSem,area_id & areaID)3012d690920SAxel Dörfler MessagingService::RegisterService(sem_id lockSem, sem_id counterSem,
3022d690920SAxel Dörfler area_id &areaID)
3032d690920SAxel Dörfler {
3042d690920SAxel Dörfler // check, if a service is already registered
3052d690920SAxel Dörfler if (fFirstArea)
3062d690920SAxel Dörfler return B_BAD_VALUE;
3072d690920SAxel Dörfler
3082d690920SAxel Dörfler status_t error = B_OK;
3092d690920SAxel Dörfler
3102d690920SAxel Dörfler // check, if the semaphores are valid and belong to the calling team
3112d690920SAxel Dörfler thread_info threadInfo;
3122d690920SAxel Dörfler error = get_thread_info(find_thread(NULL), &threadInfo);
3132d690920SAxel Dörfler
3142d690920SAxel Dörfler sem_info lockSemInfo;
3152d690920SAxel Dörfler if (error == B_OK)
3162d690920SAxel Dörfler error = get_sem_info(lockSem, &lockSemInfo);
3172d690920SAxel Dörfler
3182d690920SAxel Dörfler sem_info counterSemInfo;
3192d690920SAxel Dörfler if (error == B_OK)
3202d690920SAxel Dörfler error = get_sem_info(counterSem, &counterSemInfo);
3212d690920SAxel Dörfler
3222d690920SAxel Dörfler if (error != B_OK)
3232d690920SAxel Dörfler return error;
3242d690920SAxel Dörfler
3252d690920SAxel Dörfler if (threadInfo.team != lockSemInfo.team
3262d690920SAxel Dörfler || threadInfo.team != counterSemInfo.team) {
3272d690920SAxel Dörfler return B_BAD_VALUE;
3282d690920SAxel Dörfler }
3292d690920SAxel Dörfler
3302d690920SAxel Dörfler // create an area
3312d690920SAxel Dörfler fFirstArea = fLastArea = MessagingArea::Create(lockSem, counterSem);
3322d690920SAxel Dörfler if (!fFirstArea)
3332d690920SAxel Dörfler return B_NO_MEMORY;
3342d690920SAxel Dörfler
3352d690920SAxel Dörfler areaID = fFirstArea->ID();
3362d690920SAxel Dörfler fFirstArea->Unlock();
3372d690920SAxel Dörfler
3382d690920SAxel Dörfler // store the server team and the semaphores
3392d690920SAxel Dörfler fServerTeam = threadInfo.team;
3402d690920SAxel Dörfler fLockSem = lockSem;
3412d690920SAxel Dörfler fCounterSem = counterSem;
3422d690920SAxel Dörfler
3432d690920SAxel Dörfler return B_OK;
3442d690920SAxel Dörfler }
3452d690920SAxel Dörfler
3461462a082SIngo Weinhold
3472d690920SAxel Dörfler status_t
UnregisterService()3482d690920SAxel Dörfler MessagingService::UnregisterService()
3492d690920SAxel Dörfler {
3502d690920SAxel Dörfler // check, if the team calling this function is indeed the server team
3512d690920SAxel Dörfler thread_info threadInfo;
3522d690920SAxel Dörfler status_t error = get_thread_info(find_thread(NULL), &threadInfo);
3532d690920SAxel Dörfler if (error != B_OK)
3542d690920SAxel Dörfler return error;
3552d690920SAxel Dörfler
3562d690920SAxel Dörfler if (threadInfo.team != fServerTeam)
3572d690920SAxel Dörfler return B_BAD_VALUE;
3582d690920SAxel Dörfler
3592d690920SAxel Dörfler // delete all areas
3602d690920SAxel Dörfler while (fFirstArea) {
3612d690920SAxel Dörfler MessagingArea *area = fFirstArea;
3622d690920SAxel Dörfler fFirstArea = area->NextArea();
3632d690920SAxel Dörfler delete area;
3642d690920SAxel Dörfler }
3652d690920SAxel Dörfler fLastArea = NULL;
3662d690920SAxel Dörfler
3672d690920SAxel Dörfler // unset the other members
3682d690920SAxel Dörfler fLockSem = -1;
369a8f9741cSMichael Lotz fCounterSem = -1;
3702d690920SAxel Dörfler fServerTeam = -1;
3712d690920SAxel Dörfler
3722d690920SAxel Dörfler return B_OK;
3732d690920SAxel Dörfler }
3742d690920SAxel Dörfler
3751462a082SIngo Weinhold
3762d690920SAxel Dörfler status_t
SendMessage(const void * message,int32 messageSize,const messaging_target * targets,int32 targetCount)3772d690920SAxel Dörfler MessagingService::SendMessage(const void *message, int32 messageSize,
3782d690920SAxel Dörfler const messaging_target *targets, int32 targetCount)
3792d690920SAxel Dörfler {
3802d690920SAxel Dörfler PRINT(("MessagingService::SendMessage(%p, %ld, %p, %ld)\n", message,
3812d690920SAxel Dörfler messageSize, targets, targetCount));
3822d690920SAxel Dörfler if (!message || messageSize <= 0 || !targets || targetCount <= 0)
3832d690920SAxel Dörfler return B_BAD_VALUE;
3842d690920SAxel Dörfler
3852d690920SAxel Dörfler int32 dataSize = sizeof(messaging_command_send_message)
3862d690920SAxel Dörfler + targetCount * sizeof(messaging_target) + messageSize;
3872d690920SAxel Dörfler
3882d690920SAxel Dörfler // allocate space for the command
3892d690920SAxel Dörfler MessagingArea *area;
3902d690920SAxel Dörfler void *data;
3912d690920SAxel Dörfler bool wasEmpty;
3922d690920SAxel Dörfler status_t error = _AllocateCommand(MESSAGING_COMMAND_SEND_MESSAGE, dataSize,
3932d690920SAxel Dörfler area, data, wasEmpty);
3942d690920SAxel Dörfler if (error != B_OK) {
3952d690920SAxel Dörfler PRINT(("MessagingService::SendMessage(): Failed to allocate space for "
3962d690920SAxel Dörfler "send message command.\n"));
3972d690920SAxel Dörfler return error;
3982d690920SAxel Dörfler }
3992d690920SAxel Dörfler PRINT((" Allocated space for send message command: area: %p, data: %p, "
4002d690920SAxel Dörfler "wasEmpty: %d\n", area, data, wasEmpty));
4012d690920SAxel Dörfler
4022d690920SAxel Dörfler // prepare the command
4032d690920SAxel Dörfler messaging_command_send_message *command
4042d690920SAxel Dörfler = (messaging_command_send_message*)data;
4052d690920SAxel Dörfler command->message_size = messageSize;
4062d690920SAxel Dörfler command->target_count = targetCount;
4072d690920SAxel Dörfler memcpy(command->targets, targets, sizeof(messaging_target) * targetCount);
4082d690920SAxel Dörfler memcpy((char*)command + (dataSize - messageSize), message, messageSize);
4092d690920SAxel Dörfler
4102d690920SAxel Dörfler // shoot
4112d690920SAxel Dörfler area->Unlock();
4122d690920SAxel Dörfler if (wasEmpty)
4132d690920SAxel Dörfler area->CommitCommand();
4142d690920SAxel Dörfler
4152d690920SAxel Dörfler return B_OK;
4162d690920SAxel Dörfler }
4172d690920SAxel Dörfler
4181462a082SIngo Weinhold
4192d690920SAxel Dörfler status_t
_AllocateCommand(int32 commandWhat,int32 size,MessagingArea * & area,void * & data,bool & wasEmpty)4202d690920SAxel Dörfler MessagingService::_AllocateCommand(int32 commandWhat, int32 size,
4212d690920SAxel Dörfler MessagingArea *&area, void *&data, bool &wasEmpty)
4222d690920SAxel Dörfler {
4232d690920SAxel Dörfler if (!fFirstArea)
4242d690920SAxel Dörfler return B_NO_INIT;
4252d690920SAxel Dörfler
4262d690920SAxel Dörfler if (!MessagingArea::CheckCommandSize(size))
4272d690920SAxel Dörfler return B_BAD_VALUE;
4282d690920SAxel Dörfler
4292d690920SAxel Dörfler // delete the discarded areas (save one)
4302d690920SAxel Dörfler ObjectDeleter<MessagingArea> discardedAreaDeleter;
4312d690920SAxel Dörfler MessagingArea *discardedArea = NULL;
432289b6c8dSRene Gollent
4332d690920SAxel Dörfler while (fFirstArea != fLastArea) {
4342d690920SAxel Dörfler area = fFirstArea;
4352d690920SAxel Dörfler area->Lock();
43675d1cb28SRene Gollent if (!area->IsEmpty()) {
4372d690920SAxel Dörfler area->Unlock();
4382d690920SAxel Dörfler break;
4392d690920SAxel Dörfler }
4402d690920SAxel Dörfler
4412d690920SAxel Dörfler PRINT(("MessagingService::_AllocateCommand(): Discarding area: %p\n",
4422d690920SAxel Dörfler area));
4432d690920SAxel Dörfler
4442d690920SAxel Dörfler fFirstArea = area->NextArea();
4452d690920SAxel Dörfler area->SetNextArea(NULL);
4462d690920SAxel Dörfler discardedArea = area;
4472d690920SAxel Dörfler discardedAreaDeleter.SetTo(area);
4482d690920SAxel Dörfler }
4492d690920SAxel Dörfler
4502d690920SAxel Dörfler // allocate space for the command in the last area
4512d690920SAxel Dörfler area = fLastArea;
4522d690920SAxel Dörfler area->Lock();
4532d690920SAxel Dörfler data = area->AllocateCommand(commandWhat, size, wasEmpty);
4542d690920SAxel Dörfler
4552d690920SAxel Dörfler if (!data) {
4562d690920SAxel Dörfler // not enough space in the last area: create a new area or reuse a
4572d690920SAxel Dörfler // discarded one
4582d690920SAxel Dörfler if (discardedArea) {
4592d690920SAxel Dörfler area = discardedAreaDeleter.Detach();
4602d690920SAxel Dörfler area->InitHeader();
4612d690920SAxel Dörfler PRINT(("MessagingService::_AllocateCommand(): Not enough space "
4622d690920SAxel Dörfler "left in current area. Recycling discarded one: %p\n", area));
4632d690920SAxel Dörfler } else {
4642d690920SAxel Dörfler area = MessagingArea::Create(fLockSem, fCounterSem);
4652d690920SAxel Dörfler PRINT(("MessagingService::_AllocateCommand(): Not enough space "
4662d690920SAxel Dörfler "left in current area. Allocated new one: %p\n", area));
4672d690920SAxel Dörfler }
4682d690920SAxel Dörfler if (!area) {
4692d690920SAxel Dörfler fLastArea->Unlock();
4702d690920SAxel Dörfler return B_NO_MEMORY;
4712d690920SAxel Dörfler }
4722d690920SAxel Dörfler
4732d690920SAxel Dörfler // add the new area
4742d690920SAxel Dörfler fLastArea->SetNextArea(area);
4752d690920SAxel Dörfler fLastArea->Unlock();
4762d690920SAxel Dörfler fLastArea = area;
4772d690920SAxel Dörfler
4782d690920SAxel Dörfler // allocate space for the command
4792d690920SAxel Dörfler data = area->AllocateCommand(commandWhat, size, wasEmpty);
4802d690920SAxel Dörfler
4812d690920SAxel Dörfler if (!data) {
4822d690920SAxel Dörfler // that should never happen
4832d690920SAxel Dörfler area->Unlock();
4842d690920SAxel Dörfler return B_NO_MEMORY;
4852d690920SAxel Dörfler }
4862d690920SAxel Dörfler }
4872d690920SAxel Dörfler
4882d690920SAxel Dörfler return B_OK;
4892d690920SAxel Dörfler }
4902d690920SAxel Dörfler
4911462a082SIngo Weinhold
4921462a082SIngo Weinhold // #pragma mark - kernel private
4931462a082SIngo Weinhold
4941462a082SIngo Weinhold
4951462a082SIngo Weinhold status_t
send_message(const void * message,int32 messageSize,const messaging_target * targets,int32 targetCount)4961462a082SIngo Weinhold send_message(const void *message, int32 messageSize,
4971462a082SIngo Weinhold const messaging_target *targets, int32 targetCount)
4981462a082SIngo Weinhold {
4991462a082SIngo Weinhold // check, if init_messaging_service() has been called yet
5001462a082SIngo Weinhold if (!sMessagingService)
5011462a082SIngo Weinhold return B_NO_INIT;
5021462a082SIngo Weinhold
5031462a082SIngo Weinhold if (!sMessagingService->Lock())
5041462a082SIngo Weinhold return B_BAD_VALUE;
5051462a082SIngo Weinhold
5061462a082SIngo Weinhold status_t error = sMessagingService->SendMessage(message, messageSize,
5071462a082SIngo Weinhold targets, targetCount);
5081462a082SIngo Weinhold
5091462a082SIngo Weinhold sMessagingService->Unlock();
5101462a082SIngo Weinhold
5111462a082SIngo Weinhold return error;
5121462a082SIngo Weinhold }
5131462a082SIngo Weinhold
5141462a082SIngo Weinhold
5151462a082SIngo Weinhold status_t
send_message(const KMessage * message,const messaging_target * targets,int32 targetCount)5161462a082SIngo Weinhold send_message(const KMessage *message, const messaging_target *targets,
5171462a082SIngo Weinhold int32 targetCount)
5181462a082SIngo Weinhold {
5191462a082SIngo Weinhold if (!message)
5201462a082SIngo Weinhold return B_BAD_VALUE;
5211462a082SIngo Weinhold
5221462a082SIngo Weinhold return send_message(message->Buffer(), message->ContentSize(), targets,
5231462a082SIngo Weinhold targetCount);
5241462a082SIngo Weinhold }
5251462a082SIngo Weinhold
5261462a082SIngo Weinhold
5271462a082SIngo Weinhold status_t
init_messaging_service()5281462a082SIngo Weinhold init_messaging_service()
5291462a082SIngo Weinhold {
5301462a082SIngo Weinhold static char buffer[sizeof(MessagingService)];
5311462a082SIngo Weinhold
5321462a082SIngo Weinhold if (!sMessagingService)
5331462a082SIngo Weinhold sMessagingService = new(buffer) MessagingService;
5341462a082SIngo Weinhold
5351462a082SIngo Weinhold status_t error = sMessagingService->InitCheck();
5361462a082SIngo Weinhold
5371462a082SIngo Weinhold // cleanup on error
5381462a082SIngo Weinhold if (error != B_OK) {
5391462a082SIngo Weinhold dprintf("ERROR: Failed to init messaging service: %s\n",
5401462a082SIngo Weinhold strerror(error));
5411462a082SIngo Weinhold sMessagingService->~MessagingService();
5421462a082SIngo Weinhold sMessagingService = NULL;
5431462a082SIngo Weinhold }
5441462a082SIngo Weinhold
5451462a082SIngo Weinhold return error;
5461462a082SIngo Weinhold }
5471462a082SIngo Weinhold
5481462a082SIngo Weinhold
5491462a082SIngo Weinhold // #pragma mark - syscalls
5501462a082SIngo Weinhold
5511462a082SIngo Weinhold
5521462a082SIngo Weinhold /** \brief Called by the userland server to register itself as a messaging
5531462a082SIngo Weinhold service for the kernel.
5541462a082SIngo Weinhold \param lockingSem A semaphore used for locking the shared data. Semaphore
5551462a082SIngo Weinhold counter must be initialized to 0.
5561462a082SIngo Weinhold \param counterSem A semaphore released every time the kernel pushes a
5571462a082SIngo Weinhold command into an empty area. Semaphore counter must be initialized
5581462a082SIngo Weinhold to 0.
5591462a082SIngo Weinhold \return
5601462a082SIngo Weinhold - The ID of the kernel area used for communication, if everything went fine,
5611462a082SIngo Weinhold - an error code otherwise.
5621462a082SIngo Weinhold */
5631462a082SIngo Weinhold area_id
_user_register_messaging_service(sem_id lockSem,sem_id counterSem)5641462a082SIngo Weinhold _user_register_messaging_service(sem_id lockSem, sem_id counterSem)
5651462a082SIngo Weinhold {
5661462a082SIngo Weinhold // check, if init_messaging_service() has been called yet
5671462a082SIngo Weinhold if (!sMessagingService)
5681462a082SIngo Weinhold return B_NO_INIT;
5691462a082SIngo Weinhold
5701462a082SIngo Weinhold if (!sMessagingService->Lock())
5711462a082SIngo Weinhold return B_BAD_VALUE;
5721462a082SIngo Weinhold
5731e6dd3feSMurai Takashi area_id areaID = 0;
5741462a082SIngo Weinhold status_t error = sMessagingService->RegisterService(lockSem, counterSem,
5751462a082SIngo Weinhold areaID);
5761462a082SIngo Weinhold
5771462a082SIngo Weinhold sMessagingService->Unlock();
5781462a082SIngo Weinhold
5791462a082SIngo Weinhold return (error != B_OK ? error : areaID);
5801462a082SIngo Weinhold }
5811462a082SIngo Weinhold
5821462a082SIngo Weinhold
5831462a082SIngo Weinhold status_t
_user_unregister_messaging_service()5841462a082SIngo Weinhold _user_unregister_messaging_service()
5851462a082SIngo Weinhold {
5861462a082SIngo Weinhold // check, if init_messaging_service() has been called yet
5871462a082SIngo Weinhold if (!sMessagingService)
5881462a082SIngo Weinhold return B_NO_INIT;
5891462a082SIngo Weinhold
5901462a082SIngo Weinhold if (!sMessagingService->Lock())
5911462a082SIngo Weinhold return B_BAD_VALUE;
5921462a082SIngo Weinhold
5931462a082SIngo Weinhold status_t error = sMessagingService->UnregisterService();
5941462a082SIngo Weinhold
5951462a082SIngo Weinhold sMessagingService->Unlock();
5961462a082SIngo Weinhold
5971462a082SIngo Weinhold return error;
5981462a082SIngo Weinhold }
599