mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
aec5e5666e
- bug 1083930 - cpu spin during large h2/spdy upload r=hurley (0949388a6a)
- Bug 1241906 - Spdy deadlock on suspended channel r=hurley (f40e9677d5)
- Bug 1247205 - dont loop on http2 softerror r=dragana (2ab3cb69ef)
- Bug 1246778 - dont loop in nshttpconnection during shutdown r=dragana (0677b9d34b)
- Bug 1201037 - only send "HTTP pings" on seemingly idle connections, r=mcmanus (134198bc79)
- Bug 1174899 - discarded spdy data with fin attributed to wrong stream r=bagder (f3b801c734)
- Bug 1236170 - Make Http2Session::UncompressAndDiscard push-aware. r=mcmanus (e71634e853)
- Bug 1240025 - incorrect close state on pushed stream r=hurley (eb2832177a)
- Bug 1227931 - init Http2Stream::mReceivedData in the constructor. r=nwgh (44f1d8e897)
- Bug 241788 - net_FilterURIString should filter \r\n\t from the entire URL r=honzab (734d9b8cae)
- Bug 1259459 - h2 0 length options puts end-stream on headers r=hurley (31ac211a9b)
- Bug 1174899 - fixup log format strings for spdy/h2 r=bagder (967c9ff71e)
- Bug 1211694 - dataLength has been added twice. r=mcmanus (6773981db3)
- cleanup (26517f5de0)
- Bug 1247998 - Let nsHttpChannel::AsyncOpen* throw after nsHttpHandler has been shutdown, r=mcmanus (90bb2364be)
- Bug 1231512 - Allow nsIHttpChannel.redirectTo() work also on an open channel, r=jduell (198fb72816)
- Bug 1242472 - Properly propagate mTopWindowURI through redirects. r=francois/ckerschb (1d27a15770)
- Bug 1133873 - some spdy logs r=hurley (cd95cfed5a)
- bug 1215724 - enable brotli on spdy r=hurley (83cca72fa5)
- Bug 137852 - Add a new working HTTP authentication identity to the begining of the session cache list. r=honzab (f670349771)
- Bug 1245414, part 1 - Delete the mfbt/decimal/LICENSE* files since upstream now just uses inline comments. r=Waldo (15bb211e14)
- Bug 1245414, part 2 - Update mfbt/decimal/update.sh to reflect Blink's switch from svn to git, and the different files we now pull. r=Waldo (4dd0b5916a)
- Bug 1245414, part 3 - Overwrite mfbt/decimal/Decimal.* with vanilla upstream copies. r=Waldo (98f7ba4711)
- Bug 1245414, part 4 - Update mfbt/decimal/zero-serialization.patch. r =Waldo (055e1354a7)
- Bug 1245414, part 5 - Update mfbt/decimal/comparison-with-nan.patch. r=Waldo (583e0f3e76)
- Bug 1245414, part 6 - Update mfbt/decimal/mfbt-abi-markers.patch. r=Waldo (148b1ac08b)
- Bug 1245414, part 7 - Update mfbt/decimal/to-moz-dependencies.patch. r=Waldo (2e2a6a33d7)
- Bug 1245414, part 8 - Remove mfbt/decimal/floor-ceiling.patch now that the issue is fixed upstream. r=Waldo (84fc02c068)
- Bug 1245414, part 9 - Disable mfbt/decimal/fix-wshadow-warnings.patch. r=cpeterson (4476d04c5d)
- Bug 1245414, part 10 - Apply the Mozilla patches via mfbt/decimal/update.sh. r=Waldo (1f95ef5524)
- Bug 1247082 - Suppress rendering of nsBackdropFrame for VR content r=dholbert (0ffeae4267)
- Bug 1206545 - Initialize AccessibleCaretEventHub in nsCanvasFrame. r=roc (687d4997fb)
- Bug 591737 - Add SummaryFrame. r=bz (1b750bfeb8)
- Bug 1165893 - Fix rounding issue in nsDisplaySelectionOverlay::Paint. r=mattwoodro (9994cc983a)
- Bug 1245450 - Only setup AutoSaveRestorePerspectiveIndex for the descendants of the element with perspective. r=roc (fe8a350417)
- Bug 1243282 - Wrap items having clips with a separator. r=mattwoodrow (915737e3d0)
- Bug 1223232 - Use GetUsedBorder() instead of the computed border value when calculating CB size. r=roc (f4c05b30c7)
- Bug 1223232 - Crashtest. (394e112818)
- Bug 1230665 - Make anonymous flex/grid items non-tabbable and non-focusable. r=roc (0d3f70e672)
- Bug 1142295 - Closing descriptor when GECKO_DISPLAY_REFLOW_RULES_FILE is setted. r=erahm (664ae6ba0a)
- minor change (b914bd2602)
- Bug 1237754 part 1 - [css-grid][css-align] Make 'align/justify-content:normal' behave as 'stretch' for Grid containers. r=dholbert (09a9a09629)
- Bug 1237754 part 2 - [css-grid][css-align] Test updates to account for new default behavior for 'align/justify-content'. (5e62e837ff)
- minor of Bug 1141931 part 2 (a12f5b430e)
- Bu 974309: Fixes the IsEditable() logic for table cells. r=ehsan (2a3caa932f)
- Bug 1238137 - Telemetry pings for main thread keyboard-driven scroll input methods. r=ehsan (e9c07427f9)
- Bug 1238137 - Telemetry pings for main thread scrolling to bring the caret into view after moving it in response to keyboard input. r=ehsan (834bc12b7a)
- Bug 1246405 - Declare mTextRun earlier to avoid alignment spill on 64-bit architectures. r=roc (7ba93b72c9)
- Fixing bug 440486. Work around a Windows XP fax dialog bug. r=rstrong. (a59409acd6)
- Bug 1240911 - Prevent SerializedStructuredCloneBuffer from escaping into the heap. r=amarchesini (2c0b7c474b)
- Bug 1240985 - Hold off processing some messages during timeout (r=dvander) (10f6f6d7a2)
- Bug 1146471 - Release thread asserts for IPC (r=dvander) (f94d0ee09a)
- Bug 1240985 - Fix bug where mAwaitingSyncReply can be overwritten in Send after Cancel (r=dvander) (7b95acdca6)
- Bug 1193861: Log to the process log when launching a sandboxed process on Windows. r=billm (0ad1afd0d0)
- Bug 1233061 - add override declarations for MessagePumpForNonMainUIThreads; r=billm (94b9a5bfe9)
- Bug 1172467: Fix an IPC channel file descriptor leak from Nuwa to the child process. r=khuey (908601ed0e)
- Bug 1240985 - Check WasTransactionCanceled after timeout (and avoid timing out) (r=dvander) (33aade0a92)
- Bug 1237458 - Use MOZ_RELEASE_ASSERT for IPC assertions (r=jld) (cb0f058205)
- Bug 1247429 - Warn instead of error if shmem deallocated before IPDL sends it. r=nical (3c94d99b21)
- Bug 1175999 - Deallocate mach SharedMemory properly. r=blassey. (542649b570)
- Bug 1188186 - Fix leak of FDs in |CreateTransport|. r=bds (a40b9a0c58)
- Bg 1240607 - Force CreateWindow hooks to be detours. r=jmathies (895d1c21c4)
- Bug 1209464: Fix missing neutered window region in MessageChannel::WaitForInterruptNotify. Regression from bug 1189709; r=jimm (204256880b)
- Bug 1229825 - Make GIF deinterlacer respect the frame rect bounds. r=tn (904f6bd9b7)
- Bug 1242093 - Fix assertion in Downscaler::ClearRow. r=njn (63ffe82e99)
- Bug 1235859 - Add FrameSize to non-skia downscaler. r=edwin (e7474630e0)
- Bug 1237709: During RasterImage error-handling cleanup, set UniquePtr mAnim to null instead of using reset(), to avoid leaking. r=dholbert (b064f9c20d)
- Bug 1235605 - Use CheckedInt in Deinterlacer and make its buffer allocation fallible. r=tn (f6f3858c65)
- cleanup (f02aa9441e)
- Bug 1242778: Add MOZ_COUNT_CTOR & MOZ_COUNT_DTOR calls to track leaks of imagelib's FrameAnimator class. r=tn (b1aa366694)
- Bug 1241728. Add crashtest. (17d80a3387)
- Bug 1241729. Add crashtest. (bd6d7337d7)
- Bug 1241728. Limit the size of images that we will downscale from to 1048576 pixels. r=edwin (ad38a82aad)
- Bug 1218782 - use fallible allocations in Downscaler.cpp; r=seth (b22caa1121)
- Bug 1224979. Check if we compute usable filters for the downscaler, and if not put the downscaler in error state so it's not used. r=edwin (8fb59463ef)
- Bug 1235297 - Annotate intentional switch fallthroughs to suppress -Wimplicit-fallthrough warnings in image/decoders/. r=tn (094c37c0fe)
- Bug 1238558 (part 1) - Add Decoder::BeforeFinishInternal(). r=tnikkel. (c7922054d6)
- Bug 1238558 (part 2) - Add a test. r=tnikkel. (7e09caf47f)
- Bug 1238551 (part 2) - Add a test. r=tn. (f548a2cb97)
- Bug 1238551 (part 1) - Reject BITMAPV3INFOHEADER BMP images. r=tn. (c4c8f95cb3)
- Bug 1240629. Don't buffer image file data that we are never going to look at in the gap between the header and the pixel data for BMP files. r=njn (f580910cd3)
- Bug 1237171 - Improve a case where ICO and BMP files disagree on an image size. r=tn. (615db65802)
- Bug 1220021 (part 1) - Don't treat 0RGB ICO files as transparent. r=seth. (b97298285f)
- Bug 1220021 (part 2) - Add four reftests. r=seth. (b1e7b58a98)
- Bug 1163856 (Part 2) - Fix tests that depended on image load event timing. r=tn (4304c676a0)
- Bug 1207958 - Fix heuristic for choosing which ICO sub-image to render - r=tn (3d4db5a033)
- Bug 987625 - Conditionally define MOZ_PNG_MAX_DIMENSION. r=jrmuizel (859bae490c)
- Bug 75077 - Interpolate interlaced PNG images instead of libpng blocky display. r=seth (bc17b43fa6)
- fix side-effect of 1219405 (6536821e18)
- Bug 1245845, part 1 - Stop Moz2D Path::CopyToBuilder/TransformedCopyToBuilder implicitly converting the Path's FillRule. r=Bas (ecc552f359)
- Bug 1245845, part 2 - Remove code that is now useless from gfxContext::EnsurePath. r=Bas (2430be2837)
- Bug 1237448 - Moz2Dify two functions in gfxSurfaceDrawable. r=roc. (bb768302c5)
- Bug 1231888 (follow-up) - Simplify CurrentSurface(). r=jrmuizel. (303cea98f3)
- Bug 1247380: Only copy the background if we can succesfully get a snapshot. r=jrmuizel (13b64445e9)
- Bug 1228507 - Initialize mBlendOpacity. r=Bas (b301a2c9f4)
- Bug 1238846 (part 2) - Remove gfxContext::mOriginalDT, which is unused. r=mattwoodrow. (a5b0f948b7)
- Bug 1240819 - cleanup dead branches in gfxXlibNativeRender.cpp. r=jrmuizel (57bbec6693)
- Bug 1234950 - When advancing APZ animations, use the next vsync timestamp instead of the current one, since that is what will be composited. r=mstange (421829d459)
- Bug 1021845 - Don't skip checkerboarding layers during compositing, even if the layer's visible region is empty. r=botond (6cf1497019)
- Bug 1230149 - check bigImgIter to see if it's not null. r=jmuizelaar (aeef579f9f)
- Bug 1248325 - Update BufferTextureHost::GetAsSurface() r=nical (39a8b3ca71)
- reapply per misspatch Bug 1200595 - Consolidate the TextureClient's destruction logic (68966e4dc3)
- Bug 1249245 - Add missing header gfxPrefs.h to GrallocTextureClient.cpp. r=cyu (676669eb01)
- Bug 1245057: Refer to |gfx::IntPoint| in |GrallocTextureHostOGL::SetCropRect|, r=sotaro (99e572f3f6)
- Bug 1240867 - Fix non-unified build bustage in OGLShaderProgram.cpp. r=nical (0071f08285)
- Bug 1238015 - Make sure PTexture actors are destroyed after all messages referring to them are sent. r=sotaro (250f99b4a4)
- Bug 1220895 - Add layerviewer for layer tree & display list visualization NPOTB. r=botond (fa211145a1)
- Bug 1213464 - ImageBridgeChild and CompositorChild should delete their Transport. r=billm (a37a0dbdfd)
- Bug 1234343 (part 1) - Make GfxMemoryImageReporter::sAmount signed. r=Bas. (18f0cb61ec)
- Bug 1234343 (part 2) - Add a missing GfxMemoryImageReporter::DidAlloc() call. r=Bas. (69df7f3674)
- Bug 1245249 - Check actor state before calling Send__delete__(); r=luke (65716a5915)
- Bug 1221418 - A better cleanup method for AsmJSCache::ChildRunnable, r=janv (5c8c023b9d)
- Bug 1235657 - Session storage needs to handle origin attributes correctly - part 1 - createOriginAttributesWithUserContextId, r=huseby (f2df8109ef)
- Bug 1245954 - Console StartTimer/StopTimer and IncrementCounter should run in the owning thread, r=bz (64f73d7759)
- Bug 1245957 - Adding assertions in Console about in which thread is running what, r=bz (291ee70e2d)
- Bug 1248022 - ConsoleEvent.styles can be a sequence of nullable strings, r=bz (b94ec79ac0)
- Bug 1245242 - Normalize to unit vector for DOMMatrix.rotateAxisAngleSelf. r=roc (3a9e684b4d)
- Bug 1236329. Back out the patch for bug 492933 (revision d8012b35413b) because it's not web-compatible in practice. r=smaug (f6540d84c3)
- mTarget can be null in CanvasRenderingContext2D::ClearRect(), return early if so. (13e8a4e26a)
678 lines
21 KiB
Plaintext
678 lines
21 KiB
Plaintext
/* -*- 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/. */
|
|
|
|
#include <map>
|
|
|
|
#include <mach/vm_map.h>
|
|
#include <mach/mach_port.h>
|
|
#if defined(XP_IOS)
|
|
#include <mach/vm_map.h>
|
|
#define mach_vm_address_t vm_address_t
|
|
#define mach_vm_allocate vm_allocate
|
|
#define mach_vm_deallocate vm_deallocate
|
|
#define mach_vm_map vm_map
|
|
#define mach_vm_read vm_read
|
|
#define mach_vm_region_recurse vm_region_recurse_64
|
|
#define mach_vm_size_t vm_size_t
|
|
#else
|
|
#include <mach/mach_vm.h>
|
|
#endif
|
|
#include <pthread.h>
|
|
#include <unistd.h>
|
|
#include "SharedMemoryBasic.h"
|
|
#include "chrome/common/mach_ipc_mac.h"
|
|
|
|
#include "mozilla/StaticMutex.h"
|
|
|
|
#ifdef DEBUG
|
|
#define LOG_ERROR(str, args...) \
|
|
PR_BEGIN_MACRO \
|
|
char *msg = PR_smprintf(str, ## args); \
|
|
NS_WARNING(msg); \
|
|
PR_smprintf_free(msg); \
|
|
PR_END_MACRO
|
|
#else
|
|
#define LOG_ERROR(str, args...) do { /* nothing */ } while(0)
|
|
#endif
|
|
|
|
#define CHECK_MACH_ERROR(kr, msg) \
|
|
PR_BEGIN_MACRO \
|
|
if (kr != KERN_SUCCESS) { \
|
|
LOG_ERROR("%s %s (%x)\n", msg, mach_error_string(kr), kr); \
|
|
return false; \
|
|
} \
|
|
PR_END_MACRO
|
|
|
|
/*
|
|
* This code is responsible for sharing memory between processes. Memory can be
|
|
* shared between parent and child or between two children. Each memory region is
|
|
* referenced via a Mach port. Mach ports are also used for messaging when
|
|
* sharing a memory region.
|
|
*
|
|
* When the parent starts a child, it starts a thread whose only purpose is to
|
|
* communicate with the child about shared memory. Once the child has started,
|
|
* it starts a similar thread for communicating with the parent. Each side can
|
|
* communicate with the thread on the other side via Mach ports. When either
|
|
* side wants to share memory with the other, it sends a Mach message to the
|
|
* other side. Attached to the message is the port that references the shared
|
|
* memory region. When the other side receives the message, it automatically
|
|
* gets access to the region. It sends a reply (also via a Mach port) so that
|
|
* the originating side can continue.
|
|
*
|
|
* The two sides communicate using four ports. Two ports are used when the
|
|
* parent shares memory with the child. The other two are used when the child
|
|
* shares memory with the parent. One of these two ports is used for sending the
|
|
* "share" message and the other is used for the reply.
|
|
*
|
|
* If a child wants to share memory with another child, it sends a "GetPorts"
|
|
* message to the parent. The parent forwards this GetPorts message to the
|
|
* target child. The message includes some ports so that the children can talk
|
|
* directly. Both children start up a thread to communicate with the other child,
|
|
* similar to the way parent and child communicate. In the future, when these
|
|
* two children want to communicate, they re-use the channels that were created.
|
|
*
|
|
* When a child shuts down, the parent notifies all other children. Those
|
|
* children then have the opportunity to shut down any threads they might have
|
|
* been using to communicate directly with that child.
|
|
*/
|
|
|
|
namespace mozilla {
|
|
namespace ipc {
|
|
|
|
struct MemoryPorts {
|
|
MachPortSender* mSender;
|
|
ReceivePort* mReceiver;
|
|
|
|
MemoryPorts() {}
|
|
MemoryPorts(MachPortSender* sender, ReceivePort* receiver)
|
|
: mSender(sender), mReceiver(receiver) {}
|
|
};
|
|
|
|
// Protects gMemoryCommPorts and gThreads.
|
|
static StaticMutex gMutex;
|
|
|
|
static std::map<pid_t, MemoryPorts> gMemoryCommPorts;
|
|
|
|
enum {
|
|
kGetPortsMsg = 1,
|
|
kSharePortsMsg,
|
|
kReturnIdMsg,
|
|
kReturnPortsMsg,
|
|
kShutdownMsg,
|
|
kCleanupMsg,
|
|
};
|
|
|
|
const int kTimeout = 1000;
|
|
const int kLongTimeout = 60 * kTimeout;
|
|
|
|
pid_t gParentPid = 0;
|
|
|
|
struct PIDPair {
|
|
pid_t mRequester;
|
|
pid_t mRequested;
|
|
|
|
PIDPair(pid_t requester, pid_t requested)
|
|
: mRequester(requester), mRequested(requested) {}
|
|
};
|
|
|
|
struct ListeningThread {
|
|
pthread_t mThread;
|
|
MemoryPorts* mPorts;
|
|
|
|
ListeningThread() {}
|
|
ListeningThread(pthread_t thread, MemoryPorts* ports)
|
|
: mThread(thread), mPorts(ports) {}
|
|
};
|
|
|
|
struct SharePortsReply {
|
|
uint64_t serial;
|
|
mach_port_t port;
|
|
};
|
|
|
|
std::map<pid_t, ListeningThread> gThreads;
|
|
|
|
static void *
|
|
PortServerThread(void *argument);
|
|
|
|
|
|
static void
|
|
SetupMachMemory(pid_t pid,
|
|
ReceivePort* listen_port,
|
|
MachPortSender* listen_port_ack,
|
|
MachPortSender* send_port,
|
|
ReceivePort* send_port_ack,
|
|
bool pidIsParent)
|
|
{
|
|
if (pidIsParent) {
|
|
gParentPid = pid;
|
|
}
|
|
MemoryPorts* listen_ports = new MemoryPorts(listen_port_ack, listen_port);
|
|
pthread_t thread;
|
|
pthread_attr_t attr;
|
|
pthread_attr_init(&attr);
|
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
int err = pthread_create(&thread, &attr, PortServerThread, listen_ports);
|
|
if (err) {
|
|
LOG_ERROR("pthread_create failed with %x\n", err);
|
|
return;
|
|
}
|
|
|
|
gMutex.AssertCurrentThreadOwns();
|
|
gThreads[pid] = ListeningThread(thread, listen_ports);
|
|
gMemoryCommPorts[pid] = MemoryPorts(send_port, send_port_ack);
|
|
}
|
|
|
|
// Send two communication ports to another process along with the pid of the process that is
|
|
// listening on them.
|
|
bool
|
|
SendPortsMessage(MachPortSender* sender,
|
|
mach_port_t ports_in_receiver,
|
|
mach_port_t ports_out_receiver,
|
|
PIDPair pid_pair)
|
|
{
|
|
MachSendMessage getPortsMsg(kGetPortsMsg);
|
|
if (!getPortsMsg.AddDescriptor(MachMsgPortDescriptor(ports_in_receiver))) {
|
|
LOG_ERROR("Adding descriptor to message failed");
|
|
return false;
|
|
}
|
|
if (!getPortsMsg.AddDescriptor(MachMsgPortDescriptor(ports_out_receiver))) {
|
|
LOG_ERROR("Adding descriptor to message failed");
|
|
return false;
|
|
}
|
|
|
|
getPortsMsg.SetData(&pid_pair, sizeof(PIDPair));
|
|
kern_return_t err = sender->SendMessage(getPortsMsg, kTimeout);
|
|
if (KERN_SUCCESS != err) {
|
|
LOG_ERROR("Error sending get ports message %s (%x)\n", mach_error_string(err), err);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Receive two communication ports from another process
|
|
bool
|
|
RecvPortsMessage(ReceivePort* receiver, mach_port_t* ports_in_sender, mach_port_t* ports_out_sender)
|
|
{
|
|
MachReceiveMessage rcvPortsMsg;
|
|
kern_return_t err = receiver->WaitForMessage(&rcvPortsMsg, kTimeout);
|
|
if (KERN_SUCCESS != err) {
|
|
LOG_ERROR("Error receiving get ports message %s (%x)\n", mach_error_string(err), err);
|
|
}
|
|
if (rcvPortsMsg.GetTranslatedPort(0) == MACH_PORT_NULL) {
|
|
LOG_ERROR("GetTranslatedPort(0) failed");
|
|
return false;
|
|
}
|
|
*ports_in_sender = rcvPortsMsg.GetTranslatedPort(0);
|
|
|
|
if (rcvPortsMsg.GetTranslatedPort(1) == MACH_PORT_NULL) {
|
|
LOG_ERROR("GetTranslatedPort(1) failed");
|
|
return false;
|
|
}
|
|
*ports_out_sender = rcvPortsMsg.GetTranslatedPort(1);
|
|
return true;
|
|
}
|
|
|
|
// Send two communication ports to another process and receive two back
|
|
bool
|
|
RequestPorts(const MemoryPorts& request_ports,
|
|
mach_port_t ports_in_receiver,
|
|
mach_port_t* ports_in_sender,
|
|
mach_port_t* ports_out_sender,
|
|
mach_port_t ports_out_receiver,
|
|
PIDPair pid_pair)
|
|
{
|
|
if (!SendPortsMessage(request_ports.mSender, ports_in_receiver, ports_out_receiver, pid_pair)) {
|
|
return false;
|
|
}
|
|
return RecvPortsMessage(request_ports.mReceiver, ports_in_sender, ports_out_sender);
|
|
}
|
|
|
|
MemoryPorts*
|
|
GetMemoryPortsForPid(pid_t pid)
|
|
{
|
|
gMutex.AssertCurrentThreadOwns();
|
|
|
|
if (gMemoryCommPorts.find(pid) == gMemoryCommPorts.end()) {
|
|
// We don't have the ports open to communicate with that pid, so we're going to
|
|
// ask our parent process over IPC to set them up for us.
|
|
if (gParentPid == 0) {
|
|
// If we're the top level parent process, we have no parent to ask.
|
|
LOG_ERROR("request for ports for pid %d, but we're the chrome process\n", pid);
|
|
return nullptr;
|
|
}
|
|
const MemoryPorts& parent = gMemoryCommPorts[gParentPid];
|
|
|
|
// Create two receiving ports in this process to send to the parent. One will be used for
|
|
// for listening for incoming memory to be shared, the other for getting the Handle of
|
|
// memory we share to the other process.
|
|
ReceivePort* ports_in_receiver = new ReceivePort();
|
|
ReceivePort* ports_out_receiver = new ReceivePort();
|
|
mach_port_t raw_ports_in_sender, raw_ports_out_sender;
|
|
if (!RequestPorts(parent,
|
|
ports_in_receiver->GetPort(),
|
|
&raw_ports_in_sender,
|
|
&raw_ports_out_sender,
|
|
ports_out_receiver->GetPort(),
|
|
PIDPair(getpid(), pid))) {
|
|
LOG_ERROR("failed to request ports\n");
|
|
return nullptr;
|
|
}
|
|
// Our parent process sent us two ports, one is for sending new memory to, the other
|
|
// is for replying with the Handle when we receive new memory.
|
|
MachPortSender* ports_in_sender = new MachPortSender(raw_ports_in_sender);
|
|
MachPortSender* ports_out_sender = new MachPortSender(raw_ports_out_sender);
|
|
SetupMachMemory(pid,
|
|
ports_in_receiver,
|
|
ports_in_sender,
|
|
ports_out_sender,
|
|
ports_out_receiver,
|
|
false);
|
|
MOZ_ASSERT(gMemoryCommPorts.find(pid) != gMemoryCommPorts.end());
|
|
}
|
|
return &gMemoryCommPorts.at(pid);
|
|
}
|
|
|
|
// We just received a port representing a region of shared memory, reply to
|
|
// the process that set it with the mach_port_t that represents it in this process.
|
|
// That will be the Handle to be shared over normal IPC
|
|
void
|
|
HandleSharePortsMessage(MachReceiveMessage* rmsg, MemoryPorts* ports)
|
|
{
|
|
mach_port_t port = rmsg->GetTranslatedPort(0);
|
|
uint64_t* serial = reinterpret_cast<uint64_t*>(rmsg->GetData());
|
|
MachSendMessage msg(kReturnIdMsg);
|
|
// Construct the reply message, echoing the serial, and adding the port
|
|
SharePortsReply replydata;
|
|
replydata.port = port;
|
|
replydata.serial = *serial;
|
|
msg.SetData(&replydata, sizeof(SharePortsReply));
|
|
kern_return_t err = ports->mSender->SendMessage(msg, kTimeout);
|
|
if (KERN_SUCCESS != err) {
|
|
LOG_ERROR("SendMessage failed 0x%x %s\n", err, mach_error_string(err));
|
|
}
|
|
}
|
|
|
|
// We were asked by another process to get communications ports to some process. Return
|
|
// those ports via an IPC message.
|
|
bool
|
|
SendReturnPortsMsg(MachPortSender* sender,
|
|
mach_port_t raw_ports_in_sender,
|
|
mach_port_t raw_ports_out_sender)
|
|
{
|
|
MachSendMessage getPortsMsg(kReturnPortsMsg);
|
|
if (!getPortsMsg.AddDescriptor(MachMsgPortDescriptor(raw_ports_in_sender))) {
|
|
LOG_ERROR("Adding descriptor to message failed");
|
|
return false;
|
|
}
|
|
|
|
if (!getPortsMsg.AddDescriptor(MachMsgPortDescriptor(raw_ports_out_sender))) {
|
|
LOG_ERROR("Adding descriptor to message failed");
|
|
return false;
|
|
}
|
|
kern_return_t err = sender->SendMessage(getPortsMsg, kTimeout);
|
|
if (KERN_SUCCESS != err) {
|
|
LOG_ERROR("Error sending get ports message %s (%x)\n", mach_error_string(err), err);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// We were asked for communcations ports to a process that isn't us. Assuming that process
|
|
// is one of our children, forward that request on.
|
|
void
|
|
ForwardGetPortsMessage(MachReceiveMessage* rmsg, MemoryPorts* ports, PIDPair* pid_pair)
|
|
{
|
|
if (rmsg->GetTranslatedPort(0) == MACH_PORT_NULL) {
|
|
LOG_ERROR("GetTranslatedPort(0) failed");
|
|
return;
|
|
}
|
|
if (rmsg->GetTranslatedPort(1) == MACH_PORT_NULL) {
|
|
LOG_ERROR("GetTranslatedPort(1) failed");
|
|
return;
|
|
}
|
|
mach_port_t raw_ports_in_sender, raw_ports_out_sender;
|
|
MemoryPorts* requestedPorts = GetMemoryPortsForPid(pid_pair->mRequested);
|
|
if (!requestedPorts) {
|
|
LOG_ERROR("failed to find port for process\n");
|
|
return;
|
|
}
|
|
if (!RequestPorts(*requestedPorts, rmsg->GetTranslatedPort(0), &raw_ports_in_sender,
|
|
&raw_ports_out_sender, rmsg->GetTranslatedPort(1), *pid_pair)) {
|
|
LOG_ERROR("failed to request ports\n");
|
|
return;
|
|
}
|
|
SendReturnPortsMsg(ports->mSender, raw_ports_in_sender, raw_ports_out_sender);
|
|
}
|
|
|
|
// We receieved a message asking us to get communications ports for another process
|
|
void
|
|
HandleGetPortsMessage(MachReceiveMessage* rmsg, MemoryPorts* ports)
|
|
{
|
|
PIDPair* pid_pair;
|
|
if (rmsg->GetDataLength() != sizeof(PIDPair)) {
|
|
LOG_ERROR("Improperly formatted message\n");
|
|
return;
|
|
}
|
|
pid_pair = reinterpret_cast<PIDPair*>(rmsg->GetData());
|
|
if (pid_pair->mRequested != getpid()) {
|
|
// This request is for ports to a process that isn't us, forward it to that process
|
|
ForwardGetPortsMessage(rmsg, ports, pid_pair);
|
|
} else {
|
|
if (rmsg->GetTranslatedPort(0) == MACH_PORT_NULL) {
|
|
LOG_ERROR("GetTranslatedPort(0) failed");
|
|
return;
|
|
}
|
|
|
|
if (rmsg->GetTranslatedPort(1) == MACH_PORT_NULL) {
|
|
LOG_ERROR("GetTranslatedPort(1) failed");
|
|
return;
|
|
}
|
|
|
|
MachPortSender* ports_in_sender = new MachPortSender(rmsg->GetTranslatedPort(0));
|
|
MachPortSender* ports_out_sender = new MachPortSender(rmsg->GetTranslatedPort(1));
|
|
|
|
ReceivePort* ports_in_receiver = new ReceivePort();
|
|
ReceivePort* ports_out_receiver = new ReceivePort();
|
|
if (SendReturnPortsMsg(ports->mSender, ports_in_receiver->GetPort(), ports_out_receiver->GetPort())) {
|
|
SetupMachMemory(pid_pair->mRequester,
|
|
ports_out_receiver,
|
|
ports_out_sender,
|
|
ports_in_sender,
|
|
ports_in_receiver,
|
|
false);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void *
|
|
PortServerThread(void *argument)
|
|
{
|
|
MemoryPorts* ports = static_cast<MemoryPorts*>(argument);
|
|
MachReceiveMessage child_message;
|
|
while (true) {
|
|
MachReceiveMessage rmsg;
|
|
kern_return_t err = ports->mReceiver->WaitForMessage(&rmsg, MACH_MSG_TIMEOUT_NONE);
|
|
if (err != KERN_SUCCESS) {
|
|
LOG_ERROR("Wait for message failed 0x%x %s\n", err, mach_error_string(err));
|
|
continue;
|
|
}
|
|
if (rmsg.GetMessageID() == kShutdownMsg) {
|
|
delete ports->mSender;
|
|
delete ports->mReceiver;
|
|
delete ports;
|
|
return nullptr;
|
|
}
|
|
StaticMutexAutoLock smal(gMutex);
|
|
switch (rmsg.GetMessageID()) {
|
|
case kSharePortsMsg:
|
|
HandleSharePortsMessage(&rmsg, ports);
|
|
break;
|
|
case kGetPortsMsg:
|
|
HandleGetPortsMessage(&rmsg, ports);
|
|
break;
|
|
case kCleanupMsg:
|
|
if (gParentPid == 0) {
|
|
LOG_ERROR("Cleanup message not valid for parent process");
|
|
continue;
|
|
}
|
|
|
|
pid_t* pid;
|
|
if (rmsg.GetDataLength() != sizeof(pid_t)) {
|
|
LOG_ERROR("Improperly formatted message\n");
|
|
continue;
|
|
}
|
|
pid = reinterpret_cast<pid_t*>(rmsg.GetData());
|
|
SharedMemoryBasic::CleanupForPid(*pid);
|
|
break;
|
|
default:
|
|
LOG_ERROR("Unknown message\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
SharedMemoryBasic::SetupMachMemory(pid_t pid,
|
|
ReceivePort* listen_port,
|
|
MachPortSender* listen_port_ack,
|
|
MachPortSender* send_port,
|
|
ReceivePort* send_port_ack,
|
|
bool pidIsParent)
|
|
{
|
|
StaticMutexAutoLock smal(gMutex);
|
|
mozilla::ipc::SetupMachMemory(pid, listen_port, listen_port_ack, send_port, send_port_ack, pidIsParent);
|
|
}
|
|
|
|
void
|
|
SharedMemoryBasic::Shutdown()
|
|
{
|
|
StaticMutexAutoLock smal(gMutex);
|
|
|
|
for (auto it = gThreads.begin(); it != gThreads.end(); ++it) {
|
|
MachSendMessage shutdownMsg(kShutdownMsg);
|
|
it->second.mPorts->mReceiver->SendMessageToSelf(shutdownMsg, kTimeout);
|
|
}
|
|
gThreads.clear();
|
|
|
|
for (auto it = gMemoryCommPorts.begin(); it != gMemoryCommPorts.end(); ++it) {
|
|
delete it->second.mSender;
|
|
delete it->second.mReceiver;
|
|
}
|
|
gMemoryCommPorts.clear();
|
|
}
|
|
|
|
void
|
|
SharedMemoryBasic::CleanupForPid(pid_t pid)
|
|
{
|
|
if (gThreads.find(pid) == gThreads.end()) {
|
|
return;
|
|
}
|
|
const ListeningThread& listeningThread = gThreads[pid];
|
|
MachSendMessage shutdownMsg(kShutdownMsg);
|
|
kern_return_t ret = listeningThread.mPorts->mReceiver->SendMessageToSelf(shutdownMsg, kTimeout);
|
|
if (ret != KERN_SUCCESS) {
|
|
LOG_ERROR("sending shutdown msg failed %s %x\n", mach_error_string(ret), ret);
|
|
}
|
|
gThreads.erase(pid);
|
|
|
|
if (gParentPid == 0) {
|
|
// We're the parent. Broadcast the cleanup message to everyone else.
|
|
for (auto it = gMemoryCommPorts.begin(); it != gMemoryCommPorts.end(); ++it) {
|
|
MachSendMessage msg(kCleanupMsg);
|
|
msg.SetData(&pid, sizeof(pid));
|
|
// We don't really care if this fails, we could be trying to send to an already shut down proc
|
|
it->second.mSender->SendMessage(msg, kTimeout);
|
|
}
|
|
}
|
|
|
|
MemoryPorts& ports = gMemoryCommPorts[pid];
|
|
delete ports.mSender;
|
|
delete ports.mReceiver;
|
|
gMemoryCommPorts.erase(pid);
|
|
}
|
|
|
|
SharedMemoryBasic::SharedMemoryBasic()
|
|
: mPort(MACH_PORT_NULL)
|
|
, mMemory(nullptr)
|
|
{
|
|
}
|
|
|
|
SharedMemoryBasic::~SharedMemoryBasic()
|
|
{
|
|
Unmap();
|
|
CloseHandle();
|
|
}
|
|
|
|
bool
|
|
SharedMemoryBasic::SetHandle(const Handle& aHandle)
|
|
{
|
|
MOZ_ASSERT(mPort == MACH_PORT_NULL, "already initialized");
|
|
|
|
mPort = aHandle;
|
|
return true;
|
|
}
|
|
|
|
static inline void*
|
|
toPointer(mach_vm_address_t address)
|
|
{
|
|
return reinterpret_cast<void*>(static_cast<uintptr_t>(address));
|
|
}
|
|
|
|
static inline mach_vm_address_t
|
|
toVMAddress(void* pointer)
|
|
{
|
|
return static_cast<mach_vm_address_t>(reinterpret_cast<uintptr_t>(pointer));
|
|
}
|
|
|
|
bool
|
|
SharedMemoryBasic::Create(size_t size)
|
|
{
|
|
mach_vm_address_t address;
|
|
|
|
kern_return_t kr = mach_vm_allocate(mach_task_self(), &address, round_page(size), VM_FLAGS_ANYWHERE);
|
|
if (kr != KERN_SUCCESS) {
|
|
LOG_ERROR("Failed to allocate mach_vm_allocate shared memory (%zu bytes). %s (%x)\n",
|
|
size, mach_error_string(kr), kr);
|
|
return false;
|
|
}
|
|
|
|
memory_object_size_t memoryObjectSize = round_page(size);
|
|
|
|
kr = mach_make_memory_entry_64(mach_task_self(),
|
|
&memoryObjectSize,
|
|
address,
|
|
VM_PROT_DEFAULT,
|
|
&mPort,
|
|
MACH_PORT_NULL);
|
|
if (kr != KERN_SUCCESS) {
|
|
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n",
|
|
size, mach_error_string(kr), kr);
|
|
return false;
|
|
}
|
|
|
|
mMemory = toPointer(address);
|
|
Mapped(size);
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
SharedMemoryBasic::Map(size_t size)
|
|
{
|
|
if (mMemory) {
|
|
return true;
|
|
}
|
|
|
|
if (MACH_PORT_NULL == mPort) {
|
|
return false;
|
|
}
|
|
|
|
kern_return_t kr;
|
|
mach_vm_address_t address = 0;
|
|
|
|
vm_prot_t vmProtection = VM_PROT_READ | VM_PROT_WRITE;
|
|
|
|
kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0, VM_FLAGS_ANYWHERE,
|
|
mPort, 0, false, vmProtection, vmProtection, VM_INHERIT_NONE);
|
|
if (kr != KERN_SUCCESS) {
|
|
LOG_ERROR("Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
|
|
size, mach_task_self(), mPort, mach_error_string(kr), kr);
|
|
return false;
|
|
}
|
|
|
|
mMemory = toPointer(address);
|
|
Mapped(size);
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
SharedMemoryBasic::ShareToProcess(base::ProcessId pid,
|
|
Handle* aNewHandle)
|
|
{
|
|
if (pid == getpid()) {
|
|
*aNewHandle = mPort;
|
|
return mach_port_mod_refs(mach_task_self(), *aNewHandle, MACH_PORT_RIGHT_SEND, 1) == KERN_SUCCESS;
|
|
}
|
|
StaticMutexAutoLock smal(gMutex);
|
|
|
|
// Serially number the messages, to check whether
|
|
// the reply we get was meant for us.
|
|
static uint64_t serial = 0;
|
|
uint64_t my_serial = serial;
|
|
serial++;
|
|
|
|
MemoryPorts* ports = GetMemoryPortsForPid(pid);
|
|
if (!ports) {
|
|
LOG_ERROR("Unable to get ports for process.\n");
|
|
return false;
|
|
}
|
|
MachSendMessage smsg(kSharePortsMsg);
|
|
smsg.AddDescriptor(MachMsgPortDescriptor(mPort, MACH_MSG_TYPE_COPY_SEND));
|
|
smsg.SetData(&my_serial, sizeof(uint64_t));
|
|
kern_return_t err = ports->mSender->SendMessage(smsg, kTimeout);
|
|
if (err != KERN_SUCCESS) {
|
|
LOG_ERROR("sending port failed %s %x\n", mach_error_string(err), err);
|
|
return false;
|
|
}
|
|
MachReceiveMessage msg;
|
|
err = ports->mReceiver->WaitForMessage(&msg, kTimeout);
|
|
if (err != KERN_SUCCESS) {
|
|
LOG_ERROR("short timeout didn't get an id %s %x\n", mach_error_string(err), err);
|
|
MOZ_ASSERT(false, "Receiver message short time out");
|
|
err = ports->mReceiver->WaitForMessage(&msg, kLongTimeout);
|
|
|
|
if (err != KERN_SUCCESS) {
|
|
LOG_ERROR("long timeout didn't get an id %s %x\n", mach_error_string(err), err);
|
|
return false;
|
|
}
|
|
}
|
|
if (msg.GetDataLength() != sizeof(SharePortsReply)) {
|
|
LOG_ERROR("Improperly formatted reply\n");
|
|
return false;
|
|
}
|
|
SharePortsReply* msg_data = reinterpret_cast<SharePortsReply*>(msg.GetData());
|
|
mach_port_t id = msg_data->port;
|
|
uint64_t serial_check = msg_data->serial;
|
|
if (serial_check != my_serial) {
|
|
LOG_ERROR("Serials do not match up: %d vs %d", serial_check, my_serial);
|
|
return false;
|
|
}
|
|
*aNewHandle = id;
|
|
return true;
|
|
}
|
|
|
|
void
|
|
SharedMemoryBasic::Unmap()
|
|
{
|
|
if (!mMemory) {
|
|
return;
|
|
}
|
|
vm_address_t address = toVMAddress(mMemory);
|
|
kern_return_t kr = vm_deallocate(mach_task_self(), address, round_page(mMappedSize));
|
|
if (kr != KERN_SUCCESS) {
|
|
LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n", mach_error_string(kr), kr);
|
|
return;
|
|
}
|
|
mMemory = nullptr;
|
|
}
|
|
|
|
void
|
|
SharedMemoryBasic::CloseHandle()
|
|
{
|
|
if (mPort != MACH_PORT_NULL) {
|
|
mach_port_deallocate(mach_task_self(), mPort);
|
|
mPort = MACH_PORT_NULL;
|
|
}
|
|
}
|
|
|
|
bool
|
|
SharedMemoryBasic::IsHandleValid(const Handle& aHandle) const
|
|
{
|
|
return aHandle > 0;
|
|
}
|
|
|
|
} // namespace ipc
|
|
} // namespace mozilla
|