diff options
Diffstat (limited to 'ipc')
75 files changed, 661 insertions, 1447 deletions
diff --git a/ipc/chromium/src/base/process_util_posix.cc b/ipc/chromium/src/base/process_util_posix.cc index d91dc25e9f..57ae82ebbf 100644 --- a/ipc/chromium/src/base/process_util_posix.cc +++ b/ipc/chromium/src/base/process_util_posix.cc @@ -10,6 +10,7 @@ #include <signal.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/resource.h> #include <sys/time.h> #include <sys/types.h> @@ -37,6 +38,7 @@ #ifdef MOZ_ENABLE_FORKSERVER # include "mozilla/ipc/ForkServiceChild.h" +# include "mozilla/Printf.h" #endif // We could configure-test for `waitid`, but it's been in POSIX for a @@ -195,6 +197,63 @@ void CloseSuperfluousFds(void* aCtx, bool (*aShouldPreserve)(void*, int)) { } } +#ifdef MOZ_ENABLE_FORKSERVER +// Returns whether a process (assumed to still exist) is in the zombie +// state. Any failures (if the process doesn't exist, if /proc isn't +// mounted, etc.) will return true, so that we don't try again. +static bool IsZombieProcess(pid_t pid) { +# ifdef XP_LINUX + auto path = mozilla::Smprintf("/proc/%d/stat", pid); + int fd = open(path.get(), O_RDONLY | O_CLOEXEC); + if (fd < 0) { + int e = errno; + CHROMIUM_LOG(ERROR) << "failed to open " << path.get() << ": " + << strerror(e); + return true; + } + + // /proc/%d/stat format is approximately: + // + // %d (%s) %c %d %d %d %d %d ... + // + // The state is the third field; the second field is the thread + // name, in parentheses, but it can contain arbitrary characters. + // So, we read the whole line, check for the last ')' because all of + // the following fields are numeric, and move forward from there. + // + // And because (unlike other uses of this info the codebase) we + // don't care about those other fields, we can read a smaller amount + // of the file. + + char buffer[64]; + ssize_t len = HANDLE_EINTR(read(fd, buffer, sizeof(buffer) - 1)); + int e = errno; + close(fd); + if (len < 1) { + CHROMIUM_LOG(ERROR) << "failed to read " << buffer << ": " << strerror(e); + return true; + } + + buffer[len] = '\0'; + char* rparen = strrchr(buffer, ')'); + if (!rparen || rparen[1] != ' ' || rparen[2] == '\0') { + DCHECK(false) << "/proc/{pid}/stat parse error"; + CHROMIUM_LOG(ERROR) << "bad data in /proc/" << pid << "/stat"; + return true; + } + if (rparen[2] == 'Z') { + CHROMIUM_LOG(ERROR) << "process " << pid << " is a zombie"; + return true; + } + return false; +# else // not XP_LINUX + // The situation where this matters is Linux-specific (pid + // namespaces), so we don't need to bother on other Unixes. + return false; +# endif +} +#endif // MOZ_ENABLE_FORKSERVER + bool IsProcessDead(ProcessHandle handle, bool blocking) { auto handleForkServer = [handle]() -> mozilla::Maybe<bool> { #ifdef MOZ_ENABLE_FORKSERVER @@ -205,10 +264,21 @@ bool IsProcessDead(ProcessHandle handle, bool blocking) { // process any more, it is impossible to use |waitpid()| to wait for // them. const int r = kill(handle, 0); - // FIXME: for unexpected errors we should probably log a warning - // and return true, so that the caller doesn't loop / hang / - // try to kill the process. (Bug 1658072 will rewrite this code.) - return mozilla::Some(r < 0 && errno == ESRCH); + if (r < 0) { + const int e = errno; + if (e != ESRCH) { + CHROMIUM_LOG(WARNING) << "unexpected error checking for process " + << handle << ": " << strerror(e); + // Return true for unknown errors, to avoid the possibility + // of getting stuck in loop of failures. + } + return mozilla::Some(true); + } + // Annoying edge case (bug NNNNNNN): if pid 1 isn't a real + // `init`, like in some container environments, and if the child + // exited after the fork server, it could become a permanent + // zombie. We treat it as dead in that case. + return mozilla::Some(IsZombieProcess(handle)); } #else mozilla::Unused << handle; diff --git a/ipc/chromium/src/chrome/common/ipc_channel.h b/ipc/chromium/src/chrome/common/ipc_channel.h index 5d342d7252..d755810078 100644 --- a/ipc/chromium/src/chrome/common/ipc_channel.h +++ b/ipc/chromium/src/chrome/common/ipc_channel.h @@ -142,11 +142,12 @@ class Channel { void StartAcceptingHandles(Mode mode); #endif -#if defined(MOZ_WIDGET_ANDROID) - // Used to set the first IPC file descriptor in the child process on Android. - // See ipc_channel_posix.cc for further details on how this is used. +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT) + // Used to set the first IPC file descriptor in the child process on + // Android and iOS. See ipc_channel_posix.cc for further details on how this + // is used. static void SetClientChannelFd(int fd); -#endif // defined(MOZ_WIDGET_ANDROID) +#endif // defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT) // Get the first IPC channel handle in the child process. This will have been // set by SetClientChannelFd on Android, will be a constant on other unix diff --git a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc index 0b34af40b1..19e777a52a 100644 --- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc +++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc @@ -84,8 +84,8 @@ namespace { // This is the file descriptor number that a client process expects to find its // IPC socket. static int gClientChannelFd = -#if defined(MOZ_WIDGET_ANDROID) - // On android the fd is set at the time of child creation. +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT) + // On android/ios the fd is set at the time of child creation. -1 #else 3 @@ -135,9 +135,9 @@ static inline ssize_t corrected_sendmsg(int socket, } // namespace //------------------------------------------------------------------------------ -#if defined(MOZ_WIDGET_ANDROID) +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT) void Channel::SetClientChannelFd(int fd) { gClientChannelFd = fd; } -#endif // defined(MOZ_WIDGET_ANDROID) +#endif // defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT) int Channel::GetClientChannelHandle() { return gClientChannelFd; } diff --git a/ipc/chromium/src/mojo/core/ports/port.cc b/ipc/chromium/src/mojo/core/ports/port.cc index 871ec8fca6..df46ae100d 100644 --- a/ipc/chromium/src/mojo/core/ports/port.cc +++ b/ipc/chromium/src/mojo/core/ports/port.cc @@ -8,6 +8,10 @@ namespace mojo { namespace core { namespace ports { +#ifdef MOZ_USE_SINGLETON_PORT_MUTEX +mozilla::StaticMutex detail::PortMutex::sSingleton; +#endif + // Used by std::{push,pop}_heap functions inline bool operator<(const mozilla::UniquePtr<Event>& a, const mozilla::UniquePtr<Event>& b) { diff --git a/ipc/chromium/src/mojo/core/ports/port.h b/ipc/chromium/src/mojo/core/ports/port.h index 44529ddb6f..78fe0109b8 100644 --- a/ipc/chromium/src/mojo/core/ports/port.h +++ b/ipc/chromium/src/mojo/core/ports/port.h @@ -18,6 +18,18 @@ #include "mozilla/RefPtr.h" #include "nsISupportsImpl.h" +#ifdef MOZ_TSAN +// In TSAN builds, a single static mutex is used for all ports, rather than +// per-port mutexes, to avoid overloading the maximum 64 concurrently-held locks +// limit of its deadlock detector when sending messages with a large number of +// attached ports. +# define MOZ_USE_SINGLETON_PORT_MUTEX 1 +#endif + +#ifdef MOZ_USE_SINGLETON_PORT_MUTEX +# include "mozilla/StaticMutex.h" +#endif + namespace mojo { namespace core { namespace ports { @@ -28,20 +40,38 @@ namespace detail { // Ports cannot use mozilla::Mutex, as the acquires-before relationships handled // by PortLocker can overload the debug-only deadlock detector. -class MOZ_CAPABILITY("mutex") PortMutex : private ::mozilla::detail::MutexImpl { +class MOZ_CAPABILITY("mutex") PortMutex +#ifndef MOZ_USE_SINGLETON_PORT_MUTEX + : private ::mozilla::detail::MutexImpl +#endif +{ public: void AssertCurrentThreadOwns() const MOZ_ASSERT_CAPABILITY(this) { #ifdef DEBUG MOZ_ASSERT(mOwningThread == PR_GetCurrentThread()); #endif +#ifdef MOZ_USE_SINGLETON_PORT_MUTEX + sSingleton.AssertCurrentThreadOwns(); +#endif } private: // PortMutex should only be locked/unlocked via PortLocker friend class ::mojo::core::ports::PortLocker; +#ifdef MOZ_USE_SINGLETON_PORT_MUTEX + // If the singleton mutex is in use, it must be locked before calling `Lock()` + // on any port, and must only be unlocked after calling `Unlock()` on every + // locked port. + static ::mozilla::StaticMutex sSingleton; +#endif + void Lock() MOZ_CAPABILITY_ACQUIRE() { +#ifdef MOZ_USE_SINGLETON_PORT_MUTEX + sSingleton.AssertCurrentThreadOwns(); +#else ::mozilla::detail::MutexImpl::lock(); +#endif #ifdef DEBUG mOwningThread = PR_GetCurrentThread(); #endif @@ -51,7 +81,11 @@ class MOZ_CAPABILITY("mutex") PortMutex : private ::mozilla::detail::MutexImpl { MOZ_ASSERT(mOwningThread == PR_GetCurrentThread()); mOwningThread = nullptr; #endif +#ifdef MOZ_USE_SINGLETON_PORT_MUTEX + sSingleton.AssertCurrentThreadOwns(); +#else ::mozilla::detail::MutexImpl::unlock(); +#endif } #ifdef DEBUG diff --git a/ipc/chromium/src/mojo/core/ports/port_locker.cc b/ipc/chromium/src/mojo/core/ports/port_locker.cc index 044a26f143..a09bed31c3 100644 --- a/ipc/chromium/src/mojo/core/ports/port_locker.cc +++ b/ipc/chromium/src/mojo/core/ports/port_locker.cc @@ -36,6 +36,10 @@ PortLocker::PortLocker(const PortRef** port_refs, size_t num_ports) UpdateTLS(nullptr, this); #endif +#ifdef MOZ_USE_SINGLETON_PORT_MUTEX + detail::PortMutex::sSingleton.Lock(); +#endif + // Sort the ports by address to lock them in a globally consistent order. std::sort( port_refs_, port_refs_ + num_ports_, @@ -52,6 +56,10 @@ PortLocker::~PortLocker() { port_refs_[i]->port()->lock_.Unlock(); } +#ifdef MOZ_USE_SINGLETON_PORT_MUTEX + detail::PortMutex::sSingleton.Unlock(); +#endif + #ifdef DEBUG UpdateTLS(this, nullptr); #endif diff --git a/ipc/docs/ipdl.rst b/ipc/docs/ipdl.rst index cf35a23f69..d3bafbb11b 100644 --- a/ipc/docs/ipdl.rst +++ b/ipc/docs/ipdl.rst @@ -73,8 +73,8 @@ order is well defined since the related actor can only send from one thread. .. warning:: There are a few (rare) exceptions to the message order guarantee. They - include `synchronous nested`_ messages, `interrupt`_ messages, and - messages with a ``[Priority]`` or ``[Compress]`` annotation. + include `synchronous nested`_ messages and messages with a ``[Priority]`` + or ``[Compress]`` annotation. An IPDL protocol file specifies the messages that may be sent between parent and child actors, as well as the direction and payload of those messages. @@ -85,13 +85,10 @@ running in the actor's thread's ``MessageLoop``. .. note:: Not all IPDL messages are asynchronous. Again, we run into exceptions for - messages that are synchronous, `synchronous nested`_ or `interrupt`_. Use - of synchronous and nested messages is strongly discouraged but may not - always be avoidable. They will be defined later, along with superior - alternatives to both that should work in nearly all cases. Interrupt - messages were prone to misuse and are deprecated, with removal expected in - the near future - (`Bug 1729044 <https://bugzilla.mozilla.org/show_bug.cgi?id=1729044>`_). + messages that are synchronous or `synchronous nested`_. Use of synchronous + and nested messages is strongly discouraged but may not always be avoidable. + They will be defined later, along with superior alternatives to both that + should work in nearly all cases. Protocol files are compiled by the *IPDL compiler* in an early stage of the build process. The compiler generates C++ code that reflects the protocol. @@ -120,7 +117,6 @@ and `here ``chromium-config.mozbuild`` in its ``moz.build`` file. See `Using The IPDL compiler`_ for a complete list of required build changes. -.. _interrupt: `The Old Ways`_ .. _synchronous nested: `The Rest`_ The Steps To Making A New Actor @@ -386,10 +382,6 @@ the options for the actor-blocking policy of messages: ``sync`` Actor has ``async`` capabilities and adds ``sync`` messages. ``sync`` messages can only be sent from the child actor to the parent. -``intr`` (deprecated) Actor has ``sync`` capabilities and adds ``intr`` - messages. Some messages can be received while an actor - waits for an ``intr`` response. This type will be - removed soon. ======================= ======================================================= Beyond these protocol blocking strategies, IPDL supports annotations that @@ -538,8 +530,6 @@ resembles the list in `Defining Actors`_: ``sync`` Actor has ``async`` capabilities and adds ``sync`` messages. ``sync`` messages can only be sent from the child actor to the parent. -``intr`` (deprecated) Actor has ``sync`` capabilities and adds ``intr`` - messages. This type will be removed soon. ====================== ======================================================== The policy defines whether an actor will wait for a response when it sends a @@ -653,18 +643,13 @@ for use in IPDL files: ``sync/async`` These are used in two cases: (1) to indicate whether a message blocks as it waits for a result and (2) because an actor that contains ``sync`` - messages must itself be labeled ``sync`` or - ``intr``. + messages must itself be labeled ``sync``. ``[NestedUpTo=inside_sync]`` Indicates that an actor contains [Nested=inside_sync] messages, in addition to normal messages. ``[NestedUpTo=inside_cpow]`` Indicates that an actor contains [Nested=inside_cpow] messages, in addition to normal messages. -``intr`` Used to indicate either that (1) an actor - contains ``sync``, ``async`` and (deprecated) - ``intr`` messages, or (2) a message is ``intr`` - type. ``[Nested=inside_sync]`` Indicates that the message can be handled while waiting for lower-priority, or in-message-thread, sync responses. diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp index 435e29f635..eb1e46fb42 100644 --- a/ipc/glue/BackgroundUtils.cpp +++ b/ipc/glue/BackgroundUtils.cpp @@ -249,7 +249,7 @@ nsresult CSPToCSPInfo(nsIContentSecurityPolicy* aCSP, CSPInfo* aCSPInfo) { selfURI->GetSpec(selfURISpec); } - nsAutoString referrer; + nsAutoCString referrer; aCSP->GetReferrer(referrer); uint64_t windowID = aCSP->GetInnerWindowID(); diff --git a/ipc/glue/ExtensionKitUtils.h b/ipc/glue/ExtensionKitUtils.h new file mode 100644 index 0000000000..88ee5ac0f9 --- /dev/null +++ b/ipc/glue/ExtensionKitUtils.h @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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_ExtensionKitUtils_h +#define mozilla_ipc_ExtensionKitUtils_h + +#include <functional> +#include <xpc/xpc.h> +#include "mozilla/DarwinObjectPtr.h" +#include "mozilla/Result.h" +#include "mozilla/ResultVariant.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/ipc/LaunchError.h" + +namespace mozilla::ipc { + +class BEProcessCapabilityGrantDeleter { + public: + void operator()(void* aGrant) const; +}; + +using UniqueBEProcessCapabilityGrant = + mozilla::UniquePtr<void, BEProcessCapabilityGrantDeleter>; + +class ExtensionKitProcess { + public: + enum class Kind { + WebContent, + Networking, + Rendering, + }; + + // Called to start the process. The `aCompletion` function may be executed on + // a background libdispatch thread. + static void StartProcess( + Kind aKind, + const std::function<void(Result<ExtensionKitProcess, LaunchError>&&)>& + aCompletion); + + // Get the kind of process being started. + Kind GetKind() const { return mKind; } + + // Make an xpc_connection_t to this process. If an error is encountered, + // `aError` will be populated with the error. + // + // Ownership over the newly created connection is returned to the caller. + // The connection is returned in a suspended state, and must be resumed. + DarwinObjectPtr<xpc_connection_t> MakeLibXPCConnection(); + + UniqueBEProcessCapabilityGrant GrantForegroundCapability(); + + // Invalidate the process, indicating that it should be cleaned up & + // destroyed. + void Invalidate(); + + // Explicit copy constructors + ExtensionKitProcess(const ExtensionKitProcess&); + ExtensionKitProcess& operator=(const ExtensionKitProcess&); + + // Release the object when completed. + ~ExtensionKitProcess(); + + private: + ExtensionKitProcess(Kind aKind, void* aProcessObject) + : mKind(aKind), mProcessObject(aProcessObject) {} + + // Type tag for `mProcessObject`. + Kind mKind; + + // This is one of `BEWebContentProcess`, `BENetworkingProcess` or + // `BERenderingProcess`. It has been type erased to be usable from C++ code. + void* mProcessObject; +}; + +} // namespace mozilla::ipc + +#endif // mozilla_ipc_ExtensionKitUtils_h diff --git a/ipc/glue/ExtensionKitUtils.mm b/ipc/glue/ExtensionKitUtils.mm new file mode 100644 index 0000000000..9a42251b38 --- /dev/null +++ b/ipc/glue/ExtensionKitUtils.mm @@ -0,0 +1,129 @@ +/* -*- Mode: c++; c-basic-offset: 2; tab-width: 4; indent-tabs-mode: nil; -*- + * vim: set sw=2 ts=4 expandtab: + * 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 "ExtensionKitUtils.h" +#include "LaunchError.h" + +#import <BrowserEngineKit/BrowserEngineKit.h> + +namespace mozilla::ipc { + +void BEProcessCapabilityGrantDeleter::operator()(void* aGrant) const { + auto grant = static_cast<id<BEProcessCapabilityGrant>>(aGrant); + [grant invalidate]; + [grant release]; +} + +void ExtensionKitProcess::StartProcess( + Kind aKind, + const std::function<void(Result<ExtensionKitProcess, LaunchError>&&)>& + aCompletion) { + auto callCompletion = [=](auto* aProcess, NSError* aError) { + if (aProcess) { + [aProcess retain]; + aCompletion(ExtensionKitProcess(aKind, aProcess)); + } else { + NSLog(@"Error launching process, description '%@', reason '%@'", + [aError localizedDescription], [aError localizedFailureReason]); + aCompletion(Err(LaunchError("ExtensionKitProcess::StartProcess"))); + } + }; + + switch (aKind) { + case Kind::WebContent: { + [BEWebContentProcess + webContentProcessWithInterruptionHandler:^{ + } + completion:^(BEWebContentProcess* process, NSError* error) { + callCompletion(process, error); + }]; + return; + } + case Kind::Networking: { + [BENetworkingProcess + networkProcessWithInterruptionHandler:^{ + } + completion:^(BENetworkingProcess* process, NSError* error) { + callCompletion(process, error); + }]; + return; + } + case Kind::Rendering: { + [BERenderingProcess + renderingProcessWithInterruptionHandler:^{ + } + completion:^(BERenderingProcess* process, NSError* error) { + callCompletion(process, error); + }]; + return; + } + } +} + +template <typename F> +static void SwitchObject(ExtensionKitProcess::Kind aKind, void* aProcessObject, + F&& aMatcher) { + switch (aKind) { + case ExtensionKitProcess::Kind::WebContent: + aMatcher(static_cast<BEWebContentProcess*>(aProcessObject)); + break; + case ExtensionKitProcess::Kind::Networking: + aMatcher(static_cast<BENetworkingProcess*>(aProcessObject)); + break; + case ExtensionKitProcess::Kind::Rendering: + aMatcher(static_cast<BERenderingProcess*>(aProcessObject)); + break; + } +} + +DarwinObjectPtr<xpc_connection_t> ExtensionKitProcess::MakeLibXPCConnection() { + NSError* error = nullptr; + DarwinObjectPtr<xpc_connection_t> xpcConnection; + SwitchObject(mKind, mProcessObject, [&](auto* aProcessObject) { + xpcConnection = [aProcessObject makeLibXPCConnectionError:&error]; + }); + return xpcConnection; +} + +void ExtensionKitProcess::Invalidate() { + SwitchObject(mKind, mProcessObject, + [&](auto* aProcessObject) { [aProcessObject invalidate]; }); +} + +UniqueBEProcessCapabilityGrant +ExtensionKitProcess::GrantForegroundCapability() { + NSError* error = nullptr; + BEProcessCapability* cap = [BEProcessCapability foreground]; + id<BEProcessCapabilityGrant> grant = nil; + SwitchObject(mKind, mProcessObject, [&](auto* aProcessObject) { + grant = [aProcessObject grantCapability:cap error:&error]; + }); + return UniqueBEProcessCapabilityGrant(grant ? [grant retain] : nil); +} + +ExtensionKitProcess::ExtensionKitProcess(const ExtensionKitProcess& aOther) + : mKind(aOther.mKind), mProcessObject(aOther.mProcessObject) { + SwitchObject(mKind, mProcessObject, + [&](auto* aProcessObject) { [aProcessObject retain]; }); +} + +ExtensionKitProcess& ExtensionKitProcess::operator=( + const ExtensionKitProcess& aOther) { + Kind oldKind = std::exchange(mKind, aOther.mKind); + void* oldProcessObject = std::exchange(mProcessObject, aOther.mProcessObject); + SwitchObject(mKind, mProcessObject, + [&](auto* aProcessObject) { [aProcessObject retain]; }); + SwitchObject(oldKind, oldProcessObject, + [&](auto* aProcessObject) { [aProcessObject release]; }); + return *this; +} + +ExtensionKitProcess::~ExtensionKitProcess() { + SwitchObject(mKind, mProcessObject, + [&](auto* aProcessObject) { [aProcessObject release]; }); +} + +} // namespace mozilla::ipc diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp index 3e444060bc..cb038911d4 100644 --- a/ipc/glue/GeckoChildProcessHost.cpp +++ b/ipc/glue/GeckoChildProcessHost.cpp @@ -13,15 +13,16 @@ #include "base/task.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/process_watcher.h" -#include "mozilla/ProcessType.h" -#ifdef MOZ_WIDGET_COCOA -# include <bsm/libbsm.h> +#ifdef XP_DARWIN # include <mach/mach_traps.h> -# include <servers/bootstrap.h> # include "SharedMemoryBasic.h" # include "base/rand_util.h" # include "chrome/common/mach_ipc_mac.h" # include "mozilla/StaticPrefs_media.h" +#endif +#ifdef MOZ_WIDGET_COCOA +# include <bsm/libbsm.h> +# include <servers/bootstrap.h> # include "nsILocalFileMac.h" #endif @@ -128,9 +129,14 @@ namespace ipc { struct LaunchResults { base::ProcessHandle mHandle = 0; -#ifdef XP_MACOSX +#ifdef XP_DARWIN task_t mChildTask = MACH_PORT_NULL; #endif +#ifdef XP_IOS + Maybe<ExtensionKitProcess> mExtensionKitProcess; + DarwinObjectPtr<xpc_connection_t> mXPCConnection; + UniqueBEProcessCapabilityGrant mForegroundCapabilityGrant; +#endif #if defined(XP_WIN) && defined(MOZ_SANDBOX) RefPtr<AbstractSandboxBroker> mSandboxBroker; #endif @@ -354,9 +360,9 @@ class IosProcessLauncher : public PosixProcessLauncher { : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {} protected: - virtual RefPtr<ProcessHandlePromise> DoLaunch() override { - MOZ_CRASH("IosProcessLauncher::DoLaunch not implemented"); - } + virtual RefPtr<ProcessHandlePromise> DoLaunch() override; + + DarwinObjectPtr<xpc_object_t> mBootstrapMessage; }; typedef IosProcessLauncher ProcessLauncher; # else @@ -390,7 +396,7 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType, #endif mHandleLock("mozilla.ipc.GeckoChildProcessHost.mHandleLock"), mChildProcessHandle(0), -#if defined(MOZ_WIDGET_COCOA) +#if defined(XP_DARWIN) mChildTask(MACH_PORT_NULL), #endif #if defined(MOZ_SANDBOX) && defined(XP_MACOSX) @@ -443,11 +449,22 @@ GeckoChildProcessHost::~GeckoChildProcessHost() { mozilla::AutoWriteLock hLock(mHandleLock); -#if defined(MOZ_WIDGET_COCOA) +#if defined(XP_DARWIN) if (mChildTask != MACH_PORT_NULL) { mach_port_deallocate(mach_task_self(), mChildTask); } #endif +#if defined(XP_IOS) + if (mForegroundCapabilityGrant) { + mForegroundCapabilityGrant.reset(); + } + if (mExtensionKitProcess) { + mExtensionKitProcess->Invalidate(); + } + if (mXPCConnection) { + xpc_connection_cancel(mXPCConnection.get()); + } +#endif if (mChildProcessHandle != 0) { ProcessWatcher::EnsureProcessTerminated( @@ -483,7 +500,7 @@ base::ProcessId GeckoChildProcessHost::GetChildProcessId() { return base::GetProcId(mChildProcessHandle); } -#ifdef XP_MACOSX +#ifdef XP_DARWIN task_t GeckoChildProcessHost::GetChildTask() { mozilla::AutoReadLock handleLock(mHandleLock); return mChildTask; @@ -765,14 +782,20 @@ bool GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts) { // "safe" invalid value to use in places like this. aResults.mHandle = 0; -#ifdef XP_MACOSX +#ifdef XP_DARWIN this->mChildTask = aResults.mChildTask; #endif +#ifdef XP_IOS + this->mExtensionKitProcess = aResults.mExtensionKitProcess; + this->mXPCConnection = aResults.mXPCConnection; + this->mForegroundCapabilityGrant = + std::move(aResults.mForegroundCapabilityGrant); +#endif if (mNodeChannel) { mNodeChannel->SetOtherPid( base::GetProcId(this->mChildProcessHandle)); -#ifdef XP_MACOSX +#ifdef XP_DARWIN mNodeChannel->SetMachTaskPort(this->mChildTask); #endif } @@ -798,7 +821,8 @@ bool GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts) { CHROMIUM_LOG(ERROR) << "Failed to launch " << XRE_GeckoProcessTypeToString(mProcessType) - << " subprocess"; + << " subprocess @" << aError.FunctionName() + << " (Error:" << aError.ErrorCode() << ")"; Telemetry::Accumulate( Telemetry::SUBPROCESS_LAUNCH_FAILURE, nsDependentCString( @@ -1243,16 +1267,13 @@ Result<Ok, LaunchError> PosixProcessLauncher::DoSetup() { // STDOUT_FILENO, for example // The fork server doesn't use IPC::Channel, so can skip this step. if (mProcessType != GeckoProcessType_ForkServer) { -# ifdef MOZ_WIDGET_ANDROID - // On Android mChannelDstFd is uninitialised and the launching code uses - // only the first of each pair. - mLaunchOptions->fds_to_remap.push_back( - std::pair<int, int>(mClientChannelHandle.get(), -1)); -# else +# if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_UIKIT) + // On Android/iOS, mChannelDstFd is initialised to -1 and the launching + // code uses only the first of each pair. MOZ_ASSERT(mChannelDstFd >= 0); +# endif mLaunchOptions->fds_to_remap.push_back( std::pair<int, int>(mClientChannelHandle.get(), mChannelDstFd)); -# endif } // no need for kProcessChannelID, the child process inherits the @@ -1356,6 +1377,143 @@ RefPtr<ProcessHandlePromise> PosixProcessLauncher::DoLaunch() { } #endif // XP_UNIX +#ifdef XP_IOS +RefPtr<ProcessHandlePromise> IosProcessLauncher::DoLaunch() { + MOZ_RELEASE_ASSERT(mLaunchOptions->fds_to_remap.size() == 3, + "Unexpected fds_to_remap on iOS"); + + ExtensionKitProcess::Kind kind = ExtensionKitProcess::Kind::WebContent; + if (mProcessType == GeckoProcessType_GPU) { + kind = ExtensionKitProcess::Kind::Rendering; + } else if (mProcessType == GeckoProcessType_Socket) { + kind = ExtensionKitProcess::Kind::Networking; + } + + DarwinObjectPtr<xpc_object_t> bootstrapMessage = + AdoptDarwinObject(xpc_dictionary_create_empty()); + xpc_dictionary_set_string(bootstrapMessage.get(), "message-name", + "bootstrap"); + + DarwinObjectPtr<xpc_object_t> environDict = + AdoptDarwinObject(xpc_dictionary_create_empty()); + for (auto& [envKey, envValue] : mLaunchOptions->env_map) { + xpc_dictionary_set_string(environDict.get(), envKey.c_str(), + envValue.c_str()); + } + xpc_dictionary_set_value(bootstrapMessage.get(), "environ", + environDict.get()); + + // XXX: this processing depends entirely on the internals of + // ContentParent::LaunchSubprocess() + // GeckoChildProcessHost::PerformAsyncLaunch(), and the order in + // which they append to fds_to_remap. There must be a better way to do it. + // See bug 1440207. + int prefsFd = mLaunchOptions->fds_to_remap[0].first; + int prefMapFd = mLaunchOptions->fds_to_remap[1].first; + int ipcFd = mLaunchOptions->fds_to_remap[2].first; + xpc_dictionary_set_fd(bootstrapMessage.get(), "prefs", prefsFd); + xpc_dictionary_set_fd(bootstrapMessage.get(), "prefmap", prefMapFd); + xpc_dictionary_set_fd(bootstrapMessage.get(), "channel", ipcFd); + + // Setup stdout and stderr to inherit. + xpc_dictionary_set_fd(bootstrapMessage.get(), "stdout", STDOUT_FILENO); + xpc_dictionary_set_fd(bootstrapMessage.get(), "stderr", STDERR_FILENO); + + DarwinObjectPtr<xpc_object_t> argsArray = + AdoptDarwinObject(xpc_array_create_empty()); + for (auto& argv : mChildArgv) { + xpc_array_set_string(argsArray.get(), XPC_ARRAY_APPEND, argv.c_str()); + } + MOZ_ASSERT(xpc_array_get_count(argsArray.get()) == mChildArgv.size()); + xpc_dictionary_set_value(bootstrapMessage.get(), "argv", argsArray.get()); + + auto promise = MakeRefPtr<ProcessHandlePromise::Private>(__func__); + ExtensionKitProcess::StartProcess(kind, [self = RefPtr{this}, promise, + bootstrapMessage = + std::move(bootstrapMessage)]( + Result<ExtensionKitProcess, + LaunchError>&& result) { + if (result.isErr()) { + CHROMIUM_LOG(ERROR) << "ExtensionKitProcess::StartProcess failed"; + promise->Reject(result.unwrapErr(), __func__); + return; + } + + auto process = result.unwrap(); + self->mResults.mForegroundCapabilityGrant = + process.GrantForegroundCapability(); + self->mResults.mXPCConnection = process.MakeLibXPCConnection(); + self->mResults.mExtensionKitProcess = Some(std::move(process)); + + // We don't actually use the event handler for anything other than + // watching for errors. Once the promise is resolved, this becomes a + // no-op. + xpc_connection_set_event_handler(self->mResults.mXPCConnection.get(), ^( + xpc_object_t event) { + if (!event || xpc_get_type(event) == XPC_TYPE_ERROR) { + CHROMIUM_LOG(WARNING) << "XPC connection received encountered an error"; + promise->Reject(LaunchError("xpc_connection_event_handler"), __func__); + } + }); + xpc_connection_resume(self->mResults.mXPCConnection.get()); + + // Send our bootstrap message to the content and wait for it to reply with + // the task port before resolving. + // FIXME: Should we have a time-out for if the child process doesn't respond + // in time? The main thread may be blocked while we're starting this + // process. + xpc_connection_send_message_with_reply( + self->mResults.mXPCConnection.get(), bootstrapMessage.get(), nullptr, + ^(xpc_object_t reply) { + if (xpc_get_type(reply) == XPC_TYPE_ERROR) { + CHROMIUM_LOG(ERROR) + << "Got error sending XPC bootstrap message to child"; + promise->Reject( + LaunchError("xpc_connection_send_message_with_reply error"), + __func__); + return; + } + + if (xpc_get_type(reply) != XPC_TYPE_DICTIONARY) { + CHROMIUM_LOG(ERROR) + << "Unexpected reply type for bootstrap message from child"; + promise->Reject( + LaunchError( + "xpc_connection_send_message_with_reply non-dictionary"), + __func__); + return; + } + + // FIXME: We have to trust the child to tell us its pid & mach task. + // WebKit uses `xpc_connection_get_pid` to get the pid, however this + // is marked as unavailable on iOS. + // + // Given how the process is started, however, validating this + // information it sends us this early during startup may be + // unnecessary. + self->mResults.mChildTask = + xpc_dictionary_copy_mach_send(reply, "task"); + pid_t pid = + static_cast<pid_t>(xpc_dictionary_get_int64(reply, "pid")); + CHROMIUM_LOG(INFO) << "ExtensionKit process started, task: " + << self->mResults.mChildTask << ", pid: " << pid; + + pid_t taskPid; + kern_return_t kr = pid_for_task(self->mResults.mChildTask, &taskPid); + if (kr != KERN_SUCCESS || pid != taskPid) { + CHROMIUM_LOG(ERROR) << "Could not validate child task matches pid"; + promise->Reject(LaunchError("pid_for_task mismatch"), __func__); + return; + } + + promise->Resolve(pid, __func__); + }); + }); + + return promise; +} +#endif + #ifdef XP_MACOSX Result<Ok, LaunchError> MacProcessLauncher::DoFinishLaunch() { Result<Ok, LaunchError> aError = PosixProcessLauncher::DoFinishLaunch(); @@ -1647,7 +1805,7 @@ RefPtr<ProcessLaunchPromise> BaseProcessLauncher::FinishLaunch() { Telemetry::AccumulateTimeDelta(Telemetry::CHILD_PROCESS_LAUNCH_MS, mStartTimeStamp); - return ProcessLaunchPromise::CreateAndResolve(mResults, __func__); + return ProcessLaunchPromise::CreateAndResolve(std::move(mResults), __func__); } bool GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid) { diff --git a/ipc/glue/GeckoChildProcessHost.h b/ipc/glue/GeckoChildProcessHost.h index 89ed399fea..61c986c5a2 100644 --- a/ipc/glue/GeckoChildProcessHost.h +++ b/ipc/glue/GeckoChildProcessHost.h @@ -33,6 +33,10 @@ #include "nsXULAppAPI.h" // for GeckoProcessType #include "nsString.h" +#if defined(XP_IOS) +# include "mozilla/ipc/ExtensionKitUtils.h" +#endif + #if defined(XP_WIN) && defined(MOZ_SANDBOX) # include "sandboxBroker.h" #endif @@ -151,7 +155,7 @@ class GeckoChildProcessHost : public SupportsWeakPtr, GeckoProcessType GetProcessType() { return mProcessType; } -#ifdef XP_MACOSX +#ifdef XP_DARWIN task_t GetChildTask(); #endif @@ -266,6 +270,12 @@ class GeckoChildProcessHost : public SupportsWeakPtr, #if defined(XP_DARWIN) task_t mChildTask MOZ_GUARDED_BY(mHandleLock); #endif +#if defined(MOZ_WIDGET_UIKIT) + Maybe<ExtensionKitProcess> mExtensionKitProcess MOZ_GUARDED_BY(mHandleLock); + DarwinObjectPtr<xpc_connection_t> mXPCConnection MOZ_GUARDED_BY(mHandleLock); + UniqueBEProcessCapabilityGrant mForegroundCapabilityGrant + MOZ_GUARDED_BY(mHandleLock); +#endif RefPtr<ProcessHandlePromise> mHandlePromise; #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) diff --git a/ipc/glue/NodeChannel.cpp b/ipc/glue/NodeChannel.cpp index 169aa91f9b..7da0fa3543 100644 --- a/ipc/glue/NodeChannel.cpp +++ b/ipc/glue/NodeChannel.cpp @@ -112,7 +112,7 @@ void NodeChannel::SetOtherPid(base::ProcessId aNewPid) { mChannel->SetOtherPid(aNewPid); } -#ifdef XP_MACOSX +#ifdef XP_DARWIN void NodeChannel::SetMachTaskPort(task_t aTask) { AssertIOThread(); diff --git a/ipc/glue/NodeChannel.h b/ipc/glue/NodeChannel.h index fb3d297348..56f9a19ce1 100644 --- a/ipc/glue/NodeChannel.h +++ b/ipc/glue/NodeChannel.h @@ -118,7 +118,7 @@ class NodeChannel final : public IPC::Channel::Listener { // THREAD. void SetOtherPid(base::ProcessId aNewPid); -#ifdef XP_MACOSX +#ifdef XP_DARWIN // Called by the GeckoChildProcessHost to provide the task_t for the peer // process. MUST BE CALLED FROM THE IO THREAD. void SetMachTaskPort(task_t aTask); diff --git a/ipc/glue/NodeController.cpp b/ipc/glue/NodeController.cpp index 532e4fa509..7781771660 100644 --- a/ipc/glue/NodeController.cpp +++ b/ipc/glue/NodeController.cpp @@ -315,7 +315,7 @@ void NodeController::ForwardEvent(const NodeName& aNode, // On Windows and macOS, messages holding HANDLEs or mach ports must be // relayed via the broker process so it can transfer ownership. bool needsRelay = false; -#if defined(XP_WIN) || defined(XP_MACOSX) +#if defined(XP_WIN) || defined(XP_DARWIN) if (!IsBroker() && aNode != kBrokerNodeName && aEvent->type() == Event::kUserMessage) { auto* userEvent = static_cast<UserMessageEvent*>(aEvent.get()); @@ -439,7 +439,7 @@ void NodeController::OnEventMessage(const NodeName& aFromNode, } NodeName fromNode = aFromNode; -#if defined(XP_WIN) || defined(XP_MACOSX) +#if defined(XP_WIN) || defined(XP_DARWIN) if (isRelay) { if (event->type() != Event::kUserMessage) { NODECONTROLLER_WARNING( diff --git a/ipc/glue/PBackgroundSharedTypes.ipdlh b/ipc/glue/PBackgroundSharedTypes.ipdlh index 92175b782d..101f5eb6d7 100644 --- a/ipc/glue/PBackgroundSharedTypes.ipdlh +++ b/ipc/glue/PBackgroundSharedTypes.ipdlh @@ -64,7 +64,7 @@ namespace ipc { ContentSecurityPolicy[] policyInfos; PrincipalInfo requestPrincipalInfo; nsCString selfURISpec; - nsString referrer; + nsCString referrer; uint64_t innerWindowID; bool skipAllowInlineStyleCheck; }; diff --git a/ipc/glue/ProcessUtils.h b/ipc/glue/ProcessUtils.h index b0f146ef6d..27c336a92c 100644 --- a/ipc/glue/ProcessUtils.h +++ b/ipc/glue/ProcessUtils.h @@ -71,8 +71,8 @@ class SharedPreferenceDeserializer final { base::SharedMemory mShmem; }; -#ifdef ANDROID -// Android doesn't use -prefsHandle or -prefMapHandle. It gets those FDs +#if defined(ANDROID) || defined(XP_IOS) +// Android/iOS doesn't use -prefsHandle or -prefMapHandle. It gets those FDs // another way. void SetPrefsFd(int aFd); void SetPrefMapFd(int aFd); diff --git a/ipc/glue/ProcessUtils_common.cpp b/ipc/glue/ProcessUtils_common.cpp index 69eb4bdf28..8fccce5862 100644 --- a/ipc/glue/ProcessUtils_common.cpp +++ b/ipc/glue/ProcessUtils_common.cpp @@ -98,7 +98,7 @@ void SharedPreferenceSerializer::AddSharedPrefCmdLineArgs( geckoargs::sPrefMapSize.Put((uintptr_t)(GetPrefMapSize()), aExtraOpts); } -#ifdef ANDROID +#if defined(ANDROID) || defined(XP_IOS) static int gPrefsFd = -1; static int gPrefMapFd = -1; @@ -145,8 +145,8 @@ bool SharedPreferenceDeserializer::DeserializeFromSharedMemory( return false; } -#ifdef ANDROID - // Android is different; get the FD via gPrefsFd instead of a fixed fd. +#if defined(ANDROID) || defined(XP_IOS) + // Android/iOS is different; get the FD via gPrefsFd instead of a fixed fd. MOZ_RELEASE_ASSERT(gPrefsFd != -1); prefsHandle = Some(UniqueFileHandle(gPrefsFd)); @@ -195,8 +195,8 @@ static const int kJSInitFileDescriptor = 11; void ExportSharedJSInit(mozilla::ipc::GeckoChildProcessHost& procHost, std::vector<std::string>& aExtraOpts) { -#ifdef ANDROID - // The code to support Android is added in a follow-up patch. +#if defined(ANDROID) || defined(XP_IOS) + // The code to support Android/iOS is added in a follow-up patch. return; #else auto& shmem = xpc::SelfHostedShmem::GetSingleton(); diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h index 7edce9612b..2800a41c91 100644 --- a/ipc/glue/ProtocolUtils.h +++ b/ipc/glue/ProtocolUtils.h @@ -110,9 +110,6 @@ struct ActorHandle { int mId; }; -// What happens if Interrupt calls race? -enum RacyInterruptPolicy { RIPError, RIPChildWins, RIPParentWins }; - enum class LinkStatus : uint8_t { // The actor has not established a link yet, or the actor is no longer in use // by IPC, and its 'Dealloc' method has been called or is being called. @@ -128,7 +125,7 @@ enum class LinkStatus : uint8_t { Connected, // The link has begun being destroyed. Messages may still be received, but - // cannot be sent. (exception: sync/intr replies may be sent while Doomed). + // cannot be sent. (exception: sync replies may be sent while Doomed). Doomed, // The link has been destroyed, and messages will no longer be sent or @@ -223,8 +220,6 @@ class IProtocol : public HasResultCodes { virtual Result OnMessageReceived(const Message& aMessage) = 0; virtual Result OnMessageReceived(const Message& aMessage, UniquePtr<Message>& aReply) = 0; - virtual Result OnCallReceived(const Message& aMessage, - UniquePtr<Message>& aReply) = 0; bool AllocShmem(size_t aSize, Shmem* aOutMem); bool AllocUnsafeShmem(size_t aSize, Shmem* aOutMem); bool DeallocShmem(Shmem& aMem); @@ -461,8 +456,7 @@ class IToplevelProtocol : public IRefCountedProtocol { // the same thread. This method should be called on the thread to perform // the link. // - // WARNING: Attempting to send a sync or intr message on the same thread - // will crash. + // WARNING: Attempting to send a sync message on the same thread will crash. bool OpenOnSameThread(IToplevelProtocol* aTarget, mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide); diff --git a/ipc/glue/UtilityAudioDecoderChild.cpp b/ipc/glue/UtilityAudioDecoderChild.cpp index cc3560e05b..ec46927870 100644 --- a/ipc/glue/UtilityAudioDecoderChild.cpp +++ b/ipc/glue/UtilityAudioDecoderChild.cpp @@ -246,7 +246,7 @@ void UtilityAudioDecoderChild::GetKeySystemCapabilities( info->mClearlead = DoesKeySystemSupportClearLead(info->mKeySystemName); if (capabilities.isHDCP22Compatible()) { - info->mIsHDCP22Compatible = true; + info->mIsHDCP22Compatible = *capabilities.isHDCP22Compatible(); } } promise->MaybeResolve(cdmInfo); diff --git a/ipc/glue/moz.build b/ipc/glue/moz.build index 7aa29612b8..f5bf67f777 100644 --- a/ipc/glue/moz.build +++ b/ipc/glue/moz.build @@ -153,6 +153,14 @@ if CONFIG["OS_ARCH"] != "WINNT": "FileDescriptorShuffle.cpp", ] +if CONFIG["TARGET_OS"] == "iOS": + EXPORTS.mozilla.ipc += [ + "ExtensionKitUtils.h", + ] + UNIFIED_SOURCES += [ + "ExtensionKitUtils.mm", + ] + EXPORTS.ipc += [ "EnumSerializer.h", "IPCMessageUtils.h", @@ -284,8 +292,10 @@ include("/ipc/chromium/chromium-config.mozbuild") FINAL_LIBRARY = "xul" -if CONFIG["OS_ARCH"] == "Darwin": +if CONFIG["TARGET_OS"] == "OSX": OS_LIBS += ["bsm"] # for audit_token_to_pid +elif CONFIG["TARGET_OS"] == "iOS": + OS_LIBS += ["-framework BrowserEngineKit"] for var in ( "MOZ_CHILD_PROCESS_NAME", diff --git a/ipc/ipdl/Makefile.in b/ipc/ipdl/Makefile.in index 7a4d2acfba..6ebff9cba0 100644 --- a/ipc/ipdl/Makefile.in +++ b/ipc/ipdl/Makefile.in @@ -18,14 +18,14 @@ ipdl_py_deps := \ # NB: the IPDL compiler manages .ipdl-->.h/.cpp dependencies itself, # which is why we don't have explicit .h/.cpp targets here -ipdl.track: $(ALL_IPDLSRCS) $(srcdir)/sync-messages.ini $(srcdir)/message-metadata.ini $(ipdl_py_deps) +ipdl.track: $(ALL_IPDLSRCS) $(ALL_IPDLSRCS_FILE) $(srcdir)/sync-messages.ini $(srcdir)/message-metadata.ini $(ipdl_py_deps) $(PYTHON3) $(srcdir)/ipdl.py \ --sync-msg-list=$(srcdir)/sync-messages.ini \ --msg-metadata=$(srcdir)/message-metadata.ini \ --outheaders-dir=_ipdlheaders \ --outcpp-dir=. \ $(IPDLDIRS:%=-I%) \ - $(ALL_IPDLSRCS) + --file-list $(ALL_IPDLSRCS_FILE) touch $@ export:: ipdl.track diff --git a/ipc/ipdl/ipdl.py b/ipc/ipdl/ipdl.py index befaacca45..8e5dd5db3d 100644 --- a/ipc/ipdl/ipdl.py +++ b/ipc/ipdl/ipdl.py @@ -78,8 +78,16 @@ A protocol Foo in the namespace bar will cause the sources cppdir/FooParent.cpp, cppdir/FooChild.cpp to be generated""", ) +op.add_option( + "-F", + "--file-list", + dest="file_list_file", + default=None, + help="""A file containing IPDL files to parse. This will be +merged with files provided on the commandline.""", +) -options, files = op.parse_args() +options, cmdline_files = op.parse_args() _verbosity = options.verbosity syncMsgList = options.syncMsgList msgMetadata = options.msgMetadata @@ -87,6 +95,14 @@ headersdir = options.headersdir cppdir = options.cppdir includedirs = [os.path.abspath(incdir) for incdir in options.includedirs] +files = [] + +if options.file_list_file is not None: + with open(options.file_list_file) as f: + files.extend(f.read().splitlines()) + +files.extend(cmdline_files) + if not len(files): op.error("No IPDL files specified") diff --git a/ipc/ipdl/ipdl/ast.py b/ipc/ipdl/ipdl/ast.py index 9329bd3d23..ddf4428a41 100644 --- a/ipc/ipdl/ipdl/ast.py +++ b/ipc/ipdl/ipdl/ast.py @@ -266,10 +266,6 @@ class ASYNC(metaclass=PrettyPrinted): pretty = "async" -class INTR(metaclass=PrettyPrinted): - pretty = "intr" - - class SYNC(metaclass=PrettyPrinted): pretty = "sync" diff --git a/ipc/ipdl/ipdl/lower.py b/ipc/ipdl/ipdl/lower.py index 94699fdcab..291e1c698f 100644 --- a/ipc/ipdl/ipdl/lower.py +++ b/ipc/ipdl/ipdl/lower.py @@ -218,15 +218,11 @@ def _putInNamespaces(cxxthing, namespaces): def _sendPrefix(msgtype): """Prefix of the name of the C++ method that sends |msgtype|.""" - if msgtype.isInterrupt(): - return "Call" return "Send" def _recvPrefix(msgtype): """Prefix of the name of the C++ method that handles |msgtype|.""" - if msgtype.isInterrupt(): - return "Answer" return "Recv" @@ -237,13 +233,16 @@ def _flatTypeName(ipdltype): # NB: this logic depends heavily on what IPDL types are allowed to # be constructed; e.g., Foo[][] is disallowed. needs to be kept in # sync with grammar. - if ipdltype.isIPDL() and ipdltype.isArray(): + if not ipdltype.isIPDL(): + return ipdltype.name() + if ipdltype.isArray(): return "ArrayOf" + _flatTypeName(ipdltype.basetype) - if ipdltype.isIPDL() and ipdltype.isMaybe(): + if ipdltype.isMaybe(): return "Maybe" + _flatTypeName(ipdltype.basetype) - # NotNull types just assume the underlying variant name to avoid unnecessary - # noise, as a NotNull<T> and T should never exist in the same union. - if ipdltype.isIPDL() and ipdltype.isNotNull(): + # NotNull and UniquePtr types just assume the underlying variant name + # to avoid unnecessary noise, as eg a NotNull<T> and T should never exist + # in the same union. + if ipdltype.isNotNull() or ipdltype.isUniquePtr(): return _flatTypeName(ipdltype.basetype) return ipdltype.name() @@ -413,6 +412,13 @@ def _sentinelReadError(classname): ) +identifierRegExp = re.compile("[a-zA-Z_][a-zA-Z0-9_]*") + + +def _validCxxIdentifier(name): + return identifierRegExp.fullmatch(name) is not None + + # Results that IPDL-generated code returns back to *Channel code. # Users never see these @@ -937,6 +943,7 @@ class _UnionMember(_CompoundTypeComponent): def __init__(self, ipdltype, ud): flatname = _flatTypeName(ipdltype) + assert _validCxxIdentifier(flatname) _CompoundTypeComponent.__init__(self, ipdltype, "V" + flatname) self.flattypename = flatname @@ -1856,16 +1863,6 @@ def _generateMessageConstructor(md, segmentSize, protocol, forReply=False): else: syncEnum = "ASYNC" - # FIXME(bug ???) - remove support for interrupt messages from the IPDL compiler. - if md.decl.type.isInterrupt(): - func.addcode( - """ - static_assert( - false, - "runtime support for intr messages has been removed from IPDL"); - """ - ) - if md.decl.type.isCtor(): ctorEnum = "CONSTRUCTOR" else: @@ -2497,9 +2494,7 @@ class _ComputeTypeDeps(TypeVisitor): self.visitActorType(s.actor) def visitUniquePtrType(self, s): - if s in self.visited: - return - self.visited.add(s) + return TypeVisitor.visitUniquePtrType(self, s) def visitVoidType(self, v): assert 0 @@ -4033,7 +4028,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): for managed in ptype.manages: self.genManagedEndpoint(managed) - # OnMessageReceived()/OnCallReceived() + # OnMessageReceived() # save these away for use in message handler case stmts msgvar = ExprVar("msg__") @@ -4051,11 +4046,8 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): msgtype = ExprCode("msg__.type()") self.asyncSwitch = StmtSwitch(msgtype) self.syncSwitch = None - self.interruptSwitch = None - if toplevel.isSync() or toplevel.isInterrupt(): + if toplevel.isSync(): self.syncSwitch = StmtSwitch(msgtype) - if toplevel.isInterrupt(): - self.interruptSwitch = StmtSwitch(msgtype) # Add a handler for the MANAGED_ENDPOINT_BOUND and # MANAGED_ENDPOINT_DROPPED message types for managed actors. @@ -4103,10 +4095,8 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): """ ) self.asyncSwitch.addcase(DefaultLabel(), default) - if toplevel.isSync() or toplevel.isInterrupt(): + if toplevel.isSync(): self.syncSwitch.addcase(DefaultLabel(), default) - if toplevel.isInterrupt(): - self.interruptSwitch.addcase(DefaultLabel(), default) self.cls.addstmts(self.implementManagerIface()) @@ -4197,17 +4187,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): Whitespace.NL, ] ) - self.cls.addstmts( - [ - makeHandlerMethod( - "OnCallReceived", - self.interruptSwitch, - hasReply=True, - dispatches=dispatches, - ), - Whitespace.NL, - ] - ) clearsubtreevar = ExprVar("ClearSubtree") @@ -4244,22 +4223,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): ) self.cls.addstmts([onerror, Whitespace.NL]) - if ptype.isToplevel() and ptype.isInterrupt(): - processnative = MethodDefn( - MethodDecl("ProcessNativeEventsInInterruptCall", ret=Type.VOID) - ) - processnative.addcode( - """ - #ifdef XP_WIN - GetIPCChannel()->ProcessNativeEventsInInterruptCall(); - #else - FatalError("This method is Windows-only"); - #endif - """ - ) - - self.cls.addstmts([processnative, Whitespace.NL]) - # private methods self.cls.addstmt(Label.PRIVATE) @@ -4566,8 +4529,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): self.asyncSwitch.addcase(lbl, case) elif decltype.isSync(): self.syncSwitch.addcase(lbl, case) - elif decltype.isInterrupt(): - self.interruptSwitch.addcase(lbl, case) else: assert 0 @@ -5417,8 +5378,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): def sendBlocking(self, md, msgexpr, replyexpr, actor=None): send = ExprVar("ChannelSend") - if md.decl.type.isInterrupt(): - send = ExprVar("ChannelCall") if actor is not None: send = ExprSelect(actor, "->", send.name) diff --git a/ipc/ipdl/ipdl/parser.py b/ipc/ipdl/ipdl/parser.py index 1857131868..f462bb6fad 100644 --- a/ipc/ipdl/ipdl/parser.py +++ b/ipc/ipdl/ipdl/parser.py @@ -126,7 +126,6 @@ reserved = set( "class", "from", "include", - "intr", "manager", "manages", "namespace", @@ -552,15 +551,12 @@ def p_AttributeValue(p): def p_SendSemantics(p): """SendSemantics : ASYNC - | SYNC - | INTR""" + | SYNC""" if p[1] == "async": p[0] = ASYNC - elif p[1] == "sync": - p[0] = SYNC else: - assert p[1] == "intr" - p[0] = INTR + assert p[1] == "sync" + p[0] = SYNC def p_OptionalSendSemantics(p): diff --git a/ipc/ipdl/ipdl/type.py b/ipc/ipdl/ipdl/type.py index d8e893ddf5..2475cab0fb 100644 --- a/ipc/ipdl/ipdl/type.py +++ b/ipc/ipdl/ipdl/type.py @@ -8,7 +8,7 @@ import sys from ipdl.ast import CxxInclude, Decl, Loc, QualifiedId, StructDecl from ipdl.ast import UnionDecl, UsingStmt, Visitor, StringLiteral -from ipdl.ast import ASYNC, SYNC, INTR +from ipdl.ast import ASYNC, SYNC from ipdl.ast import IN, OUT, INOUT from ipdl.ast import NOT_NESTED, INSIDE_SYNC_NESTED, INSIDE_CPOW_NESTED from ipdl.ast import priorityList @@ -300,9 +300,6 @@ class SendSemanticsType(IPDLType): def isSync(self): return self.sendSemantics == SYNC - def isInterrupt(self): - return self.sendSemantics is INTR - def sendSemanticsSatisfiedBy(self, greater): def _unwrap(nr): if isinstance(nr, dict): @@ -322,17 +319,10 @@ class SendSemanticsType(IPDLType): if lnr0 < gnr0 or lnr1 > gnr1: return False - # Protocols that use intr semantics are not allowed to use - # message nesting. - if greater.isInterrupt() and lesser.nestedRange != (NOT_NESTED, NOT_NESTED): - return False - if lesser.isAsync(): return True elif lesser.isSync() and not greater.isAsync(): return True - elif greater.isInterrupt(): - return True return False @@ -391,7 +381,7 @@ class MessageType(SendSemanticsType): return self.direction is INOUT def hasReply(self): - return len(self.returns) or self.isSync() or self.isInterrupt() + return len(self.returns) or self.isSync() def hasImplicitActorParam(self): return self.isCtor() @@ -1372,25 +1362,11 @@ class GatherDecls(TcheckVisitor): "Priority": priorityList, "ReplyPriority": priorityList, "Nested": ("not", "inside_sync", "inside_cpow"), - "LegacyIntr": None, "VirtualSendImpl": None, "LazySend": None, }, ) - if md.sendSemantics is INTR and "LegacyIntr" not in md.attributes: - self.error( - loc, - "intr message `%s' allowed only with [LegacyIntr]; DO NOT USE IN SHIPPING CODE", - msgname, - ) - - if md.sendSemantics is INTR and "Priority" in md.attributes: - self.error(loc, "intr message `%s' cannot specify [Priority]", msgname) - - if md.sendSemantics is INTR and "Nested" in md.attributes: - self.error(loc, "intr message `%s' cannot specify [Nested]", msgname) - if md.sendSemantics is not ASYNC and "LazySend" in md.attributes: self.error(loc, "non-async message `%s' cannot specify [LazySend]", msgname) @@ -1631,11 +1607,6 @@ class CheckTypes(TcheckVisitor): mgrtype.name(), ) - if ptype.isInterrupt() and ptype.nestedRange != (NOT_NESTED, NOT_NESTED): - self.error( - p.decl.loc, "intr protocol `%s' cannot specify [NestedUpTo]", p.name - ) - if ptype.isToplevel(): cycles = checkcycles(p.decl.type) if cycles: diff --git a/ipc/ipdl/sync-messages.ini b/ipc/ipdl/sync-messages.ini index 9fdb216859..1de50773b9 100644 --- a/ipc/ipdl/sync-messages.ini +++ b/ipc/ipdl/sync-messages.ini @@ -357,8 +357,6 @@ description = Reflection is cold code, but synchronous by spec. description = Reflection is cold code, but synchronous by spec. [PWebGL::GetVertexAttrib] description = Reflection is cold code, but synchronous by spec. -[PWebGL::IsEnabled] -description = Reflection is cold code, but synchronous by spec. [PWebGL::ValidateProgram] description = Reflection is cold code, but synchronous by spec. [PWebGL::SyncPing] diff --git a/ipc/ipdl/test/README.txt b/ipc/ipdl/test/README.txt index ca6db8bb3c..3b8444d50f 100644 --- a/ipc/ipdl/test/README.txt +++ b/ipc/ipdl/test/README.txt @@ -7,7 +7,10 @@ specifications, and successfully rejecting erroneous specifications. To run these tests yourself locally, the correct invocation is make -C obj-dir/ipc/ipdl/test/ipdl check +or + mach build ipc/ipdl/test/ipdl check -The second category (cxx/) is C++ tests of IPDL semantics. These -tests check that async/sync/rpc semantics are implemented correctly, + +The second category (gtest/) is C++ tests of IPDL semantics. These +tests check that async/sync semantics are implemented correctly, ctors/dtors behave as they should, etc. diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp deleted file mode 100644 index 7683808535..0000000000 --- a/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ -/* 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 "mozilla/ipc/IOThreadChild.h" - -#include "IPDLUnitTestProcessChild.h" -#include "IPDLUnitTests.h" - -#include "nsRegion.h" - -using mozilla::ipc::IOThreadChild; - -namespace mozilla { -namespace _ipdltest { - -bool IPDLUnitTestProcessChild::Init(int aArgc, char* aArgv[]) { - // FIXME(nika): this is quite clearly broken and needs to be fixed. - IPDLUnitTestChildInit(IOThreadChild::TakeChannel(), ParentPid(), - IOThreadChild::message_loop()); - - return true; -} - -} // namespace _ipdltest -} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h deleted file mode 100644 index 94578e3520..0000000000 --- a/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ -/* 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__ipdltest_IPDLUnitTestThreadChild_h -#define mozilla__ipdltest_IPDLUnitTestThreadChild_h 1 - -#include "mozilla/ipc/ProcessChild.h" - -namespace mozilla { -namespace _ipdltest { - -class IPDLUnitTestProcessChild : public mozilla::ipc::ProcessChild { - typedef mozilla::ipc::ProcessChild ProcessChild; - - public: - using ProcessChild::ProcessChild; - - ~IPDLUnitTestProcessChild() {} - - virtual bool Init(int aArgc, char* aArgv[]) override; -}; - -} // namespace _ipdltest -} // namespace mozilla - -#endif // ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.cpp b/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.cpp deleted file mode 100644 index 660e5928d3..0000000000 --- a/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ -/* 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 "IPDLUnitTestSubprocess.h" - -using mozilla::ipc::GeckoChildProcessHost; - -namespace mozilla { -namespace _ipdltest { - -IPDLUnitTestSubprocess::IPDLUnitTestSubprocess() - : GeckoChildProcessHost(GeckoProcessType_IPDLUnitTest) {} - -IPDLUnitTestSubprocess::~IPDLUnitTestSubprocess() {} - -} // namespace _ipdltest -} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.h b/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.h deleted file mode 100644 index 384cf25ce9..0000000000 --- a/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ -/* 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__ipdltest_IPDLUnitTestTestSubprocess_h -#define mozilla__ipdltest_IPDLUnitTestTestSubprocess_h 1 - -#include "mozilla/ipc/GeckoChildProcessHost.h" - -namespace mozilla { -namespace _ipdltest { -//----------------------------------------------------------------------------- - -class IPDLUnitTestSubprocess : public mozilla::ipc::GeckoChildProcessHost { - public: - IPDLUnitTestSubprocess(); - - /** - * Asynchronously launch the plugin process. - */ - // Could override parent Launch, but don't need to here - // bool Launch(); - - private: - ~IPDLUnitTestSubprocess(); - - DISALLOW_EVIL_CONSTRUCTORS(IPDLUnitTestSubprocess); -}; - -} // namespace _ipdltest -} // namespace mozilla - -#endif // ifndef mozilla__ipdltest_IPDLUnitTestTestSubprocess_h diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestTypes.h b/ipc/ipdl/test/cxx/IPDLUnitTestTypes.h deleted file mode 100644 index 02696f7df7..0000000000 --- a/ipc/ipdl/test/cxx/IPDLUnitTestTypes.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ -/* 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__ipdltest_IPDLUnitTestTypes_h -#define mozilla__ipdltest_IPDLUnitTestTypes_h - -#include "mozilla/ipc/ProtocolUtils.h" // ActorDestroyReason - -namespace mozilla { -namespace _ipdltest { - -struct DirtyRect { - int x; - int y; - int w; - int h; -}; - -} // namespace _ipdltest -} // namespace mozilla - -namespace IPC { -template <> -struct ParamTraits<mozilla::_ipdltest::DirtyRect> { - typedef mozilla::_ipdltest::DirtyRect paramType; - static void Write(MessageWriter* aWriter, const paramType& aParam) { - WriteParam(aWriter, aParam.x); - WriteParam(aWriter, aParam.y); - WriteParam(aWriter, aParam.w); - WriteParam(aWriter, aParam.h); - } - static bool Read(MessageReader* aReader, void** aIter, paramType* aResult) { - return (ReadParam(aReader, aIter, &aResult->x) && - ReadParam(aReader, aIter, &aResult->y) && - ReadParam(aReader, aIter, &aResult->w) && - ReadParam(aReader, aIter, &aResult->h)); - } -}; -} // namespace IPC - -#endif // ifndef mozilla__ipdltest_IPDLUnitTestTypes_h diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestUtils.h b/ipc/ipdl/test/cxx/IPDLUnitTestUtils.h deleted file mode 100644 index e454ae7b61..0000000000 --- a/ipc/ipdl/test/cxx/IPDLUnitTestUtils.h +++ /dev/null @@ -1,28 +0,0 @@ - -#ifndef mozilla__ipdltest_IPDLUnitTestUtils -#define mozilla__ipdltest_IPDLUnitTestUtils 1 - -#include "ipc/IPCMessageUtils.h" - -namespace mozilla { -namespace _ipdltest { - -struct Bad {}; - -} // namespace _ipdltest -} // namespace mozilla - -namespace IPC { - -template <> -struct ParamTraits<mozilla::_ipdltest::Bad> { - typedef mozilla::_ipdltest::Bad paramType; - - // Defined in TestActorPunning.cpp. - static void Write(MessageWriter* aWriter, const paramType& aParam); - static bool Read(MessageReader* aReader, paramType* aResult); -}; - -} // namespace IPC - -#endif // mozilla__ipdltest_IPDLUnitTestUtils diff --git a/ipc/ipdl/test/cxx/IPDLUnitTests.h b/ipc/ipdl/test/cxx/IPDLUnitTests.h deleted file mode 100644 index 28fc4ee372..0000000000 --- a/ipc/ipdl/test/cxx/IPDLUnitTests.h +++ /dev/null @@ -1,85 +0,0 @@ -/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ -/* 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__ipdltest_IPDLUnitTests_h -#define mozilla__ipdltest_IPDLUnitTests_h 1 - -#include "base/message_loop.h" -#include "base/process.h" -#include "chrome/common/ipc_channel.h" - -#include "nsCOMPtr.h" -#include "nsDebug.h" -#include "nsServiceManagerUtils.h" // do_GetService() -#include "nsWidgetsCID.h" // NS_APPSHELL_CID -#include "nsXULAppAPI.h" - -#define MOZ_IPDL_TESTFAIL_LABEL "TEST-UNEXPECTED-FAIL" -#define MOZ_IPDL_TESTPASS_LABEL "TEST-PASS" -#define MOZ_IPDL_TESTINFO_LABEL "TEST-INFO" - -namespace mozilla { -namespace _ipdltest { - -//----------------------------------------------------------------------------- -// both processes -const char* IPDLUnitTestName(); - -// NB: these are named like the similar functions in -// xpcom/test/TestHarness.h. The names should nominally be kept in -// sync. - -inline void fail(const char* fmt, ...) { - va_list ap; - - fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL " | %s | ", IPDLUnitTestName()); - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - - fputc('\n', stderr); - - MOZ_CRASH("failed test"); -} - -inline void passed(const char* fmt, ...) { - va_list ap; - - printf(MOZ_IPDL_TESTPASS_LABEL " | %s | ", IPDLUnitTestName()); - - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - - fputc('\n', stdout); -} - -//----------------------------------------------------------------------------- -// parent process only - -class IPDLUnitTestSubprocess; - -extern void* gParentActor; -extern IPDLUnitTestSubprocess* gSubprocess; - -void IPDLUnitTestMain(void* aData); - -void QuitParent(); - -//----------------------------------------------------------------------------- -// child process only - -extern void* gChildActor; - -void IPDLUnitTestChildInit(IPC::Channel* transport, base::ProcessId parentPid, - MessageLoop* worker); - -void QuitChild(); - -} // namespace _ipdltest -} // namespace mozilla - -#endif // ifndef mozilla__ipdltest_IPDLUnitTests_h diff --git a/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp b/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp deleted file mode 100644 index 113e7cd287..0000000000 --- a/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp +++ /dev/null @@ -1,345 +0,0 @@ -// -// Autogenerated from Python template. Hands off. -// - -#include <stdlib.h> -#include <string.h> - -#include "IPDLUnitTests.h" - -#include "base/command_line.h" -#include "base/string_util.h" -#include "base/task.h" -#include "base/thread.h" - -#include "nsRegion.h" - -#include "IPDLUnitTestSubprocess.h" - -// clang-format off -//----------------------------------------------------------------------------- -//===== TEMPLATED ===== -${INCLUDES} -//----------------------------------------------------------------------------- -// clang-format on - -using namespace std; - -using base::Thread; - -namespace mozilla { -namespace _ipdltest { - -void* gParentActor; -IPDLUnitTestSubprocess* gSubprocess; - -void* gChildActor; - -// Note: in threaded mode, this will be non-null (for both parent and -// child, since they share one set of globals). -Thread* gChildThread; -MessageLoop* gParentMessageLoop; -bool gParentDone; -bool gChildDone; - -void DeleteChildActor(); - -//----------------------------------------------------------------------------- -// data/functions accessed by both parent and child processes - -char* gIPDLUnitTestName = nullptr; - -const char* IPDLUnitTestName() { - if (!gIPDLUnitTestName) { -#if defined(XP_WIN) - vector<wstring> args = CommandLine::ForCurrentProcess()->GetLooseValues(); - gIPDLUnitTestName = ::strdup(WideToUTF8(args[0]).c_str()); -#else - vector<string> argv = CommandLine::ForCurrentProcess()->argv(); - gIPDLUnitTestName = ::moz_xstrdup(argv[1].c_str()); -#endif - } - return gIPDLUnitTestName; -} - -} // namespace _ipdltest -} // namespace mozilla - -namespace { - -enum IPDLUnitTestType { - NoneTest = 0, - - // clang-format off -//----------------------------------------------------------------------------- -//===== TEMPLATED ===== -${ENUM_VALUES} - - LastTest = ${LAST_ENUM} -//----------------------------------------------------------------------------- -//clang-format on -}; - -IPDLUnitTestType IPDLUnitTestFromString(const char* const aString) { - if (!aString) return static_cast<IPDLUnitTestType>(0); -// clang-format off -//----------------------------------------------------------------------------- -//===== TEMPLATED ===== -${STRING_TO_ENUMS} -//----------------------------------------------------------------------------- - // clang-format on - else return static_cast<IPDLUnitTestType>(0); -} - -IPDLUnitTestType IPDLUnitTest() { - return IPDLUnitTestFromString(::mozilla::_ipdltest::IPDLUnitTestName()); -} - -} // namespace - -//----------------------------------------------------------------------------- -// parent process only - -namespace mozilla { -namespace _ipdltest { - -void DeferredParentShutdown(); - -void IPDLUnitTestThreadMain(char* testString); - -void IPDLUnitTestMain(void* aData) { - char* testString = reinterpret_cast<char*>(aData); - - // Check if we are to run the test using threads instead: - const char* prefix = "thread:"; - const int prefixLen = strlen(prefix); - if (!strncmp(testString, prefix, prefixLen)) { - IPDLUnitTestThreadMain(testString + prefixLen); - return; - } - - IPDLUnitTestType test = IPDLUnitTestFromString(testString); - if (!test) { - // use this instead of |fail()| because we don't know what the test is - fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n", - "<--->", testString); - MOZ_CRASH("can't continue"); - } - gIPDLUnitTestName = testString; - - // Check whether this test is enabled for processes: - switch (test) { - // clang-format off -//----------------------------------------------------------------------------- -//===== TEMPLATED ===== -${PARENT_ENABLED_CASES_PROC} -//----------------------------------------------------------------------------- - // clang-format on - - default: - fail("not reached"); - return; // unreached - } - - printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName); - - std::vector<std::string> testCaseArgs; - testCaseArgs.push_back(testString); - - gSubprocess = new IPDLUnitTestSubprocess(); - if (!gSubprocess->SyncLaunch(testCaseArgs)) - fail("problem launching subprocess"); - - IPC::Channel* transport = gSubprocess->GetChannel(); - if (!transport) fail("no transport"); - - base::ProcessId child = base::GetProcId(gSubprocess->GetChildProcessHandle()); - - switch (test) { - // clang-format off -//----------------------------------------------------------------------------- -//===== TEMPLATED ===== -${PARENT_MAIN_CASES_PROC} -//----------------------------------------------------------------------------- - // clang-format on - - default: - fail("not reached"); - return; // unreached - } -} - -void IPDLUnitTestThreadMain(char* testString) { - IPDLUnitTestType test = IPDLUnitTestFromString(testString); - if (!test) { - // use this instead of |fail()| because we don't know what the test is - fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n", - "<--->", testString); - MOZ_CRASH("can't continue"); - } - gIPDLUnitTestName = testString; - - // Check whether this test is enabled for threads: - switch (test) { - // clang-format off -//----------------------------------------------------------------------------- -//===== TEMPLATED ===== -${PARENT_ENABLED_CASES_THREAD} -//----------------------------------------------------------------------------- - // clang-format on - - default: - fail("not reached"); - return; // unreached - } - - printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName); - - std::vector<std::string> testCaseArgs; - testCaseArgs.push_back(testString); - - gChildThread = new Thread("ParentThread"); - if (!gChildThread->Start()) fail("starting parent thread"); - - gParentMessageLoop = MessageLoop::current(); - MessageLoop* childMessageLoop = gChildThread->message_loop(); - - switch (test) { - // clang-format off -//----------------------------------------------------------------------------- -//===== TEMPLATED ===== -${PARENT_MAIN_CASES_THREAD} -//----------------------------------------------------------------------------- - // clang-format on - - default: - fail("not reached"); - return; // unreached - } -} - -void DeleteParentActor() { - if (!gParentActor) return; - - switch (IPDLUnitTest()) { - // clang-format off -//----------------------------------------------------------------------------- -//===== TEMPLATED ===== -${PARENT_DELETE_CASES} -//----------------------------------------------------------------------------- - // clang-format on - default: - ::mozilla::_ipdltest::fail("???"); - } -} - -void QuitXPCOM() { - DeleteParentActor(); - - static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); - nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID)); - appShell->Exit(); -} - -void DeleteSubprocess(MessageLoop* uiLoop) { - // pong to QuitXPCOM - gSubprocess->Destroy(); - gSubprocess = nullptr; - uiLoop->PostTask(NewRunnableFunction("QuitXPCOM", QuitXPCOM)); -} - -void DeferredParentShutdown() { - // ping to DeleteSubprocess - XRE_GetIOMessageLoop()->PostTask(NewRunnableFunction( - "DeleteSubprocess", DeleteSubprocess, MessageLoop::current())); -} - -void TryThreadedShutdown() { - // Stop if either: - // - the child has not finished, - // - the parent has not finished, - // - or this code has already executed. - // Remember: this TryThreadedShutdown() task is enqueued - // by both parent and child (though always on parent's msg loop). - if (!gChildDone || !gParentDone || !gChildThread) return; - - delete gChildThread; - gChildThread = 0; - DeferredParentShutdown(); -} - -void ChildCompleted() { - // Executes on the parent message loop once child has completed. - gChildDone = true; - TryThreadedShutdown(); -} - -void QuitParent() { - if (gChildThread) { - gParentDone = true; - MessageLoop::current()->PostTask( - NewRunnableFunction("TryThreadedShutdown", TryThreadedShutdown)); - } else { - // defer "real" shutdown to avoid *Channel::Close() racing with the - // deletion of the subprocess - MessageLoop::current()->PostTask( - NewRunnableFunction("DeferredParentShutdown", DeferredParentShutdown)); - } -} - -static void ChildDie() { - DeleteChildActor(); - XRE_ShutdownChildProcess(); -} - -void QuitChild() { - if (gChildThread) { // Threaded-mode test - gParentMessageLoop->PostTask( - NewRunnableFunction("ChildCompleted", ChildCompleted)); - } else { // Process-mode test - MessageLoop::current()->PostTask(NewRunnableFunction("ChildDie", ChildDie)); - } -} - -} // namespace _ipdltest -} // namespace mozilla - -//----------------------------------------------------------------------------- -// child process only - -namespace mozilla { -namespace _ipdltest { - -void DeleteChildActor() { - if (!gChildActor) return; - - switch (IPDLUnitTest()) { - // clang-format off -//----------------------------------------------------------------------------- -//===== TEMPLATED ===== -${CHILD_DELETE_CASES} -//----------------------------------------------------------------------------- - // clang-format on - default: - ::mozilla::_ipdltest::fail("???"); - } -} - -void IPDLUnitTestChildInit(IPC::Channel* transport, base::ProcessId parentPid, - MessageLoop* worker) { - switch (IPDLUnitTest()) { - // clang-format off -//----------------------------------------------------------------------------- -//===== TEMPLATED ===== -${CHILD_INIT_CASES} -//----------------------------------------------------------------------------- - // clang-format on - - default: - fail("not reached"); - return; // unreached - } -} - -} // namespace _ipdltest -} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/Makefile.in b/ipc/ipdl/test/cxx/Makefile.in deleted file mode 100644 index b32533a648..0000000000 --- a/ipc/ipdl/test/cxx/Makefile.in +++ /dev/null @@ -1,45 +0,0 @@ -# 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/. - -IPDLTESTSRCS = $(filter Test%,$(CPPSRCS)) -IPDLTESTS = $(IPDLTESTSRCS:.cpp=) - -EXTRA_PROTOCOLS = \ - TestEndpointBridgeSub \ - $(NULL) - -IPDLTESTHDRS = $(addprefix $(srcdir)/,$(addsuffix .h,$(IPDLTESTS))) - -TESTER_TEMPLATE := $(srcdir)/IPDLUnitTests.template.cpp -GENTESTER := $(srcdir)/genIPDLUnitTests.py - -include $(topsrcdir)/config/rules.mk - - -IPDLUNITTEST_BIN = $(DEPTH)/dist/bin/ipdlunittest$(BIN_SUFFIX) - -IPDLUnitTests.cpp : Makefile.in moz.build $(GENTESTER) $(TESTER_TEMPLATE) $(IPDLTESTHDRS) - $(PYTHON3) $(GENTESTER) $(TESTER_TEMPLATE) -t $(IPDLTESTS) -e $(EXTRA_PROTOCOLS) > $@ - -check-proc:: - @$(EXIT_ON_ERROR) \ - for test in $(IPDLTESTS); do \ - $(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) $$test ; \ - done - -check-thread:: - @$(EXIT_ON_ERROR) \ - for test in $(IPDLTESTS); do \ - $(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) thread:$$test ; \ - done - -check:: check-proc check-thread - -check-valgrind:: - @$(EXIT_ON_ERROR) \ - for test in $(IPDLTESTS); do \ - $(RUN_TEST_PROGRAM) -g -d \ - valgrind -a '--leak-check=full --trace-children=yes -q' \ - $(IPDLUNITTEST_BIN) $$test ; \ - done diff --git a/ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh b/ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh deleted file mode 100644 index a81fcdee46..0000000000 --- a/ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh +++ /dev/null @@ -1,15 +0,0 @@ -include protocol PTestIndirectProtocolParamSecond;
-
-namespace mozilla {
-namespace _ipdltest {
-
-struct IndirectParamStruct {
- PTestIndirectProtocolParamSecond actor;
-};
-
-union IndirectParamUnion {
- IndirectParamStruct;
-};
-
-}
-}
diff --git a/ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl deleted file mode 100644 index 5364d79ffb..0000000000 --- a/ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl +++ /dev/null @@ -1,20 +0,0 @@ -include protocol PTestIndirectProtocolParamManage; -// FIXME/bug 792908 protocol PTestIndirectProtocolParamSecond is -// already included in PTestIndirectProtocolParam.ipdlh -include protocol PTestIndirectProtocolParamSecond; -include PTestIndirectProtocolParam; - -namespace mozilla { -namespace _ipdltest { - -[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual] -sync protocol PTestIndirectProtocolParamFirst { - manager PTestIndirectProtocolParamManage; -parent: - sync Test(IndirectParamUnion actor); -both: - async __delete__(); -}; - -} -} diff --git a/ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl deleted file mode 100644 index 8d3c6f81b1..0000000000 --- a/ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl +++ /dev/null @@ -1,18 +0,0 @@ -include protocol PTestIndirectProtocolParamFirst; -include protocol PTestIndirectProtocolParamSecond; - -namespace mozilla { -namespace _ipdltest { - -[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual] -sync protocol PTestIndirectProtocolParamManage { - manages PTestIndirectProtocolParamFirst; - manages PTestIndirectProtocolParamSecond; -both: - async PTestIndirectProtocolParamFirst(); - async PTestIndirectProtocolParamSecond(); - async __delete__(); -}; - -} -} diff --git a/ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl deleted file mode 100644 index 27545ca2cb..0000000000 --- a/ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl +++ /dev/null @@ -1,14 +0,0 @@ -include protocol PTestIndirectProtocolParamManage; - -namespace mozilla { -namespace _ipdltest { - -[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual] -sync protocol PTestIndirectProtocolParamSecond { - manager PTestIndirectProtocolParamManage; -both: - async __delete__(); -}; - -} -} diff --git a/ipc/ipdl/test/cxx/PTestPaintThread.ipdl b/ipc/ipdl/test/cxx/PTestPaintThread.ipdl deleted file mode 100644 index 00d46c9757..0000000000 --- a/ipc/ipdl/test/cxx/PTestPaintThread.ipdl +++ /dev/null @@ -1,15 +0,0 @@ -include "mozilla/_ipdltest/TestOffMainThreadPainting.h"; - -namespace mozilla { -namespace _ipdltest { - -// This is supposed to be analagous to PPaintingBridge. -[ManualDealloc, ChildImpl="TestPaintThreadChild", ParentImpl="TestPaintThreadParent"] -sync protocol PTestPaintThread -{ -parent: - sync FinishedPaint(uint64_t aTxnId); -}; - -} // namespace mozilla -} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestPriority.ipdl b/ipc/ipdl/test/cxx/PTestPriority.ipdl deleted file mode 100644 index 8b85368072..0000000000 --- a/ipc/ipdl/test/cxx/PTestPriority.ipdl +++ /dev/null @@ -1,24 +0,0 @@ -namespace mozilla { -namespace _ipdltest { - -[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual] -sync protocol PTestPriority { -parent: - [Priority=input] async PMsg1(); - [Priority=input] sync PMsg2(); - [Priority=vsync] async PMsg3(); - [Priority=vsync] sync PMsg4(); - [Priority=mediumhigh] async PMsg5(); - [Priority=mediumhigh] sync PMsg6(); - [Priority=control] async PMsg7(); - [Priority=control] sync PMsg8(); - -child: - [Priority=input] async CMsg1(); - [Priority=vsync] async CMsg2(); - [Priority=mediumhigh] async CMsg3(); - [Priority=control] async CMsg4(); -}; - -} // namespace _ipdltest -} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/README.txt b/ipc/ipdl/test/cxx/README.txt deleted file mode 100644 index 0fe6c07320..0000000000 --- a/ipc/ipdl/test/cxx/README.txt +++ /dev/null @@ -1,61 +0,0 @@ -To add a new IPDL C++ unit test, you need to create (at least) the -following files (for a test "TestFoo"): - - - PTestFoo.ipdl, specifying the top-level protocol used for the test - - - TestFoo.h, declaring the top-level parent/child actors used for - the test - - - TestFoo.cpp, defining the top-level actors - - - (make sure all are in the namespace mozilla::_ipdltest) - -Next - - - add PTestFoo.ipdl to ipdl.mk - - - append TestFoo to the variable IPDLTESTS in Makefile.in - -You must define three methods in your |TestFooParent| class: - - - static methods |bool RunTestInProcesses()| and - |bool RunTestInThreads()|. These methods control whether - to execute the test using actors in separate processes and - threads respectively. Generally, both should return true. - - - an instance method |void Main()|. The test harness wil first - initialize the processes or threads, create and open both actors, - and then kick off the test using |Main()|. Make sure you define - it. - -If your test passes its criteria, please call -|MOZ_IPDL_TESTPASS("msg")| and "exit gracefully". - -If your tests fails, please call |MOZ_IPDL_TESTFAIL("msg")| and "exit -ungracefully", preferably by abort()ing. - - -If all goes well, running - - make -C $OBJDIR/ipc/ipdl/test/cxx - -will update the file IPDLUnitTests.cpp (the test launcher), and your -new code will be built automatically. - - -You can launch your new test by invoking one of - - make -C $OBJDIR/ipc/ipdl/test/cxx check-proc (test process-based tests) - make -C $OBJDIR/ipc/ipdl/test/cxx check-threads (test thread-based tests) - make -C $OBJDIR/ipc/ipdl/test/cxx check (tests both) - -If you want to launch only your test, run - - cd $OBJDIR/dist/bin - ./run-mozilla.sh ./ipdlunittest TestFoo (test in two processes, if appl.) - ./run-mozilla.sh ./ipdlunittest thread:TestFoo (test in two threads, if appl.) - - -For a bare-bones example of adding a test, take a look at -PTestSanity.ipdl, TestSanity.h, TestSanity.cpp, and how "TestSanity" -is included in ipdl.mk and Makefile.in. diff --git a/ipc/ipdl/test/cxx/app/TestIPDL.cpp b/ipc/ipdl/test/cxx/app/TestIPDL.cpp deleted file mode 100644 index 3891aead62..0000000000 --- a/ipc/ipdl/test/cxx/app/TestIPDL.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* 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/. */ - -#define MOZ_IPDL_TESTS -#include "mozilla/Bootstrap.h" - -#if defined(XP_WIN) -# include <windows.h> -# include "nsWindowsWMain.cpp" -#endif - -using namespace mozilla; - -int main(int argc, char** argv) { - // the first argument specifies which IPDL test case/suite to load - if (argc < 2) return 1; - - Bootstrap::UniquePtr bootstrap = GetBootstrap(); - if (!bootstrap) { - return 2; - } - return bootstrap->XRE_RunIPDLTest(argc, argv); -} diff --git a/ipc/ipdl/test/cxx/app/moz.build b/ipc/ipdl/test/cxx/app/moz.build deleted file mode 100644 index 909360062a..0000000000 --- a/ipc/ipdl/test/cxx/app/moz.build +++ /dev/null @@ -1,20 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -GeckoProgram("ipdlunittest", linkage="dependent") - -SOURCES += [ - "TestIPDL.cpp", -] -include("/ipc/chromium/chromium-config.mozbuild") - -LOCAL_INCLUDES += [ - "/toolkit/xre", - "/xpcom/base", -] - -if CONFIG["CC_TYPE"] == "clang-cl": - WIN32_EXE_LDFLAGS += ["-ENTRY:wmainCRTStartup"] diff --git a/ipc/ipdl/test/cxx/genIPDLUnitTests.py b/ipc/ipdl/test/cxx/genIPDLUnitTests.py deleted file mode 100644 index 160b90a031..0000000000 --- a/ipc/ipdl/test/cxx/genIPDLUnitTests.py +++ /dev/null @@ -1,193 +0,0 @@ -# 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/. - -import string -import sys - - -def usage(): - print( - """ -%s template_file -t unit_tests... -e extra_protocols... - - TEMPLATE_FILE is used to generate to generate the unit-tester .cpp - UNIT_TESTS are the top-level protocols defining unit tests - EXTRA_PROTOCOLS are top-level protocols for subprocesses that can be - spawned in tests but are not unit tests in and of - themselves -""" - % (sys.argv[0]), - file=sys.stderr, - ) - sys.exit(1) - - -def main(argv): - template = argv[1] - - if argv[2] != "-t": - usage() - i = 3 - unittests = [] - while argv[i] != "-e": - unittests.append(argv[i]) - i += 1 - - extras = argv[(i + 1) :] - - includes = "\n".join(['#include "%s.h"' % (t) for t in unittests]) - - enum_values = "\n".join([" %s," % (t) for t in unittests + extras]) - last_enum = unittests[-1] - - string_to_enums = "\n".join( - [ - """ else if (!strcmp(aString, "%s")) - return %s;""" - % (t, t) - for t in unittests + extras - ] - ) - - enum_to_strings = "\n".join( - [ - """ case %s: - return "%s";""" - % (t, t) - for t in unittests + extras - ] - ) - - parent_delete_cases = "\n".join( - [ - """ case %s: { - delete reinterpret_cast<%sParent*>(gParentActor); - return; - } -""" - % (t, t) - for t in unittests - ] - ) - - parent_enabled_cases_proc = "\n".join( - [ - """ case %s: { - if (!%sParent::RunTestInProcesses()) { - passed("N/A to proc"); - DeferredParentShutdown(); - return; - } - break; - } -""" - % (t, t) - for t in unittests - ] - ) - - parent_main_cases_proc = "\n".join( - [ - """ case %s: { - %sParent** parent = - reinterpret_cast<%sParent**>(&gParentActor); - *parent = new %sParent(); - (*parent)->Open(transport, child); - return (*parent)->Main(); - } -""" - % (t, t, t, t) - for t in unittests - ] - ) - - parent_enabled_cases_thread = "\n".join( - [ - """ case %s: { - if (!%sParent::RunTestInThreads()) { - passed("N/A to threads"); - DeferredParentShutdown(); - return; - } - break; - } -""" - % (t, t) - for t in unittests - ] - ) - - parent_main_cases_thread = "\n".join( - [ - """ case %s: { - %sParent** parent = - reinterpret_cast<%sParent**>(&gParentActor); - *parent = new %sParent(); - - %sChild** child = - reinterpret_cast<%sChild**>(&gChildActor); - *child = new %sChild(); - - ::mozilla::ipc::MessageChannel *childChannel = (*child)->GetIPCChannel(); - ::mozilla::ipc::Side parentSide = - ::mozilla::ipc::ParentSide; - - (*parent)->Open(childChannel, childMessageLoop, parentSide); - return (*parent)->Main(); - } -""" - % (t, t, t, t, t, t, t) - for t in unittests - ] - ) - - child_delete_cases = "\n".join( - [ - """ case %s: { - delete reinterpret_cast<%sChild*>(gChildActor); - return; - } -""" - % (t, t) - for t in unittests + extras - ] - ) - - child_init_cases = "\n".join( - [ - """ case %s: { - %sChild** child = - reinterpret_cast<%sChild**>(&gChildActor); - *child = new %sChild(); - (*child)->Open(transport, parentPid, worker); - return; - } -""" - % (t, t, t, t) - for t in unittests + extras - ] - ) - - templatefile = open(template, "r", encoding="utf-8") - sys.stdout.write( - string.Template(templatefile.read()).substitute( - INCLUDES=includes, - ENUM_VALUES=enum_values, - LAST_ENUM=last_enum, - STRING_TO_ENUMS=string_to_enums, - ENUM_TO_STRINGS=enum_to_strings, - PARENT_DELETE_CASES=parent_delete_cases, - PARENT_ENABLED_CASES_PROC=parent_enabled_cases_proc, - PARENT_MAIN_CASES_PROC=parent_main_cases_proc, - PARENT_ENABLED_CASES_THREAD=parent_enabled_cases_thread, - PARENT_MAIN_CASES_THREAD=parent_main_cases_thread, - CHILD_DELETE_CASES=child_delete_cases, - CHILD_INIT_CASES=child_init_cases, - ) - ) - templatefile.close() - - -if __name__ == "__main__": - main(sys.argv) diff --git a/ipc/ipdl/test/cxx/moz.build b/ipc/ipdl/test/cxx/moz.build deleted file mode 100644 index 196dc09add..0000000000 --- a/ipc/ipdl/test/cxx/moz.build +++ /dev/null @@ -1,38 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -DIRS += ["app"] - -EXPORTS.mozilla._ipdltest += [ - "IPDLUnitTestProcessChild.h", - "IPDLUnitTests.h", - "IPDLUnitTestTypes.h", - "IPDLUnitTestUtils.h", - "TestOffMainThreadPainting.h", -] - -SOURCES += [ - "TestOffMainThreadPainting.cpp", -] - -SOURCES += [ - "!IPDLUnitTests.cpp", - "IPDLUnitTestProcessChild.cpp", - "IPDLUnitTestSubprocess.cpp", -] - -IPDL_SOURCES += [ - "PTestIndirectProtocolParam.ipdlh", - "PTestIndirectProtocolParamFirst.ipdl", - "PTestIndirectProtocolParamManage.ipdl", - "PTestIndirectProtocolParamSecond.ipdl", - "PTestPaintThread.ipdl", - "PTestPriority.ipdl", -] - -include("/ipc/chromium/chromium-config.mozbuild") - -FINAL_LIBRARY = "xul" diff --git a/ipc/ipdl/test/gtest/PTestUniquePtrIPC.ipdl b/ipc/ipdl/test/gtest/PTestUniquePtrIPC.ipdl index b55d8f19d1..2ef3d9cb59 100644 --- a/ipc/ipdl/test/gtest/PTestUniquePtrIPC.ipdl +++ b/ipc/ipdl/test/gtest/PTestUniquePtrIPC.ipdl @@ -1,15 +1,25 @@ +using std::string from "string"; + +// std::string is an arbitrary simple type declared inside a namespace, +// to test that that will work when used in a UniquePtr inside a union. + namespace mozilla { namespace _ipdltest { struct DummyStruct { - int x; + string x; +}; + +union DummyUnion { + UniquePtr<string>; + int; }; [ChildProc=any, ChildImpl=virtual, ParentImpl=virtual] protocol PTestUniquePtrIPC { child: - async TestMessage(UniquePtr<int> a1, UniquePtr<DummyStruct> a2, - DummyStruct a3, UniquePtr<int> a4); + async TestMessage(UniquePtr<string> a1, UniquePtr<DummyStruct> a2, + DummyStruct a3, UniquePtr<string> a4, DummyUnion a5); async TestSendReference(UniquePtr<DummyStruct> a); }; diff --git a/ipc/ipdl/test/gtest/TestHangs.cpp b/ipc/ipdl/test/gtest/TestHangs.cpp index ddc4a0c7d0..56f28c8afa 100644 --- a/ipc/ipdl/test/gtest/TestHangs.cpp +++ b/ipc/ipdl/test/gtest/TestHangs.cpp @@ -25,8 +25,7 @@ enum class HangMode : uint32_t { /// The synchronous call should time out. Hang, /// The synchronous call should time out but the response should still be - /// received - /// (racing with the reply timeout logic). + /// received (racing with the reply timeout logic). HangButReceive, /// The synchronous call should time out but the response should still be /// received because the child indicates that processing should continue after @@ -50,8 +49,10 @@ class TestHangsChild : public PTestHangsChild { this->hangMode = (HangMode)hangMode; auto result = SendHang(hangMode, timeout->CloneHandle()); + // Only the `Hang` mode should actually fail. if (this->hangMode == HangMode::Hang) { - // Only the `Hang` mode should actually fail. + // See description in parent. + timeout->Signal(); EXPECT_FALSE(result); } else { EXPECT_TRUE(result); @@ -102,6 +103,13 @@ class TestHangsParent : public PTestHangsParent { // Wait to ensure the child process has called // ShouldContinueFromReplyTimeout(). timeout->Wait(); + + if (hangMode == (uint32_t)HangMode::Hang) { + // Wait to ensure the child process has returned from `SendHang()`, + // otherwise the reply message can race with the processing after + // ShouldContinueFromReplyTimeout(). + timeout->Wait(); + } } return IPC_OK(); } diff --git a/ipc/ipdl/test/gtest/TestUniquePtrIPC.cpp b/ipc/ipdl/test/gtest/TestUniquePtrIPC.cpp index 52ca322f8e..b3c68b99b4 100644 --- a/ipc/ipdl/test/gtest/TestUniquePtrIPC.cpp +++ b/ipc/ipdl/test/gtest/TestUniquePtrIPC.cpp @@ -26,18 +26,20 @@ class TestUniquePtrIPCParent : public PTestUniquePtrIPCParent { class TestUniquePtrIPCChild : public PTestUniquePtrIPCChild { NS_INLINE_DECL_REFCOUNTING(TestUniquePtrIPCChild, override) private: - IPCResult RecvTestMessage(const UniquePtr<int>& aA1, + IPCResult RecvTestMessage(const UniquePtr<std::string>& aA1, const UniquePtr<DummyStruct>& aA2, const DummyStruct& aA3, - const UniquePtr<int>& aA4) final override { + const UniquePtr<std::string>& aA4, + const DummyUnion& aA5) final override { EXPECT_TRUE(aA1) << "TestMessage received NULL aA1"; EXPECT_TRUE(aA2) << "TestMessage received NULL aA2"; EXPECT_FALSE(aA4) << "TestMessage received non-NULL when expecting NULL aA4"; - EXPECT_EQ(*aA1, 1); - EXPECT_EQ(aA2->x(), 2); - EXPECT_EQ(aA3.x(), 3); + EXPECT_EQ(*aA1, std::string("unique")); + EXPECT_EQ(aA2->x(), std::string("uniqueStruct")); + EXPECT_EQ(aA3.x(), std::string("struct")); + EXPECT_EQ(*aA5.get_string(), std::string("union")); return IPC_OK(); } @@ -45,7 +47,7 @@ class TestUniquePtrIPCChild : public PTestUniquePtrIPCChild { IPCResult RecvTestSendReference( const UniquePtr<DummyStruct>& aA) final override { EXPECT_TRUE(aA) << "TestSendReference received NULL item in child"; - EXPECT_EQ(aA->x(), 1); + EXPECT_EQ(aA->x(), std::string("reference")); Close(); return IPC_OK(); @@ -55,12 +57,13 @@ class TestUniquePtrIPCChild : public PTestUniquePtrIPCChild { }; IPDL_TEST(TestUniquePtrIPC) { - UniquePtr<int> a1 = MakeUnique<int>(1); - UniquePtr<DummyStruct> a2 = MakeUnique<DummyStruct>(2); - DummyStruct a3(3); - UniquePtr<int> a4; + UniquePtr<std::string> a1 = MakeUnique<std::string>("unique"); + UniquePtr<DummyStruct> a2 = MakeUnique<DummyStruct>("uniqueStruct"); + DummyStruct a3("struct"); + UniquePtr<std::string> a4; + DummyUnion a5(MakeUnique<std::string>("union")); - EXPECT_TRUE(mActor->SendTestMessage(a1, a2, a3, a4)); + EXPECT_TRUE(mActor->SendTestMessage(a1, a2, a3, a4, a5)); EXPECT_TRUE(a1) << "IPC arguments are passed by const reference and shouldn't be moved"; @@ -70,7 +73,7 @@ IPDL_TEST(TestUniquePtrIPC) { EXPECT_FALSE(a4) << "somehow turned null ptr into non-null by sending it"; // Pass UniquePtr by reference - UniquePtr<DummyStruct> b = MakeUnique<DummyStruct>(1); + UniquePtr<DummyStruct> b = MakeUnique<DummyStruct>("reference"); EXPECT_TRUE(mActor->SendTestSendReference(b)); EXPECT_TRUE(b) diff --git a/ipc/ipdl/test/ipdl/error/IntrAsyncManagee.ipdl b/ipc/ipdl/test/ipdl/error/IntrAsyncManagee.ipdl deleted file mode 100644 index 527c007ec4..0000000000 --- a/ipc/ipdl/test/ipdl/error/IntrAsyncManagee.ipdl +++ /dev/null @@ -1,9 +0,0 @@ -//error: protocol `IntrAsyncManagee' requires more powerful send semantics than its manager `IntrAsyncManager' provides - -include protocol IntrAsyncManager; - -intr protocol IntrAsyncManagee { - manager IntrAsyncManager; -child: - async __delete__(); -}; diff --git a/ipc/ipdl/test/ipdl/error/IntrAsyncManager.ipdl b/ipc/ipdl/test/ipdl/error/IntrAsyncManager.ipdl deleted file mode 100644 index dc5768df28..0000000000 --- a/ipc/ipdl/test/ipdl/error/IntrAsyncManager.ipdl +++ /dev/null @@ -1,10 +0,0 @@ -//error: protocol `IntrAsyncManagee' requires more powerful send semantics than its manager `IntrAsyncManager' provides - -include protocol IntrAsyncManagee; - -[ChildProc=any] -async protocol IntrAsyncManager { - manages IntrAsyncManagee; -parent: - async IntrAsyncManagee(); -}; diff --git a/ipc/ipdl/test/ipdl/error/IntrSyncManagee.ipdl b/ipc/ipdl/test/ipdl/error/IntrSyncManagee.ipdl deleted file mode 100644 index d0b1462e86..0000000000 --- a/ipc/ipdl/test/ipdl/error/IntrSyncManagee.ipdl +++ /dev/null @@ -1,9 +0,0 @@ -//error: protocol `IntrSyncManagee' requires more powerful send semantics than its manager `IntrSyncManager' provides - -include protocol IntrSyncManager; - -intr protocol IntrSyncManagee { - manager IntrSyncManager; -child: - async __delete__(); -}; diff --git a/ipc/ipdl/test/ipdl/error/IntrSyncManager.ipdl b/ipc/ipdl/test/ipdl/error/IntrSyncManager.ipdl deleted file mode 100644 index f8e762093c..0000000000 --- a/ipc/ipdl/test/ipdl/error/IntrSyncManager.ipdl +++ /dev/null @@ -1,10 +0,0 @@ -//error: protocol `IntrSyncManagee' requires more powerful send semantics than its manager `IntrSyncManager' provides - -include protocol IntrSyncManagee; - -[ChildProc=any] -sync protocol IntrSyncManager { - manages IntrSyncManagee; -parent: - async IntrSyncManagee(); -}; diff --git a/ipc/ipdl/test/ipdl/error/PIntrNested.ipdl b/ipc/ipdl/test/ipdl/error/PIntrNested.ipdl deleted file mode 100644 index c487bcd49d..0000000000 --- a/ipc/ipdl/test/ipdl/error/PIntrNested.ipdl +++ /dev/null @@ -1,7 +0,0 @@ -//error: intr message `Msg' cannot specify [Nested] - -[ChildProc=any] -intr protocol PIntrNested { -child: - [Nested=inside_sync, LegacyIntr] intr Msg(); -}; diff --git a/ipc/ipdl/test/ipdl/error/PIntrNestedProtocol.ipdl b/ipc/ipdl/test/ipdl/error/PIntrNestedProtocol.ipdl deleted file mode 100644 index dd95a7c002..0000000000 --- a/ipc/ipdl/test/ipdl/error/PIntrNestedProtocol.ipdl +++ /dev/null @@ -1,7 +0,0 @@ -//error: intr protocol `PIntrNestedProtocol' cannot specify [NestedUpTo] - -[NestedUpTo=inside_sync, ChildProc=any] -intr protocol PIntrNestedProtocol { -child: - [LegacyIntr] intr Msg(); -}; diff --git a/ipc/ipdl/test/ipdl/error/PIntrPriority.ipdl b/ipc/ipdl/test/ipdl/error/PIntrPriority.ipdl deleted file mode 100644 index c8bf75e9a3..0000000000 --- a/ipc/ipdl/test/ipdl/error/PIntrPriority.ipdl +++ /dev/null @@ -1,7 +0,0 @@ -//error: intr message `Msg' cannot specify [Priority] - -[ChildProc=any] -intr protocol PIntrPriority { -child: - [Priority=vsync, LegacyIntr] intr Msg(); -}; diff --git a/ipc/ipdl/test/ipdl/error/PNoTaintWithoutTainted.ipdl b/ipc/ipdl/test/ipdl/error/PNoTaintWithoutTainted.ipdl index b196050c48..8a80689ec0 100644 --- a/ipc/ipdl/test/ipdl/error/PNoTaintWithoutTainted.ipdl +++ b/ipc/ipdl/test/ipdl/error/PNoTaintWithoutTainted.ipdl @@ -1,7 +1,7 @@ //error: argument typename `int' of message `foo' has a NoTaint attribute, but the message lacks the Tainted attribute [ChildProc=any] -intr protocol PNoTaintWithoutTainted { +sync protocol PNoTaintWithoutTainted { child: async foo([NoTaint=passback] int id); }; diff --git a/ipc/ipdl/test/ipdl/error/compressCtor.ipdl b/ipc/ipdl/test/ipdl/error/compressCtor.ipdl index 93c300333d..a5e0e4062b 100644 --- a/ipc/ipdl/test/ipdl/error/compressCtor.ipdl +++ b/ipc/ipdl/test/ipdl/error/compressCtor.ipdl @@ -4,7 +4,7 @@ include protocol compressCtorManagee; [ChildProc=any] -intr protocol compressCtor { +sync protocol compressCtor { manages compressCtorManagee; parent: diff --git a/ipc/ipdl/test/ipdl/error/compressCtorManagee.ipdl b/ipc/ipdl/test/ipdl/error/compressCtorManagee.ipdl index 52ec2cc1cd..cf867ce54b 100644 --- a/ipc/ipdl/test/ipdl/error/compressCtorManagee.ipdl +++ b/ipc/ipdl/test/ipdl/error/compressCtorManagee.ipdl @@ -3,7 +3,7 @@ include protocol compressCtor; -intr protocol compressCtorManagee { +sync protocol compressCtorManagee { manager compressCtor; child: diff --git a/ipc/ipdl/test/ipdl/error/intrMessageCompress.ipdl b/ipc/ipdl/test/ipdl/error/intrMessageCompress.ipdl deleted file mode 100644 index e56cfc5d8c..0000000000 --- a/ipc/ipdl/test/ipdl/error/intrMessageCompress.ipdl +++ /dev/null @@ -1,10 +0,0 @@ -//error: message `foo' in protocol `intrMessageCompress' requests compression but is not async -//error: message `bar' in protocol `intrMessageCompress' requests compression but is not async - -[ChildProc=any] -intr protocol intrMessageCompress { -parent: - [Compress, LegacyIntr] intr foo(); -child: - [Compress, LegacyIntr] intr bar(); -}; diff --git a/ipc/ipdl/test/ipdl/error/syncParentToChild.ipdl b/ipc/ipdl/test/ipdl/error/syncParentToChild.ipdl index 8ce7c0be47..8cc0fdb72d 100644 --- a/ipc/ipdl/test/ipdl/error/syncParentToChild.ipdl +++ b/ipc/ipdl/test/ipdl/error/syncParentToChild.ipdl @@ -1,7 +1,7 @@ //error: sync parent-to-child messages are verboten (here, message `Msg' in protocol `syncParentToChild') [ChildProc=any] -intr protocol syncParentToChild { +sync protocol syncParentToChild { // can't declare sync parent-to-child messages child: sync Msg(); diff --git a/ipc/ipdl/test/ipdl/error/tooWeakIntrAsync.ipdl b/ipc/ipdl/test/ipdl/error/tooWeakIntrAsync.ipdl deleted file mode 100644 index 7dad5e68ef..0000000000 --- a/ipc/ipdl/test/ipdl/error/tooWeakIntrAsync.ipdl +++ /dev/null @@ -1,10 +0,0 @@ -//error: message `Msg' requires more powerful send semantics than its protocol `tooWeakIntrAsync' provides - -[ChildProc=any] -protocol tooWeakIntrAsync { - - // it's an error to declare an async protocol with an intr message - -parent: [LegacyIntr] intr Msg(); - -}; diff --git a/ipc/ipdl/test/ipdl/error/tooWeakIntrSync.ipdl b/ipc/ipdl/test/ipdl/error/tooWeakIntrSync.ipdl deleted file mode 100644 index a56e884e73..0000000000 --- a/ipc/ipdl/test/ipdl/error/tooWeakIntrSync.ipdl +++ /dev/null @@ -1,9 +0,0 @@ -//error: message `Msg' requires more powerful send semantics than its protocol `tooWeakIntrSync' provides - -[ChildProc=any] -sync protocol tooWeakIntrSync { - - // it's an error to declare a sync protocol with an interrupt message -parent: - [LegacyIntr] intr Msg(); -}; diff --git a/ipc/ipdl/test/ipdl/error/unknownIntrMessage.ipdl b/ipc/ipdl/test/ipdl/error/unknownIntrMessage.ipdl deleted file mode 100644 index 7ce415aba0..0000000000 --- a/ipc/ipdl/test/ipdl/error/unknownIntrMessage.ipdl +++ /dev/null @@ -1,7 +0,0 @@ -//error: Unknown sync IPC message unknownIntrMessage::Msg - -[ChildProc=any] -intr protocol unknownIntrMessage { -parent: - [LegacyIntr] intr Msg(); -}; diff --git a/ipc/ipdl/test/ipdl/ok/PMessageTainted.ipdl b/ipc/ipdl/test/ipdl/ok/PMessageTainted.ipdl index deb10fb7ac..e6565c6264 100644 --- a/ipc/ipdl/test/ipdl/ok/PMessageTainted.ipdl +++ b/ipc/ipdl/test/ipdl/ok/PMessageTainted.ipdl @@ -1,5 +1,5 @@ [ChildProc=any] -intr protocol PMessageTainted { +sync protocol PMessageTainted { child: [Tainted] async foo(); }; diff --git a/ipc/ipdl/test/ipdl/ok/PMessageTaintedWithPassback.ipdl b/ipc/ipdl/test/ipdl/ok/PMessageTaintedWithPassback.ipdl index 8db2c8b742..25fbae1f92 100644 --- a/ipc/ipdl/test/ipdl/ok/PMessageTaintedWithPassback.ipdl +++ b/ipc/ipdl/test/ipdl/ok/PMessageTaintedWithPassback.ipdl @@ -1,5 +1,5 @@ [ChildProc=any] -intr protocol PMessageTaintedWithPassback { +sync protocol PMessageTaintedWithPassback { child: [Tainted] async foo([NoTaint=passback] int id); }; diff --git a/ipc/ipdl/test/ipdl/ok/Pbytebuf.ipdl b/ipc/ipdl/test/ipdl/ok/Pbytebuf.ipdl index a0ceac937f..d51878b872 100644 --- a/ipc/ipdl/test/ipdl/ok/Pbytebuf.ipdl +++ b/ipc/ipdl/test/ipdl/ok/Pbytebuf.ipdl @@ -4,11 +4,9 @@ union Foo { }; [ChildProc=any] -intr protocol Pbytebuf { +sync protocol Pbytebuf { parent: async Msg(ByteBuf s, Foo f); sync SyncMsg(ByteBuf s, Foo f) returns (ByteBuf t, Foo g); - [LegacyIntr] intr InterruptMsg(ByteBuf s, Foo f) - returns (ByteBuf t, Foo g); }; diff --git a/ipc/ipdl/test/ipdl/ok/PintrProtocol.ipdl b/ipc/ipdl/test/ipdl/ok/PintrProtocol.ipdl deleted file mode 100644 index 4b663327e6..0000000000 --- a/ipc/ipdl/test/ipdl/ok/PintrProtocol.ipdl +++ /dev/null @@ -1,14 +0,0 @@ -[ChildProc=any] -intr protocol PintrProtocol { - - // sanity check of Interrupt protocols -child: - async AsyncMsg(); - -parent: - sync SyncMsg(int i) returns (int r); - -both: - [LegacyIntr] intr InterruptMsg(int x) returns (int y); - -}; diff --git a/ipc/ipdl/test/ipdl/ok/PmessageCompress.ipdl b/ipc/ipdl/test/ipdl/ok/PmessageCompress.ipdl index 7e14c888dd..0ec6476299 100644 --- a/ipc/ipdl/test/ipdl/ok/PmessageCompress.ipdl +++ b/ipc/ipdl/test/ipdl/ok/PmessageCompress.ipdl @@ -1,5 +1,5 @@ [ChildProc=any] -intr protocol PmessageCompress { +sync protocol PmessageCompress { child: [Compress] async foo(); [Compress=all] async bar(); diff --git a/ipc/ipdl/test/ipdl/ok/Pplugin.ipdl b/ipc/ipdl/test/ipdl/ok/Pplugin.ipdl deleted file mode 100644 index f7d9352a08..0000000000 --- a/ipc/ipdl/test/ipdl/ok/Pplugin.ipdl +++ /dev/null @@ -1,6 +0,0 @@ -[ChildProc=any] -intr protocol Pplugin { -child: - async __delete__(); - -}; diff --git a/ipc/ipdl/test/ipdl/ok/Pshmem.ipdl b/ipc/ipdl/test/ipdl/ok/Pshmem.ipdl index a46e777d8c..2779a2437f 100644 --- a/ipc/ipdl/test/ipdl/ok/Pshmem.ipdl +++ b/ipc/ipdl/test/ipdl/ok/Pshmem.ipdl @@ -4,11 +4,9 @@ union Foo { }; [ChildProc=any] -intr protocol Pshmem { +sync protocol Pshmem { parent: async Msg(Shmem s, Foo f); sync SyncMsg(Shmem s, Foo f) returns (Shmem t, Foo g); - [LegacyIntr] intr InterruptMsg(Shmem s, Foo f) - returns (Shmem t, Foo g); }; diff --git a/ipc/ipdl/test/ipdl/sync-messages.ini b/ipc/ipdl/test/ipdl/sync-messages.ini index 82af605d01..afd0ff3d5d 100644 --- a/ipc/ipdl/test/ipdl/sync-messages.ini +++ b/ipc/ipdl/test/ipdl/sync-messages.ini @@ -10,30 +10,16 @@ description = test only description = test only [Punion_Comparable::Msg] description = test only -[PintrProtocol::SyncMsg] -description = test only -[PintrProtocol::InterruptMsg] -description = test only [Pshmem::SyncMsg] description = test only -[Pshmem::InterruptMsg] -description = test only [Pbytebuf::SyncMsg] description = test only -[Pbytebuf::InterruptMsg] -description = test only [PsyncProtocol::SyncMsg] description = test only -[PintrMessageCompress::foo] -description = test only -[PintrMessageCompress::bar] -description = test only [PsyncMessageCompress::foo] description = test only [PsyncParentToChild::Msg] description = test only -[PtooWeakIntrSync::Msg] -description = test only [PtooWeakSyncAsync::Msg] description = test only [PundeclReturnType::Msg] |