xref: /haiku/src/servers/media/AppManager.cpp (revision a09c983cc63b6d50c46a0f2a872fb1adbffcc363)
1 /*
2  * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files or portions
6  * thereof (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject
10  * to the following conditions:
11  *
12  *  * Redistributions of source code must retain the above copyright notice,
13  *    this list of conditions and the following disclaimer.
14  *
15  *  * Redistributions in binary form must reproduce the above copyright notice
16  *    in the  binary, as well as this list of conditions and the following
17  *    disclaimer in the documentation and/or other materials provided with
18  *    the distribution.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  *
28  */
29 
30 
31 #include "AppManager.h"
32 
33 #include <stdio.h>
34 
35 #include <Application.h>
36 #include <Autolock.h>
37 #include <OS.h>
38 #include <Roster.h>
39 
40 #include <debug.h>
41 #include <MediaMisc.h>
42 
43 #include "BufferManager.h"
44 #include "media_server.h"
45 #include "NodeManager.h"
46 #include "NotificationManager.h"
47 
48 
49 AppManager::AppManager()
50 	:
51 	BLocker("media app manager")
52 {
53 	fQuit = create_sem(0, "big brother waits");
54 	fBigBrother = spawn_thread(_BigBrotherEntry, "big brother is watching you",
55 		B_NORMAL_PRIORITY, this);
56 	resume_thread(fBigBrother);
57 }
58 
59 
60 AppManager::~AppManager()
61 {
62 	delete_sem(fQuit);
63 	wait_for_thread(fBigBrother, NULL);
64 }
65 
66 
67 bool
68 AppManager::HasTeam(team_id team)
69 {
70 	BAutolock lock(this);
71 	return fMap.find(team) != fMap.end();
72 }
73 
74 
75 status_t
76 AppManager::RegisterTeam(team_id team, const BMessenger& messenger)
77 {
78 	BAutolock lock(this);
79 
80 	TRACE("AppManager::RegisterTeam %" B_PRId32 "\n", team);
81 	if (HasTeam(team)) {
82 		ERROR("AppManager::RegisterTeam: team %" B_PRId32 " already"
83 			" registered\n", team);
84 		return B_ERROR;
85 	}
86 
87 	try {
88 		fMap.insert(std::make_pair(team, messenger));
89 	} catch (std::bad_alloc& exception) {
90 		return B_NO_MEMORY;
91 	}
92 
93 	return B_OK;
94 }
95 
96 
97 status_t
98 AppManager::UnregisterTeam(team_id team)
99 {
100 	TRACE("AppManager::UnregisterTeam %" B_PRId32 "\n", team);
101 
102 	Lock();
103 	bool isRemoved = fMap.erase(team) != 0;
104 	Unlock();
105 
106 	_CleanupTeam(team);
107 
108 	return isRemoved ? B_OK : B_ERROR;
109 }
110 
111 
112 team_id
113 AppManager::AddOnServerTeam()
114 {
115 	team_id id = be_roster->TeamFor(B_MEDIA_ADDON_SERVER_SIGNATURE);
116 	if (id < 0) {
117 		ERROR("media_server: Trouble, media_addon_server is dead!\n");
118 		return -1;
119 	}
120 	return id;
121 }
122 
123 
124 status_t
125 AppManager::SendMessage(team_id team, BMessage* message)
126 {
127 	BAutolock lock(this);
128 
129 	AppMap::iterator found = fMap.find(team);
130 	if (found == fMap.end())
131 		return B_NAME_NOT_FOUND;
132 
133 	return found->second.SendMessage(message);
134 }
135 
136 
137 void
138 AppManager::Dump()
139 {
140 	BAutolock lock(this);
141 
142 	printf("\n");
143 	printf("AppManager: list of applications follows:\n");
144 
145 	app_info info;
146 	AppMap::iterator iterator = fMap.begin();
147 	for (; iterator != fMap.end(); iterator++) {
148 		app_info info;
149 		be_roster->GetRunningAppInfo(iterator->first, &info);
150 		printf(" team %" B_PRId32 " \"%s\", messenger %svalid\n",
151 			iterator->first, info.ref.name,
152 			iterator->second.IsValid() ? "" : "NOT ");
153 	}
154 
155 	printf("AppManager: list end\n");
156 }
157 
158 
159 void
160 AppManager::_CleanupTeam(team_id team)
161 {
162 	ASSERT(!IsLocked());
163 
164 	TRACE("AppManager: cleaning up team %" B_PRId32 "\n", team);
165 
166 	gNodeManager->CleanupTeam(team);
167 	gBufferManager->CleanupTeam(team);
168 	gNotificationManager->CleanupTeam(team);
169 }
170 
171 
172 void
173 AppManager::_TeamDied(team_id team)
174 {
175 	UnregisterTeam(team);
176 }
177 
178 
179 status_t
180 AppManager::_BigBrotherEntry(void* self)
181 {
182 	static_cast<AppManager*>(self)->_BigBrother();
183 	return 0;
184 }
185 
186 
187 /*!	The BigBrother thread send ping messages to the BMediaRoster of
188 	all currently running teams. If the reply times out or is wrong,
189 	the team cleanup function _TeamDied() will be called.
190 */
191 void
192 AppManager::_BigBrother()
193 {
194 	status_t status = B_TIMED_OUT;
195 	BMessage ping('PING');
196 	BMessage reply;
197 
198 	do {
199 		if (!Lock())
200 			break;
201 
202 		bool startOver = false;
203 		AppMap::iterator iterator = fMap.begin();
204 		for (; iterator != fMap.end(); iterator++) {
205 			reply.what = 0;
206 			status = iterator->second.SendMessage(&ping, &reply, 5000000,
207 				2000000);
208 			if (status != B_OK || reply.what != 'PONG') {
209 				team_id team = iterator->first;
210 				Unlock();
211 
212 				_TeamDied(team);
213 				startOver = true;
214 				break;
215 			}
216 		}
217 
218 		if (startOver)
219 			continue;
220 
221 		Unlock();
222 		status = acquire_sem_etc(fQuit, 1, B_RELATIVE_TIMEOUT, 2000000);
223 	} while (status == B_TIMED_OUT || status == B_INTERRUPTED);
224 }
225