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