MessagingArea * MessagingArea::Create(sem_id lockSem, sem_id counterSem) { // allocate the object on the heap MessagingArea *area = new(nothrow) MessagingArea; if (!area) return NULL; // create the area area->fID = create_area("messaging", (void**)&area->fHeader, B_ANY_KERNEL_ADDRESS, kMessagingAreaSize, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA); if (area->fID < 0) { delete area; return NULL; } // finish the initialization of the object area->fSize = kMessagingAreaSize; area->fLockSem = lockSem; area->fCounterSem = counterSem; area->fNextArea = NULL; area->InitHeader(); return area; }
status_t MessagingService::UnregisterService() { // check, if the team calling this function is indeed the server team thread_info threadInfo; status_t error = get_thread_info(find_thread(NULL), &threadInfo); if (error != B_OK) return error; if (threadInfo.team != fServerTeam) return B_BAD_VALUE; // delete all areas while (fFirstArea) { MessagingArea *area = fFirstArea; fFirstArea = area->NextArea(); delete area; } fLastArea = NULL; // unset the other members fLockSem = -1; fCounterSem = -1; fServerTeam = -1; return B_OK; }
status_t MessagingService::SendMessage(const void *message, int32 messageSize, const messaging_target *targets, int32 targetCount) { PRINT(("MessagingService::SendMessage(%p, %ld, %p, %ld)\n", message, messageSize, targets, targetCount)); if (!message || messageSize <= 0 || !targets || targetCount <= 0) return B_BAD_VALUE; int32 dataSize = sizeof(messaging_command_send_message) + targetCount * sizeof(messaging_target) + messageSize; // allocate space for the command MessagingArea *area; void *data; bool wasEmpty; status_t error = _AllocateCommand(MESSAGING_COMMAND_SEND_MESSAGE, dataSize, area, data, wasEmpty); if (error != B_OK) { PRINT(("MessagingService::SendMessage(): Failed to allocate space for " "send message command.\n")); return error; } PRINT((" Allocated space for send message command: area: %p, data: %p, " "wasEmpty: %d\n", area, data, wasEmpty)); // prepare the command messaging_command_send_message *command = (messaging_command_send_message*)data; command->message_size = messageSize; command->target_count = targetCount; memcpy(command->targets, targets, sizeof(messaging_target) * targetCount); memcpy((char*)command + (dataSize - messageSize), message, messageSize); // shoot area->Unlock(); if (wasEmpty) area->CommitCommand(); return B_OK; }
// _CommandProcessor int32 MessagingService::_CommandProcessor() { bool commandWaiting = false; while (!fTerminating) { // wait for the next command if (!commandWaiting) { status_t error = acquire_sem(fCounterSem); if (error != B_OK) continue; } else commandWaiting = false; // get it from the first area MessagingArea *area = fFirstArea; area->Lock(); while (area->CountCommands() > 0) { const messaging_command *command = area->PopCommand(); if (!command) { // something's seriously wrong ERROR("MessagingService::_CommandProcessor(): area %p (%" B_PRId32 ") has command count %" B_PRId32 ", but doesn't " "return any more commands.", area, area->ID(), area->CountCommands()); break; } PRINT("MessagingService::_CommandProcessor(): got command %" B_PRIu32 "\n", command->command); // dispatch the command MessagingCommandHandler *handler = _GetCommandHandler(command->command); if (handler) { handler->HandleMessagingCommand(command->command, command->data, command->size - sizeof(messaging_command)); } else { WARNING("MessagingService::_CommandProcessor(): No handler " "found for command %" B_PRIu32 "\n", command->command); } } // there is a new area we don't know yet if (!area->NextArea() && area->NextKernelAreaID() >= 0) { // create it MessagingArea *nextArea; status_t error = MessagingArea::Create(area->NextKernelAreaID(), fLockSem, fCounterSem, nextArea); if (error == B_OK) { area->SetNextArea(nextArea); commandWaiting = true; } else { // Bad, but what can we do? ERROR("MessagingService::_CommandProcessor(): Failed to clone " "kernel area %" B_PRId32 ": %s\n", area->NextKernelAreaID(), strerror(error)); } } // if the current area is empty and there is a next one, we discard the // current one if (area->NextArea() && area->CountCommands() == 0) { fFirstArea = area->NextArea(); area->Discard(); area->Unlock(); delete area; } else { area->Unlock(); } } return 0; }