--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -163,16 +163,21 @@
#include "nsILocalFileMac.h"
#include "nsCommandLineServiceMac.h"
#endif
// for X remote support
#ifdef MOZ_ENABLE_XREMOTE
#include "XRemoteClient.h"
#include "nsIRemoteService.h"
+#include "nsProfileLock.h"
+#include "SpecialSystemDirectory.h"
+#include <sched.h>
+// Time to wait for the remoting service to start
+#define MOZ_XREMOTE_START_TIMEOUT_SEC 5
#endif
#if defined(DEBUG) && defined(XP_WIN32)
#include <malloc.h>
#endif
#if defined (XP_MACOSX)
#include <Carbon/Carbon.h>
@@ -1674,49 +1679,54 @@ DumpVersion()
printf("%s %s", gAppData->name, gAppData->version);
if (gAppData->copyright)
printf(", %s", gAppData->copyright);
printf("\n");
}
#ifdef MOZ_ENABLE_XREMOTE
static RemoteResult
-RemoteCommandLine(const char* aDesktopStartupID)
+ParseRemoteCommandLine(nsCString& program,
+ const char** profile,
+ const char** username)
{
- nsresult rv;
ArgResult ar;
- const char *profile = 0;
- nsAutoCString program(gAppData->remotingName);
- ToLowerCase(program);
- const char *username = getenv("LOGNAME");
-
- ar = CheckArg("p", false, &profile, false);
+ ar = CheckArg("p", false, profile, false);
if (ar == ARG_BAD) {
// Leave it to the normal command line handling to handle this situation.
return REMOTE_NOT_FOUND;
}
const char *temp = nullptr;
ar = CheckArg("a", true, &temp);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
return REMOTE_ARG_BAD;
} else if (ar == ARG_FOUND) {
program.Assign(temp);
}
- ar = CheckArg("u", true, &username);
+ ar = CheckArg("u", true, username);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
return REMOTE_ARG_BAD;
}
+ return REMOTE_FOUND;
+}
+
+static RemoteResult
+StartRemoteClient(const char* aDesktopStartupID,
+ nsCString& program,
+ const char* profile,
+ const char* username)
+{
XRemoteClient client;
- rv = client.Init();
+ nsresult rv = client.Init();
if (NS_FAILED(rv))
return REMOTE_NOT_FOUND;
nsXPIDLCString response;
bool success = false;
rv = client.SendCommandLine(program.get(), username, profile,
gArgc, gArgv, aDesktopStartupID,
getter_Copies(response), &success);
@@ -3013,16 +3023,18 @@ public:
nsCOMPtr<nsINativeAppSupport> mNativeApp;
nsCOMPtr<nsIToolkitProfileService> mProfileSvc;
nsCOMPtr<nsIFile> mProfD;
nsCOMPtr<nsIFile> mProfLD;
nsCOMPtr<nsIProfileLock> mProfileLock;
#ifdef MOZ_ENABLE_XREMOTE
nsCOMPtr<nsIRemoteService> mRemoteService;
+ nsProfileLock mRemoteLock;
+ nsCOMPtr<nsIFile> mRemoteLockDir;
#endif
UniquePtr<ScopedXPCOMStartup> mScopedXPCOM;
nsAutoPtr<mozilla::ScopedAppData> mAppData;
nsXREDirProvider mDirProvider;
nsAutoCString mProfileName;
nsAutoCString mDesktopStartupID;
@@ -3750,27 +3762,68 @@ XREMain::XRE_mainStartup(bool* aExitFlag
newInstance = true;
} else {
e = PR_GetEnv("MOZ_NEW_INSTANCE");
newInstance = (e && *e);
}
}
if (!newInstance) {
+ nsAutoCString program(gAppData->remotingName);
+ ToLowerCase(program);
+
+ const char* username = getenv("LOGNAME");
+ const char* profile = nullptr;
+
+ RemoteResult rr = ParseRemoteCommandLine(program, &profile, &username);
+ if (rr == REMOTE_ARG_BAD) {
+ return 1;
+ }
+
+ nsCOMPtr<nsIFile> mutexDir;
+ rv = GetSpecialSystemDirectory(OS_TemporaryDirectory, getter_AddRefs(mutexDir));
+ if (NS_SUCCEEDED(rv)) {
+ nsAutoCString mutexPath =
+ program + NS_LITERAL_CSTRING("_") + nsDependentCString(username);
+ if (profile) {
+ mutexPath.Append(NS_LITERAL_CSTRING("_") + nsDependentCString(profile));
+ }
+ mutexDir->AppendNative(mutexPath);
+
+ rv = mutexDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
+ if (NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_ALREADY_EXISTS) {
+ mRemoteLockDir = mutexDir;
+ }
+ }
+
+ if (mRemoteLockDir) {
+ const TimeStamp epoch = mozilla::TimeStamp::Now();
+ do {
+ rv = mRemoteLock.Lock(mRemoteLockDir, nullptr);
+ if (NS_SUCCEEDED(rv))
+ break;
+ sched_yield();
+ } while ((TimeStamp::Now() - epoch)
+ < TimeDuration::FromSeconds(MOZ_XREMOTE_START_TIMEOUT_SEC));
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Cannot lock XRemote start mutex");
+ }
+ }
+
// Try to remote the entire command line. If this fails, start up normally.
const char* desktopStartupIDPtr =
mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
- RemoteResult rr = RemoteCommandLine(desktopStartupIDPtr);
+ rr = StartRemoteClient(desktopStartupIDPtr, program, profile, username);
if (rr == REMOTE_FOUND) {
*aExitFlag = true;
return 0;
+ } else if (rr == REMOTE_ARG_BAD) {
+ return 1;
}
- else if (rr == REMOTE_ARG_BAD)
- return 1;
}
#endif
#if defined(MOZ_WIDGET_GTK)
g_set_application_name(mAppData->name);
gtk_window_set_auto_startup_notification(false);
#if (MOZ_WIDGET_GTK == 2)
gtk_widget_set_default_colormap(gdk_rgb_get_colormap());
@@ -4326,16 +4379,20 @@ XREMain::XRE_mainRun()
if (!mShuttingDown) {
#ifdef MOZ_ENABLE_XREMOTE
// if we have X remote support, start listening for requests on the
// proxy window.
if (!mDisableRemote)
mRemoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
if (mRemoteService)
mRemoteService->Startup(mAppData->remotingName, mProfileName.get());
+ if (mRemoteLockDir) {
+ mRemoteLock.Unlock();
+ mRemoteLockDir->Remove(false);
+ }
#endif /* MOZ_ENABLE_XREMOTE */
mNativeApp->Enable();
}
#ifdef MOZ_INSTRUMENT_EVENT_LOOP
if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP")) {
bool logToConsole = true;