haiku/src/servers/registrar/Registrar.cpp
Ingo Weinhold 6bfd06d1ff BRoster::Launch() eventually launches the application in question
in several steps:
1. early pre-registration with the registrar ("I wanna launch the
   app, make sure noone interferes.")
2. load the app image
3. finish pre-registration with the registrar ("I have launched
   the app, here is its team ID.")
4. start app main thread
5. send "on launch" messages to the app (argv, refs, others)

If the app is already running or being launched, 1. fails with a
conclusive error code and returns the team ID and the pre-registration
token of the app. Steps 2 - 4 are skipped and only the messages are
delivered using the team ID returned by 1.

This change fixes a race condition: The failed early pre-registration
request obviously cannot return the team ID, if the other thread
launching the app has not finished step 3 yet. Thus the argv/refs
message would not get delivered and Launch() would not return the
correct team ID.

Now we wait for the pre-registration to be finished in this case, using
the former _IsAppPreRegistered() mechanism, which already provided
such a waiting feature for one request. It has been extended to
accomodate an arbitrary number of waiting requests and renamed to
_IsAppRegistered().

This fixed bug #763.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18728 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-08-31 17:54:16 +00:00

384 lines
9.0 KiB
C++

// Registrar.cpp
#include "Debug.h"
#include <stdio.h>
#include <string.h>
#include <Application.h>
#include <Message.h>
#include <OS.h>
#include <RegistrarDefs.h>
#include <RosterPrivate.h>
#include "ClipboardHandler.h"
#include "EventQueue.h"
#include "MessageDeliverer.h"
#include "MessageEvent.h"
#include "MessageRunnerManager.h"
#include "MessagingService.h"
#include "MIMEManager.h"
#include "Registrar.h"
#include "ShutdownProcess.h"
#include "TRoster.h"
/*!
\class Registrar
\brief The application class of the registrar.
Glues the registrar services together and dispatches the roster messages.
*/
using std::nothrow;
using namespace BPrivate;
//! Name of the event queue.
static const char *kEventQueueName = "timer_thread";
//! Time interval between two roster sanity checks (1 s).
static const bigtime_t kRosterSanityEventInterval = 1000000LL;
// constructor
/*! \brief Creates the registrar application class.
\param error Passed to the BApplication constructor for returning an
error code.
*/
Registrar::Registrar(status_t *error)
: BServer(kRegistrarSignature, false, error),
fRoster(NULL),
fClipboardHandler(NULL),
fMIMEManager(NULL),
fEventQueue(NULL),
fMessageRunnerManager(NULL),
fSanityEvent(NULL),
fShutdownProcess(NULL)
{
FUNCTION_START();
}
// destructor
/*! \brief Frees all resources associated with the registrar.
All registrar services, that haven't been shut down earlier, are
terminated.
*/
Registrar::~Registrar()
{
FUNCTION_START();
Lock();
fEventQueue->Die();
delete fMessageRunnerManager;
delete fEventQueue;
delete fSanityEvent;
fMIMEManager->Lock();
fMIMEManager->Quit();
RemoveHandler(fClipboardHandler);
delete fClipboardHandler;
delete fRoster;
// Invalidate the global be_roster, so that the BApplication destructor
// won't dead-lock when sending a message to itself.
BRoster::Private().SetTo(BMessenger(), BMessenger());
FUNCTION_END();
}
// MessageReceived
/*! \brief Overrides the super class version to dispatch roster specific
messages.
\param message The message to be handled
*/
void
Registrar::MessageReceived(BMessage *message)
{
switch (message->what) {
// general requests
case B_REG_GET_MIME_MESSENGER:
{
PRINT(("B_REG_GET_MIME_MESSENGER\n"));
BMessenger messenger(NULL, fMIMEManager);
BMessage reply(B_REG_SUCCESS);
reply.AddMessenger("messenger", messenger);
message->SendReply(&reply);
break;
}
case B_REG_GET_CLIPBOARD_MESSENGER:
{
PRINT(("B_REG_GET_CLIPBOARD_MESSENGER\n"));
BMessenger messenger(fClipboardHandler);
BMessage reply(B_REG_SUCCESS);
reply.AddMessenger("messenger", messenger);
message->SendReply(&reply);
break;
}
case B_REG_SHUT_DOWN:
{
PRINT(("B_REG_SHUT_DOWN\n"));
_HandleShutDown(message);
break;
}
// roster requests
case B_REG_ADD_APP:
fRoster->HandleAddApplication(message);
break;
case B_REG_COMPLETE_REGISTRATION:
fRoster->HandleCompleteRegistration(message);
break;
case B_REG_IS_APP_REGISTERED:
fRoster->HandleIsAppRegistered(message);
break;
case B_REG_REMOVE_PRE_REGISTERED_APP:
fRoster->HandleRemovePreRegApp(message);
break;
case B_REG_REMOVE_APP:
fRoster->HandleRemoveApp(message);
break;
case B_REG_SET_THREAD_AND_TEAM:
fRoster->HandleSetThreadAndTeam(message);
break;
case B_REG_SET_SIGNATURE:
fRoster->HandleSetSignature(message);
break;
case B_REG_GET_APP_INFO:
fRoster->HandleGetAppInfo(message);
break;
case B_REG_GET_APP_LIST:
fRoster->HandleGetAppList(message);
break;
case B_REG_ACTIVATE_APP:
fRoster->HandleActivateApp(message);
break;
case B_REG_BROADCAST:
fRoster->HandleBroadcast(message);
break;
case B_REG_START_WATCHING:
fRoster->HandleStartWatching(message);
break;
case B_REG_STOP_WATCHING:
fRoster->HandleStopWatching(message);
break;
case B_REG_GET_RECENT_DOCUMENTS:
fRoster->HandleGetRecentDocuments(message);
break;
case B_REG_GET_RECENT_FOLDERS:
fRoster->HandleGetRecentFolders(message);
break;
case B_REG_GET_RECENT_APPS:
fRoster->HandleGetRecentApps(message);
break;
case B_REG_ADD_TO_RECENT_DOCUMENTS:
fRoster->HandleAddToRecentDocuments(message);
break;
case B_REG_ADD_TO_RECENT_FOLDERS:
fRoster->HandleAddToRecentFolders(message);
break;
case B_REG_ADD_TO_RECENT_APPS:
fRoster->HandleAddToRecentApps(message);
break;
case B_REG_CLEAR_RECENT_DOCUMENTS:
fRoster->ClearRecentDocuments();
break;
case B_REG_CLEAR_RECENT_FOLDERS:
fRoster->ClearRecentFolders();
break;
case B_REG_CLEAR_RECENT_APPS:
fRoster->ClearRecentApps();
break;
case B_REG_LOAD_RECENT_LISTS:
fRoster->HandleLoadRecentLists(message);
break;
case B_REG_SAVE_RECENT_LISTS:
fRoster->HandleSaveRecentLists(message);
break;
// message runner requests
case B_REG_REGISTER_MESSAGE_RUNNER:
fMessageRunnerManager->HandleRegisterRunner(message);
break;
case B_REG_UNREGISTER_MESSAGE_RUNNER:
fMessageRunnerManager->HandleUnregisterRunner(message);
break;
case B_REG_SET_MESSAGE_RUNNER_PARAMS:
fMessageRunnerManager->HandleSetRunnerParams(message);
break;
case B_REG_GET_MESSAGE_RUNNER_INFO:
fMessageRunnerManager->HandleGetRunnerInfo(message);
break;
// internal messages
case B_REG_ROSTER_SANITY_EVENT:
fRoster->CheckSanity();
fSanityEvent->SetTime(system_time() + kRosterSanityEventInterval);
fEventQueue->AddEvent(fSanityEvent);
break;
case B_REG_SHUTDOWN_FINISHED:
if (fShutdownProcess) {
fShutdownProcess->PostMessage(B_QUIT_REQUESTED,
fShutdownProcess);
fShutdownProcess = NULL;
}
break;
default:
BApplication::MessageReceived(message);
break;
}
}
// ReadyToRun
/*! \brief Overrides the super class version to initialize the registrar
services.
*/
void
Registrar::ReadyToRun()
{
FUNCTION_START();
// create message deliverer
status_t error = MessageDeliverer::CreateDefault();
if (error != B_OK) {
FATAL(("Registrar::ReadyToRun(): Failed to create the message "
"deliverer: %s\n", strerror(error)));
}
// create event queue
fEventQueue = new EventQueue(kEventQueueName);
// create roster
fRoster = new TRoster;
fRoster->Init();
// create clipboard handler
fClipboardHandler = new ClipboardHandler;
AddHandler(fClipboardHandler);
// create MIME manager
fMIMEManager = new MIMEManager;
fMIMEManager->Run();
// create message runner manager
fMessageRunnerManager = new MessageRunnerManager(fEventQueue);
// init the global be_roster
BRoster::Private().SetTo(be_app_messenger, BMessenger(NULL, fMIMEManager));
// create the messaging service
error = MessagingService::CreateDefault();
if (error != B_OK) {
ERROR(("Registrar::ReadyToRun(): Failed to init messaging service "
"(that's by design when running under R5): %s\n", strerror(error)));
}
// create and schedule the sanity message event
fSanityEvent = new MessageEvent(system_time() + kRosterSanityEventInterval,
this, B_REG_ROSTER_SANITY_EVENT);
fSanityEvent->SetAutoDelete(false);
fEventQueue->AddEvent(fSanityEvent);
FUNCTION_END();
}
// QuitRequested
/*! \brief Overrides the super class version to avoid termination of the
registrar until the system shutdown.
*/
bool
Registrar::QuitRequested()
{
FUNCTION_START();
// The final registrar must not quit. At least not that easily. ;-)
return BApplication::QuitRequested();
}
// GetEventQueue
/*! \brief Returns the registrar's event queue.
\return The registrar's event queue.
*/
EventQueue*
Registrar::GetEventQueue() const
{
return fEventQueue;
}
// App
/*! \brief Returns the Registrar application object.
\return The Registrar application object.
*/
Registrar*
Registrar::App()
{
return dynamic_cast<Registrar*>(be_app);
}
// _HandleShutDown
/*! \brief Handle a shut down request message.
\param request The request to be handled.
*/
void
Registrar::_HandleShutDown(BMessage *request)
{
status_t error = B_OK;
// check, whether we're already shutting down
if (fShutdownProcess)
error = B_SHUTTING_DOWN;
bool needsReply = true;
if (error == B_OK) {
// create a ShutdownProcess
fShutdownProcess = new(nothrow) ShutdownProcess(fRoster, fEventQueue);
if (fShutdownProcess) {
error = fShutdownProcess->Init(request);
if (error == B_OK) {
DetachCurrentMessage();
fShutdownProcess->Run();
needsReply = false;
} else {
delete fShutdownProcess;
fShutdownProcess = NULL;
}
} else
error = B_NO_MEMORY;
}
if (needsReply)
ShutdownProcess::SendReply(request, error);
}
// main
/*! \brief Creates and runs the registrar application.
The main thread is renamed.
\return 0.
*/
int
main()
{
FUNCTION_START();
// create and run the registrar application
status_t error;
Registrar *app = new Registrar(&error);
if (error != B_OK) {
fprintf(stderr, "REG: Failed to create the BApplication: %s\n",
strerror(error));
return 1;
}
// rename the main thread
rename_thread(find_thread(NULL), kRosterThreadName);
PRINT(("app->Run()...\n"));
app->Run();
PRINT(("delete app...\n"));
delete app;
FUNCTION_END();
return 0;
}