Bug 1245241 - part 4 - move SharedMemorySysV details into nsShmImage. r=nical
authorLee Salzman <lsalzman@mozilla.com>
Thu, 18 Feb 2016 10:56:15 -0500 (2016-02-18)
changeset 284721 94f9bb9e325342ef86c534a14a651060d76bd8b4
parent 284720 48fa8a92f9364a82985021ae1dfe940de09dd898
child 284722 1fff1b2ac665d640e0f2e669647aca6d2ec31dc9
push id72076
push userlsalzman@mozilla.com
push dateThu, 18 Feb 2016 15:56:31 +0000 (2016-02-18)
treeherdermozilla-inbound@94f9bb9e3253 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1245241
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1245241 - part 4 - move SharedMemorySysV details into nsShmImage. r=nical
ipc/glue/SharedMemory.h
ipc/glue/SharedMemorySysV.h
ipc/glue/moz.build
widget/gtk/nsWindow.h
widget/nsShmImage.cpp
widget/nsShmImage.h
--- a/ipc/glue/SharedMemory.h
+++ b/ipc/glue/SharedMemory.h
@@ -42,17 +42,16 @@ protected:
   {
     Unmapped();
     Destroyed();
   }
 
 public:
   enum SharedMemoryType {
     TYPE_BASIC,
-    TYPE_SYSV,
     TYPE_UNKNOWN
   };
 
   size_t Size() const { return mMappedSize; }
 
   virtual void* memory() const = 0;
 
   virtual bool Create(size_t size) = 0;
