[Mac OS X] properly select architecture for child process

RESOLVED FIXED

Status

()

Core
Plug-ins
RESOLVED FIXED
7 years ago
2 years ago

People

(Reporter: Josh Aas, Assigned: Josh Aas)

Tracking

Trunk
x86_64
Mac OS X
Points:
---
Dependency tree / graph

Firefox Tracking Flags

(blocking2.0 beta7+)

Details

Attachments

(1 attachment, 9 obsolete attachments)

(Assignee)

Description

7 years ago
We're planning to support using i386 plugins from an x86_64 host. The host will need to decide what architecture its child plugin process should be and launch it properly.
(Assignee)

Updated

7 years ago
Blocks: 559142
Summary: properly select architecture for child process → [Mac OS X] properly select architecture for child process
(Assignee)

Updated

7 years ago
blocking2.0: --- → beta6+
(Assignee)

Comment 1

7 years ago
Created attachment 473735 [details] [diff] [review]
fix v0.8
(Assignee)

Comment 2

7 years ago
Created attachment 473983 [details] [diff] [review]
fix v0.9
Attachment #473735 - Attachment is obsolete: true
(Assignee)

Comment 3

7 years ago
Created attachment 474159 [details] [diff] [review]
fix v0.95

Linux build fixes.
Attachment #473983 - Attachment is obsolete: true
(Assignee)

Comment 4

7 years ago
Created attachment 474335 [details] [diff] [review]
fix v1.0
Attachment #474159 - Attachment is obsolete: true
(Assignee)

Updated

7 years ago
Attachment #474335 - Flags: review?(jones.chris.g)
(Assignee)

Updated

7 years ago
Attachment #474335 - Flags: review?(b56girard)
Comment on attachment 474335 [details] [diff] [review]
fix v1.0

I think all the changes to chromium code should be wrapped around '#if defined(CHROMIUM_MOZILLA_BUILD)'. Perhaps cjones can clarify the rules for that.

