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