diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
commit | 40736c5763bf61337c8c14e16d8587db021a87d4 (patch) | |
tree | b17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/WebKit2/UIProcess/Launcher | |
download | qtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz |
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/WebKit2/UIProcess/Launcher')
16 files changed, 1788 insertions, 0 deletions
diff --git a/Source/WebKit2/UIProcess/Launcher/ProcessLauncher.cpp b/Source/WebKit2/UIProcess/Launcher/ProcessLauncher.cpp new file mode 100644 index 000000000..e53d4156b --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/ProcessLauncher.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ProcessLauncher.h" + +#include "WorkQueue.h" +#include <wtf/StdLibExtras.h> + +namespace WebKit { + +static WorkQueue& processLauncherWorkQueue() +{ + DEFINE_STATIC_LOCAL(WorkQueue, processLauncherWorkQueue, ("com.apple.WebKit.ProcessLauncher")); + return processLauncherWorkQueue; +} + +ProcessLauncher::ProcessLauncher(Client* client, const LaunchOptions& launchOptions) + : m_client(client) + , m_launchOptions(launchOptions) + , m_processIdentifier(0) +{ + // Launch the process. + m_isLaunching = true; + processLauncherWorkQueue().dispatch(bind(&ProcessLauncher::launchProcess, this)); +} + +void ProcessLauncher::didFinishLaunchingProcess(PlatformProcessIdentifier processIdentifier, CoreIPC::Connection::Identifier identifier) +{ + m_processIdentifier = processIdentifier; + m_isLaunching = false; + + if (!m_client) { + // FIXME: Dispose of the connection identifier. + return; + } + + m_client->didFinishLaunching(this, identifier); +} + +void ProcessLauncher::invalidate() +{ + m_client = 0; + platformInvalidate(); +} + +const char* ProcessLauncher::processTypeAsString(ProcessType processType) +{ + switch (processType) { + case WebProcess: + return "webprocess"; + case PluginProcess: + return "pluginprocess"; + } + + ASSERT_NOT_REACHED(); + return 0; +} + +bool ProcessLauncher::getProcessTypeFromString(const char* string, ProcessType& processType) +{ + if (!strcmp(string, "webprocess")) { + processType = WebProcess; + return true; + } + + if (!strcmp(string, "pluginprocess")) { + processType = PluginProcess; + return true; + } + + return false; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/Launcher/ProcessLauncher.h b/Source/WebKit2/UIProcess/Launcher/ProcessLauncher.h new file mode 100644 index 000000000..8dbfb1101 --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/ProcessLauncher.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebProcessLauncher_h +#define WebProcessLauncher_h + +#include "Connection.h" +#include "PlatformProcessIdentifier.h" +#include <wtf/RefPtr.h> +#include <wtf/Threading.h> + +#if PLATFORM(QT) +class QLocalSocket; +#endif + +namespace WebKit { + +class ProcessLauncher : public ThreadSafeRefCounted<ProcessLauncher> { +public: + class Client { + public: + virtual ~Client() { } + + virtual void didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier) = 0; + }; + + enum ProcessType { + WebProcess, + PluginProcess + }; + + struct LaunchOptions { + ProcessType processType; +#if PLATFORM(MAC) + static const cpu_type_t MatchCurrentArchitecture = 0; + cpu_type_t architecture; + bool executableHeap; +#endif + }; + + static PassRefPtr<ProcessLauncher> create(Client* client, const LaunchOptions& launchOptions) + { + return adoptRef(new ProcessLauncher(client, launchOptions)); + } + + bool isLaunching() const { return m_isLaunching; } + PlatformProcessIdentifier processIdentifier() const { return m_processIdentifier; } + + void terminateProcess(); + void invalidate(); + + static bool getProcessTypeFromString(const char*, ProcessType&); + +private: + ProcessLauncher(Client*, const LaunchOptions& launchOptions); + + static const char* processTypeAsString(ProcessType); + + void launchProcess(); + void didFinishLaunchingProcess(PlatformProcessIdentifier, CoreIPC::Connection::Identifier); + + void platformInvalidate(); + + Client* m_client; + + const LaunchOptions m_launchOptions; + bool m_isLaunching; + PlatformProcessIdentifier m_processIdentifier; +}; + +} // namespace WebKit + +#endif // WebProcessLauncher_h diff --git a/Source/WebKit2/UIProcess/Launcher/ThreadLauncher.cpp b/Source/WebKit2/UIProcess/Launcher/ThreadLauncher.cpp new file mode 100644 index 000000000..3c0fbf160 --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/ThreadLauncher.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ThreadLauncher.h" + +#include "RunLoop.h" + +namespace WebKit { + +ThreadLauncher::ThreadLauncher(Client* client) + : m_client(client) +{ + launchThread(); +} + +void ThreadLauncher::launchThread() +{ + m_isLaunching = true; + + CoreIPC::Connection::Identifier connectionIdentifier = createWebThread(); + + // We've finished launching the thread, message back to the main run loop. + RunLoop::main()->dispatch(bind(&ThreadLauncher::didFinishLaunchingThread, this, connectionIdentifier)); +} + +void ThreadLauncher::didFinishLaunchingThread(CoreIPC::Connection::Identifier identifier) +{ + m_isLaunching = false; + + if (!m_client) { + // FIXME: Dispose of the connection identifier. + return; + } + + m_client->didFinishLaunching(this, identifier); +} + +void ThreadLauncher::invalidate() +{ + m_client = 0; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/Launcher/ThreadLauncher.h b/Source/WebKit2/UIProcess/Launcher/ThreadLauncher.h new file mode 100644 index 000000000..f3a5312a2 --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/ThreadLauncher.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ThreadLauncher_h +#define ThreadLauncher_h + +#include "Connection.h" +#include "PlatformProcessIdentifier.h" +#include <wtf/RefPtr.h> +#include <wtf/Threading.h> + +#if PLATFORM(QT) +class QLocalSocket; +#endif + +namespace WebKit { + +class ThreadLauncher : public ThreadSafeRefCounted<ThreadLauncher> { +public: + class Client { + public: + virtual ~Client() { } + virtual void didFinishLaunching(ThreadLauncher*, CoreIPC::Connection::Identifier) = 0; + }; + + static PassRefPtr<ThreadLauncher> create(Client* client) + { + return adoptRef(new ThreadLauncher(client)); + } + + bool isLaunching() const { return m_isLaunching; } + + void invalidate(); + +private: + explicit ThreadLauncher(Client*); + + void launchThread(); + void didFinishLaunchingThread(CoreIPC::Connection::Identifier); + + static CoreIPC::Connection::Identifier createWebThread(); + + bool m_isLaunching; + Client* m_client; +}; + +} // namespace WebKit + +#endif // ThreadLauncher_h diff --git a/Source/WebKit2/UIProcess/Launcher/gtk/ProcessLauncherGtk.cpp b/Source/WebKit2/UIProcess/Launcher/gtk/ProcessLauncherGtk.cpp new file mode 100644 index 000000000..d7a50829d --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/gtk/ProcessLauncherGtk.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Portions Copyright (c) 2010 Motorola Mobility, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY MOTOROLA INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ProcessLauncher.h" + +#include "Connection.h" +#include "RunLoop.h" +#include <WebCore/FileSystem.h> +#include <WebCore/ResourceHandle.h> +#include <errno.h> +#if OS(LINUX) +#include <sys/prctl.h> +#endif +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> +#include <wtf/gobject/GOwnPtr.h> +#include <wtf/gobject/GlibUtilities.h> + +#ifdef SOCK_SEQPACKET +#define SOCKET_TYPE SOCK_SEQPACKET +#else +#define SOCKET_TYPE SOCK_STREAM +#endif + +using namespace WebCore; + +namespace WebKit { + +const char* gWebKitWebProcessName = "WebKitWebProcess"; +const char* gWebKitPluginProcessName = "WebKitPluginProcess"; + +static void childSetupFunction(gpointer userData) +{ + int socket = GPOINTER_TO_INT(userData); + close(socket); + +#if OS(LINUX) + // Kill child process when parent dies. + prctl(PR_SET_PDEATHSIG, SIGKILL); +#endif +} + +static void childFinishedFunction(GPid, gint status, gpointer userData) +{ + if (WIFEXITED(status) && !WEXITSTATUS(status)) + return; + + close(GPOINTER_TO_INT(userData)); +} + +static CString findWebKitProcess(const char* processName) +{ + const char* execDirectory = g_getenv("WEBKIT_EXEC_PATH"); + if (execDirectory) { + String processPath = pathByAppendingComponent(filenameToString(execDirectory), processName); + if (fileExists(processPath)) + return fileSystemRepresentation(processPath); + } + + static bool gotExecutablePath = false; + static String executablePath; + if (!gotExecutablePath) { + gotExecutablePath = true; + + CString executableFile = getCurrentExecutablePath(); + if (!executableFile.isNull()) + executablePath = directoryName(filenameToString(executableFile.data())); + } + + if (!executablePath.isNull()) { + String processPath = pathByAppendingComponent(executablePath, processName); + if (fileExists(processPath)) + return fileSystemRepresentation(processPath); + } + + return fileSystemRepresentation(pathByAppendingComponent(filenameToString(LIBEXECDIR), processName)); +} + +void ProcessLauncher::launchProcess() +{ + GPid pid = 0; + + int sockets[2]; + if (socketpair(AF_UNIX, SOCKET_TYPE, 0, sockets) < 0) { + g_printerr("Creation of socket failed: %s.\n", g_strerror(errno)); + ASSERT_NOT_REACHED(); + return; + } + + CString binaryPath = findWebKitProcess(m_launchOptions.processType == ProcessLauncher::WebProcess ? gWebKitWebProcessName : gWebKitPluginProcessName); + GOwnPtr<gchar> socket(g_strdup_printf("%d", sockets[0])); + char* argv[3]; + argv[0] = const_cast<char*>(binaryPath.data()); + argv[1] = socket.get(); + argv[2] = 0; + + GOwnPtr<GError> error; + int spawnFlags = G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_DO_NOT_REAP_CHILD; + if (!g_spawn_async(0, argv, 0, static_cast<GSpawnFlags>(spawnFlags), childSetupFunction, GINT_TO_POINTER(sockets[1]), &pid, &error.outPtr())) { + g_printerr("Unable to fork a new WebProcess: %s.\n", error->message); + ASSERT_NOT_REACHED(); + } + + close(sockets[0]); + m_processIdentifier = pid; + + // Monitor the child process, it calls waitpid to prevent the child process from becomming a zombie, + // and it allows us to close the socket when the child process crashes. + g_child_watch_add(m_processIdentifier, childFinishedFunction, GINT_TO_POINTER(sockets[1])); + + // We've finished launching the process, message back to the main run loop. + RunLoop::main()->dispatch(bind(&ProcessLauncher::didFinishLaunchingProcess, this, m_processIdentifier, sockets[1])); +} + +void ProcessLauncher::terminateProcess() +{ + if (!m_processIdentifier) + return; + + kill(m_processIdentifier, SIGKILL); +} + +void ProcessLauncher::platformInvalidate() +{ +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/Launcher/gtk/ThreadLauncherGtk.cpp b/Source/WebKit2/UIProcess/Launcher/gtk/ThreadLauncherGtk.cpp new file mode 100644 index 000000000..84f72b54d --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/gtk/ThreadLauncherGtk.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Portions Copyright (c) 2010 Motorola Mobility, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ThreadLauncher.h" + +#include <WebCore/NotImplemented.h> + +namespace WebKit { + +CoreIPC::Connection::Identifier ThreadLauncher::createWebThread() +{ + notImplemented(); + return -1; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/Launcher/mac/DynamicLinkerEnvironmentExtractor.h b/Source/WebKit2/UIProcess/Launcher/mac/DynamicLinkerEnvironmentExtractor.h new file mode 100644 index 000000000..311e59087 --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/mac/DynamicLinkerEnvironmentExtractor.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DynamicLinkerEnvironmentExtractor_h +#define DynamicLinkerEnvironmentExtractor_h + +#ifndef BUILDING_ON_SNOW_LEOPARD + +#include <mach/machine.h> +#include <wtf/Noncopyable.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/CString.h> + +namespace WebKit { + +class EnvironmentVariables; + +class DynamicLinkerEnvironmentExtractor { + WTF_MAKE_NONCOPYABLE(DynamicLinkerEnvironmentExtractor); + +public: + DynamicLinkerEnvironmentExtractor(NSString *executablePath, cpu_type_t architecture); + + void getExtractedEnvironmentVariables(EnvironmentVariables&) const; + +private: + void processSingleArchitecture(const void* data, size_t length); + void processFatFile(const void* data, size_t length); + void processLoadCommands(const void* data, size_t length, int32_t numberOfCommands, bool shouldByteSwap); + size_t processLoadCommand(const void* data, size_t length, bool shouldByteSwap); + void processEnvironmentVariable(const char* environmentString); + + RetainPtr<NSString> m_executablePath; + cpu_type_t m_architecture; + + Vector<std::pair<CString, CString> > m_extractedVariables; +}; + +} // namespace WebKit + +#endif // BUILDING_ON_SNOW_LEOPARD + +#endif // DynamicLinkerEnvironmentExtractor_h diff --git a/Source/WebKit2/UIProcess/Launcher/mac/DynamicLinkerEnvironmentExtractor.mm b/Source/WebKit2/UIProcess/Launcher/mac/DynamicLinkerEnvironmentExtractor.mm new file mode 100644 index 000000000..70dccc58a --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/mac/DynamicLinkerEnvironmentExtractor.mm @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DynamicLinkerEnvironmentExtractor.h" + +#ifndef BUILDING_ON_SNOW_LEOPARD + +#include "EnvironmentVariables.h" +#include <mach-o/loader.h> +#include <mach-o/swap.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/text/WTFString.h> + +namespace WebKit { + +DynamicLinkerEnvironmentExtractor::DynamicLinkerEnvironmentExtractor(NSString *executablePath, cpu_type_t architecture) + : m_executablePath(executablePath) + , m_architecture(architecture) +{ + NSData *mainExecutableData = [NSData dataWithContentsOfFile:m_executablePath.get() options:NSDataReadingMappedIfSafe error:0]; + if (!mainExecutableData) + return; + + const void* mainExecutableBytes = [mainExecutableData bytes]; + size_t length = [mainExecutableData length]; + if (length < sizeof(uint32_t)) + return; + + uint32_t magicValue = *static_cast<const uint32_t*>(mainExecutableBytes); + if (magicValue == FAT_MAGIC || magicValue == FAT_CIGAM) { + processFatFile(mainExecutableBytes, length); + return; + } + + processSingleArchitecture(mainExecutableBytes, length); +} + +#define DEFINE_BYTE_SWAPPER(type) inline type byteSwapIfNeeded(const type& data, bool shouldByteSwap) \ +{ \ + type swapped = data; \ + if (shouldByteSwap) \ + swap_##type(&swapped, NX_UnknownByteOrder); \ + return swapped; \ +} + +DEFINE_BYTE_SWAPPER(load_command) +DEFINE_BYTE_SWAPPER(dylinker_command) +DEFINE_BYTE_SWAPPER(mach_header) +DEFINE_BYTE_SWAPPER(mach_header_64) + +#undef DEFINE_BYTE_SWAPPER + +void DynamicLinkerEnvironmentExtractor::processEnvironmentVariable(const char* environmentString) +{ + const char* equalsLocation = strchr(environmentString, '='); + if (!equalsLocation) + return; + + size_t nameLength = equalsLocation - environmentString; + String name(environmentString, nameLength); + + // LC_DYLD_ENVIRONMENT only respects DYLD_*_PATH variables. + if (!name.startsWith("DYLD_") || !name.endsWith("_PATH")) + return; + + CString value(equalsLocation + 1); + m_extractedVariables.append(make_pair(name.latin1(), value)); +} + +size_t DynamicLinkerEnvironmentExtractor::processLoadCommand(const void* data, size_t length, bool shouldByteSwap) +{ + if (length < sizeof(load_command)) + return 0; + + const load_command* rawLoadCommand = static_cast<const load_command*>(data); + load_command loadCommand = byteSwapIfNeeded(*rawLoadCommand, shouldByteSwap); + + if (length < loadCommand.cmdsize) + return 0; + + if (loadCommand.cmd == LC_DYLD_ENVIRONMENT) { + if (length < sizeof(dylinker_command)) + return 0; + + dylinker_command environmentCommand = byteSwapIfNeeded(*reinterpret_cast<const dylinker_command*>(rawLoadCommand), shouldByteSwap); + if (loadCommand.cmdsize < environmentCommand.name.offset) + return 0; + + size_t environmentStringLength = loadCommand.cmdsize - environmentCommand.name.offset; + Vector<char, 256> environmentString; + environmentString.reserveCapacity(environmentStringLength + 1); + environmentString.append(reinterpret_cast<const char*>(rawLoadCommand) + environmentCommand.name.offset, environmentStringLength); + environmentString.append(0); + + processEnvironmentVariable(environmentString.data()); + } + + return loadCommand.cmdsize; +} + +void DynamicLinkerEnvironmentExtractor::processLoadCommands(const void* data, size_t length, int32_t numberOfCommands, bool shouldByteSwap) +{ + const void* dataRemaining = data; + size_t lengthRemaining = length; + for (int i = 0; i < numberOfCommands; i++) { + size_t commandLength = processLoadCommand(dataRemaining, lengthRemaining, shouldByteSwap); + if (!commandLength || lengthRemaining < commandLength) + return; + + dataRemaining = static_cast<const char*>(dataRemaining) + commandLength; + lengthRemaining -= commandLength; + } +} + +void DynamicLinkerEnvironmentExtractor::processSingleArchitecture(const void* data, size_t length) +{ + if (length < sizeof(mach_header)) + return; + + const mach_header* header = static_cast<const mach_header*>(data); + if (header->magic == MH_MAGIC || header->magic == MH_CIGAM) { + bool shouldByteSwap = header->magic == MH_CIGAM; + mach_header swappedHeader = byteSwapIfNeeded(*header, shouldByteSwap); + if (swappedHeader.cputype == m_architecture) + processLoadCommands(static_cast<const char*>(data) + sizeof(*header), length - sizeof(*header), swappedHeader.ncmds, shouldByteSwap); + return; + } + + if (length < sizeof(mach_header_64)) + return; + + const mach_header_64* header64 = static_cast<const mach_header_64*>(data); + bool shouldByteSwap = header->magic == MH_CIGAM_64; + mach_header_64 swappedHeader64 = byteSwapIfNeeded(*header64, shouldByteSwap); + if (swappedHeader64.cputype == m_architecture) + processLoadCommands(static_cast<const char*>(data) + sizeof(*header64), length - sizeof(*header64), swappedHeader64.ncmds, shouldByteSwap); +} + +void DynamicLinkerEnvironmentExtractor::processFatFile(const void* data, size_t length) +{ + if (length < sizeof(fat_header)) + return; + + const fat_header* header = static_cast<const fat_header*>(data); + + size_t numberOfArchitectures = OSSwapBigToHostInt32(header->nfat_arch); + + // Ensure that we have enough data remaining for numberOfArchitectures fat_arch structs. + if ((length - sizeof(fat_header)) / sizeof(fat_arch) < numberOfArchitectures) + return; + + const fat_arch* archs = reinterpret_cast<const fat_arch*>(reinterpret_cast<const char*>(data) + sizeof(*header)); + for (uint32_t i = 0; i < numberOfArchitectures; i++) { + uint32_t architectureOffset = OSSwapBigToHostInt32(archs[i].offset); + uint32_t architectureSize = OSSwapBigToHostInt32(archs[i].size); + if (length < architectureOffset + architectureSize) + return; + + processSingleArchitecture(static_cast<const char*>(data) + architectureOffset, architectureSize); + } +} + +void DynamicLinkerEnvironmentExtractor::getExtractedEnvironmentVariables(EnvironmentVariables& environmentVariables) const +{ + size_t extractedVariableCount = m_extractedVariables.size(); + for (size_t i = 0; i < extractedVariableCount; ++i) { + const CString& name = m_extractedVariables[i].first; + + // Preserve any existing environment variable by this name so that it will take + // precedence over what we extracted from the executable file. + if (environmentVariables.get(name.data())) + continue; + + environmentVariables.set(name.data(), m_extractedVariables[i].second.data()); + } +} + +} // namespace WebKit + +#endif // BUILDING_ON_SNOW_LEOPARD diff --git a/Source/WebKit2/UIProcess/Launcher/mac/EnvironmentVariables.cpp b/Source/WebKit2/UIProcess/Launcher/mac/EnvironmentVariables.cpp new file mode 100644 index 000000000..72979f8f7 --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/mac/EnvironmentVariables.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "EnvironmentVariables.h" + +#include <crt_externs.h> + +namespace WebKit { + +EnvironmentVariables::EnvironmentVariables() + : m_environmentPointer(*_NSGetEnviron()) +{ +} + +EnvironmentVariables::~EnvironmentVariables() +{ + size_t size = m_allocatedStrings.size(); + for (size_t i = 0; i < size; ++i) + fastFree(m_allocatedStrings[i]); +} + +void EnvironmentVariables::set(const char* name, const char* value) +{ + // Check if we need to copy the environment. + if (m_environmentPointer == *_NSGetEnviron()) + copyEnvironmentVariables(); + + // Allocate a string for the name and value. + const char* nameAndValue = createStringForVariable(name, value); + + for (size_t i = 0; i < m_environmentVariables.size() - 1; ++i) { + if (valueIfVariableHasName(m_environmentVariables[i], name)) { + // Just replace the environment variable. + m_environmentVariables[i] = const_cast<char*>(nameAndValue); + return; + } + } + + // Append the new string. + ASSERT(!m_environmentVariables.last()); + m_environmentVariables.last() = const_cast<char*>(nameAndValue); + m_environmentVariables.append(static_cast<char*>(0)); + + m_environmentPointer = m_environmentVariables.data(); +} + +const char* EnvironmentVariables::get(const char* name) const +{ + for (size_t i = 0; m_environmentPointer[i]; ++i) { + if (const char* value = valueIfVariableHasName(m_environmentPointer[i], name)) + return value; + } + return 0; +} + +void EnvironmentVariables::appendValue(const char* name, const char* value, char separator) +{ + const char* existingValue = get(name); + if (!existingValue) { + set(name, value); + return; + } + + Vector<char, 128> newValue; + newValue.append(existingValue, strlen(existingValue)); + newValue.append(separator); + newValue.append(value, strlen(value) + 1); + + set(name, newValue.data()); +} + +const char* EnvironmentVariables::valueIfVariableHasName(const char* environmentVariable, const char* name) const +{ + // Find the environment variable name. + const char* equalsLocation = strchr(environmentVariable, '='); + ASSERT(equalsLocation); + + size_t nameLength = equalsLocation - environmentVariable; + if (strlen(name) != nameLength) + return 0; + if (memcmp(environmentVariable, name, nameLength)) + return 0; + + return equalsLocation + 1; +} + +const char* EnvironmentVariables::createStringForVariable(const char* name, const char* value) +{ + int nameLength = strlen(name); + int valueLength = strlen(value); + + // Allocate enough room to hold 'name=value' and the null character. + char* string = static_cast<char*>(fastMalloc(nameLength + 1 + valueLength + 1)); + memcpy(string, name, nameLength); + string[nameLength] = '='; + memcpy(string + nameLength + 1, value, valueLength); + string[nameLength + 1 + valueLength] = '\0'; + + m_allocatedStrings.append(string); + + return string; +} + +void EnvironmentVariables::copyEnvironmentVariables() +{ + for (size_t i = 0; (*_NSGetEnviron())[i]; i++) + m_environmentVariables.append((*_NSGetEnviron())[i]); + + // Null-terminate the array. + m_environmentVariables.append(static_cast<char*>(0)); + + // Update the environment pointer. + m_environmentPointer = m_environmentVariables.data(); +} + +#if !defined(BUILDING_ON_SNOW_LEOPARD) + +const char* EnvironmentVariables::preexistingProcessServiceNameKey() +{ + return "WEBKIT_PREEXISTING_PROCESS_SERVICE_NAME"; +} + +const char* EnvironmentVariables::preexistingProcessTypeKey() +{ + return "WEBKIT_PREEXISTING_PROCESS_TYPE"; +} + +#endif // !defined(BUILDING_ON_SNOW_LEOPARD) + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/Launcher/mac/EnvironmentVariables.h b/Source/WebKit2/UIProcess/Launcher/mac/EnvironmentVariables.h new file mode 100644 index 000000000..33829398d --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/mac/EnvironmentVariables.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EnvironmentVariables_h +#define EnvironmentVariables_h + +#include <wtf/Noncopyable.h> +#include <wtf/Vector.h> + +namespace WebKit { + +class EnvironmentVariables { + WTF_MAKE_NONCOPYABLE(EnvironmentVariables); + +public: + EnvironmentVariables(); + ~EnvironmentVariables(); + + void set(const char* name, const char* value); + const char* get(const char* name) const; + + // Will append the value with the given separator if the environment variable already exists. + void appendValue(const char* name, const char* value, char separator); + + char** environmentPointer() const { return m_environmentPointer; } + +#if !defined(BUILDING_ON_SNOW_LEOPARD) + static const char* preexistingProcessServiceNameKey(); + static const char* preexistingProcessTypeKey(); +#endif + +private: + const char* valueIfVariableHasName(const char* environmentVariable, const char* name) const; + const char* createStringForVariable(const char* name, const char* value); + void copyEnvironmentVariables(); + + char** m_environmentPointer; + Vector<char*> m_environmentVariables; + + // These allocated strings will be freed in the destructor. + Vector<char*> m_allocatedStrings; +}; + +} // namespace WebKit + +#endif // EnvironmentVariables_h diff --git a/Source/WebKit2/UIProcess/Launcher/mac/ProcessLauncherMac.mm b/Source/WebKit2/UIProcess/Launcher/mac/ProcessLauncherMac.mm new file mode 100644 index 000000000..c70f62edf --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/mac/ProcessLauncherMac.mm @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "ProcessLauncher.h" + +#import "DynamicLinkerEnvironmentExtractor.h" +#import "EnvironmentVariables.h" +#import "RunLoop.h" +#import "WebProcess.h" +#import "WebKitSystemInterface.h" +#import <crt_externs.h> +#import <mach-o/dyld.h> +#import <mach/machine.h> +#import <runtime/InitializeThreading.h> +#import <servers/bootstrap.h> +#import <spawn.h> +#import <sys/param.h> +#import <sys/stat.h> +#import <wtf/PassRefPtr.h> +#import <wtf/RetainPtr.h> +#import <wtf/Threading.h> +#import <wtf/text/CString.h> +#import <wtf/text/WTFString.h> + +using namespace WebCore; + +// FIXME: We should be doing this another way. +extern "C" kern_return_t bootstrap_register2(mach_port_t, name_t, mach_port_t, uint64_t); + +namespace WebKit { + +static void setUpTerminationNotificationHandler(pid_t pid) +{ +#if HAVE(DISPATCH_H) + dispatch_source_t processDiedSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, dispatch_get_current_queue()); + dispatch_source_set_event_handler(processDiedSource, ^{ + int status; + waitpid(dispatch_source_get_handle(processDiedSource), &status, 0); + dispatch_source_cancel(processDiedSource); + }); + dispatch_source_set_cancel_handler(processDiedSource, ^{ + dispatch_release(processDiedSource); + }); + dispatch_resume(processDiedSource); +#endif +} + +void ProcessLauncher::launchProcess() +{ + // Create the listening port. + mach_port_t listeningPort; + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort); + + // Insert a send right so we can send to it. + mach_port_insert_right(mach_task_self(), listeningPort, listeningPort, MACH_MSG_TYPE_MAKE_SEND); + + pid_t processIdentifier = 0; + + EnvironmentVariables environmentVariables; +#if !defined(BUILDING_ON_SNOW_LEOPARD) + static const char* preexistingProcessServiceName = environmentVariables.get(EnvironmentVariables::preexistingProcessServiceNameKey()); + ProcessType preexistingProcessType; + if (preexistingProcessServiceName) + getProcessTypeFromString(environmentVariables.get(EnvironmentVariables::preexistingProcessTypeKey()), preexistingProcessType); + + bool usePreexistingProcess = preexistingProcessServiceName && preexistingProcessType == m_launchOptions.processType; + + if (usePreexistingProcess) { + mach_port_t lookupPort; + bootstrap_look_up(bootstrap_port, preexistingProcessServiceName, &lookupPort); + + mach_msg_header_t header; + header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND); + header.msgh_id = 0; + header.msgh_local_port = listeningPort; + header.msgh_remote_port = lookupPort; + header.msgh_size = sizeof(header); + kern_return_t kr = mach_msg(&header, MACH_SEND_MSG, sizeof(header), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + + if (kr) { + LOG_ERROR("Failed to pick up preexisting process at %s (%x). Launching a new process of type %s instead.", preexistingProcessServiceName, kr, processTypeAsString(m_launchOptions.processType)); + usePreexistingProcess = false; + } + + mach_port_deallocate(mach_task_self(), lookupPort); + + preexistingProcessServiceName = 0; + } + + if (!usePreexistingProcess) { +#endif + NSBundle *webKit2Bundle = [NSBundle bundleWithIdentifier:@"com.apple.WebKit2"]; + NSString *frameworksPath = [[webKit2Bundle bundlePath] stringByDeletingLastPathComponent]; + const char* frameworkExecutablePath = [[webKit2Bundle executablePath] fileSystemRepresentation]; + + NSString *processPath; + if (m_launchOptions.processType == ProcessLauncher::PluginProcess) + processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"PluginProcess.app"]; + else + processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"WebProcess.app"]; + + NSString *processAppExecutablePath = [[NSBundle bundleWithPath:processPath] executablePath]; + + RetainPtr<CFStringRef> cfLocalization(AdoptCF, WKCopyCFLocalizationPreferredName(NULL)); + CString localization = String(cfLocalization.get()).utf8(); + + // Make a unique, per pid, per process launcher web process service name. + CString serviceName = String::format("com.apple.WebKit.WebProcess-%d-%p", getpid(), this).utf8(); + + const char* args[] = { [processAppExecutablePath fileSystemRepresentation], frameworkExecutablePath, "-type", processTypeAsString(m_launchOptions.processType), "-servicename", serviceName.data(), "-localization", localization.data(), 0 }; + + // Register ourselves. + kern_return_t kr = bootstrap_register2(bootstrap_port, const_cast<char*>(serviceName.data()), listeningPort, 0); + ASSERT_UNUSED(kr, kr == KERN_SUCCESS); + + posix_spawnattr_t attr; + posix_spawnattr_init(&attr); + + short flags = 0; + + // We want our process to receive all signals. + sigset_t signalMaskSet; + sigemptyset(&signalMaskSet); + + posix_spawnattr_setsigmask(&attr, &signalMaskSet); + flags |= POSIX_SPAWN_SETSIGMASK; + + // Determine the architecture to use. + cpu_type_t architecture = m_launchOptions.architecture; + if (architecture == LaunchOptions::MatchCurrentArchitecture) + architecture = _NSGetMachExecuteHeader()->cputype; + + cpu_type_t cpuTypes[] = { architecture }; + size_t outCount = 0; + posix_spawnattr_setbinpref_np(&attr, 1, cpuTypes, &outCount); + + // Start suspended so we can set up the termination notification handler. + flags |= POSIX_SPAWN_START_SUSPENDED; + +#ifndef BUILDING_ON_SNOW_LEOPARD + static const int allowExecutableHeapFlag = 0x2000; + if (m_launchOptions.executableHeap) + flags |= allowExecutableHeapFlag; +#endif + + posix_spawnattr_setflags(&attr, flags); + +#ifndef BUILDING_ON_SNOW_LEOPARD + DynamicLinkerEnvironmentExtractor environmentExtractor([[NSBundle mainBundle] executablePath], architecture); + environmentExtractor.getExtractedEnvironmentVariables(environmentVariables); +#endif + + // To make engineering builds work, if the path is outside of /System set up + // DYLD_FRAMEWORK_PATH to pick up other frameworks, but don't do it for the + // production configuration because it involves extra file system access. + if (![frameworksPath hasPrefix:@"/System/"]) + environmentVariables.appendValue("DYLD_FRAMEWORK_PATH", [frameworksPath fileSystemRepresentation], ':'); + + NSString *processShimPathNSString = nil; + if (m_launchOptions.processType == ProcessLauncher::PluginProcess) + processShimPathNSString = [[processAppExecutablePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"PluginProcessShim.dylib"]; + else if (m_launchOptions.processType == ProcessLauncher::WebProcess) + processShimPathNSString = [[processAppExecutablePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"WebProcessShim.dylib"]; + + // Make sure that the shim library file exists and insert it. + if (processShimPathNSString) { + const char* processShimPath = [processShimPathNSString fileSystemRepresentation]; + struct stat statBuf; + if (stat(processShimPath, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFREG) + environmentVariables.appendValue("DYLD_INSERT_LIBRARIES", processShimPath, ':'); + } + + int result = posix_spawn(&processIdentifier, args[0], 0, &attr, const_cast<char**>(args), environmentVariables.environmentPointer()); + + posix_spawnattr_destroy(&attr); + + if (!result) { + // Set up the termination notification handler and then ask the child process to continue. + setUpTerminationNotificationHandler(processIdentifier); + kill(processIdentifier, SIGCONT); + } else { + // We failed to launch. Release the send right. + mach_port_deallocate(mach_task_self(), listeningPort); + + // And the receive right. + mach_port_mod_refs(mach_task_self(), listeningPort, MACH_PORT_RIGHT_RECEIVE, -1); + + listeningPort = MACH_PORT_NULL; + processIdentifier = 0; + } +#if !defined(BUILDING_ON_SNOW_LEOPARD) + } +#endif + + // We've finished launching the process, message back to the main run loop. + RunLoop::main()->dispatch(bind(&ProcessLauncher::didFinishLaunchingProcess, this, processIdentifier, listeningPort)); +} + +void ProcessLauncher::terminateProcess() +{ + if (!m_processIdentifier) + return; + + kill(m_processIdentifier, SIGKILL); +} + +void ProcessLauncher::platformInvalidate() +{ +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/Launcher/mac/ThreadLauncherMac.mm b/Source/WebKit2/UIProcess/Launcher/mac/ThreadLauncherMac.mm new file mode 100644 index 000000000..1c74b7d28 --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/mac/ThreadLauncherMac.mm @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "ThreadLauncher.h" + +#import "RunLoop.h" +#import "WebProcess.h" +#import "WebSystemInterface.h" +#import <runtime/InitializeThreading.h> +#import <wtf/MainThread.h> +#import <wtf/Threading.h> + +namespace WebKit { + +static void* webThreadBody(void* context) +{ + mach_port_t serverPort = static_cast<mach_port_t>(reinterpret_cast<uintptr_t>(context)); + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + InitWebCoreSystemInterface(); + JSC::initializeThreading(); + WTF::initializeMainThread(); + + WebProcess::shared().initialize(serverPort, RunLoop::current()); + + [pool drain]; + + RunLoop::current()->run(); + + return 0; +} + +CoreIPC::Connection::Identifier ThreadLauncher::createWebThread() +{ + // Create the service port. + mach_port_t listeningPort; + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort); + + // Insert a send right so we can send to it. + mach_port_insert_right(mach_task_self(), listeningPort, listeningPort, MACH_MSG_TYPE_MAKE_SEND); + + if (!createThread(webThreadBody, reinterpret_cast<void*>(listeningPort), "WebKit2: WebThread")) { + mach_port_destroy(mach_task_self(), listeningPort); + return MACH_PORT_NULL; + } + + return listeningPort; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/Launcher/qt/ProcessLauncherQt.cpp b/Source/WebKit2/UIProcess/Launcher/qt/ProcessLauncherQt.cpp new file mode 100644 index 000000000..837f59baf --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/qt/ProcessLauncherQt.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ProcessLauncher.h" + +#include "Connection.h" +#include "RunLoop.h" +#include "WebProcess.h" +#include <QCoreApplication> +#include <QDebug> +#include <QFile> +#include <QLocalServer> +#include <QMetaType> +#include <QProcess> +#include <QString> +#include <QtCore/qglobal.h> +#include <WebCore/NotImplemented.h> +#include <errno.h> +#include <fcntl.h> +#include <runtime/InitializeThreading.h> +#include <string> +#include <sys/resource.h> +#include <sys/socket.h> +#include <unistd.h> +#include <wtf/HashSet.h> +#include <wtf/PassRefPtr.h> +#include <wtf/Threading.h> +#include <wtf/text/WTFString.h> +#if defined(Q_OS_LINUX) +#include <sys/prctl.h> +#include <signal.h> +#endif + +#if OS(DARWIN) +#include <mach/mach_init.h> +#include <servers/bootstrap.h> + +extern "C" kern_return_t bootstrap_register2(mach_port_t, name_t, mach_port_t, uint64_t); +#endif + +#if defined(SOCK_SEQPACKET) && !defined(Q_OS_MACX) +#define SOCKET_TYPE SOCK_SEQPACKET +#else +#define SOCKET_TYPE SOCK_DGRAM +#endif + +using namespace WebCore; + +namespace WebKit { + +class QtWebProcess : public QProcess +{ + Q_OBJECT +public: + QtWebProcess(QObject* parent = 0) + : QProcess(parent) + { + } + +protected: + virtual void setupChildProcess(); +}; + +void QtWebProcess::setupChildProcess() +{ +#if defined(Q_OS_LINUX) +#ifndef NDEBUG + if (qgetenv("QT_WEBKIT2_DEBUG") == "1") + return; +#endif + prctl(PR_SET_PDEATHSIG, SIGKILL); +#endif +#if defined(Q_OS_MACX) + qputenv("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM", QByteArray("1")); +#endif +} + +void ProcessLauncher::launchProcess() +{ + QString applicationPath = QLatin1String("%1 %2"); + + if (QFile::exists(QCoreApplication::applicationDirPath() + QLatin1String("/QtWebProcess"))) { + applicationPath = applicationPath.arg(QCoreApplication::applicationDirPath() + QLatin1String("/QtWebProcess")); + } else { + applicationPath = applicationPath.arg(QLatin1String("QtWebProcess")); + } + +#if OS(DARWIN) + // Create the listening port. + mach_port_t connector; + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &connector); + + // Insert a send right so we can send to it. + mach_port_insert_right(mach_task_self(), connector, connector, MACH_MSG_TYPE_MAKE_SEND); + + // Register port with a service name to the system. + QString serviceName = QString("com.nokia.Qt.WebKit.QtWebProcess-%1-%2"); + serviceName = serviceName.arg(QString().setNum(getpid()), QString().setNum((size_t)this)); + kern_return_t kr = bootstrap_register2(bootstrap_port, const_cast<char*>(serviceName.toUtf8().data()), connector, 0); + ASSERT_UNUSED(kr, kr == KERN_SUCCESS); + + QString program(applicationPath.arg(serviceName)); +#else + int sockets[2]; + if (socketpair(AF_UNIX, SOCKET_TYPE, 0, sockets) == -1) { + qDebug() << "Creation of socket failed with errno:" << errno; + ASSERT_NOT_REACHED(); + return; + } + + // Don't expose the ui socket to the web process + while (fcntl(sockets[1], F_SETFD, FD_CLOEXEC) == -1) { + if (errno != EINTR) { + ASSERT_NOT_REACHED(); + while (close(sockets[0]) == -1 && errno == EINTR) { } + while (close(sockets[1]) == -1 && errno == EINTR) { } + return; + } + } + + int connector = sockets[1]; + QString program(applicationPath.arg(sockets[0])); +#endif + + QProcess* webProcess = new QtWebProcess(); + webProcess->setProcessChannelMode(QProcess::ForwardedChannels); + webProcess->start(program); + +#if !OS(DARWIN) + // Don't expose the web socket to possible future web processes + while (fcntl(sockets[0], F_SETFD, FD_CLOEXEC) == -1) { + if (errno != EINTR) { + ASSERT_NOT_REACHED(); + delete webProcess; + return; + } + } +#endif + + if (!webProcess->waitForStarted()) { + qDebug() << "Failed to start" << program; + ASSERT_NOT_REACHED(); +#if OS(DARWIN) + mach_port_deallocate(mach_task_self(), connector); + mach_port_mod_refs(mach_task_self(), connector, MACH_PORT_RIGHT_RECEIVE, -1); +#endif + delete webProcess; + return; + } + + setpriority(PRIO_PROCESS, webProcess->pid(), 10); + + RunLoop::main()->dispatch(bind(&WebKit::ProcessLauncher::didFinishLaunchingProcess, this, webProcess, connector)); +} + +void ProcessLauncher::terminateProcess() +{ + if (!m_processIdentifier) + return; + + QObject::connect(m_processIdentifier, SIGNAL(finished(int)), m_processIdentifier, SLOT(deleteLater()), Qt::QueuedConnection); + m_processIdentifier->terminate(); +} + +void ProcessLauncher::platformInvalidate() +{ + +} + +} // namespace WebKit + +#include "ProcessLauncherQt.moc" diff --git a/Source/WebKit2/UIProcess/Launcher/qt/ThreadLauncherQt.cpp b/Source/WebKit2/UIProcess/Launcher/qt/ThreadLauncherQt.cpp new file mode 100644 index 000000000..7b95ca049 --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/qt/ThreadLauncherQt.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ThreadLauncher.h" + +#include "RunLoop.h" +#include "WebProcess.h" +#include <runtime/InitializeThreading.h> +#include <wtf/MainThread.h> +#include <wtf/Threading.h> + +#include <QDebug> +#include <QFile> +#include <QLocalServer> +#include <QProcess> + +#include <QtCore/qglobal.h> + +#include <sys/resource.h> +#include <unistd.h> + +using namespace WebCore; + +namespace WebKit { + +static void* webThreadBody(void* /* context */) +{ + // Initialization + JSC::initializeThreading(); + WTF::initializeMainThread(); + + // FIXME: We do not support threaded mode for now. + + WebProcess::shared().initialize(-1, RunLoop::current()); + RunLoop::run(); + + return 0; +} + +CoreIPC::Connection::Identifier ThreadLauncher::createWebThread() +{ + srandom(time(0)); + int connectionIdentifier = random(); + + if (!createThread(webThreadBody, reinterpret_cast<void*>(connectionIdentifier), "WebKit2: WebThread")) { + qWarning() << "failed starting thread"; + return 0; + } + + return connectionIdentifier; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/Launcher/win/ProcessLauncherWin.cpp b/Source/WebKit2/UIProcess/Launcher/win/ProcessLauncherWin.cpp new file mode 100644 index 000000000..d526c0307 --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/win/ProcessLauncherWin.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ProcessLauncher.h" + +#include "Connection.h" +#include "RunLoop.h" +#include <shlwapi.h> +#include <wtf/text/WTFString.h> + +#ifdef DEBUG_ALL +const LPCWSTR webProcessName = L"WebKit2WebProcess_debug.exe"; +#else +const LPCWSTR webProcessName = L"WebKit2WebProcess.exe"; +#endif + +#ifdef DEBUG_ALL +const LPCWSTR webKitDLLName = L"WebKit_debug.dll"; +#else +const LPCWSTR webKitDLLName = L"WebKit.dll"; +#endif + +namespace WebKit { + +void ProcessLauncher::launchProcess() +{ + // First, create the server and client identifiers. + HANDLE serverIdentifier, clientIdentifier; + if (!CoreIPC::Connection::createServerAndClientIdentifiers(serverIdentifier, clientIdentifier)) { + // FIXME: What should we do here? + ASSERT_NOT_REACHED(); + } + + // Ensure that the child process inherits the client identifier. + ::SetHandleInformation(clientIdentifier, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); + + // To get the full file path to WebKit2WebProcess.exe, we fild the location of WebKit.dll, + // remove the last path component, and then append WebKit2WebProcess(_debug).exe. + HMODULE webKitModule = ::GetModuleHandleW(webKitDLLName); + ASSERT(webKitModule); + if (!webKitModule) + return; + + WCHAR pathStr[MAX_PATH]; + if (!::GetModuleFileNameW(webKitModule, pathStr, WTF_ARRAY_LENGTH(pathStr))) + return; + + ::PathRemoveFileSpecW(pathStr); + if (!::PathAppendW(pathStr, webProcessName)) + return; + + String commandLine(pathStr); + + // FIXME: It would be nice if we could just create a CommandLine object and output a command line vector from it. + Vector<UChar> commandLineVector; + append(commandLineVector, "\""); + append(commandLineVector, commandLine); + append(commandLineVector, "\""); + append(commandLineVector, " -type webprocess"); + append(commandLineVector, " -clientIdentifier "); + append(commandLineVector, String::number(reinterpret_cast<uintptr_t>(clientIdentifier))); + commandLineVector.append('\0'); + + STARTUPINFO startupInfo = { 0 }; + startupInfo.cb = sizeof(startupInfo); + PROCESS_INFORMATION processInformation = { 0 }; + BOOL result = ::CreateProcessW(0, commandLineVector.data(), 0, 0, true, 0, 0, 0, &startupInfo, &processInformation); + + // We can now close the client identifier handle. + ::CloseHandle(clientIdentifier); + + if (!result) { + // FIXME: What should we do here? + DWORD error = ::GetLastError(); + ASSERT_NOT_REACHED(); + } + + // Don't leak the thread handle. + ::CloseHandle(processInformation.hThread); + + // We've finished launching the process, message back to the run loop. + RunLoop::main()->dispatch(bind(&ProcessLauncher::didFinishLaunchingProcess, this, processInformation.hProcess, serverIdentifier)); +} + +void ProcessLauncher::terminateProcess() +{ + if (!m_processIdentifier) + return; + + ::TerminateProcess(m_processIdentifier, 0); +} + +void ProcessLauncher::platformInvalidate() +{ + if (!m_processIdentifier) + return; + + ::CloseHandle(m_processIdentifier); + m_processIdentifier = 0; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/Launcher/win/ThreadLauncherWin.cpp b/Source/WebKit2/UIProcess/Launcher/win/ThreadLauncherWin.cpp new file mode 100644 index 000000000..2596998ea --- /dev/null +++ b/Source/WebKit2/UIProcess/Launcher/win/ThreadLauncherWin.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ThreadLauncher.h" + +#include "RunLoop.h" +#include "WebProcess.h" +#include <runtime/InitializeThreading.h> +#include <wtf/MainThread.h> +#include <wtf/Threading.h> + +using namespace WebCore; + +namespace WebKit { + +static void* webThreadBody(void* context) +{ + HANDLE clientIdentifier = reinterpret_cast<HANDLE>(context); + + // Initialization + JSC::initializeThreading(); + WTF::initializeMainThread(); + + WebProcess::shared().initialize(clientIdentifier, RunLoop::current()); + RunLoop::run(); + + return 0; +} + +CoreIPC::Connection::Identifier ThreadLauncher::createWebThread() +{ + // First, create the server and client identifiers. + HANDLE serverIdentifier, clientIdentifier; + if (!CoreIPC::Connection::createServerAndClientIdentifiers(serverIdentifier, clientIdentifier)) { + // FIXME: What should we do here? + ASSERT_NOT_REACHED(); + } + + if (!createThread(webThreadBody, reinterpret_cast<void*>(clientIdentifier), "WebKit2: WebThread")) { + ::CloseHandle(serverIdentifier); + ::CloseHandle(clientIdentifier); + return 0; + } + + return serverIdentifier; +} + +} // namespace WebKit |