189ab121eSAxel Dörfler/*
2f744935bSAxel Dörfler * Copyright 2005-2016, Haiku.
389ab121eSAxel Dörfler * Distributed under the terms of the MIT License.
489ab121eSAxel Dörfler *
589ab121eSAxel Dörfler * Authors:
689ab121eSAxel Dörfler *		Axel D��rfler, axeld@pinc-software.de
789ab121eSAxel Dörfler */
889ab121eSAxel Dörfler
989ab121eSAxel Dörfler
1089ab121eSAxel Dörfler#include "MessageLooper.h"
1189ab121eSAxel Dörfler
12399fe9fcSAugustin Cavalier#include <malloc.h>
13770c05d6SAxel Dörfler#include <stdio.h>
14758b1d0eSIngo Weinhold#include <string.h>
1589ab121eSAxel Dörfler
16b9bedde4SClemens Zeidler#include <Autolock.h>
17b9bedde4SClemens Zeidler
1889ab121eSAxel Dörfler
1989ab121eSAxel DörflerMessageLooper::MessageLooper(const char* name)
20b9bedde4SClemens Zeidler	:
21b9bedde4SClemens Zeidler	BLocker(name),
22bae7a949SAugustin Cavalier	fName(strdup(name)),
2319b0fb93SAxel Dörfler	fThread(-1),
2419b0fb93SAxel Dörfler	fQuitting(false),
2519b0fb93SAxel Dörfler	fDeathSemaphore(-1)
2689ab121eSAxel Dörfler{
2789ab121eSAxel Dörfler}
2889ab121eSAxel Dörfler
2989ab121eSAxel Dörfler
3089ab121eSAxel DörflerMessageLooper::~MessageLooper()
3189ab121eSAxel Dörfler{
32bae7a949SAugustin Cavalier	free((void*)fName);
3389ab121eSAxel Dörfler}
3489ab121eSAxel Dörfler
3589ab121eSAxel Dörfler
36f744935bSAxel Dörflerstatus_t
3789ab121eSAxel DörflerMessageLooper::Run()
3889ab121eSAxel Dörfler{
3989ab121eSAxel Dörfler	BAutolock locker(this);
4089ab121eSAxel Dörfler
4189ab121eSAxel Dörfler	fQuitting = false;
4289ab121eSAxel Dörfler
4389ab121eSAxel Dörfler	char name[B_OS_NAME_LENGTH];
4489ab121eSAxel Dörfler	_GetLooperName(name, sizeof(name));
4589ab121eSAxel Dörfler
4689ab121eSAxel Dörfler	// Spawn our message-monitoring thread
475131b5bcSAxel Dörfler	fThread = spawn_thread(_message_thread, name, B_DISPLAY_PRIORITY, this);
4889ab121eSAxel Dörfler	if (fThread < B_OK) {
4989ab121eSAxel Dörfler		fQuitting = true;
50f744935bSAxel Dörfler		return fThread;
5189ab121eSAxel Dörfler	}
5289ab121eSAxel Dörfler
5389ab121eSAxel Dörfler	if (resume_thread(fThread) != B_OK) {
5489ab121eSAxel Dörfler		fQuitting = true;
5589ab121eSAxel Dörfler		kill_thread(fThread);
5689ab121eSAxel Dörfler		fThread = -1;
57f744935bSAxel Dörfler		return B_BAD_THREAD_ID;
5889ab121eSAxel Dörfler	}
5989ab121eSAxel Dörfler
60f744935bSAxel Dörfler	return B_OK;
6189ab121eSAxel Dörfler}
6289ab121eSAxel Dörfler
6389ab121eSAxel Dörfler
6489ab121eSAxel Dörflervoid
6589ab121eSAxel DörflerMessageLooper::Quit()
6689ab121eSAxel Dörfler{
67c6a25272SAxel Dörfler	fQuitting = true;
68c6a25272SAxel Dörfler	_PrepareQuit();
69c6a25272SAxel Dörfler
70c6a25272SAxel Dörfler	if (fThread < B_OK) {
71c6a25272SAxel Dörfler		// thread has not been started yet
72c6a25272SAxel Dörfler		delete this;
73c6a25272SAxel Dörfler		return;
74c6a25272SAxel Dörfler	}
75c6a25272SAxel Dörfler
76c6a25272SAxel Dörfler	if (fThread == find_thread(NULL)) {
77c6a25272SAxel Dörfler		// called from our message looper
78c6a25272SAxel Dörfler		delete this;
79c6a25272SAxel Dörfler		exit_thread(0);
80c6a25272SAxel Dörfler	} else {
81c6a25272SAxel Dörfler		// called from a different thread
82c6a25272SAxel Dörfler		PostMessage(kMsgQuitLooper);
83c6a25272SAxel Dörfler	}
8489ab121eSAxel Dörfler}
8589ab121eSAxel Dörfler
8689ab121eSAxel Dörfler
8789ab121eSAxel Dörfler/*!
8889ab121eSAxel Dörfler	\brief Send a message to the looper without any attachments
8989ab121eSAxel Dörfler	\param code ID code of the message to post
9089ab121eSAxel Dörfler*/
9167e79bf4SAxel Dörflerstatus_t
92b02ce811SAxel DörflerMessageLooper::PostMessage(int32 code, bigtime_t timeout)
9389ab121eSAxel Dörfler{
94770c05d6SAxel Dörfler	BPrivate::LinkSender link(MessagePort());
9589ab121eSAxel Dörfler	link.StartMessage(code);
96b02ce811SAxel Dörfler	return link.Flush(timeout);
9767e79bf4SAxel Dörfler}
9867e79bf4SAxel Dörfler
9967e79bf4SAxel Dörfler
10067e79bf4SAxel Dörfler/*static*/
10167e79bf4SAxel Dörflerstatus_t
10267e79bf4SAxel DörflerMessageLooper::WaitForQuit(sem_id semaphore, bigtime_t timeout)
10367e79bf4SAxel Dörfler{
10467e79bf4SAxel Dörfler	status_t status;
10567e79bf4SAxel Dörfler	do {
10667e79bf4SAxel Dörfler		status = acquire_sem_etc(semaphore, 1, B_RELATIVE_TIMEOUT, timeout);
10767e79bf4SAxel Dörfler	} while (status == B_INTERRUPTED);
10867e79bf4SAxel Dörfler
10967e79bf4SAxel Dörfler	if (status == B_TIMED_OUT)
11067e79bf4SAxel Dörfler		return status;
11167e79bf4SAxel Dörfler
11267e79bf4SAxel Dörfler	return B_OK;
11389ab121eSAxel Dörfler}
11489ab121eSAxel Dörfler
11589ab121eSAxel Dörfler
116c6a25272SAxel Dörflervoid
117c6a25272SAxel DörflerMessageLooper::_PrepareQuit()
118c6a25272SAxel Dörfler{
119c6a25272SAxel Dörfler	// to be implemented by subclasses
120c6a25272SAxel Dörfler}
121c6a25272SAxel Dörfler
122c6a25272SAxel Dörfler
12389ab121eSAxel Dörflervoid
12489ab121eSAxel DörflerMessageLooper::_GetLooperName(char* name, size_t length)
12589ab121eSAxel Dörfler{
126565155afSAugustin Cavalier	if (fName != NULL)
127565155afSAugustin Cavalier		strlcpy(name, fName, length);
128a632458dSAxel Dörfler	else
129a632458dSAxel Dörfler		strlcpy(name, "unnamed looper", length);
13089ab121eSAxel Dörfler}
13189ab121eSAxel Dörfler
13289ab121eSAxel Dörfler
13389ab121eSAxel Dörflervoid
13489ab121eSAxel DörflerMessageLooper::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
13589ab121eSAxel Dörfler{
13689ab121eSAxel Dörfler}
13789ab121eSAxel Dörfler
13889ab121eSAxel Dörfler
13989ab121eSAxel Dörflervoid
14089ab121eSAxel DörflerMessageLooper::_MessageLooper()
14189ab121eSAxel Dörfler{
142770c05d6SAxel Dörfler	BPrivate::LinkReceiver& receiver = fLink.Receiver();
143770c05d6SAxel Dörfler
144770c05d6SAxel Dörfler	while (true) {
145770c05d6SAxel Dörfler		int32 code;
146770c05d6SAxel Dörfler		status_t status = receiver.GetNextMessage(code);
147770c05d6SAxel Dörfler		if (status < B_OK) {
148770c05d6SAxel Dörfler			// that shouldn't happen, it's our port
149a632458dSAxel Dörfler			char name[256];
150a632458dSAxel Dörfler			_GetLooperName(name, 256);
1513fed1a15SAlex Smith			printf("MessageLooper \"%s\": Someone deleted our message port %"
1523fed1a15SAlex Smith				B_PRId32 ", %s!\n", name, receiver.Port(), strerror(status));
153770c05d6SAxel Dörfler			break;
154770c05d6SAxel Dörfler		}
155770c05d6SAxel Dörfler
156770c05d6SAxel Dörfler		Lock();
157770c05d6SAxel Dörfler
158e3d73948SJulian Harnath		if (code == kMsgQuitLooper)
159770c05d6SAxel Dörfler			Quit();
160e3d73948SJulian Harnath		else
161770c05d6SAxel Dörfler			_DispatchMessage(code, receiver);
162770c05d6SAxel Dörfler
163770c05d6SAxel Dörfler		Unlock();
164770c05d6SAxel Dörfler	}
16589ab121eSAxel Dörfler}
16689ab121eSAxel Dörfler
16789ab121eSAxel Dörfler
16889ab121eSAxel Dörfler/*!
16989ab121eSAxel Dörfler	\brief Message-dispatching loop starter
17089ab121eSAxel Dörfler*/
17189ab121eSAxel Dörfler/*static*/
17289ab121eSAxel Dörflerint32
17389ab121eSAxel DörflerMessageLooper::_message_thread(void* _looper)
17489ab121eSAxel Dörfler{
17589ab121eSAxel Dörfler	MessageLooper* looper = (MessageLooper*)_looper;
17689ab121eSAxel Dörfler
17789ab121eSAxel Dörfler	looper->_MessageLooper();
17889ab121eSAxel Dörfler	return 0;
17989ab121eSAxel Dörfler}
18089ab121eSAxel Dörfler
181