示例#1
0
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;
}
示例#2
0
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());
}
示例#4
0
/* 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);
	}
}					
示例#5
0
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();
		}
	}
}
示例#7
0
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;
}
示例#8
0
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"));
}
示例#9
0
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);
	}
}
示例#10
0
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
}