xref: /haiku/src/servers/media/AppManager.cpp (revision 4afae676ad98b8f1e219f704dfc9c8507bce106e)
1 /*
2  * Copyright 2002, Marcus Overhagen. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <OS.h>
7 #include <Application.h>
8 #include <Roster.h>
9 #include <Directory.h>
10 #include <Entry.h>
11 #include <Messenger.h>
12 #include <Autolock.h>
13 #include <stdio.h>
14 #include "debug.h"
15 #include "AppManager.h"
16 #include "NodeManager.h"
17 #include "BufferManager.h"
18 #include "NotificationManager.h"
19 #include "media_server.h"
20 
21 AppManager::AppManager()
22  :	fAddonServer(-1)
23 {
24 	fAppMap = new Map<team_id, App>;
25 	fLocker = new BLocker("app manager locker");
26 	fQuit = create_sem(0, "big brother waits");
27 	fBigBrother = spawn_thread(bigbrother, "big brother is watching you", B_NORMAL_PRIORITY, this);
28 	resume_thread(fBigBrother);
29 }
30 
31 AppManager::~AppManager()
32 {
33 	status_t err;
34 	delete_sem(fQuit);
35 	wait_for_thread(fBigBrother, &err);
36 	delete fLocker;
37 	delete fAppMap;
38 }
39 
40 bool AppManager::HasTeam(team_id team)
41 {
42 	BAutolock lock(fLocker);
43 	return fAppMap->Has(team);
44 }
45 
46 status_t AppManager::RegisterTeam(team_id team, BMessenger messenger)
47 {
48 	BAutolock lock(fLocker);
49 	TRACE("AppManager::RegisterTeam %ld\n", team);
50 	if (HasTeam(team)) {
51 		FATAL("Erorr: AppManager::RegisterTeam: team %ld already registered\n", team);
52 		return B_ERROR;
53 	}
54 	App app;
55 	app.team = team;
56 	app.messenger = messenger;
57 	return fAppMap->Insert(team, app) ? B_OK : B_ERROR;
58 }
59 
60 status_t AppManager::UnregisterTeam(team_id team)
61 {
62 	bool is_removed;
63 	bool is_addon_server;
64 
65 	TRACE("AppManager::UnregisterTeam %ld\n", team);
66 
67 	fLocker->Lock();
68 	is_removed = fAppMap->Remove(team);
69 	is_addon_server = fAddonServer == team;
70 	if (is_addon_server)
71 		fAddonServer = -1;
72 	fLocker->Unlock();
73 
74 	CleanupTeam(team);
75 	if (is_addon_server)
76 		CleanupAddonServer();
77 
78 	return is_removed ? B_OK : B_ERROR;
79 }
80 
81 void AppManager::RestartAddonServer()
82 {
83 	static bigtime_t restart_period = 0;
84 	static int restart_tries = 0;
85 	restart_tries++;
86 
87 	if (((system_time() - restart_period) > 60000000LL) && (restart_tries < 5)) {
88 		restart_period = system_time();
89 		restart_tries = 0;
90 	}
91 	if (restart_tries < 5) {
92 		FATAL("AppManager: Restarting media_addon_server...\n");
93 		// XXX fixme. We should wait until it is *really* gone
94 		snooze(5000000);
95 		StartAddonServer();
96 	} else {
97 		FATAL("AppManager: media_addon_server crashed too often, not restarted\n");
98 	}
99 }
100 
101 
102 void AppManager::TeamDied(team_id team)
103 {
104 	CleanupTeam(team);
105 	fLocker->Lock();
106 	fAppMap->Remove(team);
107 	fLocker->Unlock();
108 }
109 
110 status_t AppManager::RegisterAddonServer(team_id team)
111 {
112 	BAutolock lock(fLocker);
113 	if (fAddonServer != -1)
114 		return B_ERROR;
115 	fAddonServer = team;
116 	return B_OK;
117 }
118 
119 //=========================================================================
120 // The BigBrother thread send ping messages to the BMediaRoster of
121 // all currently running teams. If the reply times out or is wrong,
122 // the team cleanup function TeamDied() will be called. If the dead
123 // team is the media_addon_server, additionally CleanupAddonServer()
124 // will be called and also RestartAddonServer()
125 //=========================================================================
126 
127 int32 AppManager::bigbrother(void *self)
128 {
129 	static_cast<AppManager *>(self)->BigBrother();
130 	return 0;
131 }
132 
133 void AppManager::BigBrother()
134 {
135 	bool restart_addon_server;
136 	status_t status;
137 	BMessage msg('PING');
138 	BMessage reply;
139 	team_id team;
140 	App *app;
141 	do {
142 		if (!fLocker->Lock())
143 			break;
144 		for (fAppMap->Rewind(); fAppMap->GetNext(&app); ) {
145 			reply.what = 0;
146 			status = app->messenger.SendMessage(&msg, &reply, 5000000, 2000000);
147 			if (status != B_OK || reply.what != 'PONG') {
148 				team = app->team;
149 				if (fAddonServer == team) {
150 					restart_addon_server = true;
151 					fAddonServer = -1;
152 				} else {
153 					restart_addon_server = false;
154 				}
155 				fLocker->Unlock();
156 				TeamDied(team);
157 				if (restart_addon_server) {
158 					CleanupAddonServer();
159 					RestartAddonServer();
160 				}
161 				continue;
162 			}
163 		}
164 		fLocker->Unlock();
165 		status = acquire_sem_etc(fQuit, 1, B_RELATIVE_TIMEOUT, 2000000);
166 	} while (status == B_TIMED_OUT || status == B_INTERRUPTED);
167 }
168 
169 //=========================================================================
170 // The following functions must be called unlocked.
171 // They clean up after a crash, or start/terminate the media_addon_server.
172 //=========================================================================
173 
174 void AppManager::CleanupTeam(team_id team)
175 {
176 	ASSERT(false == fLocker->IsLocked());
177 
178 	TRACE("AppManager: cleaning up team %ld\n", team);
179 
180 	gNodeManager->CleanupTeam(team);
181 	gBufferManager->CleanupTeam(team);
182 	gNotificationManager->CleanupTeam(team);
183 }
184 
185 void AppManager::CleanupAddonServer()
186 {
187 	ASSERT(false == fLocker->IsLocked());
188 
189 	TRACE("AppManager: cleaning up media_addon_server\n");
190 
191 }
192 
193 void AppManager::StartAddonServer()
194 {
195 	ASSERT(false == fLocker->IsLocked());
196 
197 	app_info info;
198 	be_app->GetAppInfo(&info);
199 	BEntry entry(&info.ref);
200 	entry.GetParent(&entry);
201 	BDirectory dir(&entry);
202 	entry.SetTo(&dir, "media_addon_server");
203 	entry_ref ref;
204 	entry.GetRef(&ref);
205 	be_roster->Launch(&ref);
206 }
207 
208 void AppManager::TerminateAddonServer()
209 {
210 	ASSERT(false == fLocker->IsLocked());
211 
212 	if (fAddonServer != -1) {
213 		BMessenger msger(NULL, fAddonServer);
214 		msger.SendMessage(B_QUIT_REQUESTED);
215 		// XXX fixme. We should wait until it is gone
216 		snooze(1000000);
217 	}
218 }
219