xref: /haiku/src/servers/media/AppManager.cpp (revision 7a74a5df454197933bc6e80a542102362ee98703)
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 %ld\n", team);
81 	if (HasTeam(team)) {
82 		ERROR("AppManager::RegisterTeam: team %ld already registered\n", team);
83 		return B_ERROR;
84 	}
85 
86 	try {
87 		fMap.insert(std::make_pair(team, messenger));
88 	} catch (std::bad_alloc& exception) {
89 		return B_NO_MEMORY;
90 	}
91 
92 	return B_OK;
93 }
94 
95 
96 status_t
97 AppManager::UnregisterTeam(team_id team)
98 {
99 	TRACE("AppManager::UnregisterTeam %ld\n", team);
100 
101 	Lock();
102 	bool isRemoved = fMap.erase(team) != 0;
103 	Unlock();
104 
105 	_CleanupTeam(team);
106 
107 	return isRemoved ? B_OK : B_ERROR;
108 }
109 
110 
111 team_id
112 AppManager::AddOnServerTeam()
113 {
114 	team_id id = be_roster->TeamFor(B_MEDIA_ADDON_SERVER_SIGNATURE);
115 	if (id < 0) {
116 		ERROR("media_server: Trouble, media_addon_server is dead!\n");
117 		return -1;
118 	}
119 	return id;
120 }
121 
122 
123 status_t
124 AppManager::SendMessage(team_id team, BMessage* message)
125 {
126 	BAutolock lock(this);
127 
128 	AppMap::iterator found = fMap.find(team);
129 	if (found == fMap.end())
130 		return B_NAME_NOT_FOUND;
131 
132 	return found->second.SendMessage(message);
133 }
134 
135 
136 void
137 AppManager::Dump()
138 {
139 	BAutolock lock(this);
140 
141 	printf("\n");
142 	printf("AppManager: list of applications follows:\n");
143 
144 	app_info info;
145 	AppMap::iterator iterator = fMap.begin();
146 	for (; iterator != fMap.end(); iterator++) {
147 		app_info info;
148 		be_roster->GetRunningAppInfo(iterator->first, &info);
149 		printf(" team %ld \"%s\", messenger %svalid\n", iterator->first,
150 			info.ref.name, iterator->second.IsValid() ? "" : "NOT ");
151 	}
152 
153 	printf("AppManager: list end\n");
154 }
155 
156 
157 void
158 AppManager::_CleanupTeam(team_id team)
159 {
160 	ASSERT(!IsLocked());
161 
162 	TRACE("AppManager: cleaning up team %ld\n", team);
163 
164 	gNodeManager->CleanupTeam(team);
165 	gBufferManager->CleanupTeam(team);
166 	gNotificationManager->CleanupTeam(team);
167 }
168 
169 
170 void
171 AppManager::_TeamDied(team_id team)
172 {
173 	UnregisterTeam(team);
174 }
175 
176 
177 status_t
178 AppManager::_BigBrotherEntry(void* self)
179 {
180 	static_cast<AppManager*>(self)->_BigBrother();
181 	return 0;
182 }
183 
184 
185 /*!	The BigBrother thread send ping messages to the BMediaRoster of
186 	all currently running teams. If the reply times out or is wrong,
187 	the team cleanup function _TeamDied() will be called.
188 */
189 void
190 AppManager::_BigBrother()
191 {
192 	status_t status = B_TIMED_OUT;
193 	BMessage ping('PING');
194 	BMessage reply;
195 
196 	do {
197 		if (!Lock())
198 			break;
199 
200 		bool startOver = false;
201 		AppMap::iterator iterator = fMap.begin();
202 		for (; iterator != fMap.end(); iterator++) {
203 			reply.what = 0;
204 			status = iterator->second.SendMessage(&ping, &reply, 5000000,
205 				2000000);
206 			if (status != B_OK || reply.what != 'PONG') {
207 				team_id team = iterator->first;
208 				Unlock();
209 
210 				_TeamDied(team);
211 				startOver = true;
212 				break;
213 			}
214 		}
215 
216 		if (startOver)
217 			continue;
218 
219 		Unlock();
220 		status = acquire_sem_etc(fQuit, 1, B_RELATIVE_TIMEOUT, 2000000);
221 	} while (status == B_TIMED_OUT || status == B_INTERRUPTED);
222 }
223