1*2d690920SAxel Dörfler /* 2*2d690920SAxel Dörfler * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. All rights reserved. 3*2d690920SAxel Dörfler * Distributed under the terms of the MIT License. 4*2d690920SAxel Dörfler */ 5*2d690920SAxel Dörfler 6*2d690920SAxel Dörfler // kernel-side implementation of the messaging service 7*2d690920SAxel Dörfler 8*2d690920SAxel Dörfler #include <new> 9*2d690920SAxel Dörfler 10*2d690920SAxel Dörfler #include <AutoDeleter.h> 11*2d690920SAxel Dörfler #include <KernelExport.h> 12*2d690920SAxel Dörfler #include <KMessage.h> 13*2d690920SAxel Dörfler #include <messaging.h> 14*2d690920SAxel Dörfler #include <MessagingServiceDefs.h> 15*2d690920SAxel Dörfler 16*2d690920SAxel Dörfler #include "MessagingService.h" 17*2d690920SAxel Dörfler 18*2d690920SAxel Dörfler //#define TRACE_MESSAGING_SERVICE 19*2d690920SAxel Dörfler #ifdef TRACE_MESSAGING_SERVICE 20*2d690920SAxel Dörfler # define PRINT(x) dprintf x 21*2d690920SAxel Dörfler #else 22*2d690920SAxel Dörfler # define PRINT(x) ; 23*2d690920SAxel Dörfler #endif 24*2d690920SAxel Dörfler 25*2d690920SAxel Dörfler using namespace std; 26*2d690920SAxel Dörfler 27*2d690920SAxel Dörfler static MessagingService *sMessagingService = NULL; 28*2d690920SAxel Dörfler 29*2d690920SAxel Dörfler static const int32 kMessagingAreaSize = B_PAGE_SIZE * 4; 30*2d690920SAxel Dörfler 31*2d690920SAxel Dörfler // init_messaging_service 32*2d690920SAxel Dörfler status_t 33*2d690920SAxel Dörfler init_messaging_service() 34*2d690920SAxel Dörfler { 35*2d690920SAxel Dörfler static char buffer[sizeof(MessagingService)]; 36*2d690920SAxel Dörfler 37*2d690920SAxel Dörfler if (!sMessagingService) 38*2d690920SAxel Dörfler sMessagingService = new(buffer) MessagingService; 39*2d690920SAxel Dörfler 40*2d690920SAxel Dörfler status_t error = sMessagingService->InitCheck(); 41*2d690920SAxel Dörfler 42*2d690920SAxel Dörfler // cleanup on error 43*2d690920SAxel Dörfler if (error != B_OK) { 44*2d690920SAxel Dörfler dprintf("ERROR: Failed to init messaging service: %s\n", 45*2d690920SAxel Dörfler strerror(error)); 46*2d690920SAxel Dörfler sMessagingService->~MessagingService(); 47*2d690920SAxel Dörfler sMessagingService = NULL; 48*2d690920SAxel Dörfler } 49*2d690920SAxel Dörfler 50*2d690920SAxel Dörfler return error; 51*2d690920SAxel Dörfler } 52*2d690920SAxel Dörfler 53*2d690920SAxel Dörfler // _user_register_messaging_service 54*2d690920SAxel Dörfler /** \brief Called by the userland server to register itself as a messaging 55*2d690920SAxel Dörfler service for the kernel. 56*2d690920SAxel Dörfler \param lockingSem A semaphore used for locking the shared data. Semaphore 57*2d690920SAxel Dörfler counter must be initialized to 0. 58*2d690920SAxel Dörfler \param counterSem A semaphore released every time the kernel pushes a 59*2d690920SAxel Dörfler command into an empty area. Semaphore counter must be initialized 60*2d690920SAxel Dörfler to 0. 61*2d690920SAxel Dörfler \return 62*2d690920SAxel Dörfler - The ID of the kernel area used for communication, if everything went fine, 63*2d690920SAxel Dörfler - an error code otherwise. 64*2d690920SAxel Dörfler */ 65*2d690920SAxel Dörfler area_id 66*2d690920SAxel Dörfler _user_register_messaging_service(sem_id lockSem, sem_id counterSem) 67*2d690920SAxel Dörfler { 68*2d690920SAxel Dörfler // check, if init_messaging_service() has been called yet 69*2d690920SAxel Dörfler if (!sMessagingService) 70*2d690920SAxel Dörfler return B_NO_INIT; 71*2d690920SAxel Dörfler 72*2d690920SAxel Dörfler if (!sMessagingService->Lock()) 73*2d690920SAxel Dörfler return B_BAD_VALUE; 74*2d690920SAxel Dörfler 75*2d690920SAxel Dörfler area_id areaID; 76*2d690920SAxel Dörfler status_t error = sMessagingService->RegisterService(lockSem, counterSem, 77*2d690920SAxel Dörfler areaID); 78*2d690920SAxel Dörfler 79*2d690920SAxel Dörfler sMessagingService->Unlock(); 80*2d690920SAxel Dörfler 81*2d690920SAxel Dörfler return (error != B_OK ? error : areaID); 82*2d690920SAxel Dörfler } 83*2d690920SAxel Dörfler 84*2d690920SAxel Dörfler // _user_unregister_messaging_service 85*2d690920SAxel Dörfler status_t 86*2d690920SAxel Dörfler _user_unregister_messaging_service() 87*2d690920SAxel Dörfler { 88*2d690920SAxel Dörfler // check, if init_messaging_service() has been called yet 89*2d690920SAxel Dörfler if (!sMessagingService) 90*2d690920SAxel Dörfler return B_NO_INIT; 91*2d690920SAxel Dörfler 92*2d690920SAxel Dörfler if (!sMessagingService->Lock()) 93*2d690920SAxel Dörfler return B_BAD_VALUE; 94*2d690920SAxel Dörfler 95*2d690920SAxel Dörfler status_t error = sMessagingService->UnregisterService(); 96*2d690920SAxel Dörfler 97*2d690920SAxel Dörfler sMessagingService->Unlock(); 98*2d690920SAxel Dörfler 99*2d690920SAxel Dörfler return error; 100*2d690920SAxel Dörfler } 101*2d690920SAxel Dörfler 102*2d690920SAxel Dörfler 103*2d690920SAxel Dörfler // send_message 104*2d690920SAxel Dörfler status_t 105*2d690920SAxel Dörfler send_message(const void *message, int32 messageSize, 106*2d690920SAxel Dörfler const messaging_target *targets, int32 targetCount) 107*2d690920SAxel Dörfler { 108*2d690920SAxel Dörfler // check, if init_messaging_service() has been called yet 109*2d690920SAxel Dörfler if (!sMessagingService) 110*2d690920SAxel Dörfler return B_NO_INIT; 111*2d690920SAxel Dörfler 112*2d690920SAxel Dörfler if (!sMessagingService->Lock()) 113*2d690920SAxel Dörfler return B_BAD_VALUE; 114*2d690920SAxel Dörfler 115*2d690920SAxel Dörfler status_t error = sMessagingService->SendMessage(message, messageSize, 116*2d690920SAxel Dörfler targets, targetCount); 117*2d690920SAxel Dörfler 118*2d690920SAxel Dörfler sMessagingService->Unlock(); 119*2d690920SAxel Dörfler 120*2d690920SAxel Dörfler return error; 121*2d690920SAxel Dörfler } 122*2d690920SAxel Dörfler 123*2d690920SAxel Dörfler // send_message 124*2d690920SAxel Dörfler status_t 125*2d690920SAxel Dörfler send_message(const KMessage *message, const messaging_target *targets, 126*2d690920SAxel Dörfler int32 targetCount) 127*2d690920SAxel Dörfler { 128*2d690920SAxel Dörfler if (!message) 129*2d690920SAxel Dörfler return B_BAD_VALUE; 130*2d690920SAxel Dörfler 131*2d690920SAxel Dörfler return send_message(message->Buffer(), message->ContentSize(), targets, 132*2d690920SAxel Dörfler targetCount); 133*2d690920SAxel Dörfler } 134*2d690920SAxel Dörfler 135*2d690920SAxel Dörfler 136*2d690920SAxel Dörfler // #pragma mark - 137*2d690920SAxel Dörfler 138*2d690920SAxel Dörfler // constructor 139*2d690920SAxel Dörfler MessagingArea::MessagingArea() 140*2d690920SAxel Dörfler { 141*2d690920SAxel Dörfler } 142*2d690920SAxel Dörfler 143*2d690920SAxel Dörfler // destructor 144*2d690920SAxel Dörfler MessagingArea::~MessagingArea() 145*2d690920SAxel Dörfler { 146*2d690920SAxel Dörfler if (fID >= 0) 147*2d690920SAxel Dörfler delete_area(fID); 148*2d690920SAxel Dörfler } 149*2d690920SAxel Dörfler 150*2d690920SAxel Dörfler // Create 151*2d690920SAxel Dörfler MessagingArea * 152*2d690920SAxel Dörfler MessagingArea::Create(sem_id lockSem, sem_id counterSem) 153*2d690920SAxel Dörfler { 154*2d690920SAxel Dörfler // allocate the object on the heap 155*2d690920SAxel Dörfler MessagingArea *area = new(nothrow) MessagingArea; 156*2d690920SAxel Dörfler if (!area) 157*2d690920SAxel Dörfler return NULL; 158*2d690920SAxel Dörfler 159*2d690920SAxel Dörfler // create the area 160*2d690920SAxel Dörfler area->fID = create_area("messaging", (void**)&area->fHeader, 161*2d690920SAxel Dörfler B_ANY_KERNEL_ADDRESS, kMessagingAreaSize, B_FULL_LOCK, 162*2d690920SAxel Dörfler B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA); 163*2d690920SAxel Dörfler if (area->fID < 0) { 164*2d690920SAxel Dörfler delete area; 165*2d690920SAxel Dörfler return NULL; 166*2d690920SAxel Dörfler } 167*2d690920SAxel Dörfler 168*2d690920SAxel Dörfler // finish the initialization of the object 169*2d690920SAxel Dörfler area->fSize = kMessagingAreaSize; 170*2d690920SAxel Dörfler area->fLockSem = lockSem; 171*2d690920SAxel Dörfler area->fCounterSem = counterSem; 172*2d690920SAxel Dörfler area->fNextArea = NULL; 173*2d690920SAxel Dörfler area->InitHeader(); 174*2d690920SAxel Dörfler 175*2d690920SAxel Dörfler return area; 176*2d690920SAxel Dörfler } 177*2d690920SAxel Dörfler 178*2d690920SAxel Dörfler // InitHeader 179*2d690920SAxel Dörfler void 180*2d690920SAxel Dörfler MessagingArea::InitHeader() 181*2d690920SAxel Dörfler { 182*2d690920SAxel Dörfler fHeader->lock_counter = 1; // create locked 183*2d690920SAxel Dörfler fHeader->size = fSize; 184*2d690920SAxel Dörfler fHeader->kernel_area = fID; 185*2d690920SAxel Dörfler fHeader->next_kernel_area = (fNextArea ? fNextArea->ID() : -1); 186*2d690920SAxel Dörfler fHeader->command_count = 0; 187*2d690920SAxel Dörfler fHeader->first_command = 0; 188*2d690920SAxel Dörfler fHeader->last_command = 0; 189*2d690920SAxel Dörfler } 190*2d690920SAxel Dörfler 191*2d690920SAxel Dörfler // CheckCommandSize 192*2d690920SAxel Dörfler bool 193*2d690920SAxel Dörfler MessagingArea::CheckCommandSize(int32 dataSize) 194*2d690920SAxel Dörfler { 195*2d690920SAxel Dörfler int32 size = sizeof(messaging_command) + dataSize; 196*2d690920SAxel Dörfler 197*2d690920SAxel Dörfler return (dataSize >= 0 198*2d690920SAxel Dörfler && size <= kMessagingAreaSize - (int32)sizeof(messaging_area_header)); 199*2d690920SAxel Dörfler } 200*2d690920SAxel Dörfler 201*2d690920SAxel Dörfler // Lock 202*2d690920SAxel Dörfler bool 203*2d690920SAxel Dörfler MessagingArea::Lock() 204*2d690920SAxel Dörfler { 205*2d690920SAxel Dörfler // benaphore-like locking 206*2d690920SAxel Dörfler if (atomic_add(&fHeader->lock_counter, 1) == 0) 207*2d690920SAxel Dörfler return true; 208*2d690920SAxel Dörfler 209*2d690920SAxel Dörfler return (acquire_sem(fLockSem) == B_OK); 210*2d690920SAxel Dörfler } 211*2d690920SAxel Dörfler 212*2d690920SAxel Dörfler // Unlock 213*2d690920SAxel Dörfler void 214*2d690920SAxel Dörfler MessagingArea::Unlock() 215*2d690920SAxel Dörfler { 216*2d690920SAxel Dörfler if (atomic_add(&fHeader->lock_counter, -1) > 1) 217*2d690920SAxel Dörfler release_sem(fLockSem); 218*2d690920SAxel Dörfler } 219*2d690920SAxel Dörfler 220*2d690920SAxel Dörfler // ID 221*2d690920SAxel Dörfler area_id 222*2d690920SAxel Dörfler MessagingArea::ID() const 223*2d690920SAxel Dörfler { 224*2d690920SAxel Dörfler return fID; 225*2d690920SAxel Dörfler } 226*2d690920SAxel Dörfler 227*2d690920SAxel Dörfler // Size 228*2d690920SAxel Dörfler int32 229*2d690920SAxel Dörfler MessagingArea::Size() const 230*2d690920SAxel Dörfler { 231*2d690920SAxel Dörfler return fSize; 232*2d690920SAxel Dörfler } 233*2d690920SAxel Dörfler 234*2d690920SAxel Dörfler // AllocateCommand 235*2d690920SAxel Dörfler void * 236*2d690920SAxel Dörfler MessagingArea::AllocateCommand(uint32 commandWhat, int32 dataSize, 237*2d690920SAxel Dörfler bool &wasEmpty) 238*2d690920SAxel Dörfler { 239*2d690920SAxel Dörfler int32 size = sizeof(messaging_command) + dataSize; 240*2d690920SAxel Dörfler 241*2d690920SAxel Dörfler if (dataSize < 0 || size > fSize - (int32)sizeof(messaging_area_header)) 242*2d690920SAxel Dörfler return NULL; 243*2d690920SAxel Dörfler 244*2d690920SAxel Dörfler // the area is used as a ring buffer 245*2d690920SAxel Dörfler int32 startOffset = sizeof(messaging_area_header); 246*2d690920SAxel Dörfler 247*2d690920SAxel Dörfler // the simple case first: the area is empty 248*2d690920SAxel Dörfler int32 commandOffset; 249*2d690920SAxel Dörfler wasEmpty = (fHeader->command_count == 0); 250*2d690920SAxel Dörfler if (wasEmpty) { 251*2d690920SAxel Dörfler commandOffset = startOffset; 252*2d690920SAxel Dörfler 253*2d690920SAxel Dörfler // update the header 254*2d690920SAxel Dörfler fHeader->command_count++; 255*2d690920SAxel Dörfler fHeader->first_command = fHeader->last_command = commandOffset; 256*2d690920SAxel Dörfler } else { 257*2d690920SAxel Dörfler int32 firstCommandOffset = fHeader->first_command; 258*2d690920SAxel Dörfler int32 lastCommandOffset = fHeader->last_command; 259*2d690920SAxel Dörfler int32 firstCommandSize; 260*2d690920SAxel Dörfler int32 lastCommandSize; 261*2d690920SAxel Dörfler messaging_command *firstCommand = _CheckCommand(firstCommandOffset, 262*2d690920SAxel Dörfler firstCommandSize); 263*2d690920SAxel Dörfler messaging_command *lastCommand = _CheckCommand(lastCommandOffset, 264*2d690920SAxel Dörfler lastCommandSize); 265*2d690920SAxel Dörfler if (!firstCommand || !lastCommand) { 266*2d690920SAxel Dörfler // something has been screwed up 267*2d690920SAxel Dörfler return NULL; 268*2d690920SAxel Dörfler } 269*2d690920SAxel Dörfler 270*2d690920SAxel Dörfler // find space for the command 271*2d690920SAxel Dörfler if (firstCommandOffset < lastCommandOffset) { 272*2d690920SAxel Dörfler // not wrapped 273*2d690920SAxel Dörfler // try to allocate after the last command 274*2d690920SAxel Dörfler if (size <= fSize - (lastCommandOffset + lastCommandSize)) { 275*2d690920SAxel Dörfler commandOffset = (lastCommandOffset + lastCommandSize); 276*2d690920SAxel Dörfler } else { 277*2d690920SAxel Dörfler // is there enough space before the first command? 278*2d690920SAxel Dörfler if (size > firstCommandOffset - startOffset) 279*2d690920SAxel Dörfler return NULL; 280*2d690920SAxel Dörfler commandOffset = startOffset; 281*2d690920SAxel Dörfler } 282*2d690920SAxel Dörfler } else { 283*2d690920SAxel Dörfler // wrapped: we can only allocate between the last and the first 284*2d690920SAxel Dörfler // command 285*2d690920SAxel Dörfler commandOffset = lastCommandOffset + lastCommandSize; 286*2d690920SAxel Dörfler if (size > firstCommandOffset - commandOffset) 287*2d690920SAxel Dörfler return NULL; 288*2d690920SAxel Dörfler } 289*2d690920SAxel Dörfler 290*2d690920SAxel Dörfler // update the header and the last command 291*2d690920SAxel Dörfler fHeader->command_count++; 292*2d690920SAxel Dörfler lastCommand->next_command = fHeader->last_command = commandOffset; 293*2d690920SAxel Dörfler } 294*2d690920SAxel Dörfler 295*2d690920SAxel Dörfler // init the command 296*2d690920SAxel Dörfler messaging_command *command 297*2d690920SAxel Dörfler = (messaging_command*)((char*)fHeader + commandOffset); 298*2d690920SAxel Dörfler command->next_command = 0; 299*2d690920SAxel Dörfler command->command = commandWhat; 300*2d690920SAxel Dörfler command->size = size; 301*2d690920SAxel Dörfler 302*2d690920SAxel Dörfler return command->data; 303*2d690920SAxel Dörfler } 304*2d690920SAxel Dörfler 305*2d690920SAxel Dörfler // CommitCommand 306*2d690920SAxel Dörfler void 307*2d690920SAxel Dörfler MessagingArea::CommitCommand() 308*2d690920SAxel Dörfler { 309*2d690920SAxel Dörfler // TODO: If invoked while locked, we should supply B_DO_NOT_RESCHEDULE. 310*2d690920SAxel Dörfler release_sem(fCounterSem); 311*2d690920SAxel Dörfler } 312*2d690920SAxel Dörfler 313*2d690920SAxel Dörfler // SetNextArea 314*2d690920SAxel Dörfler void 315*2d690920SAxel Dörfler MessagingArea::SetNextArea(MessagingArea *area) 316*2d690920SAxel Dörfler { 317*2d690920SAxel Dörfler fNextArea = area; 318*2d690920SAxel Dörfler fHeader->next_kernel_area = (fNextArea ? fNextArea->ID() : -1); 319*2d690920SAxel Dörfler } 320*2d690920SAxel Dörfler 321*2d690920SAxel Dörfler // NextArea 322*2d690920SAxel Dörfler MessagingArea * 323*2d690920SAxel Dörfler MessagingArea::NextArea() const 324*2d690920SAxel Dörfler { 325*2d690920SAxel Dörfler return fNextArea; 326*2d690920SAxel Dörfler } 327*2d690920SAxel Dörfler 328*2d690920SAxel Dörfler // _CheckCommand 329*2d690920SAxel Dörfler messaging_command * 330*2d690920SAxel Dörfler MessagingArea::_CheckCommand(int32 offset, int32 &size) 331*2d690920SAxel Dörfler { 332*2d690920SAxel Dörfler // check offset 333*2d690920SAxel Dörfler if (offset < (int32)sizeof(messaging_area_header) 334*2d690920SAxel Dörfler || offset + (int32)sizeof(messaging_command) > fSize 335*2d690920SAxel Dörfler || (offset & 0x3)) { 336*2d690920SAxel Dörfler return NULL; 337*2d690920SAxel Dörfler } 338*2d690920SAxel Dörfler 339*2d690920SAxel Dörfler // get and check size 340*2d690920SAxel Dörfler messaging_command *command = (messaging_command*)((char*)fHeader + offset); 341*2d690920SAxel Dörfler size = command->size; 342*2d690920SAxel Dörfler if (size < (int32)sizeof(messaging_command)) 343*2d690920SAxel Dörfler return NULL; 344*2d690920SAxel Dörfler size = (size + 3) & 0x3; // align 345*2d690920SAxel Dörfler if (offset + size > fSize) 346*2d690920SAxel Dörfler return NULL; 347*2d690920SAxel Dörfler 348*2d690920SAxel Dörfler return command; 349*2d690920SAxel Dörfler } 350*2d690920SAxel Dörfler 351*2d690920SAxel Dörfler 352*2d690920SAxel Dörfler // #pragma mark - 353*2d690920SAxel Dörfler 354*2d690920SAxel Dörfler // constructor 355*2d690920SAxel Dörfler MessagingService::MessagingService() 356*2d690920SAxel Dörfler : fLock("messaging service"), 357*2d690920SAxel Dörfler fFirstArea(NULL), 358*2d690920SAxel Dörfler fLastArea(NULL) 359*2d690920SAxel Dörfler { 360*2d690920SAxel Dörfler } 361*2d690920SAxel Dörfler 362*2d690920SAxel Dörfler // destructor 363*2d690920SAxel Dörfler MessagingService::~MessagingService() 364*2d690920SAxel Dörfler { 365*2d690920SAxel Dörfler // Should actually never be called. Once created the service stays till the 366*2d690920SAxel Dörfler // bitter end. 367*2d690920SAxel Dörfler } 368*2d690920SAxel Dörfler 369*2d690920SAxel Dörfler // InitCheck 370*2d690920SAxel Dörfler status_t 371*2d690920SAxel Dörfler MessagingService::InitCheck() const 372*2d690920SAxel Dörfler { 373*2d690920SAxel Dörfler if (fLock.Sem() < 0) 374*2d690920SAxel Dörfler return fLock.Sem(); 375*2d690920SAxel Dörfler return B_OK; 376*2d690920SAxel Dörfler } 377*2d690920SAxel Dörfler 378*2d690920SAxel Dörfler // Lock 379*2d690920SAxel Dörfler bool 380*2d690920SAxel Dörfler MessagingService::Lock() 381*2d690920SAxel Dörfler { 382*2d690920SAxel Dörfler return fLock.Lock(); 383*2d690920SAxel Dörfler } 384*2d690920SAxel Dörfler 385*2d690920SAxel Dörfler // Unlock 386*2d690920SAxel Dörfler void 387*2d690920SAxel Dörfler MessagingService::Unlock() 388*2d690920SAxel Dörfler { 389*2d690920SAxel Dörfler fLock.Unlock(); 390*2d690920SAxel Dörfler } 391*2d690920SAxel Dörfler 392*2d690920SAxel Dörfler // RegisterService 393*2d690920SAxel Dörfler status_t 394*2d690920SAxel Dörfler MessagingService::RegisterService(sem_id lockSem, sem_id counterSem, 395*2d690920SAxel Dörfler area_id &areaID) 396*2d690920SAxel Dörfler { 397*2d690920SAxel Dörfler // check, if a service is already registered 398*2d690920SAxel Dörfler if (fFirstArea) 399*2d690920SAxel Dörfler return B_BAD_VALUE; 400*2d690920SAxel Dörfler 401*2d690920SAxel Dörfler status_t error = B_OK; 402*2d690920SAxel Dörfler 403*2d690920SAxel Dörfler // check, if the semaphores are valid and belong to the calling team 404*2d690920SAxel Dörfler thread_info threadInfo; 405*2d690920SAxel Dörfler error = get_thread_info(find_thread(NULL), &threadInfo); 406*2d690920SAxel Dörfler 407*2d690920SAxel Dörfler sem_info lockSemInfo; 408*2d690920SAxel Dörfler if (error == B_OK) 409*2d690920SAxel Dörfler error = get_sem_info(lockSem, &lockSemInfo); 410*2d690920SAxel Dörfler 411*2d690920SAxel Dörfler sem_info counterSemInfo; 412*2d690920SAxel Dörfler if (error == B_OK) 413*2d690920SAxel Dörfler error = get_sem_info(counterSem, &counterSemInfo); 414*2d690920SAxel Dörfler 415*2d690920SAxel Dörfler if (error != B_OK) 416*2d690920SAxel Dörfler return error; 417*2d690920SAxel Dörfler 418*2d690920SAxel Dörfler if (threadInfo.team != lockSemInfo.team 419*2d690920SAxel Dörfler || threadInfo.team != counterSemInfo.team) { 420*2d690920SAxel Dörfler return B_BAD_VALUE; 421*2d690920SAxel Dörfler } 422*2d690920SAxel Dörfler 423*2d690920SAxel Dörfler // create an area 424*2d690920SAxel Dörfler fFirstArea = fLastArea = MessagingArea::Create(lockSem, counterSem); 425*2d690920SAxel Dörfler if (!fFirstArea) 426*2d690920SAxel Dörfler return B_NO_MEMORY; 427*2d690920SAxel Dörfler 428*2d690920SAxel Dörfler areaID = fFirstArea->ID(); 429*2d690920SAxel Dörfler fFirstArea->Unlock(); 430*2d690920SAxel Dörfler 431*2d690920SAxel Dörfler // store the server team and the semaphores 432*2d690920SAxel Dörfler fServerTeam = threadInfo.team; 433*2d690920SAxel Dörfler fLockSem = lockSem; 434*2d690920SAxel Dörfler fCounterSem = counterSem; 435*2d690920SAxel Dörfler 436*2d690920SAxel Dörfler return B_OK; 437*2d690920SAxel Dörfler } 438*2d690920SAxel Dörfler 439*2d690920SAxel Dörfler // UnregisterService 440*2d690920SAxel Dörfler status_t 441*2d690920SAxel Dörfler MessagingService::UnregisterService() 442*2d690920SAxel Dörfler { 443*2d690920SAxel Dörfler // check, if the team calling this function is indeed the server team 444*2d690920SAxel Dörfler thread_info threadInfo; 445*2d690920SAxel Dörfler status_t error = get_thread_info(find_thread(NULL), &threadInfo); 446*2d690920SAxel Dörfler if (error != B_OK) 447*2d690920SAxel Dörfler return error; 448*2d690920SAxel Dörfler 449*2d690920SAxel Dörfler if (threadInfo.team != fServerTeam) 450*2d690920SAxel Dörfler return B_BAD_VALUE; 451*2d690920SAxel Dörfler 452*2d690920SAxel Dörfler // delete all areas 453*2d690920SAxel Dörfler while (fFirstArea) { 454*2d690920SAxel Dörfler MessagingArea *area = fFirstArea; 455*2d690920SAxel Dörfler fFirstArea = area->NextArea(); 456*2d690920SAxel Dörfler delete area; 457*2d690920SAxel Dörfler } 458*2d690920SAxel Dörfler fLastArea = NULL; 459*2d690920SAxel Dörfler 460*2d690920SAxel Dörfler // unset the other members 461*2d690920SAxel Dörfler fLockSem = -1; 462*2d690920SAxel Dörfler fCounterSem -1; 463*2d690920SAxel Dörfler fServerTeam = -1; 464*2d690920SAxel Dörfler 465*2d690920SAxel Dörfler return B_OK; 466*2d690920SAxel Dörfler } 467*2d690920SAxel Dörfler 468*2d690920SAxel Dörfler // SendMessage 469*2d690920SAxel Dörfler status_t 470*2d690920SAxel Dörfler MessagingService::SendMessage(const void *message, int32 messageSize, 471*2d690920SAxel Dörfler const messaging_target *targets, int32 targetCount) 472*2d690920SAxel Dörfler { 473*2d690920SAxel Dörfler PRINT(("MessagingService::SendMessage(%p, %ld, %p, %ld)\n", message, 474*2d690920SAxel Dörfler messageSize, targets, targetCount)); 475*2d690920SAxel Dörfler if (!message || messageSize <= 0 || !targets || targetCount <= 0) 476*2d690920SAxel Dörfler return B_BAD_VALUE; 477*2d690920SAxel Dörfler 478*2d690920SAxel Dörfler int32 dataSize = sizeof(messaging_command_send_message) 479*2d690920SAxel Dörfler + targetCount * sizeof(messaging_target) + messageSize; 480*2d690920SAxel Dörfler 481*2d690920SAxel Dörfler // allocate space for the command 482*2d690920SAxel Dörfler MessagingArea *area; 483*2d690920SAxel Dörfler void *data; 484*2d690920SAxel Dörfler bool wasEmpty; 485*2d690920SAxel Dörfler status_t error = _AllocateCommand(MESSAGING_COMMAND_SEND_MESSAGE, dataSize, 486*2d690920SAxel Dörfler area, data, wasEmpty); 487*2d690920SAxel Dörfler if (error != B_OK) { 488*2d690920SAxel Dörfler PRINT(("MessagingService::SendMessage(): Failed to allocate space for " 489*2d690920SAxel Dörfler "send message command.\n")); 490*2d690920SAxel Dörfler return error; 491*2d690920SAxel Dörfler } 492*2d690920SAxel Dörfler PRINT((" Allocated space for send message command: area: %p, data: %p, " 493*2d690920SAxel Dörfler "wasEmpty: %d\n", area, data, wasEmpty)); 494*2d690920SAxel Dörfler 495*2d690920SAxel Dörfler // prepare the command 496*2d690920SAxel Dörfler messaging_command_send_message *command 497*2d690920SAxel Dörfler = (messaging_command_send_message*)data; 498*2d690920SAxel Dörfler command->message_size = messageSize; 499*2d690920SAxel Dörfler command->target_count = targetCount; 500*2d690920SAxel Dörfler memcpy(command->targets, targets, sizeof(messaging_target) * targetCount); 501*2d690920SAxel Dörfler memcpy((char*)command + (dataSize - messageSize), message, messageSize); 502*2d690920SAxel Dörfler 503*2d690920SAxel Dörfler // shoot 504*2d690920SAxel Dörfler area->Unlock(); 505*2d690920SAxel Dörfler if (wasEmpty) 506*2d690920SAxel Dörfler area->CommitCommand(); 507*2d690920SAxel Dörfler 508*2d690920SAxel Dörfler return B_OK; 509*2d690920SAxel Dörfler } 510*2d690920SAxel Dörfler 511*2d690920SAxel Dörfler // _AllocateCommand 512*2d690920SAxel Dörfler status_t 513*2d690920SAxel Dörfler MessagingService::_AllocateCommand(int32 commandWhat, int32 size, 514*2d690920SAxel Dörfler MessagingArea *&area, void *&data, bool &wasEmpty) 515*2d690920SAxel Dörfler { 516*2d690920SAxel Dörfler if (!fFirstArea) 517*2d690920SAxel Dörfler return B_NO_INIT; 518*2d690920SAxel Dörfler 519*2d690920SAxel Dörfler if (!MessagingArea::CheckCommandSize(size)) 520*2d690920SAxel Dörfler return B_BAD_VALUE; 521*2d690920SAxel Dörfler 522*2d690920SAxel Dörfler // delete the discarded areas (save one) 523*2d690920SAxel Dörfler ObjectDeleter<MessagingArea> discardedAreaDeleter; 524*2d690920SAxel Dörfler MessagingArea *discardedArea = NULL; 525*2d690920SAxel Dörfler while (fFirstArea != fLastArea) { 526*2d690920SAxel Dörfler area = fFirstArea; 527*2d690920SAxel Dörfler area->Lock(); 528*2d690920SAxel Dörfler if (area->Size() != 0) { 529*2d690920SAxel Dörfler area->Unlock(); 530*2d690920SAxel Dörfler break; 531*2d690920SAxel Dörfler } 532*2d690920SAxel Dörfler 533*2d690920SAxel Dörfler PRINT(("MessagingService::_AllocateCommand(): Discarding area: %p\n", 534*2d690920SAxel Dörfler area)); 535*2d690920SAxel Dörfler 536*2d690920SAxel Dörfler fFirstArea = area->NextArea(); 537*2d690920SAxel Dörfler area->SetNextArea(NULL); 538*2d690920SAxel Dörfler discardedArea = area; 539*2d690920SAxel Dörfler discardedAreaDeleter.SetTo(area); 540*2d690920SAxel Dörfler } 541*2d690920SAxel Dörfler 542*2d690920SAxel Dörfler // allocate space for the command in the last area 543*2d690920SAxel Dörfler area = fLastArea; 544*2d690920SAxel Dörfler area->Lock(); 545*2d690920SAxel Dörfler data = area->AllocateCommand(commandWhat, size, wasEmpty); 546*2d690920SAxel Dörfler 547*2d690920SAxel Dörfler if (!data) { 548*2d690920SAxel Dörfler // not enough space in the last area: create a new area or reuse a 549*2d690920SAxel Dörfler // discarded one 550*2d690920SAxel Dörfler if (discardedArea) { 551*2d690920SAxel Dörfler area = discardedAreaDeleter.Detach(); 552*2d690920SAxel Dörfler area->InitHeader(); 553*2d690920SAxel Dörfler PRINT(("MessagingService::_AllocateCommand(): Not enough space " 554*2d690920SAxel Dörfler "left in current area. Recycling discarded one: %p\n", area)); 555*2d690920SAxel Dörfler } else { 556*2d690920SAxel Dörfler area = MessagingArea::Create(fLockSem, fCounterSem); 557*2d690920SAxel Dörfler PRINT(("MessagingService::_AllocateCommand(): Not enough space " 558*2d690920SAxel Dörfler "left in current area. Allocated new one: %p\n", area)); 559*2d690920SAxel Dörfler } 560*2d690920SAxel Dörfler if (!area) { 561*2d690920SAxel Dörfler fLastArea->Unlock(); 562*2d690920SAxel Dörfler return B_NO_MEMORY; 563*2d690920SAxel Dörfler } 564*2d690920SAxel Dörfler 565*2d690920SAxel Dörfler // add the new area 566*2d690920SAxel Dörfler fLastArea->SetNextArea(area); 567*2d690920SAxel Dörfler fLastArea->Unlock(); 568*2d690920SAxel Dörfler fLastArea = area; 569*2d690920SAxel Dörfler 570*2d690920SAxel Dörfler // allocate space for the command 571*2d690920SAxel Dörfler data = area->AllocateCommand(commandWhat, size, wasEmpty); 572*2d690920SAxel Dörfler 573*2d690920SAxel Dörfler if (!data) { 574*2d690920SAxel Dörfler // that should never happen 575*2d690920SAxel Dörfler area->Unlock(); 576*2d690920SAxel Dörfler return B_NO_MEMORY; 577*2d690920SAxel Dörfler } 578*2d690920SAxel Dörfler } 579*2d690920SAxel Dörfler 580*2d690920SAxel Dörfler return B_OK; 581*2d690920SAxel Dörfler } 582*2d690920SAxel Dörfler 583