haiku/src/servers/app/MessageLooper.cpp
Axel Dörfler a632458d8e The wonders of signals:
* Since the app_server launched the input_server, it would also get notified
  when the latter died via a signal - but LinkReceiver could return B_INTERRUPTED
  in that case (it didn't check the return value of port_buffer_size()) which
  the app_server misinterpreted and quit itself... this fixes the hanging part
  of bug #1298.
* But the input_server still wasn't restarted, because the Registrar had it
  still listed as being running. Now, the Registrar checks not just periodically
  for died teams, it will also check for it when a new application registers
  itself. This fixes the rest of bug #1298.
* Removed the old (disabled) R5 style input_server launch mechanism from the
  app_server.
* MessageLooper now prints a bit more information when a port is supposed to
  have been deleted.
* The default implementation of MessageLooper::_GetLooperName() is now
  returning the name of the semaphore of its BLocker instead of "unnamed
  looper".


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22115 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-08-30 00:09:43 +00:00

178 lines
2.9 KiB
C++

/*
* Copyright 2005-2007, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
*/
#include "MessageLooper.h"
#include <Autolock.h>
#include <stdio.h>
#include <string.h>
MessageLooper::MessageLooper(const char* name)
: BLocker(name),
fThread(-1),
fQuitting(false),
fDeathSemaphore(-1)
{
}
MessageLooper::~MessageLooper()
{
}
bool
MessageLooper::Run()
{
BAutolock locker(this);
fQuitting = false;
char name[B_OS_NAME_LENGTH];
_GetLooperName(name, sizeof(name));
// Spawn our message-monitoring thread
fThread = spawn_thread(_message_thread, name, B_DISPLAY_PRIORITY, this);
if (fThread < B_OK) {
fQuitting = true;
return false;
}
if (resume_thread(fThread) != B_OK) {
fQuitting = true;
kill_thread(fThread);
fThread = -1;
return false;
}
return true;
}
void
MessageLooper::Quit()
{
fQuitting = true;
_PrepareQuit();
if (fThread < B_OK) {
// thread has not been started yet
delete this;
return;
}
if (fThread == find_thread(NULL)) {
// called from our message looper
delete this;
exit_thread(0);
} else {
// called from a different thread
PostMessage(kMsgQuitLooper);
}
}
/*!
\brief Send a message to the looper without any attachments
\param code ID code of the message to post
*/
status_t
MessageLooper::PostMessage(int32 code, bigtime_t timeout)
{
BPrivate::LinkSender link(MessagePort());
link.StartMessage(code);
return link.Flush(timeout);
}
/*static*/
status_t
MessageLooper::WaitForQuit(sem_id semaphore, bigtime_t timeout)
{
status_t status;
do {
status = acquire_sem_etc(semaphore, 1, B_RELATIVE_TIMEOUT, timeout);
} while (status == B_INTERRUPTED);
if (status == B_TIMED_OUT)
return status;
return B_OK;
}
void
MessageLooper::_PrepareQuit()
{
// to be implemented by subclasses
}
void
MessageLooper::_GetLooperName(char* name, size_t length)
{
sem_id semaphore = Sem();
sem_info info;
if (get_sem_info(semaphore, &info) == B_OK)
strlcpy(name, info.name, length);
else
strlcpy(name, "unnamed looper", length);
}
void
MessageLooper::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
{
}
void
MessageLooper::_MessageLooper()
{
BPrivate::LinkReceiver& receiver = fLink.Receiver();
while (true) {
int32 code;
status_t status = receiver.GetNextMessage(code);
if (status < B_OK) {
// that shouldn't happen, it's our port
char name[256];
_GetLooperName(name, 256);
printf("MessageLooper \"%s\": Someone deleted our message port %ld, %s!\n",
name, receiver.Port(), strerror(status));
break;
}
Lock();
if (code == kMsgQuitLooper) {
Quit();
} else
_DispatchMessage(code, receiver);
Unlock();
}
}
/*!
\brief Message-dispatching loop starter
*/
/*static*/
int32
MessageLooper::_message_thread(void* _looper)
{
MessageLooper* looper = (MessageLooper*)_looper;
looper->_MessageLooper();
return 0;
}