1/*
2 * Copyright 2005-2016, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel D��rfler, axeld@pinc-software.de
7 */
8
9
10#include "MessageLooper.h"
11
12#include <malloc.h>
13#include <stdio.h>
14#include <string.h>
15
16#include <Autolock.h>
17
18
19MessageLooper::MessageLooper(const char* name)
20	:
21	BLocker(name),
22	fName(strdup(name)),
23	fThread(-1),
24	fQuitting(false),
25	fDeathSemaphore(-1)
26{
27}
28
29
30MessageLooper::~MessageLooper()
31{
32	free((void*)fName);
33}
34
35
36status_t
37MessageLooper::Run()
38{
39	BAutolock locker(this);
40
41	fQuitting = false;
42
43	char name[B_OS_NAME_LENGTH];
44	_GetLooperName(name, sizeof(name));
45
46	// Spawn our message-monitoring thread
47	fThread = spawn_thread(_message_thread, name, B_DISPLAY_PRIORITY, this);
48	if (fThread < B_OK) {
49		fQuitting = true;
50		return fThread;
51	}
52
53	if (resume_thread(fThread) != B_OK) {
54		fQuitting = true;
55		kill_thread(fThread);
56		fThread = -1;
57		return B_BAD_THREAD_ID;
58	}
59
60	return B_OK;
61}
62
63
64void
65MessageLooper::Quit()
66{
67	fQuitting = true;
68	_PrepareQuit();
69
70	if (fThread < B_OK) {
71		// thread has not been started yet
72		delete this;
73		return;
74	}
75
76	if (fThread == find_thread(NULL)) {
77		// called from our message looper
78		delete this;
79		exit_thread(0);
80	} else {
81		// called from a different thread
82		PostMessage(kMsgQuitLooper);
83	}
84}
85
86
87/*!
88	\brief Send a message to the looper without any attachments
89	\param code ID code of the message to post
90*/
91status_t
92MessageLooper::PostMessage(int32 code, bigtime_t timeout)
93{
94	BPrivate::LinkSender link(MessagePort());
95	link.StartMessage(code);
96	return link.Flush(timeout);
97}
98
99
100/*static*/
101status_t
102MessageLooper::WaitForQuit(sem_id semaphore, bigtime_t timeout)
103{
104	status_t status;
105	do {
106		status = acquire_sem_etc(semaphore, 1, B_RELATIVE_TIMEOUT, timeout);
107	} while (status == B_INTERRUPTED);
108
109	if (status == B_TIMED_OUT)
110		return status;
111
112	return B_OK;
113}
114
115
116void
117MessageLooper::_PrepareQuit()
118{
119	// to be implemented by subclasses
120}
121
122
123void
124MessageLooper::_GetLooperName(char* name, size_t length)
125{
126	if (fName != NULL)
127		strlcpy(name, fName, length);
128	else
129		strlcpy(name, "unnamed looper", length);
130}
131
132
133void
134MessageLooper::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
135{
136}
137
138
139void
140MessageLooper::_MessageLooper()
141{
142	BPrivate::LinkReceiver& receiver = fLink.Receiver();
143
144	while (true) {
145		int32 code;
146		status_t status = receiver.GetNextMessage(code);
147		if (status < B_OK) {
148			// that shouldn't happen, it's our port
149			char name[256];
150			_GetLooperName(name, 256);
151			printf("MessageLooper \"%s\": Someone deleted our message port %"
152				B_PRId32 ", %s!\n", name, receiver.Port(), strerror(status));
153			break;
154		}
155
156		Lock();
157
158		if (code == kMsgQuitLooper)
159			Quit();
160		else
161			_DispatchMessage(code, receiver);
162
163		Unlock();
164	}
165}
166
167
168/*!
169	\brief Message-dispatching loop starter
170*/
171/*static*/
172int32
173MessageLooper::_message_thread(void* _looper)
174{
175	MessageLooper* looper = (MessageLooper*)_looper;
176
177	looper->_MessageLooper();
178	return 0;
179}
180
181