xref: /haiku/src/servers/app/MessageLooper.cpp (revision 399fe9fc1a929cbbae784a4a97eff98e7934a5ac)
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 
MessageLooper(const char * name)19 MessageLooper::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 
~MessageLooper()30 MessageLooper::~MessageLooper()
31 {
32 	free((void*)fName);
33 }
34 
35 
36 status_t
Run()37 MessageLooper::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 
64 void
Quit()65 MessageLooper::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 */
91 status_t
PostMessage(int32 code,bigtime_t timeout)92 MessageLooper::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*/
101 status_t
WaitForQuit(sem_id semaphore,bigtime_t timeout)102 MessageLooper::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 
116 void
_PrepareQuit()117 MessageLooper::_PrepareQuit()
118 {
119 	// to be implemented by subclasses
120 }
121 
122 
123 void
_GetLooperName(char * name,size_t length)124 MessageLooper::_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 
133 void
_DispatchMessage(int32 code,BPrivate::LinkReceiver & link)134 MessageLooper::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
135 {
136 }
137 
138 
139 void
_MessageLooper()140 MessageLooper::_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*/
172 int32
_message_thread(void * _looper)173 MessageLooper::_message_thread(void* _looper)
174 {
175 	MessageLooper* looper = (MessageLooper*)_looper;
176 
177 	looper->_MessageLooper();
178 	return 0;
179 }
180 
181