bool BProcess::InsertHandler(BHandler **handlerP, BHandler *handler) { BHandler *p = *handlerP; if (!p) { *handlerP = handler; handler->m_next = handler->m_prev = NULL; return true; } const nsecs_t msgTime = handler->NextMessageTime(NULL); if (p->NextMessageTime(NULL) > msgTime) { (*handlerP)->m_prev = handler; *handlerP = handler; handler->m_next = p; handler->m_prev = NULL; } else { while (p->m_next && (p->m_next->NextMessageTime(NULL) < msgTime)) p = p->m_next; handler->m_next = p->m_next; handler->m_prev = p; if (p->m_next) p->m_next->m_prev = handler; p->m_next = handler; } return false; }
BLooper::~BLooper() { if (fRunCalled && !fTerminating) { debugger("You can't call delete on a BLooper object " "once it is running."); } Lock(); // In case the looper thread calls Quit() fLastMessage is not deleted. if (fLastMessage) { delete fLastMessage; fLastMessage = NULL; } // Close the message port and read and reply to the remaining messages. if (fMsgPort >= 0 && fOwnsPort) close_port(fMsgPort); // Clear the queue so our call to IsMessageWaiting() below doesn't give // us bogus info fDirectTarget->Close(); BMessage* message; while ((message = fDirectTarget->Queue()->NextMessage()) != NULL) { delete message; // msg will automagically post generic reply } if (!fOwnsPort) { do { delete ReadMessageFromPort(0); // msg will automagically post generic reply } while (IsMessageWaiting()); delete_port(fMsgPort); } fDirectTarget->Release(); // Clean up our filters SetCommonFilterList(NULL); AutoLocker<BLooperList> ListLock(gLooperList); RemoveHandler(this); // Remove all the "child" handlers int32 count = fHandlers.CountItems(); for (int32 i = 0; i < count; i++) { BHandler* handler = (BHandler*)fHandlers.ItemAtFast(i); handler->SetNextHandler(NULL); handler->SetLooper(NULL); } fHandlers.MakeEmpty(); Unlock(); gLooperList.RemoveLooper(this); delete_sem(fLockSem); }
/** RemoveHandler(BHandler* handler) @case Valid looper and handler; handler has filters @param handler Valid BHandler pointer @results RemoveHandler() returns true handler->FilterList() returns NULL after removal */ void TRemoveHandlerTest::RemoveHandler5() { BLooper Looper; BHandler Handler; BMessageFilter* MessageFilter = new BMessageFilter('1234'); Handler.AddFilter(MessageFilter); Looper.AddHandler(&Handler); CPPUNIT_ASSERT(Looper.RemoveHandler(&Handler)); CPPUNIT_ASSERT(Handler.FilterList()); }
/* We overwrite SetValue to send a message to the target everytime the setting change and not only at the end. */ void CControl::SetValue(int32 color_value) { BHandler *handler; BColorControl::SetValue(color_value); handler = Target(); if (handler) { BMessage msg; msg.AddInt32("be:value", color_value); handler->Looper()->PostMessage(&msg, handler); } }
void TorrentObject::TorrentMetadataCallback(tr_torrent* torrent, void* data) { TorrentObject* torrentObject = reinterpret_cast<TorrentObject*>(data); BHandler* handler = torrentObject->fMetadataHandler; // // // if( handler == NULL ) return; // // Build the message. // if (BLooper* looper = handler->Looper()) looper->PostMessage(new BMessage(MSG_TRANSMISSION_METADATA_CALLBACK), handler); }
void ArpNotificationType::NotifyDependents(BMessage *msg, bool deliverAsynchronously) { BHandler *h; BLooper *looper; for (long i=0; (h = (BHandler*)dependents.ItemAt(i)) != 0; i++) { if (((looper = h->Looper()) != 0) && (looper->Lock())) { // FIX: need to send out the message, and let the views // invalidate themselves! So be aware that the Update // implementation will ALWAYS be called from within this // loop, meaning within a lock/unlock #if 0 // Uncomment this to debug where messages are going printf("SENDING MESSAGE TO %s\n", h->Name()); fflush(stdout); #endif h->MessageReceived(msg); looper->Unlock(); } } }
filter_result SpinnerMsgFilter::Filter(BMessage *msg, BHandler **target) { int32 c; msg->FindInt32("raw_char",&c); switch (c) { case B_ENTER: { BTextView *text = dynamic_cast<BTextView*>(*target); if (text && text->IsFocus()) { BView *view = text->Parent(); while (view) { Spinner *spin = dynamic_cast<Spinner*>(view); if (spin) { BString string(text->Text()); int32 newvalue = 0; sscanf(string.String(),"%ld",&newvalue); if (newvalue != spin->Value()) { spin->SetValue(newvalue); spin->Invoke(); } return B_SKIP_MESSAGE; } view = view->Parent(); } } return B_DISPATCH_MESSAGE; } case B_TAB: { // Cause Tab characters to perform keybaord navigation BHandler *h = *target; BView *v = NULL; h = h->NextHandler(); while (h) { v = dynamic_cast<BView*>(h); if (v) { *target = v->Window(); return B_DISPATCH_MESSAGE; } h = h->NextHandler(); } return B_SKIP_MESSAGE; } case B_UP_ARROW: case B_DOWN_ARROW: { BTextView *text = dynamic_cast<BTextView*>(*target); if (text && text->IsFocus()) { // We have a text view. See if it currently has the focus and belongs // to a Spinner control. If so, change the value of the spinner // TextViews are complicated beasts which are actually multiple views. // Travel up the hierarchy to see if any of the target's ancestors are // a Spinner. BView *view = text->Parent(); while (view) { Spinner *spin = dynamic_cast<Spinner*>(view); if (spin) { int32 step = spin->GetSteps(); if (c == B_DOWN_ARROW) step = 0 - step; spin->SetValue(spin->Value() + step); spin->Invoke(); return B_SKIP_MESSAGE; } view = view->Parent(); } } return B_DISPATCH_MESSAGE; } default: return B_DISPATCH_MESSAGE; } // shut the stupid compiler up return B_SKIP_MESSAGE; }
void BLooper::task_looper() { PRINT(("BLooper::task_looper()\n")); // Check that looper is locked (should be) AssertLocked(); // Unlock the looper Unlock(); if (IsLocked()) debugger("looper must not be locked!"); // loop: As long as we are not terminating. while (!fTerminating) { PRINT(("LOOPER: outer loop\n")); // TODO: timeout determination algo // Read from message port (how do we determine what the timeout is?) PRINT(("LOOPER: MessageFromPort()...\n")); BMessage* msg = MessageFromPort(); PRINT(("LOOPER: ...done\n")); // Did we get a message? if (msg) _AddMessagePriv(msg); // Get message count from port int32 msgCount = port_count(fMsgPort); for (int32 i = 0; i < msgCount; ++i) { // Read 'count' messages from port (so we will not block) // We use zero as our timeout since we know there is stuff there msg = MessageFromPort(0); if (msg) _AddMessagePriv(msg); } // loop: As long as there are messages in the queue and the port is // empty... and we are not terminating, of course. bool dispatchNextMessage = true; while (!fTerminating && dispatchNextMessage) { PRINT(("LOOPER: inner loop\n")); // Get next message from queue (assign to fLastMessage after // locking) BMessage* message = fDirectTarget->Queue()->NextMessage(); Lock(); fLastMessage = message; if (fLastMessage == NULL) { // No more messages: Unlock the looper and terminate the // dispatch loop. dispatchNextMessage = false; } else { PRINT(("LOOPER: fLastMessage: 0x%lx: %.4s\n", fLastMessage->what, (char*)&fLastMessage->what)); DBG(fLastMessage->PrintToStream()); // Get the target handler BHandler* handler = NULL; BMessage::Private messagePrivate(fLastMessage); bool usePreferred = messagePrivate.UsePreferredTarget(); if (usePreferred) { PRINT(("LOOPER: use preferred target\n")); handler = fPreferred; if (handler == NULL) handler = this; } else { gDefaultTokens.GetToken(messagePrivate.GetTarget(), B_HANDLER_TOKEN, (void**)&handler); // if this handler doesn't belong to us, we drop the message if (handler != NULL && handler->Looper() != this) handler = NULL; PRINT(("LOOPER: use %ld, handler: %p, this: %p\n", messagePrivate.GetTarget(), handler, this)); } // Is this a scripting message? (BMessage::HasSpecifiers()) if (handler != NULL && fLastMessage->HasSpecifiers()) { int32 index = 0; // Make sure the current specifier is kosher if (fLastMessage->GetCurrentSpecifier(&index) == B_OK) handler = resolve_specifier(handler, fLastMessage); } if (handler) { // Do filtering handler = _TopLevelFilter(fLastMessage, handler); PRINT(("LOOPER: _TopLevelFilter(): %p\n", handler)); if (handler && handler->Looper() == this) DispatchMessage(fLastMessage, handler); } } if (fTerminating) { // we leave the looper locked when we quit return; } message = fLastMessage; fLastMessage = NULL; // Unlock the looper Unlock(); // Delete the current message (fLastMessage) if (message != NULL) delete message; // Are any messages on the port? if (port_count(fMsgPort) > 0) { // Do outer loop dispatchNextMessage = false; } } } PRINT(("BLooper::task_looper() done\n")); }
void BHandler::MessageReceived(BMessage* message) { BMessage reply(B_REPLY); switch (message->what) { case kMsgStartObserving: case kMsgStopObserving: { BMessenger target; uint32 what; if (message->FindMessenger(kObserveTarget, &target) != B_OK || message->FindInt32(B_OBSERVE_WHAT_CHANGE, (int32*)&what) != B_OK) { break; } ObserverList* list = _ObserverList(); if (list != NULL) { if (message->what == kMsgStartObserving) list->Add(target, what); else list->Remove(target, what); } break; } case B_GET_PROPERTY: { int32 cur; BMessage specifier; int32 form; const char* prop; status_t err = message->GetCurrentSpecifier(&cur, &specifier, &form, &prop); if (err != B_OK && err != B_BAD_SCRIPT_SYNTAX) break; bool known = false; // B_BAD_SCRIPT_SYNTAX defaults to the Messenger property if (err == B_BAD_SCRIPT_SYNTAX || cur < 0 || (strcmp(prop, "Messenger") == 0)) { err = reply.AddMessenger("result", this); known = true; } else if (strcmp(prop, "Suites") == 0) { err = GetSupportedSuites(&reply); known = true; } else if (strcmp(prop, "InternalName") == 0) { err = reply.AddString("result", Name()); known = true; } if (known) { reply.AddInt32("error", B_OK); message->SendReply(&reply); return; } // let's try next handler break; } case B_GET_SUPPORTED_SUITES: { reply.AddInt32("error", GetSupportedSuites(&reply)); message->SendReply(&reply); return; } } // ToDo: there is some more work needed here // (someone in the know should fill in)! if (fNextHandler) { // we need to apply the next handler's filters here, too BHandler* target = Looper()->_HandlerFilter(message, fNextHandler); if (target != NULL && target != this) { // TODO: we also need to make sure that "target" is not before // us in the handler chain - at least in case it wasn't before // the handler actually targeted with this message - this could // get ugly, though. target->MessageReceived(message); } } else if (message->what != B_MESSAGE_NOT_UNDERSTOOD && (message->WasDropped() || message->HasSpecifiers())) { printf("BHandler %s: MessageReceived() couldn't understand the message:\n", Name()); message->PrintToStream(); message->SendReply(B_MESSAGE_NOT_UNDERSTOOD); } }
void BProcess::DispatchMessage(SLooper* looper) { //bout << "BProcess::DispatchMessage: (" << SysCurrentThread() << ")@" << SysGetRunTime() << endl; BHandler* handler = NULL; int32_t priority = B_NORMAL_PRIORITY; bool firstTime = true; m_lock.LockQuick(); //DbgOnlyFatalErrorIf(m_currentEventConcurrency >= m_maxEventConcurrency, "We have gone past the limit on concurrent handlers!"); if (m_currentEventConcurrency >= m_maxEventConcurrency) { m_lock.Unlock(); return; } m_currentEventConcurrency++; // The binder driver clears its event time when processing an event, // so we always must inform it if there is another one to schedule. m_nextEventTime = B_INFINITE_TIMEOUT; nsecs_t curTime = exact_SysGetRunTime(); while (1) { if ((handler = m_pendingHandlers) != NULL && handler->NextMessageTime(&priority) <= curTime) { m_pendingHandlers = handler->m_next; handler->m_next = handler->m_prev = NULL; if (m_pendingHandlers) m_pendingHandlers->m_prev = NULL; handler->defer_scheduling(); } else { // Nothing to do right now, time to leave. break; } // If this is the first time through the loop, we need to schedule // the next pending handler so that another SLooper thread can be // activated to execute it. if (firstTime) { ScheduleNextEvent(); firstTime = false; } // We are now going to enter user code, don't hold the lock. m_lock.Unlock(); if (handler->AttemptAcquire(this)) { shortcutDispatch: // bout << "BProcess: Thread " << SysCurrentThread() << " dispatch to " << handler << " at pri " << priority << endl; looper->_SetThreadPriority(priority); handler->dispatch_message(); // bout << "BProcess: Thread " << SysCurrentThread() << " returned from dispatch!" << endl; // Update our concept of the time. curTime = approx_SysGetRunTime(); // Big shortcut (one could even call this an optimization // for a particular performance test). If this handler // has the next message that will be processed, just do // it right now. m_lock.LockQuick(); // We can do this if... there is a pending message and it is next... const nsecs_t when = handler->NextMessageTime(&priority); if (m_pendingHandlers == NULL || when <= m_pendingHandlers->NextMessageTime(NULL)) { // And ResumeScheduling() wasn't called while processing the message... if (ResumingScheduling()) { // The above flagged that this thread called ResumeScheduling(), but it // really hasn't. Psych!! ClearSchedulingResumed(); // And it is time for the message. if (when <= curTime) { m_lock.Unlock(); // Whoosh! // bout << "BProcess: Thread " << SysCurrentThread() << " redispatch to same handler!" << endl; goto shortcutDispatch; } } } m_lock.Unlock(); handler->ResumeScheduling(); ClearSchedulingResumed(); handler->Release(this); } handler->DecRefs(this); m_lock.LockQuick(); } // We have handled all available messages. While still holding the // lock, reduce concurrency and schedule the next event to make sure // the binder is up-to-date about when it is to occur. m_currentEventConcurrency--; ScheduleNextEvent(); m_lock.Unlock(); // bout << "BProcess::DispatchMessage Exit: (" << SysCurrentThread() << ")@" << SysGetRunTime() << endl; #if TARGET_HOST == TARGET_HOST_WIN32 // Handler thread pool is implemented entirely in user space on Windows. looper->_SetThreadPriority(B_REAL_TIME_PRIORITY); #endif }