deleted file mode 100644
--- a/ipc/glue/SharedMemorySysV.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: sw=2 ts=8 et :
- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_ipc_SharedMemorySysV_h
-#define mozilla_ipc_SharedMemorySysV_h
-
-#if (defined(OS_LINUX) && !defined(ANDROID)) || defined(OS_BSD)
-
-// SysV shared memory isn't available on Windows, but we define the
-// following macro so that #ifdefs are clearer (compared to #ifdef
-// OS_LINUX).
-#define MOZ_HAVE_SHAREDMEMORYSYSV
-
-#include "SharedMemory.h"
-
-#include "nsDebug.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-
-//
-// This is a low-level wrapper around platform shared memory.  Don't
-// use it directly; use Shmem allocated through IPDL interfaces.
-//
-
-namespace mozilla {
-namespace ipc {
-
-
-class SharedMemorySysV : public SharedMemoryCommon<int>
-{
-public:
-  SharedMemorySysV() :
-    mHandle(-1),
-    mData(nullptr)
-  {
-  }
-
-  virtual ~SharedMemorySysV()
-  {
-    shmdt(mData);
-    mHandle = -1;
-    mData = nullptr;
-  }
-
-  virtual bool SetHandle(const Handle& aHandle) override
-  {
-    MOZ_ASSERT(mHandle == -1, "already initialized");
-
-    mHandle = aHandle;
-    return true;
-  }
-
-  virtual bool Create(size_t aNbytes) override
-  {
-    int id = shmget(IPC_PRIVATE, aNbytes, IPC_CREAT | 0600);
-    if (id == -1)
-      return false;
-
-    mHandle = id;
-    mAllocSize = aNbytes;
-    Created(aNbytes);
-
-    return Map(aNbytes);
-  }
-
-  virtual bool Map(size_t nBytes) override
-  {
-    // already mapped
-    if (mData)
-      return true;
-
-    if (!IsHandleValid(mHandle))
-      return false;
-
-    void* mem = shmat(mHandle, nullptr, 0);
-    if (mem == (void*) -1) {
-      char warning[256];
-      ::snprintf(warning, sizeof(warning)-1,
-                 "shmat(): %s (%d)\n", strerror(errno), errno);
-
-      NS_WARNING(warning);
-
-      return false;
-    }
-
-    // Mark the handle as deleted so that, should this process go away, the
-    // segment is cleaned up.
-    shmctl(mHandle, IPC_RMID, 0);
-
-    mData = mem;
-
-#ifdef DEBUG
-    struct shmid_ds info;
-    if (shmctl(mHandle, IPC_STAT, &info) < 0)
-      return false;
-
-    MOZ_ASSERT(nBytes <= info.shm_segsz,
-               "Segment doesn't have enough space!");
-#endif
-
-    Mapped(nBytes);
-    return true;
-  }
-
-  virtual void* memory() const override
-  {
-    return mData;
-  }
-
-  virtual SharedMemoryType Type() const override
-  {
-    return TYPE_SYSV;
-  }
-
-  Handle GetHandle() const
-  {
-    MOZ_ASSERT(IsHandleValid(mHandle), "invalid handle");
-    return mHandle;
-  }
-
-  static Handle NULLHandle()
-  {
-    return -1;
-  }
-
-  virtual bool IsHandleValid(const Handle& aHandle) const override
-  {
-    return aHandle != -1;
-  }
-
-  virtual void CloseHandle() override
-  {
-  }
-
-  virtual bool ShareToProcess(base::ProcessId aProcessId, Handle* aHandle) override {
-    if (mHandle == -1) {
-      return false;
-    }
-    *aHandle = mHandle;
-    return true;
-  }
-
-private:
-  Handle mHandle;
-  void* mData;
-};
-
-} // namespace ipc
-} // namespace mozilla
-
-#endif // OS_LINUX
-
-#endif // ifndef mozilla_ipc_SharedMemorySysV_h
--- a/ipc/glue/moz.build
+++ b/ipc/glue/moz.build
@@ -26,17 +26,16 @@ EXPORTS.mozilla.ipc += [
     'MessageChannel.h',
     'MessageLink.h',
     'Neutering.h',
     'ProcessChild.h',
     'ProtocolUtils.h',
     'ScopedXREEmbed.h',
     'SharedMemory.h',
     'SharedMemoryBasic.h',
-    'SharedMemorySysV.h',
     'Shmem.h',
     'Transport.h',
     'URIUtils.h',
     'WindowsMessageLoop.h',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     DEFINES['WEBRTC_WIN'] = True
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -3,18 +3,16 @@
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __nsWindow_h__
 #define __nsWindow_h__
 
-#include "mozilla/ipc/SharedMemorySysV.h"
-
 #include "nsAutoPtr.h"
 
 #include "mozcontainer.h"
 
 #include "nsIDragService.h"
 #include "nsITimer.h"
 #include "nsGkAtoms.h"
 #include "nsRefPtrHashtable.h"
@@ -22,16 +20,18 @@
 #include "nsBaseWidget.h"
 #include <gdk/gdk.h>
 #include <gtk/gtk.h>
 
 #ifdef MOZ_X11
 #include <gdk/gdkx.h>
 #endif /* MOZ_X11 */
 
+#include "nsShmImage.h"
+
 #ifdef ACCESSIBILITY
 #include "mozilla/a11y/Accessible.h"
 #endif
 #include "mozilla/EventForwards.h"
 #include "mozilla/TouchEvents.h"
 
 #include "IMContextWrapper.h"
 
@@ -59,20 +59,16 @@ extern PRLogModuleInfo *gWidgetDrawLog;
 #define LOGDRAG(args)
 #define LOGDRAW(args)
 
 #endif /* MOZ_LOGGING */
 
 class gfxASurface;
 class gfxPattern;
 class nsPluginNativeWindowGtk;
-#if defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV)
-#  define MOZ_HAVE_SHMIMAGE
-class nsShmImage;
-#endif
 
 namespace mozilla {
 class TimeStamp;
 class CurrentX11TimeGetter;
 }
 
 class nsWindow : public nsBaseWidget
 {
--- a/widget/nsShmImage.cpp
+++ b/widget/nsShmImage.cpp
@@ -12,16 +12,24 @@
 #endif
 
 #include "nsShmImage.h"
 #ifdef MOZ_WIDGET_GTK
 #include "gfxPlatformGtk.h"
 #endif
 
 #ifdef MOZ_HAVE_SHMIMAGE
+#include "mozilla/X11Util.h"
+
+#include "mozilla/ipc/SharedMemory.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
 
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 
 // If XShm isn't available to our client, we'll try XShm once, fail,
 // set this to false and then never try again.
 static bool gShmAvailable = true;
 bool nsShmImage::UseShm()
@@ -40,102 +48,153 @@ static int
 TrapShmError(Display* aDisplay, XErrorEvent* aEvent)
 {
     // store the error code and ignore the error
     gShmError = aEvent->error_code;
     return 0;
 }
 #endif
 
-already_AddRefed<nsShmImage>
-nsShmImage::Create(const LayoutDeviceIntSize& aSize,
-                   Display* aDisplay, Visual* aVisual, unsigned int aDepth)
+bool
+nsShmImage::CreateShmSegment()
 {
-    RefPtr<nsShmImage> shm = new nsShmImage();
-    shm->mDisplay = aDisplay;
-    shm->mImage = XShmCreateImage(aDisplay, aVisual, aDepth,
-                                  ZPixmap, nullptr,
-                                  &(shm->mInfo),
-                                  aSize.width, aSize.height);
-    if (!shm->mImage) {
-        return nullptr;
-    }
+  if (!mImage) {
+    return false;
+  }
+
+  size_t size = SharedMemory::PageAlignedSize(mImage->bytes_per_line * mImage->height);
+
+  mInfo.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
+  if (mInfo.shmid == -1) {
+    return false;
+  }
 
-    size_t size = SharedMemory::PageAlignedSize(
-        shm->mImage->bytes_per_line * shm->mImage->height);
-    shm->mSegment = new SharedMemorySysV();
-    if (!shm->mSegment->Create(size) || !shm->mSegment->Map(size)) {
-        return nullptr;
-    }
-
-    shm->mInfo.shmid = shm->mSegment->GetHandle();
-    shm->mInfo.shmaddr =
-        shm->mImage->data = static_cast<char*>(shm->mSegment->memory());
-    shm->mInfo.readOnly = False;
+  mInfo.shmaddr = (char *)shmat(mInfo.shmid, nullptr, 0);
+  if (mInfo.shmaddr == (void *)-1) {
+    nsPrintfCString warning("shmat(): %s (%d)\n", strerror(errno), errno);
+    NS_WARNING(warning.get());
+    return false;
+  }
 
-#if defined(MOZ_WIDGET_GTK)
-    gShmError = 0;
-    XErrorHandler previousHandler = XSetErrorHandler(TrapShmError);
-    Status attachOk = XShmAttach(aDisplay, &shm->mInfo);
-    XSync(aDisplay, False);
-    XSetErrorHandler(previousHandler);
-    if (gShmError) {
-      attachOk = 0;
-    }
-#elif defined(MOZ_WIDGET_QT)
-    Status attachOk = XShmAttach(aDisplay, &shm->mInfo);
+  // Mark the handle as deleted so that, should this process go away, the
+  // segment is cleaned up.
+  shmctl(mInfo.shmid, IPC_RMID, 0);
+
+#ifdef DEBUG
+  struct shmid_ds info;
+  if (shmctl(mInfo.shmid, IPC_STAT, &info) < 0) {
+    return false;
+  }
+
+  MOZ_ASSERT(size <= info.shm_segsz,
+             "Segment doesn't have enough space!");
 #endif
 
-    if (!attachOk) {
-        // Assume XShm isn't available, and don't attempt to use it
-        // again.
-        gShmAvailable = false;
-        return nullptr;
-    }
+  mInfo.readOnly = False;
+
+  mImage->data = mInfo.shmaddr;
+
+  return true;
+}
+
+void
+nsShmImage::DestroyShmSegment()
+{
+  if (mInfo.shmid != -1) {
+    shmdt(mInfo.shmaddr);
+    mInfo.shmid = -1;
+  }
+}
+
+bool
+nsShmImage::CreateImage(const LayoutDeviceIntSize& aSize,
+                        Display* aDisplay, Visual* aVisual, unsigned int aDepth)
+{
+  mDisplay = aDisplay;
+  mImage = XShmCreateImage(aDisplay, aVisual, aDepth,
+                           ZPixmap, nullptr,
+                           &mInfo,
+                           aSize.width, aSize.height);
+  if (!mImage || !CreateShmSegment()) {
+    return false;
+  }
+
+#if defined(MOZ_WIDGET_GTK)
+  gShmError = 0;
+  XErrorHandler previousHandler = XSetErrorHandler(TrapShmError);
+  Status attachOk = XShmAttach(aDisplay, &mInfo);
+  XSync(aDisplay, False);
+  XSetErrorHandler(previousHandler);
+  if (gShmError) {
+    attachOk = 0;
+  }
+#elif defined(MOZ_WIDGET_QT)
+  Status attachOk = XShmAttach(aDisplay, &mInfo);
+#endif
 
-    shm->mXAttached = true;
-    shm->mSize = aSize;
-    switch (shm->mImage->depth) {
-    case 32:
-        if ((shm->mImage->red_mask == 0xff0000) &&
-            (shm->mImage->green_mask == 0xff00) &&
-            (shm->mImage->blue_mask == 0xff)) {
-            shm->mFormat = SurfaceFormat::B8G8R8A8;
-            memset(shm->mSegment->memory(), 0, size);
-            break;
-        }
-        goto unsupported;
-    case 24:
-        // Only xRGB is supported.
-        if ((shm->mImage->red_mask == 0xff0000) &&
-            (shm->mImage->green_mask == 0xff00) &&
-            (shm->mImage->blue_mask == 0xff)) {
-            shm->mFormat = SurfaceFormat::B8G8R8X8;
-            memset(shm->mSegment->memory(), 0xFF, size);
-            break;
-        }
-        goto unsupported;
-    case 16:
-        shm->mFormat = SurfaceFormat::R5G6B5_UINT16;
-        memset(shm->mSegment->memory(), 0, size);
-        break;
-    unsupported:
-    default:
-        NS_WARNING("Unsupported XShm Image format!");
-        gShmAvailable = false;
-        return nullptr;
+  if (!attachOk) {
+    // Assume XShm isn't available, and don't attempt to use it
+    // again.
+    gShmAvailable = false;
+    return false;
+  }
+
+  mXAttached = true;
+  mSize = aSize;
+  mFormat = SurfaceFormat::UNKNOWN;
+  switch (mImage->depth) {
+  case 32:
+    if ((mImage->red_mask == 0xff0000) &&
+        (mImage->green_mask == 0xff00) &&
+        (mImage->blue_mask == 0xff)) {
+      mFormat = SurfaceFormat::B8G8R8A8;
+      memset(mImage->data, 0, mImage->bytes_per_line * mImage->height);
+    }
+    break;
+  case 24:
+    // Only xRGB is supported.
+    if ((mImage->red_mask == 0xff0000) &&
+        (mImage->green_mask == 0xff00) &&
+        (mImage->blue_mask == 0xff)) {
+      mFormat = SurfaceFormat::B8G8R8X8;
+      memset(mImage->data, 0xFF, mImage->bytes_per_line * mImage->height);
     }
-    return shm.forget();
+    break;
+  case 16:
+    mFormat = SurfaceFormat::R5G6B5_UINT16;
+    memset(mImage->data, 0, mImage->bytes_per_line * mImage->height);
+    break;
+  }
+
+  if (mFormat == SurfaceFormat::UNKNOWN) {
+    NS_WARNING("Unsupported XShm Image format!");
+    gShmAvailable = false;
+    return false;
+  }
+
+  return true;
+}
+
+nsShmImage::~nsShmImage()
+{
+  if (mImage) {
+    mozilla::FinishX(mDisplay);
+    if (mXAttached) {
+      XShmDetach(mDisplay, &mInfo);
+    }
+    XDestroyImage(mImage);
+  }
+  DestroyShmSegment();
 }
 
 already_AddRefed<DrawTarget>
 nsShmImage::CreateDrawTarget()
 {
   return gfxPlatform::GetPlatform()->CreateDrawTargetForData(
-    static_cast<unsigned char*>(mSegment->memory()),
+    reinterpret_cast<unsigned char*>(mImage->data),
     mSize.ToUnknownSize(),
     mImage->bytes_per_line,
     mFormat);
 }
 
 #ifdef MOZ_WIDGET_GTK
 void
 nsShmImage::Put(Display* aDisplay, Drawable aWindow,
@@ -184,20 +243,23 @@ nsShmImage::Put(QWindow* aWindow, QRect&
 }
 #endif
 
 already_AddRefed<DrawTarget>
 nsShmImage::EnsureShmImage(const LayoutDeviceIntSize& aSize,
                            Display* aDisplay, Visual* aVisual, unsigned int aDepth,
                            RefPtr<nsShmImage>& aImage)
 {
-    if (!aImage || aImage->Size() != aSize) {
-        // Because we XSync() after XShmAttach() to trap errors, we
-        // know that the X server has the old image's memory mapped
-        // into its address space, so it's OK to destroy the old image
-        // here even if there are outstanding Puts.  The Detach is
-        // ordered after the Puts.
-        aImage = nsShmImage::Create(aSize, aDisplay, aVisual, aDepth);
+  if (!aImage || aImage->Size() != aSize) {
+    // Because we XSync() after XShmAttach() to trap errors, we
+    // know that the X server has the old image's memory mapped
+    // into its address space, so it's OK to destroy the old image
+    // here even if there are outstanding Puts.  The Detach is
+    // ordered after the Puts.
+    aImage = new nsShmImage;
+    if (!aImage->CreateImage(aSize, aDisplay, aVisual, aDepth)) {
+      aImage = nullptr;
     }
-    return !aImage ? nullptr : aImage->CreateDrawTarget();
+  }
+  return !aImage ? nullptr : aImage->CreateDrawTarget();
 }
 
-#endif  // defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV)
+#endif  // MOZ_HAVE_SHMIMAGE
--- a/widget/nsShmImage.h
+++ b/widget/nsShmImage.h
@@ -2,66 +2,45 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __mozilla_widget_nsShmImage_h__
 #define __mozilla_widget_nsShmImage_h__
 
-#include "mozilla/ipc/SharedMemorySysV.h"
-
-#if defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV)
+#if defined(MOZ_X11)
 #  define MOZ_HAVE_SHMIMAGE
 #endif
 
 #ifdef MOZ_HAVE_SHMIMAGE
 
 #include "mozilla/gfx/2D.h"
 #include "nsIWidget.h"
 #include "nsAutoPtr.h"
 
-#include "mozilla/X11Util.h"
 #include <X11/Xlib.h>
-#include <X11/Xutil.h>
 #include <X11/extensions/XShm.h>
 
 #ifdef MOZ_WIDGET_QT
 class QRect;
 class QWindow;
 #endif
 
 class nsShmImage {
     // bug 1168843, compositor thread may create shared memory instances that are destroyed by main thread on shutdown, so this must use thread-safe RC to avoid hitting assertion
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsShmImage)
 
-    typedef mozilla::ipc::SharedMemorySysV SharedMemorySysV;
-
 public:
     static bool UseShm();
-    static already_AddRefed<nsShmImage>
-        Create(const mozilla::LayoutDeviceIntSize& aSize,
-               Display* aDisplay, Visual* aVisual, unsigned int aDepth);
     static already_AddRefed<mozilla::gfx::DrawTarget>
         EnsureShmImage(const mozilla::LayoutDeviceIntSize& aSize,
                        Display* aDisplay, Visual* aVisual, unsigned int aDepth,
                        RefPtr<nsShmImage>& aImage);
 
-private:
-    ~nsShmImage() {
-        if (mImage) {
-            mozilla::FinishX(mDisplay);
-            if (mXAttached) {
-                XShmDetach(mDisplay, &mInfo);
-            }
-            XDestroyImage(mImage);
-        }
-    }
-
-public:
     already_AddRefed<mozilla::gfx::DrawTarget> CreateDrawTarget();
 
 #ifdef MOZ_WIDGET_GTK
     void Put(Display* aDisplay, Drawable aWindow,
              const mozilla::LayoutDeviceIntRegion& aRegion);
 #elif defined(MOZ_WIDGET_QT)
     void Put(QWindow* aWindow, QRect& aRect);
 #endif
@@ -69,19 +48,26 @@ public:
     mozilla::LayoutDeviceIntSize Size() const { return mSize; }
 
 private:
     nsShmImage()
         : mImage(nullptr)
         , mDisplay(nullptr)
         , mFormat(mozilla::gfx::SurfaceFormat::UNKNOWN)
         , mXAttached(false)
-    { mInfo.shmid = SharedMemorySysV::NULLHandle(); }
+    { mInfo.shmid = -1; }
+
+    ~nsShmImage();
 
-    RefPtr<SharedMemorySysV>   mSegment;
+    bool CreateShmSegment();
+    void DestroyShmSegment();
+
+    bool CreateImage(const mozilla::LayoutDeviceIntSize& aSize,
+                     Display* aDisplay, Visual* aVisual, unsigned int aDepth);
+
     XImage*                      mImage;
     Display*                     mDisplay;
     XShmSegmentInfo              mInfo;
     mozilla::LayoutDeviceIntSize mSize;
     mozilla::gfx::SurfaceFormat  mFormat;
     bool                         mXAttached;
 };