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