xref: /haiku/src/servers/media/AppManager.cpp (revision 2600324b57fa31cdea1627d584d314f2a579c4a8)
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 #include <OS.h>
31 #include <Application.h>
32 #include <Roster.h>
33 #include <Messenger.h>
34 #include <Autolock.h>
35 #include <stdio.h>
36 #include "debug.h"
37 #include "MediaMisc.h"
38 #include "AppManager.h"
39 #include "NodeManager.h"
40 #include "BufferManager.h"
41 #include "NotificationManager.h"
42 #include "media_server.h"
43 
44 AppManager::AppManager()
45 {
46 	fAppMap = new Map<team_id, App>;
47 	fLocker = new BLocker("app manager locker");
48 	fQuit = create_sem(0, "big brother waits");
49 	fBigBrother = spawn_thread(bigbrother, "big brother is watching you", B_NORMAL_PRIORITY, this);
50 	resume_thread(fBigBrother);
51 }
52 
53 
54 AppManager::~AppManager()
55 {
56 	status_t err;
57 	delete_sem(fQuit);
58 	wait_for_thread(fBigBrother, &err);
59 	delete fLocker;
60 	delete fAppMap;
61 }
62 
63 
64 bool
65 AppManager::HasTeam(team_id team)
66 {
67 	BAutolock lock(fLocker);
68 	return fAppMap->Has(team);
69 }
70 
71 
72 status_t
73 AppManager::RegisterTeam(team_id team, BMessenger messenger)
74 {
75 	BAutolock lock(fLocker);
76 	TRACE("AppManager::RegisterTeam %ld\n", team);
77 	if (HasTeam(team)) {
78 		ERROR("AppManager::RegisterTeam: team %ld already registered\n", team);
79 		return B_ERROR;
80 	}
81 	App app;
82 	app.team = team;
83 	app.messenger = messenger;
84 	return fAppMap->Insert(team, app) ? B_OK : B_ERROR;
85 }
86 
87 
88 status_t
89 AppManager::UnregisterTeam(team_id team)
90 {
91 	bool is_removed;
92 
93 	TRACE("AppManager::UnregisterTeam %ld\n", team);
94 
95 	fLocker->Lock();
96 	is_removed = fAppMap->Remove(team);
97 	fLocker->Unlock();
98 
99 	CleanupTeam(team);
100 
101 	return is_removed ? B_OK : B_ERROR;
102 }
103 
104 
105 status_t
106 AppManager::SendMessage(team_id team, BMessage *msg)
107 {
108 	BAutolock lock(fLocker);
109 	App *app;
110 	if (!fAppMap->Get(team, &app))
111 		return B_ERROR;
112 	return app->messenger.SendMessage(msg);
113 }
114 
115 
116 void
117 AppManager::TeamDied(team_id team)
118 {
119 	CleanupTeam(team);
120 	fLocker->Lock();
121 	fAppMap->Remove(team);
122 	fLocker->Unlock();
123 }
124 
125 
126 team_id
127 AppManager::AddonServerTeam()
128 {
129 	team_id id = be_roster->TeamFor(B_MEDIA_ADDON_SERVER_SIGNATURE);
130 	if (id < 0) {
131 		ERROR("media_server: Trouble, media_addon_server is dead!\n");
132 		return -1;
133 	}
134 	return id;
135 }
136 
137 
138 //=========================================================================
139 // The BigBrother thread send ping messages to the BMediaRoster of
140 // all currently running teams. If the reply times out or is wrong,
141 // the team cleanup function TeamDied() will be called.
142 //=========================================================================
143 
144 int32
145 AppManager::bigbrother(void *self)
146 {
147 	static_cast<AppManager *>(self)->BigBrother();
148 	return 0;
149 }
150 
151 
152 void
153 AppManager::BigBrother()
154 {
155 	status_t status;
156 	BMessage msg('PING');
157 	BMessage reply;
158 	team_id team;
159 	App *app;
160 	do {
161 		if (!fLocker->Lock())
162 			break;
163 		for (fAppMap->Rewind(); fAppMap->GetNext(&app); ) {
164 			reply.what = 0;
165 			status = app->messenger.SendMessage(&msg, &reply, 5000000, 2000000);
166 			if (status != B_OK || reply.what != 'PONG') {
167 				team = app->team;
168 				fLocker->Unlock();
169 				TeamDied(team);
170 				continue;
171 			}
172 		}
173 		fLocker->Unlock();
174 		status = acquire_sem_etc(fQuit, 1, B_RELATIVE_TIMEOUT, 2000000);
175 	} while (status == B_TIMED_OUT || status == B_INTERRUPTED);
176 }
177 
178 //=========================================================================
179 // The following functions must be called unlocked.
180 // They clean up after a crash, or start/terminate the media_addon_server.
181 //=========================================================================
182 
183 void
184 AppManager::CleanupTeam(team_id team)
185 {
186 	ASSERT(false == fLocker->IsLocked());
187 
188 	TRACE("AppManager: cleaning up team %ld\n", team);
189 
190 	gNodeManager->CleanupTeam(team);
191 	gBufferManager->CleanupTeam(team);
192 	gNotificationManager->CleanupTeam(team);
193 }
194 
195 
196 void
197 AppManager::Dump()
198 {
199 	BAutolock lock(fLocker);
200 	printf("\n");
201 	printf("AppManager: list of applications follows:\n");
202 	App *app;
203 	app_info info;
204 	for (fAppMap->Rewind(); fAppMap->GetNext(&app); ) {
205 		be_roster->GetRunningAppInfo(app->team, &info);
206 		printf(" team %ld \"%s\", messenger %svalid\n", app->team, info.ref.name, app->messenger.IsValid() ? "" : "NOT ");
207 	}
208 	printf("AppManager: list end\n");
209 }
210