haiku/src/servers/app/MessageLooper.cpp

181 lines
2.9 KiB
C++

/*
* Copyright 2005-2016, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
*/
#include "MessageLooper.h"
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <Autolock.h>
MessageLooper::MessageLooper(const char* name)
:
BLocker(name),
fName(strdup(name)),
fThread(-1),
fQuitting(false),
fDeathSemaphore(-1)
{
}
MessageLooper::~MessageLooper()
{
free((void*)fName);
}
status_t
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 fThread;
}
if (resume_thread(fThread) != B_OK) {
fQuitting = true;
kill_thread(fThread);
fThread = -1;
return B_BAD_THREAD_ID;
}
return B_OK;
}
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)
{
if (fName != NULL)
strlcpy(name, fName, 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 %"
B_PRId32 ", %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;
}