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