+    if (posix_spawnattr_init(&spawnattr) == 0 && spawnattr) {

This doesn't have a corresponding posix_spawnattr_destroy method. If it's not needed then perhaps a comment should clear it up. Also we should prefix '::' for system calls.
Attachment #474335 - Flags: review?(b56girard)
(Assignee)

Comment 6

7 years ago
(In reply to comment #5)
> Comment on attachment 474335 [details] [diff] [review]
> fix v1.0
> 
> I think all the changes to chromium code should be wrapped around '#if
> defined(CHROMIUM_MOZILLA_BUILD)'. Perhaps cjones can clarify the rules for
> that.

I think that effort has been recognized as futile at this point and it is probably a waste of time, but if people still care they can speak up and I'll add it back.

> +    if (posix_spawnattr_init(&spawnattr) == 0 && spawnattr) {
> 
> This doesn't have a corresponding posix_spawnattr_destroy method. 

I'll look into it.

> Also we should prefix '::' for system calls.

We only do that for Apple framework calls, not for posix-ish/unixy calls. I think the idea behind the prefix was to make it easier to spot calls that non-Apple developers might not recognize (whereas we'd expect developers to recognize the more common and portable posix/unix calls).
(Assignee)

Comment 7

7 years ago
Created attachment 474598 [details] [diff] [review]
fix v1.1
Attachment #474335 - Attachment is obsolete: true
Attachment #474598 - Flags: review?(b56girard)
Attachment #474335 - Flags: review?(jones.chris.g)
(Assignee)

Updated

7 years ago
Attachment #474598 - Flags: review?(jones.chris.g)
(Assignee)

Comment 8

7 years ago
Created attachment 474782 [details] [diff] [review]
fix v1.2

This includes a fix that allows us to compile on PPC for now. Easiest to just add some selection logic for PPC even though we won't use it.
Attachment #474598 - Attachment is obsolete: true
Attachment #474782 - Flags: review?(jones.chris.g)
Attachment #474598 - Flags: review?(jones.chris.g)
Attachment #474598 - Flags: review?(b56girard)
Comment on attachment 474782 [details] [diff] [review]
fix v1.2

>diff --git a/dom/plugins/PluginProcessParent.cpp b/dom/plugins/PluginProcessParent.cpp
>--- a/dom/plugins/PluginProcessParent.cpp
>+++ b/dom/plugins/PluginProcessParent.cpp
>@@ -35,16 +35,18 @@
>  * the provisions above, a recipient may use your version of this file under
>  * the terms of any one of the MPL, the GPL or the LGPL.
>  *
>  * ***** END LICENSE BLOCK ***** */
> 
> #include "mozilla/plugins/PluginProcessParent.h"
> 
> #include "base/string_util.h"
>+#include "base/process_util.h"
>+
> #include "mozilla/ipc/BrowserProcessSubThread.h"
> #include "mozilla/plugins/PluginMessageUtils.h"
> 
> using std::vector;
> using std::string;
> 
> using mozilla::ipc::BrowserProcessSubThread;
> using mozilla::ipc::GeckoChildProcessHost;
>@@ -65,19 +67,67 @@ PluginProcessParent::PluginProcessParent
> 
> PluginProcessParent::~PluginProcessParent()
> {
> }
> 
> bool
> PluginProcessParent::Launch(PRInt32 timeoutMs)
> {
>+    base::ProcessArchitecture arch = base::PROCESS_ARCH_DEFAULT;
>+
>+#ifdef XP_MACOSX

Instead of making this code Mac-only, we should define no-op stubs
that always return DEFAULT.

>+    // Get the plugin architecture mask.
>+    uint32 pluginArchitectures = 0;
>+    nsresult rv = mozilla::ipc::GeckoChildProcessHost::GetArchitecturesForBinary(mPluginFilePath.c_str(), &pluginArchitectures);

|using mozilla::ipc::GeckoChildProcessHost;|.  I'd be more specific
here with the name |pluginLibArches| or something.  See comments for
GeckoChildProcessHost.

>+#if defined(__i386__)
>+    base::ProcessArchitecture parentArch = base::PROCESS_ARCH_I386;
>+#elif defined(__x86_64__)
>+    base::ProcessArchitecture parentArch = base::PROCESS_ARCH_X86_64;
>+#elif defined(__PPC__)
>+    base::ProcessArchitecture parentArch = base::PROCESS_ARCH_PPC;
>+#else
>+#error "You are building on an unrecognized architecture"
>+#endif
>+

|using base::ProcessArchitecture;|.

Please make this a file-static helper |CurrentProcessArchitecture()|.
Really this should be a global helper, but we don't have a great place
to stick it at the moment.

I'd use |curProcArch| instead of |parentArch|.  The latter will be
confusing in content processes.

The style

  ProcessArchitecture curProcArch;
#if FOO
  pluginHostArch = ARCH_FOO;
#...

is easier to maintain.

Please use ARCH_CPU_X86_64/ARCH_CPU_X86/ARCH_CPU_PPC here.

>+    // Prefer the parent architecture.
>+    if (pluginArchitectures & parentArch) {
>+        arch = parentArch;
>+    }

Instead of |arch|, use |pluginContainerArch| or something like that.

>+    else {
>+        // Get host architecture mask.
>+        uint32 hostArchitectures = 0;

|= PROCESS_ARCH_DEFAULT;|

"Host" is pretty overloaded.  Maybe use |pluginContainerArches|
instead?

>diff --git a/ipc/chromium/src/base/process_util_mac.mm b/ipc/chromium/src/base/process_util_mac.mm
>--- a/ipc/chromium/src/base/process_util_mac.mm
>+++ b/ipc/chromium/src/base/process_util_mac.mm
>@@ -17,27 +17,36 @@
> #include "base/eintr_wrapper.h"
> #include "base/logging.h"
> #include "base/rand_util.h"
> #include "base/string_util.h"
> #include "base/time.h"
> 
> namespace base {
> 
>+void FreeEnvVarsArray(char** array, int length)

|char* array[]|

> 
>+  // Set up the CPU preference array.
>+  cpu_type_t cpu_types[1];
>+  switch (arch) {
>+    case PROCESS_ARCH_I386:
>+      cpu_types[0] = CPU_TYPE_X86;
>+      break;
>+    case PROCESS_ARCH_X86_64:
>+      cpu_types[0] = CPU_TYPE_X86_64;
>+      break;
>+    case PROCESS_ARCH_PPC:
>+      cpu_types[0] = CPU_TYPE_POWERPC;
>+    default:
>+      cpu_types[0] = CPU_TYPE_ANY;
>+      break;
>+  }
>+
>+  // Initialize spawn attributes.
>+  posix_spawnattr_t spawnattr;
>+  if (posix_spawnattr_init(&spawnattr) != 0) {
>+    FreeEnvVarsArray(vars, varsLen);
>+    return false;
>+  }
>+
>+  // Set spawn attributes.
>+  size_t attr_count = 1;
>+  size_t attr_ocount = 0;
>+  if (posix_spawnattr_setbinpref_np(&spawnattr, attr_count, cpu_types, &attr_ocount) != 0 ||
>+      attr_ocount != attr_count) {
>+    FreeEnvVarsArray(vars, varsLen);
>+    posix_spawnattr_destroy(&spawnattr);
>+    return false;
>+  }
>+

I don't feel qualified to review this, but it looks OK AFAICT.

>diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp
>--- a/ipc/glue/GeckoChildProcessHost.cpp
>+++ b/ipc/glue/GeckoChildProcessHost.cpp

We're accumulating enough platform-specific code in here that I think
it's time to start splitting it into separate files.  We only need
GeckoChildProcessHost_mac.cpp so far.

>@@ -41,16 +41,17 @@
> #include "base/command_line.h"
> #include "base/path_service.h"
> #include "base/string_util.h"
> #include "chrome/common/chrome_switches.h"
> #include "chrome/common/process_watcher.h"
> #ifdef XP_MACOSX
> #include "chrome/common/mach_ipc_mac.h"
> #include "base/rand_util.h"
>+#include "nsILocalFileMac.h"
> #endif
> 
> #include "prprf.h"
> 
> #if defined(OS_LINUX)
> #  define XP_LINUX 1
> #endif
> #include "nsExceptionHandler.h"
>@@ -114,16 +115,121 @@ GeckoChildProcessHost::~GeckoChildProces
>     );
> 
> #if defined(XP_MACOSX)
>   if (mChildTask != MACH_PORT_NULL)
>     mach_port_deallocate(mach_task_self(), mChildTask);
> #endif
> }
> 
>+#ifdef XP_MACOSX
>+class AutoCFTypeObject {
>+public:
>+  AutoCFTypeObject(CFTypeRef object)
>+  {
>+    mObject = object;
>+  }
>+  ~AutoCFTypeObject()
>+  {
>+    ::CFRelease(mObject);
>+  }
>+private:
>+  CFTypeRef mObject;
>+};
>+
>+nsresult GeckoChildProcessHost::GetArchitecturesForBinary(const char *path, uint32 *result)
>+{
>+  *result = 0;
>+
>+  CFURLRef url = ::CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
>+                                                           (const UInt8*)path,
>+                                                           strlen(path),
>+                                                           false);
>+  if (!url) {
>+    return NS_ERROR_FAILURE;
>+  }
>+  AutoCFTypeObject autoPluginContainerURL(url);
>+
>+  CFArrayRef pluginContainerArchs = ::CFBundleCopyExecutableArchitecturesForURL(url);
>+  if (!pluginContainerArchs) {
>+    return NS_ERROR_FAILURE;
>+  }
>+  AutoCFTypeObject autoPluginContainerArchs(pluginContainerArchs);
>+
>+  CFIndex pluginArchCount = ::CFArrayGetCount(pluginContainerArchs);
>+  for (CFIndex i = 0; i < pluginArchCount; i++) {
>+    CFNumberRef currentArch = static_cast<CFNumberRef>(::CFArrayGetValueAtIndex(pluginContainerArchs, i));
>+    int currentArchInt = 0;
>+    if (!::CFNumberGetValue(currentArch, kCFNumberIntType, &currentArchInt)) {
>+      continue;
>+    }
>+    switch (currentArchInt) {
>+      case kCFBundleExecutableArchitectureI386:
>+        *result |= base::PROCESS_ARCH_I386;
>+        break;
>+      case kCFBundleExecutableArchitectureX86_64:
>+        *result |= base::PROCESS_ARCH_X86_64;
>+      case kCFBundleExecutableArchitecturePPC:
>+        *result |= base::PROCESS_ARCH_PPC;
>+        break;
>+      default:
>+        break;
>+    }
>+  }
>+
>+  return NS_OK;
>+}
>+
>+nsresult GeckoChildProcessHost::GetChildBinaryArchitectures(uint32 *result)
>+{
>+  nsresult rv = NS_OK;
>+
>+  // Cache this, it shouldn't ever change.

Let's go even further and bake this in at compile time.

>+}
>+#endif
>+

Please move these new functions into GeckoChildProcessHost_mac.cpp.

>diff --git a/ipc/glue/GeckoChildProcessHost.h b/ipc/glue/GeckoChildProcessHost.h
>--- a/ipc/glue/GeckoChildProcessHost.h
>+++ b/ipc/glue/GeckoChildProcessHost.h
>@@ -59,19 +59,27 @@ protected:
> public:
>   typedef base::ProcessHandle ProcessHandle;
> 
>   GeckoChildProcessHost(GeckoProcessType aProcessType=GeckoProcessType_Default,
>                         base::WaitableEventWatcher::Delegate* aDelegate=nsnull);
> 
>   ~GeckoChildProcessHost();
> 
>-  bool SyncLaunch(std::vector<std::string> aExtraOpts=std::vector<std::string>(), int32 timeoutMs=0);
>+#ifdef XP_MACOSX
>+  static nsresult GetArchitecturesForBinary(const char *path, uint32 *result);
>+  static nsresult GetChildBinaryArchitectures(uint32 *result);

Let's keep these interfaces defined for all platforms and add stubs for non-mac.

Instead of |GetChildBinaryArchitectures(uint32 *result);|, let's do 

  uint32 GetSupportedArchitecturesForProcessType(GeckoProcessType type)

I don't think function should be fallible.

>diff --git a/modules/plugin/base/src/nsPluginsDirDarwin.cpp b/modules/plugin/base/src/nsNPAPIPlugin.cpp
>--- a/modules/plugin/base/src/nsNPAPIPlugin.cpp
>+++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp

The plugin tag cleanup looks OK.  This would be better served as a
separate patch, would prefer not to see it again.
(Assignee)

Comment 10

7 years ago
Created attachment 475251 [details] [diff] [review]
fix v1.3
Attachment #474782 - Attachment is obsolete: true
Attachment #474782 - Flags: review?(jones.chris.g)
(Assignee)

Comment 11

7 years ago
Created attachment 475323 [details] [diff] [review]
fix v1.4

Fix a bug I introduced in the last version of the patch.
Attachment #475251 - Attachment is obsolete: true
(Assignee)

Comment 12

7 years ago
Created attachment 475344 [details] [diff] [review]
fix v1.5

Broke out part of the patch into bug 596434.
Attachment #475323 - Attachment is obsolete: true
(Assignee)

Comment 13

7 years ago
Created attachment 475603 [details] [diff] [review]
fix v1.6
Attachment #475344 - Attachment is obsolete: true
(Assignee)

Updated

7 years ago
Attachment #475603 - Flags: review?(jones.chris.g)
(Just to add, Adobe has released a 64-bit plugin for all three platforms on http://labs.adobe.com/technologies/flashplayer10/ and I have it working correctly on mac)
(obviously, wrong bug)
Comment on attachment 475603 [details] [diff] [review]
fix v1.6

>diff --git a/dom/plugins/PluginProcessParent.cpp b/dom/plugins/PluginProcessParent.cpp
>--- a/dom/plugins/PluginProcessParent.cpp
>+++ b/dom/plugins/PluginProcessParent.cpp
> bool
> PluginProcessParent::Launch(PRInt32 timeoutMs)
> {
>+    ProcessArchitecture currentArchitecture = base::GetCurrentProcessArchitecture();
>+    uint32 containerArchitectures = GetSupportedArchitecturesForProcessType(GeckoProcessType_Plugin);
>+
>+    uint32 pluginLibArchitectures = currentArchitecture;
>+#ifdef XP_MACOSX
>+    nsresult rv = GetArchitecturesForBinary(mPluginFilePath.c_str(), &pluginLibArchitectures);
>+    if (NS_FAILED(rv)) {
>+        // If the call failed just assume that we want the current architecture.
>+        pluginLibArchitectures = currentArchitecture;
>+    }
>+#endif

You don't need the #ifdef, this function is defined for all platforms now.

Looks good, thanks.
Attachment #475603 - Flags: review?(jones.chris.g) → review+
(Assignee)

Comment 17

7 years ago
(In reply to comment #16)

> You don't need the #ifdef, this function is defined for all platforms now.

The ifdef is there because "c_str()" doesn't return the same thing on all platforms so that code won't work everywhere.
(Assignee)

Comment 18

7 years ago
pushed to mozilla-central

http://hg.mozilla.org/mozilla-central/rev/e45446b74099
Status: NEW → RESOLVED
Last Resolved: 7 years ago
Resolution: --- → FIXED
Depends on: 1235234
You need to log in before you can comment on or make changes to this bug.