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