bonefish+axeld:

* The debug_server now sends the registrar messages whenever the debug alert
  is shown, and also, if the user wants to debug the team.
* In the latter case, the registrar will now cancel a shutdown process.
* Also, it will now wait with the shutdown process until the user has
  acknowledged the debugger alert.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22926 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-11-14 01:28:47 +00:00
parent bfccde1f6a
commit 7301a7fbdb
5 changed files with 168 additions and 57 deletions

View File

@ -104,6 +104,9 @@ enum {
B_REG_UPDATE_DISK_DEVICE = 'rgud',
B_REG_DEVICE_START_WATCHING = 'rgwd',
B_REG_DEVICE_STOP_WATCHING = 'rgsd',
// debug_server notifications
B_REG_TEAM_DEBUGGER_ALERT = 'rtda',
};
// B_REG_MIME_SET_PARAM "which" constants

View File

@ -19,6 +19,7 @@
#include <Entry.h>
#include <Invoker.h>
#include <RegistrarDefs.h>
#include <RosterPrivate.h>
#include <Server.h>
@ -115,6 +116,7 @@ private:
const void *address, char *buffer, int32 bufferSize);
void _PrintStackTrace(thread_id thread);
void _NotifyAppServer(team_id team);
void _NotifyRegistrar(team_id team, bool openAlert, bool stopShutdown);
status_t _InitGUI();
@ -258,8 +260,7 @@ TeamDebugHandlerRoster *TeamDebugHandlerRoster::sRoster = NULL;
// DebugServer
class DebugServer : public BServer
{
class DebugServer : public BServer {
public:
DebugServer(status_t &error);
@ -558,16 +559,20 @@ TeamDebugHandler::_HandleMessage(DebugMessage *message)
} else if (USE_GUI && _AreGUIServersAlive() && _InitGUI() == B_OK) {
// normal app -- tell the user
_NotifyAppServer(fTeam);
_NotifyRegistrar(fTeam, true, false);
char buffer[1024];
snprintf(buffer, sizeof(buffer), "The application:\n\n %s\n\n"
"has encountered an error which prevents it from continuing. Haiku "
"will terminate the application and clean up.", fTeamInfo.args);
// TODO: It would be nice if the alert would go away automatically
// if someone else kills our teams.
BAlert *alert = new BAlert(NULL, buffer, "Debug", "OK", NULL,
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
int32 result = alert->Go();
kill = (result == 1);
_NotifyRegistrar(fTeam, false, !kill);
}
return kill;
@ -688,6 +693,22 @@ TeamDebugHandler::_NotifyAppServer(team_id team)
roster.ApplicationCrashed(team);
}
void
TeamDebugHandler::_NotifyRegistrar(team_id team, bool openAlert,
bool stopShutdown)
{
BMessage notify(BPrivate::B_REG_TEAM_DEBUGGER_ALERT);
notify.AddInt32("team", team);
notify.AddBool("open", openAlert);
notify.AddBool("stop shutdown", stopShutdown);
BRoster::Private roster;
BMessage reply;
roster.SendTo(&notify, &reply, false);
}
// _InitGUI
status_t
TeamDebugHandler::_InitGUI()
@ -895,7 +916,7 @@ DebugServer::Init()
return B_OK;
}
// QuitRequested
bool
DebugServer::QuitRequested()
{

View File

@ -222,6 +222,7 @@ Registrar::_MessageReceived(BMessage *message)
break;
}
// shutdown process
case B_REG_SHUT_DOWN:
{
PRINT(("B_REG_SHUT_DOWN\n"));
@ -229,6 +230,12 @@ Registrar::_MessageReceived(BMessage *message)
_HandleShutDown(message);
break;
}
case B_REG_TEAM_DEBUGGER_ALERT:
{
if (fShutdownProcess != NULL)
fShutdownProcess->PostMessage(message);
break;
}
// roster requests
case B_REG_ADD_APP:

View File

