Shutdown: follow up on ff6135f474eed07e58bbd1557cd2cd8ee8027677

* calling TRoster::GetShutdownApps() multiple times with the same lists
leads to problems because the lists aren't emptied first.
* instead we watch the user app launches, add them in the fUserApps list,
and let _QuitApps() iterates through the fUserApps list until it is empty.
This commit is contained in:
Jérôme Duval 2018-03-10 15:48:26 +01:00
parent 7de029128e
commit 6899a856fe
4 changed files with 64 additions and 40 deletions

View File

@ -593,7 +593,7 @@ private:
ShutdownProcess::ShutdownProcess(TRoster* roster, EventQueue* eventQueue)
:
BLooper("shutdown process"),
EventMaskWatcher(BMessenger(this), B_REQUEST_QUIT),
EventMaskWatcher(BMessenger(this), B_REQUEST_QUIT | B_REQUEST_LAUNCHED),
fWorkerLock("worker lock"),
fRequest(NULL),
fRoster(roster),
@ -769,6 +769,26 @@ ShutdownProcess::MessageReceived(BMessage* message)
break;
}
case B_SOME_APP_LAUNCHED:
{
// get the team
team_id team;
if (message->FindInt32("be:team", &team) != B_OK) {
// should not happen
return;
}
PRINT("ShutdownProcess::MessageReceived(): B_SOME_APP_LAUNCHED: %"
B_PRId32 "\n", team);
// add the user app info to the respective list
{
BAutolock _(fWorkerLock);
fRoster->AddAppInfo(fUserApps, team);
}
break;
}
case MSG_PHASE_TIMED_OUT:
{
// get the phase the event is intended for
@ -1232,20 +1252,6 @@ ShutdownProcess::_Worker()
}
status_t
ShutdownProcess::_GetUserAndSystemAppList()
{
fWorkerLock.Lock();
// Get a list of all applications to shut down
status_t status = fRoster->GetShutdownApps(fUserApps, fSystemApps,
fBackgroundApps, fVitalSystemApps);
fUserApps.Sort(&inverse_compare_by_registration_time);
fWorkerLock.Unlock();
return status;
}
void
ShutdownProcess::_WorkerDoShutdown()
{
@ -1289,6 +1295,21 @@ ShutdownProcess::_WorkerDoShutdown()
throw_error(B_SHUTDOWN_CANCELLED);
}
fWorkerLock.Lock();
// get a list of all applications to shut down and sort them
status_t status = fRoster->GetShutdownApps(fUserApps, fSystemApps,
fBackgroundApps, fVitalSystemApps);
if (status != B_OK) {
fWorkerLock.Unlock();
fRoster->RemoveWatcher(this);
return;
}
fUserApps.Sort(&inverse_compare_by_registration_time);
fSystemApps.Sort(&inverse_compare_by_registration_time);
fWorkerLock.Unlock();
// make the shutdown window ready and show it
_InitShutdownWindow();
_SetShutdownWindowCurrentApp(-1);
@ -1302,36 +1323,16 @@ ShutdownProcess::_WorkerDoShutdown()
// phase 1: terminate the user apps
_SetPhase(USER_APP_TERMINATION_PHASE);
status_t status;
// Since, new apps can still be launched,
// loop until all are gone
while ((status = _GetUserAndSystemAppList()) == B_OK
&& !fUserApps.IsEmpty()) {
// since, new apps can still be launched, loop until all are gone
if (!fUserApps.IsEmpty()) {
_QuitApps(fUserApps, false);
_WaitForDebuggedTeams();
}
if (status != B_OK) {
fRoster->RemoveWatcher(this);
return;
}
// tell TRoster not to accept new applications anymore
fRoster->SetShuttingDown(true);
// Check once again for any user apps to quit
status = _GetUserAndSystemAppList();
if (status != B_OK) {
fRoster->RemoveWatcher(this);
return;
}
_QuitApps(fUserApps, false);
_WaitForDebuggedTeams();
fWorkerLock.Lock();
fSystemApps.Sort(&inverse_compare_by_registration_time);
fWorkerLock.Unlock();
// phase 2: terminate the system apps
_SetPhase(SYSTEM_APP_TERMINATION_PHASE);
_QuitApps(fSystemApps, true);

View File

@ -88,8 +88,6 @@ private:
void _DisplayAbortingApp(team_id team);
void _WaitForDebuggedTeams();
status_t _GetUserAndSystemAppList();
private:
class TimeoutEvent;
class InternalEvent;

View File

@ -1486,6 +1486,30 @@ TRoster::GetShutdownApps(AppInfoList& userApps, AppInfoList& systemApps,
}
status_t
TRoster::AddAppInfo(AppInfoList& apps, team_id team)
{
BAutolock _(fLock);
for (AppInfoList::Iterator it(fRegisteredApps.It());
RosterAppInfo* info = *it; ++it) {
if (info->team == team) {
RosterAppInfo* clonedInfo = info->Clone();
status_t error = B_NO_MEMORY;
if (clonedInfo != NULL) {
if (!apps.AddInfo(clonedInfo))
delete clonedInfo;
else
error = B_OK;
}
return error;
}
}
return B_BAD_TEAM_ID;
}
status_t
TRoster::AddWatcher(Watcher* watcher)
{

View File

@ -78,6 +78,7 @@ public:
AppInfoList& systemApps,
AppInfoList& backgroundApps,
hash_set<team_id>& vitalSystemApps);
status_t AddAppInfo(AppInfoList& apps, team_id team);
status_t AddWatcher(Watcher* watcher);
void RemoveWatcher(Watcher* watcher);