@ -62,13 +62,13 @@ static const bigtime_t kNonAppQuitTimeout = 500000; // 0.5 s
static const bigtime_t kDisplayAbortingAppTimeout = 3000000; // 3 s
// message what fields
// message what fields (must not clobber the registrar's message namespace)
enum {
MSG_PHASE_TIMED_OUT = 'phto',
MSG_DONE = 'done',
MSG_KILL_APPLICATION = 'kill',
MSG_CANCEL_SHUTDOWN = 'cncl',
MSG_REBOOT_SYSTEM = 'rbot',
MSG_REBOOT_SYSTEM = 'lbot',
};
// internal events
@ -79,6 +79,7 @@ enum {
APP_QUIT_EVENT,
KILL_APP_EVENT,
REBOOT_SYSTEM_EVENT,
DEBUG_EVENT
};
// phases
@ -790,21 +791,15 @@ PRINT(("MSG_PHASE_TIMED_OUT: phase: %ld, team: %ld\n", phase, team));
if (message->FindInt32("team", &team) != B_OK)
break;
BAutolock _(fWorkerLock);
// post the event
_PushEvent(KILL_APP_EVENT, team, fCurrentPhase);
break;
}
case MSG_CANCEL_SHUTDOWN:
{
BAutolock _(fWorkerLock);
// post the event
_PushEvent(ABORT_EVENT, -1, fCurrentPhase);
break;
}
@ -812,7 +807,6 @@ PRINT(("MSG_PHASE_TIMED_OUT: phase: %ld, team: %ld\n", phase, team));
{
// post the event
_PushEvent(REBOOT_SYSTEM_EVENT, -1, INVALID_PHASE);
break;
}
@ -820,7 +814,34 @@ PRINT(("MSG_PHASE_TIMED_OUT: phase: %ld, team: %ld\n", phase, team));
{
// notify the registrar that we're done
be_app->PostMessage(B_REG_SHUTDOWN_FINISHED, be_app);
break;
}
case B_REG_TEAM_DEBUGGER_ALERT:
{
bool stopShutdown;
if (message->FindBool("stop shutdown", &stopShutdown) == B_OK
&& stopShutdown) {
// post abort event to the worker
_PushEvent(ABORT_EVENT, -1, fCurrentPhase);
break;
}
bool open;
team_id team;
if (message->FindInt32("team", &team) != B_OK
|| message->FindBool("open", &open) != B_OK)
break;
BAutolock _(fWorkerLock);
if (open) {
PRINT(("B_REG_TEAM_DEBUGGER_ALERT: insert %ld\n", team));
fDebuggedTeams.insert(team);
} else {
PRINT(("B_REG_TEAM_DEBUGGER_ALERT: remove %ld\n", team));
fDebuggedTeams.erase(team);
_PushEvent(DEBUG_EVENT, -1, fCurrentPhase);
}
break;
}
@ -1145,10 +1166,9 @@ ShutdownProcess::_GetNextEvent(uint32 &eventType, thread_id &team, int32 &phase,
do {
error = acquire_sem(fInternalEventSemaphore);
} while (error == B_INTERRUPTED);
if (error != B_OK)
return error;
} else {
status_t error = acquire_sem_etc(fInternalEventSemaphore, 1,
B_RELATIVE_TIMEOUT, 0);
@ -1157,10 +1177,10 @@ ShutdownProcess::_GetNextEvent(uint32 &eventType, thread_id &team, int32 &phase,
return B_OK;
}
}
// get the event
BAutolock _(fWorkerLock);
InternalEvent *event = fInternalEvents->Head();
fInternalEvents->Remove(event);
@ -1259,14 +1279,17 @@ ShutdownProcess::_WorkerDoShutdown()
// phase 1: terminate the user apps
_SetPhase(USER_APP_TERMINATION_PHASE);
_QuitApps(fUserApps, false);
_WaitForDebuggedTeams();
// phase 2: terminate the system apps
_SetPhase(SYSTEM_APP_TERMINATION_PHASE);
_QuitApps(fSystemApps, true);
_WaitForDebuggedTeams();
// phase 3: terminate the background apps
_SetPhase(BACKGROUND_APP_TERMINATION_PHASE);
_QuitBackgroundApps();
_WaitForDebuggedTeams();
// phase 4: terminate the other processes
_SetPhase(OTHER_PROCESSES_TERMINATION_PHASE);
@ -1274,6 +1297,7 @@ ShutdownProcess::_WorkerDoShutdown()
_ScheduleTimeoutEvent(kBackgroundAppQuitTimeout, -1);
_WaitForBackgroundApps();
_KillBackgroundApps();
_WaitForDebuggedTeams();
// we're through: do the shutdown
_SetPhase(DONE_PHASE);
@ -1311,7 +1335,49 @@ ShutdownProcess::_WorkerDoShutdown()
#endif
}
// _QuitApps
bool
ShutdownProcess::_WaitForApp(team_id team, AppInfoList *list, bool systemApps)
{
uint32 event;
do {
team_id eventTeam;
int32 phase;
status_t error = _GetNextEvent(event, eventTeam, phase, true);
if (error != B_OK)
throw_error(error);
if (event == APP_QUIT_EVENT && eventTeam == team)
return true;
if (event == TIMEOUT_EVENT && eventTeam == team)
return false;
if (event == ABORT_EVENT) {
if (systemApps) {
// If the app requests aborting the shutdown, we don't need
// to wait any longer. It has processed the request and
// won't quit by itself. We ignore this for system apps.
if (eventTeam == team)
return false;
} else {
PRINT(("ShutdownProcess::_QuitApps(): shutdown cancelled "
"by team %ld (-1 => user)\n", eventTeam));
_DisplayAbortingApp(team);
throw_error(B_SHUTDOWN_CANCELLED);
}
}
BAutolock _(fWorkerLock);
if (list != NULL && !list->InfoFor(team))
return true;
} while (event != NO_EVENT);
return false;
}
void
ShutdownProcess::_QuitApps(AppInfoList &list, bool systemApps)
{
@ -1401,44 +1467,7 @@ ShutdownProcess::_QuitApps(AppInfoList &list, bool systemApps)
_ScheduleTimeoutEvent(kAppQuitTimeout, team);
// wait for the app to die or for the timeout to occur
bool appGone = false;
do {
team_id eventTeam;
int32 phase;
status_t error = _GetNextEvent(event, eventTeam, phase, true);
if (error != B_OK)
throw_error(error);
if ((event == APP_QUIT_EVENT)
&& eventTeam == team) {
appGone = true;
}
if (event == TIMEOUT_EVENT && eventTeam == team)
break;
if (event == ABORT_EVENT) {
if (systemApps) {
// If the app requests aborting the shutdown, we don't need
// to wait any longer. It has processed the request and
// won't quit by itself. We ignore this for system apps.
if (eventTeam == team)
break;
} else {
PRINT(("ShutdownProcess::_QuitApps(): shutdown cancelled "
"by team %ld (-1 => user)\n", eventTeam));
_DisplayAbortingApp(team);
throw_error(B_SHUTDOWN_CANCELLED);
}
}
BAutolock _(fWorkerLock);
if (!list.InfoFor(team))
break;
} while (event != NO_EVENT);
bool appGone = _WaitForApp(team, &list, systemApps);
if (appGone) {
// fine: the app finished in an orderly manner
} else {
@ -1623,7 +1652,17 @@ void
ShutdownProcess::_QuitBlockingApp(AppInfoList &list, team_id team,
const char *appName, bool cancelAllowed)
{
if (BPrivate::is_app_showing_modal_window(team)) {
bool debugged = false;
bool modal = false;
{
BAutolock _(fWorkerLock);
if (fDebuggedTeams.find(team) != fDebuggedTeams.end())
debugged = true;
}
if (!debugged)
modal = BPrivate::is_app_showing_modal_window(team);
if (modal) {
// app blocks on a modal window
char buffer[1024];
snprintf(buffer, sizeof(buffer), "The application \"%s\" might be "
@ -1631,7 +1670,9 @@ ShutdownProcess::_QuitBlockingApp(AppInfoList &list, team_id team,
_SetShutdownWindowText(buffer);
_SetShutdownWindowCurrentApp(team);
_SetShutdownWindowKillButtonEnabled(true);
}
if (modal || debugged) {
// wait for something to happen
bool appGone = false;
while (true) {
@ -1651,7 +1692,7 @@ ShutdownProcess::_QuitBlockingApp(AppInfoList &list, team_id team,
break;
if (event == ABORT_EVENT) {
if (cancelAllowed) {
if (cancelAllowed || debugged) {
PRINT(("ShutdownProcess::_QuitBlockingApp(): shutdown "
"cancelled by team %ld (-1 => user)\n", eventTeam));
@ -1758,3 +1799,39 @@ ShutdownProcess::_DisplayAbortingApp(team_id team)
}
}
/*! Waits until the debugged team list is empty, ie. when there is no one
left to debug.
*/
void
ShutdownProcess::_WaitForDebuggedTeams()
{
PRINT(("ShutdownProcess::_WaitForDebuggedTeams()\n"));
{
BAutolock _(fWorkerLock);
if (fDebuggedTeams.empty())
return;
}
PRINT((" not empty!\n"));
// wait for something to happen
while (true) {
uint32 event;
team_id eventTeam;
int32 phase;
status_t error = _GetNextEvent(event, eventTeam, phase, true);
if (error != B_OK)
throw_error(error);
if (event == ABORT_EVENT)
throw_error(B_SHUTDOWN_CANCELLED);
BAutolock _(fWorkerLock);
if (fDebuggedTeams.empty()) {
PRINT((" out empty"));
return;
}
}
}

View File

@ -70,6 +70,7 @@ private:
status_t _Worker();
void _WorkerDoShutdown();
bool _WaitForApp(team_id team, AppInfoList *list, bool systemApps);
void _QuitApps(AppInfoList &list, bool systemApps);
void _QuitBackgroundApps();
void _WaitForBackgroundApps();
@ -78,6 +79,7 @@ private:
void _QuitBlockingApp(AppInfoList &list, team_id team, const char *appName,
bool cancelAllowed);
void _DisplayAbortingApp(team_id team);
void _WaitForDebuggedTeams();
private:
class TimeoutEvent;
@ -97,6 +99,7 @@ private:
AppInfoList fSystemApps;
AppInfoList fUserApps;
AppInfoList fBackgroundApps;
hash_set<team_id> fDebuggedTeams;
TimeoutEvent *fTimeoutEvent;
InternalEventList *fInternalEvents;
sem_id fInternalEventSemaphore;