diff options
author | Ben Murdoch <benm@google.com> | 2011-05-13 16:23:25 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-05-16 11:35:02 +0100 |
commit | 65f03d4f644ce73618e5f4f50dd694b26f55ae12 (patch) | |
tree | f478babb801e720de7bfaee23443ffe029f58731 /Source/WebKit2/Platform | |
parent | 47de4a2fb7262c7ebdb9cd133ad2c54c187454d0 (diff) | |
download | external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.zip external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.gz external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.bz2 |
Merge WebKit at r75993: Initial merge by git.
Change-Id: I602bbdc3974787a3b0450456a30a7868286921c3
Diffstat (limited to 'Source/WebKit2/Platform')
58 files changed, 8500 insertions, 0 deletions
diff --git a/Source/WebKit2/Platform/CoreIPC/ArgumentCoder.h b/Source/WebKit2/Platform/CoreIPC/ArgumentCoder.h new file mode 100644 index 0000000..bd15f51 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/ArgumentCoder.h @@ -0,0 +1,50 @@ +/* + * 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 ArgumentCoder_h +#define ArgumentCoder_h + +#include <wtf/TypeTraits.h> + +namespace CoreIPC { + +class ArgumentDecoder; +class ArgumentEncoder; + +template<typename T> struct ArgumentCoder { + static void encode(ArgumentEncoder* encoder, const T& t) + { + t.encode(encoder); + } + + static bool decode(ArgumentDecoder* decoder, T& t) + { + return T::decode(decoder, t); + } +}; + +} + +#endif // ArgumentCoder_h diff --git a/Source/WebKit2/Platform/CoreIPC/ArgumentCoders.h b/Source/WebKit2/Platform/CoreIPC/ArgumentCoders.h new file mode 100644 index 0000000..1cc1a7d --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/ArgumentCoders.h @@ -0,0 +1,301 @@ +/* + * 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 SimpleArgumentCoder_h +#define SimpleArgumentCoder_h + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" +#include <utility> +#include <wtf/HashMap.h> +#include <wtf/TypeTraits.h> +#include <wtf/Vector.h> +#include <wtf/text/AtomicString.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +namespace CoreIPC { + +// An argument coder works on POD types +template<typename T> struct SimpleArgumentCoder { + static void encode(ArgumentEncoder* encoder, const T& t) + { + encoder->encodeBytes(reinterpret_cast<const uint8_t*>(&t), sizeof(T)); + } + static bool decode(ArgumentDecoder* decoder, T& t) + { + return decoder->decodeBytes(reinterpret_cast<uint8_t*>(&t), sizeof(T)); + } +}; + +template<typename T, typename U> struct ArgumentCoder<std::pair<T, U> > { + static void encode(ArgumentEncoder* encoder, const std::pair<T, U>& pair) + { + encoder->encode(pair.first); + encoder->encode(pair.second); + } + + static bool decode(ArgumentDecoder* decoder, std::pair<T, U>& pair) + { + T first; + if (!decoder->decode(first)) + return false; + + U second; + if (!decoder->decode(second)) + return false; + + pair.first = first; + pair.second = second; + return true; + } +}; + +template<bool fixedSizeElements, typename T> struct VectorArgumentCoder; + +template<typename T> struct VectorArgumentCoder<false, T> { + static void encode(ArgumentEncoder* encoder, const Vector<T>& vector) + { + encoder->encodeUInt64(vector.size()); + for (size_t i = 0; i < vector.size(); ++i) + encoder->encode(vector[i]); + } + + static bool decode(ArgumentDecoder* decoder, Vector<T>& vector) + { + uint64_t size; + if (!decoder->decodeUInt64(size)) + return false; + + Vector<T> tmp; + for (size_t i = 0; i < size; ++i) { + T element; + if (!decoder->decode(element)) + return false; + + tmp.append(element); + } + + tmp.shrinkToFit(); + vector.swap(tmp); + return true; + } +}; + +template<typename T> struct VectorArgumentCoder<true, T> { + static void encode(ArgumentEncoder* encoder, const Vector<T>& vector) + { + encoder->encodeUInt64(vector.size()); + // FIXME: If we could tell the encoder to align the buffer, we could just do an encodeBytes here. + for (size_t i = 0; i < vector.size(); ++i) + encoder->encode(vector[i]); + } + + static bool decode(ArgumentDecoder* decoder, Vector<T>& vector) + { + uint64_t size; + if (!decoder->decodeUInt64(size)) + return false; + + // Since we know the total size of the elements, we can allocate the vector in + // one fell swoop. Before allocating we must however make sure that the decoder buffer + // is big enough. + if (!decoder->bufferIsLargeEnoughToContain<T>(size)) { + decoder->markInvalid(); + return false; + } + + Vector<T> tmp; + tmp.reserveCapacity(size); + + for (size_t i = 0; i < size; ++i) { + T element; + if (!decoder->decode(element)) + return false; + + tmp.uncheckedAppend(element); + } + + vector.swap(tmp); + return true; + } +}; + +template<typename T> struct ArgumentCoder<Vector<T> > : VectorArgumentCoder<WTF::IsArithmetic<T>::value, T> { }; + +// Specialization for Vector<uint8_t> +template<> struct ArgumentCoder<Vector<uint8_t> > { + static void encode(ArgumentEncoder* encoder, const Vector<uint8_t>& vector) + { + encoder->encodeBytes(vector.data(), vector.size()); + } + + static bool decode(ArgumentDecoder* decoder, Vector<uint8_t>& vector) + { + return decoder->decodeBytes(vector); + } +}; + +template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg> struct ArgumentCoder<HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> > { + typedef HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> HashMapType; + + static void encode(ArgumentEncoder* encoder, const HashMapType& hashMap) + { + encoder->encodeUInt64(hashMap.size()); + for (typename HashMapType::const_iterator it = hashMap.begin(), end = hashMap.end(); it != end; ++it) + encoder->encode(*it); + } + + static bool decode(ArgumentDecoder* decoder, HashMapType& hashMap) + { + uint64_t hashMapSize; + if (!decoder->decode(hashMapSize)) + return false; + + HashMapType tempHashMap; + for (uint64_t i = 0; i < hashMapSize; ++i) { + KeyArg key; + MappedArg value; + if (!decoder->decode(key)) + return false; + if (!decoder->decode(value)) + return false; + + if (!tempHashMap.add(key, value).second) { + // The hash map already has the specified key, bail. + decoder->markInvalid(); + return false; + } + } + + hashMap.swap(tempHashMap); + return true; + } +}; + +template<> struct ArgumentCoder<CString> { + static void encode(ArgumentEncoder* encoder, const CString& string) + { + // Special case the null string. + if (string.isNull()) { + encoder->encodeUInt32(std::numeric_limits<uint32_t>::max()); + return; + } + + uint32_t length = string.length(); + encoder->encode(length); + encoder->encodeBytes(reinterpret_cast<const uint8_t*>(string.data()), length); + } + + static bool decode(ArgumentDecoder* decoder, CString& result) + { + uint32_t length; + if (!decoder->decode(length)) + return false; + + if (length == std::numeric_limits<uint32_t>::max()) { + // This is the null string. + result = CString(); + return true; + } + + // Before allocating the string, make sure that the decoder buffer is big enough. + if (!decoder->bufferIsLargeEnoughToContain<char>(length)) { + decoder->markInvalid(); + return false; + } + + char* buffer; + CString string = CString::newUninitialized(length, buffer); + if (!decoder->decodeBytes(reinterpret_cast<uint8_t*>(buffer), length)) + return false; + + result = string; + return true; + } +}; + +template<> struct ArgumentCoder<String> { + static void encode(ArgumentEncoder* encoder, const String& string) + { + // Special case the null string. + if (string.isNull()) { + encoder->encodeUInt32(std::numeric_limits<uint32_t>::max()); + return; + } + + uint32_t length = string.length(); + encoder->encode(length); + encoder->encodeBytes(reinterpret_cast<const uint8_t*>(string.characters()), length * sizeof(UChar)); + } + + static bool decode(ArgumentDecoder* decoder, String& result) + { + uint32_t length; + if (!decoder->decode(length)) + return false; + + if (length == std::numeric_limits<uint32_t>::max()) { + // This is the null string. + result = String(); + return true; + } + + // Before allocating the string, make sure that the decoder buffer is big enough. + if (!decoder->bufferIsLargeEnoughToContain<UChar>(length)) { + decoder->markInvalid(); + return false; + } + + UChar* buffer; + String string = String::createUninitialized(length, buffer); + if (!decoder->decodeBytes(reinterpret_cast<uint8_t*>(buffer), length * sizeof(UChar))) + return false; + + result = string; + return true; + } +}; + +template<> struct ArgumentCoder<AtomicString> { + static void encode(ArgumentEncoder* encoder, const AtomicString& atomicString) + { + encoder->encode(atomicString.string()); + } + + static bool decode(ArgumentDecoder* decoder, AtomicString& atomicString) + { + String string; + if (!decoder->decode(string)) + return false; + + atomicString = string; + return true; + } +}; + +} // namespace CoreIPC + +#endif // SimpleArgumentCoder_h diff --git a/Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.cpp b/Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.cpp new file mode 100644 index 0000000..336f72f --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.cpp @@ -0,0 +1,225 @@ +/* + * 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 "ArgumentDecoder.h" + +#include "DataReference.h" +#include <stdio.h> + +namespace CoreIPC { + +ArgumentDecoder::ArgumentDecoder(const uint8_t* buffer, size_t bufferSize) +{ + initialize(buffer, bufferSize); +} + +ArgumentDecoder::ArgumentDecoder(const uint8_t* buffer, size_t bufferSize, Deque<Attachment>& attachments) +{ + initialize(buffer, bufferSize); + + m_attachments.swap(attachments); +} + +ArgumentDecoder::~ArgumentDecoder() +{ + ASSERT(m_buffer); + fastFree(m_buffer); + // FIXME: We need to dispose of the mach ports in cases of failure. +} + +void ArgumentDecoder::initialize(const uint8_t* buffer, size_t bufferSize) +{ + m_buffer = static_cast<uint8_t*>(fastMalloc(bufferSize)); + m_bufferPos = m_buffer; + m_bufferEnd = m_buffer + bufferSize; + memcpy(m_buffer, buffer, bufferSize); + + // Decode the destination ID. + decodeUInt64(m_destinationID); +} + +static inline uint8_t* roundUpToAlignment(uint8_t* ptr, unsigned alignment) +{ + return (uint8_t*)(((uintptr_t)ptr + alignment - 1) & ~(uintptr_t)(alignment - 1)); +} + +bool ArgumentDecoder::alignBufferPosition(unsigned alignment, size_t size) +{ + uint8_t* buffer = roundUpToAlignment(m_bufferPos, alignment); + if (buffer + size > m_bufferEnd) { + // We've walked off the end of this buffer. + markInvalid(); + return false; + } + + m_bufferPos = buffer; + return true; +} + +bool ArgumentDecoder::bufferIsLargeEnoughToContain(unsigned alignment, size_t size) const +{ + return roundUpToAlignment(m_bufferPos, alignment) + size <= m_bufferEnd; +} + +bool ArgumentDecoder::decodeBytes(Vector<uint8_t>& buffer) +{ + uint64_t size; + if (!decodeUInt64(size)) + return false; + + if (!alignBufferPosition(1, size)) + return false; + + buffer.resize(size); + if (size > 0) + memcpy(&buffer[0], m_bufferPos, size); + m_bufferPos += size; + return true; +} + +bool ArgumentDecoder::decodeBytes(DataReference& dataReference) +{ + uint64_t size; + if (!decodeUInt64(size)) + return false; + + if (!alignBufferPosition(1, size)) + return false; + + uint8_t* data = m_bufferPos; + m_bufferPos += size; + + dataReference = DataReference(data, size); + return true; +} + +bool ArgumentDecoder::decodeBytes(uint8_t* buffer, size_t bufferSize) +{ + // FIXME: Decoding the size is not strictly necessary here since we know the size upfront. + uint64_t size; + if (!decodeUInt64(size)) + return false; + + ASSERT(size == bufferSize); + if (size != bufferSize) + return false; + + if (!alignBufferPosition(1, size)) + return false; + + memcpy(buffer, m_bufferPos, size); + m_bufferPos += size; + return true; +} + +bool ArgumentDecoder::decodeBool(bool& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<bool*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::decodeUInt32(uint32_t& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<uint32_t*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::decodeUInt64(uint64_t& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<uint64_t*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::decodeInt32(int32_t& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<uint32_t*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::decodeInt64(int64_t& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<uint64_t*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::decodeFloat(float& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<float*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::decodeDouble(double& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<double*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::removeAttachment(Attachment& attachment) +{ + if (m_attachments.isEmpty()) + return false; + + attachment = m_attachments.takeFirst(); + return true; +} + +#ifndef NDEBUG +void ArgumentDecoder::debug() +{ + printf("ArgumentDecoder::debug()\n"); + printf("Number of Attachments: %d\n", (int)m_attachments.size()); + printf("Size of buffer: %d\n", (int)(m_bufferEnd - m_buffer)); +} +#endif + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.h b/Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.h new file mode 100644 index 0000000..dcf67ad --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.h @@ -0,0 +1,161 @@ +/* + * 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 ArgumentDecoder_h +#define ArgumentDecoder_h + +#include "ArgumentCoder.h" +#include "Attachment.h" +#include <wtf/Deque.h> +#include <wtf/TypeTraits.h> +#include <wtf/Vector.h> + +namespace CoreIPC { + +class DataReference; + +class ArgumentDecoder { +public: + ArgumentDecoder(const uint8_t* buffer, size_t bufferSize); + ArgumentDecoder(const uint8_t* buffer, size_t bufferSize, Deque<Attachment>&); + ~ArgumentDecoder(); + + uint64_t destinationID() const { return m_destinationID; } + + bool isInvalid() const { return m_bufferPos > m_bufferEnd; } + void markInvalid() { m_bufferPos = m_bufferEnd + 1; } + + bool decodeBytes(Vector<uint8_t>&); + bool decodeBytes(uint8_t*, size_t); + + // The data in the data reference here will only be valid for the lifetime of the ArgumentDecoder object. + bool decodeBytes(DataReference&); + + bool decodeBool(bool&); + bool decodeUInt32(uint32_t&); + bool decodeUInt64(uint64_t&); + bool decodeInt32(int32_t&); + bool decodeInt64(int64_t&); + bool decodeFloat(float&); + bool decodeDouble(double&); + + template<typename T> bool decodeEnum(T& result) + { + COMPILE_ASSERT(sizeof(T) <= sizeof(uint64_t), enum_type_must_not_be_larger_than_64_bits); + + uint64_t value; + if (!decodeUInt64(value)) + return false; + + result = static_cast<T>(value); + return true; + } + + template<typename T> + bool bufferIsLargeEnoughToContain(size_t numElements) const + { + COMPILE_ASSERT(WTF::IsArithmetic<T>::value, type_must_have_known_encoded_size); + + if (numElements > std::numeric_limits<size_t>::max() / sizeof(T)) + return false; + + return bufferIsLargeEnoughToContain(__alignof(T), numElements * sizeof(T)); + } + + // Generic type decode function. + template<typename T> bool decode(T& t) + { + return ArgumentCoder<T>::decode(this, t); + } + + // This overload exists so we can pass temporaries to decode. In the Star Trek future, it + // can take an rvalue reference instead. + template<typename T> bool decode(const T& t) + { + return decode(const_cast<T&>(t)); + } + + bool removeAttachment(Attachment&); + +#ifndef NDEBUG + void debug(); +#endif + +private: + ArgumentDecoder(const ArgumentDecoder*); + ArgumentDecoder* operator=(const ArgumentDecoder*); + + void initialize(const uint8_t* buffer, size_t bufferSize); + + bool alignBufferPosition(unsigned alignment, size_t size); + bool bufferIsLargeEnoughToContain(unsigned alignment, size_t size) const; + + uint64_t m_destinationID; + + uint8_t* m_buffer; + uint8_t* m_bufferPos; + uint8_t* m_bufferEnd; + + Deque<Attachment> m_attachments; +}; + +template<> inline bool ArgumentDecoder::decode(bool& n) +{ + return decodeBool(n); +} + +template<> inline bool ArgumentDecoder::decode(uint32_t& n) +{ + return decodeUInt32(n); +} + +template<> inline bool ArgumentDecoder::decode(uint64_t& n) +{ + return decodeUInt64(n); +} + +template<> inline bool ArgumentDecoder::decode(int32_t& n) +{ + return decodeInt32(n); +} + +template<> inline bool ArgumentDecoder::decode(int64_t& n) +{ + return decodeInt64(n); +} + +template<> inline bool ArgumentDecoder::decode(float& n) +{ + return decodeFloat(n); +} + +template<> inline bool ArgumentDecoder::decode(double& n) +{ + return decodeDouble(n); +} + +} // namespace CoreIPC + +#endif // ArgumentDecoder_h diff --git a/Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.cpp b/Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.cpp new file mode 100644 index 0000000..1340c0a --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.cpp @@ -0,0 +1,162 @@ +/* + * 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 "ArgumentEncoder.h" + +#include <algorithm> +#include <stdio.h> + +namespace CoreIPC { + +PassOwnPtr<ArgumentEncoder> ArgumentEncoder::create(uint64_t destinationID) +{ + return adoptPtr(new ArgumentEncoder(destinationID)); +} + +ArgumentEncoder::ArgumentEncoder(uint64_t destinationID) + : m_buffer(0) + , m_bufferPointer(0) + , m_bufferSize(0) + , m_bufferCapacity(0) +{ + // Encode the destination ID. + encodeUInt64(destinationID); +} + +ArgumentEncoder::~ArgumentEncoder() +{ + if (m_buffer) + fastFree(m_buffer); + // FIXME: We need to dispose of the attachments in cases of failure. +} + +static inline size_t roundUpToAlignment(size_t value, unsigned alignment) +{ + return ((value + alignment - 1) / alignment) * alignment; +} + +uint8_t* ArgumentEncoder::grow(unsigned alignment, size_t size) +{ + size_t alignedSize = roundUpToAlignment(m_bufferSize, alignment); + + if (alignedSize + size > m_bufferCapacity) { + size_t newCapacity = std::max(alignedSize + size, std::max(static_cast<size_t>(32), m_bufferCapacity + m_bufferCapacity / 4 + 1)); + if (!m_buffer) + m_buffer = static_cast<uint8_t*>(fastMalloc(newCapacity)); + else + m_buffer = static_cast<uint8_t*>(fastRealloc(m_buffer, newCapacity)); + + // FIXME: What should we do if allocating memory fails? + + m_bufferCapacity = newCapacity; + } + + m_bufferSize = alignedSize + size; + m_bufferPointer = m_buffer + alignedSize + size; + + return m_buffer + alignedSize; +} + +void ArgumentEncoder::encodeBytes(const uint8_t* bytes, size_t size) +{ + // Encode the size. + encodeUInt64(static_cast<uint64_t>(size)); + + uint8_t* buffer = grow(1, size); + + memcpy(buffer, bytes, size); +} + +void ArgumentEncoder::encodeBool(bool n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<bool*>(buffer) = n; +} + +void ArgumentEncoder::encodeUInt32(uint32_t n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<uint32_t*>(buffer) = n; +} + +void ArgumentEncoder::encodeUInt64(uint64_t n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<uint64_t*>(buffer) = n; +} + +void ArgumentEncoder::encodeInt32(int32_t n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<int32_t*>(buffer) = n; +} + +void ArgumentEncoder::encodeInt64(int64_t n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<int64_t*>(buffer) = n; +} + +void ArgumentEncoder::encodeFloat(float n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<float*>(buffer) = n; +} + +void ArgumentEncoder::encodeDouble(double n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<double*>(buffer) = n; +} + +void ArgumentEncoder::addAttachment(const Attachment& attachment) +{ + m_attachments.append(attachment); +} + +Vector<Attachment> ArgumentEncoder::releaseAttachments() +{ + Vector<Attachment> newList; + newList.swap(m_attachments); + return newList; +} + +#ifndef NDEBUG +void ArgumentEncoder::debug() +{ + printf("ArgumentEncoder::debug()\n"); + printf("Number of Attachments: %d\n", (int)m_attachments.size()); + printf("Size of buffer: %d\n", (int)m_bufferSize); +} +#endif + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.h b/Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.h new file mode 100644 index 0000000..97f0262 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.h @@ -0,0 +1,127 @@ +/* + * 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 ArgumentEncoder_h +#define ArgumentEncoder_h + +#include "ArgumentCoder.h" +#include "Attachment.h" +#include <wtf/PassOwnPtr.h> +#include <wtf/TypeTraits.h> +#include <wtf/Vector.h> + +namespace CoreIPC { + +class ArgumentEncoder; + +class ArgumentEncoder { +public: + static PassOwnPtr<ArgumentEncoder> create(uint64_t destinationID); + ~ArgumentEncoder(); + + void encodeBytes(const uint8_t*, size_t); + + void encodeBool(bool); + void encodeUInt32(uint32_t); + void encodeUInt64(uint64_t); + void encodeInt32(int32_t); + void encodeInt64(int64_t); + void encodeFloat(float); + void encodeDouble(double); + + template<typename T> void encodeEnum(T t) + { + COMPILE_ASSERT(sizeof(T) <= sizeof(uint64_t), enum_type_must_not_be_larger_than_64_bits); + + encodeUInt64(static_cast<uint64_t>(t)); + } + + // Generic type encode function. + template<typename T> void encode(const T& t) + { + ArgumentCoder<T>::encode(this, t); + } + + uint8_t* buffer() const { return m_buffer; } + size_t bufferSize() const { return m_bufferSize; } + + void addAttachment(const Attachment&); + Vector<Attachment> releaseAttachments(); + +#ifndef NDEBUG + void debug(); +#endif + +private: + explicit ArgumentEncoder(uint64_t destinationID); + uint8_t* grow(unsigned alignment, size_t size); + + uint8_t* m_buffer; + uint8_t* m_bufferPointer; + + size_t m_bufferSize; + size_t m_bufferCapacity; + + Vector<Attachment> m_attachments; +}; + +template<> inline void ArgumentEncoder::encode(const bool& n) +{ + encodeBool(n); +} + +template<> inline void ArgumentEncoder::encode(const uint32_t& n) +{ + encodeUInt32(n); +} + +template<> inline void ArgumentEncoder::encode(const uint64_t& n) +{ + encodeUInt64(n); +} + +template<> inline void ArgumentEncoder::encode(const int32_t& n) +{ + encodeInt32(n); +} + +template<> inline void ArgumentEncoder::encode(const int64_t& n) +{ + encodeInt64(n); +} + +template<> inline void ArgumentEncoder::encode(const float& n) +{ + encodeFloat(n); +} + +template<> inline void ArgumentEncoder::encode(const double& n) +{ + encodeDouble(n); +} + +} // namespace CoreIPC + +#endif // ArgumentEncoder_h diff --git a/Source/WebKit2/Platform/CoreIPC/Arguments.h b/Source/WebKit2/Platform/CoreIPC/Arguments.h new file mode 100644 index 0000000..ba7c7e8 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/Arguments.h @@ -0,0 +1,401 @@ +/* + * 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 Arguments_h +#define Arguments_h + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" +#include <wtf/TypeTraits.h> + +namespace CoreIPC { + +struct Arguments0 { + typedef Arguments0 ValueType; + + void encode(ArgumentEncoder*) const + { + } + + static bool decode(ArgumentDecoder*, Arguments0&) + { + return true; + } +}; + +inline Arguments0 In() +{ + return Arguments0(); +} + +inline Arguments0 Out() +{ + return Arguments0(); +} + +template<typename T1> struct Arguments1 { + typedef Arguments1<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type> ValueType; + + Arguments1() + { + } + + Arguments1(T1 t1) + : argument1(t1) + { + } + + void encode(ArgumentEncoder* encoder) const + { + encoder->encode(argument1); + } + + static bool decode(ArgumentDecoder* decoder, Arguments1& result) + { + return decoder->decode(result.argument1); + } + + T1 argument1; +}; + +template<typename T1> Arguments1<const T1&> In(const T1& t1) +{ + return Arguments1<const T1&>(t1); +} + +template<typename T1> Arguments1<T1&> Out(T1& t1) +{ + return Arguments1<T1&>(t1); +} + +template<typename T1, typename T2> struct Arguments2 : Arguments1<T1> { + typedef Arguments2<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type> ValueType; + + Arguments2() + { + } + + Arguments2(T1 t1, T2 t2) + : Arguments1<T1>(t1) + , argument2(t2) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments1<T1>::encode(encoder); + encoder->encode(argument2); + } + + static bool decode(ArgumentDecoder* decoder, Arguments2& result) + { + if (!Arguments1<T1>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument2); + } + + T2 argument2; +}; + +template<typename T1, typename T2> Arguments2<const T1&, const T2&> In(const T1& t1, const T2& t2) +{ + return Arguments2<const T1&, const T2&>(t1, t2); +} + +template<typename T1, typename T2> Arguments2<T1&, T2&> Out(T1& t1, T2& t2) +{ + return Arguments2<T1&, T2&>(t1, t2); +} + +template<typename T1, typename T2, typename T3> struct Arguments3 : Arguments2<T1, T2> { + typedef Arguments3<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T3>::Type>::Type> ValueType; + + Arguments3() + { + } + + Arguments3(T1 t1, T2 t2, T3 t3) + : Arguments2<T1, T2>(t1, t2) + , argument3(t3) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments2<T1, T2>::encode(encoder); + encoder->encode(argument3); + } + + static bool decode(ArgumentDecoder* decoder, Arguments3& result) + { + if (!Arguments2<T1, T2>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument3); + } + + T3 argument3; +}; + +template<typename T1, typename T2, typename T3> Arguments3<const T1&, const T2&, const T3&> In(const T1& t1, const T2& t2, const T3 &t3) +{ + return Arguments3<const T1&, const T2&, const T3&>(t1, t2, t3); +} + +template<typename T1, typename T2, typename T3> Arguments3<T1&, T2&, T3&> Out(T1& t1, T2& t2, T3& t3) +{ + return Arguments3<T1&, T2&, T3&>(t1, t2, t3); +} + +template<typename T1, typename T2, typename T3, typename T4> struct Arguments4 : Arguments3<T1, T2, T3> { + typedef Arguments4<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T3>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T4>::Type>::Type> ValueType; + + Arguments4() + { + } + + Arguments4(T1 t1, T2 t2, T3 t3, T4 t4) + : Arguments3<T1, T2, T3>(t1, t2, t3) + , argument4(t4) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments3<T1, T2, T3>::encode(encoder); + encoder->encode(argument4); + } + + static bool decode(ArgumentDecoder* decoder, Arguments4& result) + { + if (!Arguments3<T1, T2, T3>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument4); + } + + T4 argument4; +}; + +template<typename T1, typename T2, typename T3, typename T4> Arguments4<const T1&, const T2&, const T3&, const T4&> In(const T1& t1, const T2& t2, const T3 &t3, const T4& t4) +{ + return Arguments4<const T1&, const T2&, const T3&, const T4&>(t1, t2, t3, t4); +} + +template<typename T1, typename T2, typename T3, typename T4> Arguments4<T1&, T2&, T3&, T4&> Out(T1& t1, T2& t2, T3& t3, T4& t4) +{ + return Arguments4<T1&, T2&, T3&, T4&>(t1, t2, t3, t4); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5> struct Arguments5 : Arguments4<T1, T2, T3, T4> { + typedef Arguments5<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T3>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T4>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T5>::Type>::Type> ValueType; + + Arguments5() + { + } + + Arguments5(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + : Arguments4<T1, T2, T3, T4>(t1, t2, t3, t4) + , argument5(t5) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments4<T1, T2, T3, T4>::encode(encoder); + encoder->encode(argument5); + } + + static bool decode(ArgumentDecoder* decoder, Arguments5& result) + { + if (!Arguments4<T1, T2, T3, T4>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument5); + } + + T5 argument5; +}; + +template<typename T1, typename T2, typename T3, typename T4, typename T5> Arguments5<const T1&, const T2&, const T3&, const T4&, const T5&> In(const T1& t1, const T2& t2, const T3 &t3, const T4& t4, const T5& t5) +{ + return Arguments5<const T1&, const T2&, const T3&, const T4&, const T5&>(t1, t2, t3, t4, t5); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5> Arguments5<T1&, T2&, T3&, T4&, T5&> Out(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) +{ + return Arguments5<T1&, T2&, T3&, T4&, T5&>(t1, t2, t3, t4, t5); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> struct Arguments6 : Arguments5<T1, T2, T3, T4, T5> { + typedef Arguments6<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T3>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T4>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T5>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T6>::Type>::Type> ValueType; + + Arguments6() + { + } + + Arguments6(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + : Arguments5<T1, T2, T3, T4, T5>(t1, t2, t3, t4, t5) + , argument6(t6) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments5<T1, T2, T3, T4, T5>::encode(encoder); + encoder->encode(argument6); + } + + static bool decode(ArgumentDecoder* decoder, Arguments6& result) + { + if (!Arguments5<T1, T2, T3, T4, T5>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument6); + } + + T6 argument6; +}; + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> Arguments6<const T1&, const T2&, const T3&, const T4&, const T5&, const T6&> In(const T1& t1, const T2& t2, const T3 &t3, const T4& t4, const T5& t5, const T6& t6) +{ + return Arguments6<const T1&, const T2&, const T3&, const T4&, const T5&, const T6&>(t1, t2, t3, t4, t5, t6); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> Arguments6<T1&, T2&, T3&, T4&, T5&, T6&> Out(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6) +{ + return Arguments6<T1&, T2&, T3&, T4&, T5&, T6&>(t1, t2, t3, t4, t5, t6); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> struct Arguments7 : Arguments6<T1, T2, T3, T4, T5, T6> { + typedef Arguments7<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T3>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T4>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T5>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T6>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T7>::Type>::Type> ValueType; + + Arguments7() + { + } + + Arguments7(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + : Arguments6<T1, T2, T3, T4, T5, T6>(t1, t2, t3, t4, t5, t6) + , argument7(t7) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments6<T1, T2, T3, T4, T5, T6>::encode(encoder); + encoder->encode(argument7); + } + + static bool decode(ArgumentDecoder* decoder, Arguments7& result) + { + if (!Arguments6<T1, T2, T3, T4, T5, T6>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument7); + } + + T7 argument7; +}; + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> Arguments7<const T1&, const T2&, const T3&, const T4&, const T5&, const T6&, const T7&> In(const T1& t1, const T2& t2, const T3 &t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7) +{ + return Arguments7<const T1&, const T2&, const T3&, const T4&, const T5&, const T6&, const T7&>(t1, t2, t3, t4, t5, t6, t7); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> Arguments7<T1&, T2&, T3&, T4&, T5&, T6&, T7&> Out(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7) +{ + return Arguments7<T1&, T2&, T3&, T4&, T5&, T6&, T7&>(t1, t2, t3, t4, t5, t6, t7); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> struct Arguments8 : Arguments7<T1, T2, T3, T4, T5, T6, T7> { + typedef Arguments8<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T3>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T4>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T5>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T6>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T7>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T8>::Type>::Type> ValueType; + + Arguments8() { } + + Arguments8(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + : Arguments7<T1, T2, T3, T4, T5, T6, T7>(t1, t2, t3, t4, t5, t6, t7) + , argument8(t8) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments7<T1, T2, T3, T4, T5, T6, T7>::encode(encoder); + encoder->encode(argument8); + } + + static bool decode(ArgumentDecoder* decoder, Arguments8& result) + { + if (!Arguments7<T1, T2, T3, T4, T5, T6, T7>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument8); + } + + T8 argument8; +}; + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> Arguments8<const T1&, const T2&, const T3&, const T4&, const T5&, const T6&, const T7&, const T8&> In(const T1& t1, const T2& t2, const T3 &t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7, const T8& t8) +{ + return Arguments8<const T1&, const T2&, const T3&, const T4&, const T5&, const T6&, const T7&, const T8&>(t1, t2, t3, t4, t5, t6, t7, t8); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> Arguments8<T1&, T2&, T3&, T4&, T5&, T6&, T7&, T8&> Out(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8) +{ + return Arguments8<T1&, T2&, T3&, T4&, T5&, T6&, T7&, T8&>(t1, t2, t3, t4, t5, t6, t7, t8); +} + +} // namespace CoreIPC + +#endif // Arguments_h diff --git a/Source/WebKit2/Platform/CoreIPC/Attachment.cpp b/Source/WebKit2/Platform/CoreIPC/Attachment.cpp new file mode 100644 index 0000000..c8d35f4 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/Attachment.cpp @@ -0,0 +1,73 @@ +/* + * 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 "Attachment.h" + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" + +namespace CoreIPC { + +Attachment::Attachment() + : m_type(Uninitialized) +{ +} + +#if PLATFORM(MAC) +Attachment::Attachment(mach_port_name_t port, mach_msg_type_name_t disposition) + : m_type(MachPortType) +{ + m_port.port = port; + m_port.disposition = disposition; +} + +Attachment::Attachment(void* address, mach_msg_size_t size, mach_msg_copy_options_t copyOptions, bool deallocate) + : m_type(MachOOLMemoryType) +{ + m_oolMemory.address = address; + m_oolMemory.size = size; + m_oolMemory.copyOptions = copyOptions; + m_oolMemory.deallocate = deallocate; +} + +void Attachment::release() +{ + m_type = Uninitialized; +} +#endif + +void Attachment::encode(ArgumentEncoder* encoder) const +{ + encoder->addAttachment(*this); +} + +bool Attachment::decode(ArgumentDecoder* decoder, Attachment& attachment) +{ + if (!decoder->removeAttachment(attachment)) + return false; + return true; +} + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/Attachment.h b/Source/WebKit2/Platform/CoreIPC/Attachment.h new file mode 100644 index 0000000..55a09c9 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/Attachment.h @@ -0,0 +1,91 @@ +/* + * 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 Attachment_h +#define Attachment_h + +namespace CoreIPC { + +class ArgumentDecoder; +class ArgumentEncoder; + +class Attachment { +public: + Attachment(); + + enum Type { + Uninitialized, +#if PLATFORM(MAC) + MachPortType, + MachOOLMemoryType +#endif + }; + +#if PLATFORM(MAC) + Attachment(mach_port_name_t port, mach_msg_type_name_t disposition); + Attachment(void* address, mach_msg_size_t size, mach_msg_copy_options_t copyOptions, bool deallocate); +#endif + + Type type() const { return m_type; } + +#if PLATFORM(MAC) + void release(); + + // MachPortType + mach_port_name_t port() const { ASSERT(m_type == MachPortType); return m_port.port; } + mach_msg_type_name_t disposition() const { ASSERT(m_type == MachPortType); return m_port.disposition; } + + // MachOOLMemoryType + void* address() const { ASSERT(m_type == MachOOLMemoryType); return m_oolMemory.address; } + mach_msg_size_t size() const { ASSERT(m_type == MachOOLMemoryType); return m_oolMemory.size; } + mach_msg_copy_options_t copyOptions() const { ASSERT(m_type == MachOOLMemoryType); return m_oolMemory.copyOptions; } + bool deallocate() const { ASSERT(m_type == MachOOLMemoryType); return m_oolMemory.deallocate; } +#endif + + void encode(ArgumentEncoder*) const; + static bool decode(ArgumentDecoder*, Attachment&); + +private: + Type m_type; + +#if PLATFORM(MAC) + union { + struct { + mach_port_name_t port; + mach_msg_type_name_t disposition; + } m_port; + struct { + void* address; + mach_msg_size_t size; + mach_msg_copy_options_t copyOptions; + bool deallocate; + } m_oolMemory; + }; +#endif +}; + +} // namespace CoreIPC + +#endif // Attachment_h diff --git a/Source/WebKit2/Platform/CoreIPC/BinarySemaphore.cpp b/Source/WebKit2/Platform/CoreIPC/BinarySemaphore.cpp new file mode 100644 index 0000000..c975dff --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/BinarySemaphore.cpp @@ -0,0 +1,64 @@ +/* + * 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 "BinarySemaphore.h" + +namespace CoreIPC { + +BinarySemaphore::BinarySemaphore() + : m_isSet(false) +{ +} + +BinarySemaphore::~BinarySemaphore() +{ +} + +void BinarySemaphore::signal() +{ + MutexLocker locker(m_mutex); + + m_isSet = true; + m_condition.signal(); +} + +bool BinarySemaphore::wait(double absoluteTime) +{ + MutexLocker locker(m_mutex); + + bool timedOut = false; + while (!m_isSet) { + timedOut = !m_condition.timedWait(m_mutex, absoluteTime); + if (timedOut) + return false; + } + + // Reset the semaphore. + m_isSet = false; + return true; +} + + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/BinarySemaphore.h b/Source/WebKit2/Platform/CoreIPC/BinarySemaphore.h new file mode 100644 index 0000000..8113236 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/BinarySemaphore.h @@ -0,0 +1,54 @@ +/* + * 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 BinarySemaphore_h +#define BinarySemaphore_h + +#include <wtf/Noncopyable.h> +#include <wtf/ThreadingPrimitives.h> + +namespace CoreIPC { + +class BinarySemaphore { + WTF_MAKE_NONCOPYABLE(BinarySemaphore); + +public: + BinarySemaphore(); + ~BinarySemaphore(); + + void signal(); + bool wait(double absoluteTime); + +private: + bool m_isSet; + + Mutex m_mutex; + ThreadCondition m_condition; +}; + +} // namespace CoreIPC + + +#endif // BinarySemaphore_h diff --git a/Source/WebKit2/Platform/CoreIPC/Connection.cpp b/Source/WebKit2/Platform/CoreIPC/Connection.cpp new file mode 100644 index 0000000..da92ce4 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/Connection.cpp @@ -0,0 +1,453 @@ +/* + * 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 "Connection.h" + +#include "CoreIPCMessageKinds.h" +#include "RunLoop.h" +#include "WorkItem.h" +#include <wtf/CurrentTime.h> + +using namespace std; + +namespace CoreIPC { + +PassRefPtr<Connection> Connection::createServerConnection(Identifier identifier, Client* client, RunLoop* clientRunLoop) +{ + return adoptRef(new Connection(identifier, true, client, clientRunLoop)); +} + +PassRefPtr<Connection> Connection::createClientConnection(Identifier identifier, Client* client, RunLoop* clientRunLoop) +{ + return adoptRef(new Connection(identifier, false, client, clientRunLoop)); +} + +Connection::Connection(Identifier identifier, bool isServer, Client* client, RunLoop* clientRunLoop) + : m_client(client) + , m_isServer(isServer) + , m_syncRequestID(0) + , m_isConnected(false) + , m_connectionQueue("com.apple.CoreIPC.ReceiveQueue") + , m_clientRunLoop(clientRunLoop) + , m_inDispatchMessageCount(0) + , m_didReceiveInvalidMessage(false) + , m_shouldWaitForSyncReplies(true) +{ + ASSERT(m_client); + + platformInitialize(identifier); +} + +Connection::~Connection() +{ + ASSERT(!isValid()); + + m_connectionQueue.invalidate(); +} + +void Connection::invalidate() +{ + if (!isValid()) { + // Someone already called invalidate(). + return; + } + + // Reset the client. + m_client = 0; + + m_connectionQueue.scheduleWork(WorkItem::create(this, &Connection::platformInvalidate)); +} + +void Connection::markCurrentlyDispatchedMessageAsInvalid() +{ + // This should only be called while processing a message. + ASSERT(m_inDispatchMessageCount > 0); + + m_didReceiveInvalidMessage = true; +} + +PassOwnPtr<ArgumentEncoder> Connection::createSyncMessageArgumentEncoder(uint64_t destinationID, uint64_t& syncRequestID) +{ + OwnPtr<ArgumentEncoder> argumentEncoder = ArgumentEncoder::create(destinationID); + + // Encode the sync request ID. + syncRequestID = ++m_syncRequestID; + argumentEncoder->encode(syncRequestID); + + return argumentEncoder.release(); +} + +bool Connection::sendMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments) +{ + if (!isValid()) + return false; + + MutexLocker locker(m_outgoingMessagesLock); + m_outgoingMessages.append(OutgoingMessage(messageID, arguments)); + + // FIXME: We should add a boolean flag so we don't call this when work has already been scheduled. + m_connectionQueue.scheduleWork(WorkItem::create(this, &Connection::sendOutgoingMessages)); + return true; +} + +bool Connection::sendSyncReply(PassOwnPtr<ArgumentEncoder> arguments) +{ + return sendMessage(MessageID(CoreIPCMessage::SyncMessageReply), arguments); +} + +PassOwnPtr<ArgumentDecoder> Connection::waitForMessage(MessageID messageID, uint64_t destinationID, double timeout) +{ + // First, check if this message is already in the incoming messages queue. + { + MutexLocker locker(m_incomingMessagesLock); + + for (size_t i = 0; i < m_incomingMessages.size(); ++i) { + const IncomingMessage& message = m_incomingMessages[i]; + + if (message.messageID() == messageID && message.arguments()->destinationID() == destinationID) { + OwnPtr<ArgumentDecoder> arguments(message.arguments()); + + // Erase the incoming message. + m_incomingMessages.remove(i); + return arguments.release(); + } + } + } + + double absoluteTime = currentTime() + timeout; + + std::pair<unsigned, uint64_t> messageAndDestination(std::make_pair(messageID.toInt(), destinationID)); + + { + MutexLocker locker(m_waitForMessageMutex); + + // We don't support having multiple clients wait for the same message. + ASSERT(!m_waitForMessageMap.contains(messageAndDestination)); + + // Insert our pending wait. + m_waitForMessageMap.set(messageAndDestination, 0); + } + + // Now wait for it to be set. + while (true) { + MutexLocker locker(m_waitForMessageMutex); + + HashMap<std::pair<unsigned, uint64_t>, ArgumentDecoder*>::iterator it = m_waitForMessageMap.find(messageAndDestination); + if (it->second) { + OwnPtr<ArgumentDecoder> arguments(it->second); + m_waitForMessageMap.remove(it); + + return arguments.release(); + } + + // Now we wait. + if (!m_waitForMessageCondition.timedWait(m_waitForMessageMutex, absoluteTime)) { + // We timed out, now remove the pending wait. + m_waitForMessageMap.remove(messageAndDestination); + + break; + } + } + + return PassOwnPtr<ArgumentDecoder>(); +} + +PassOwnPtr<ArgumentDecoder> Connection::sendSyncMessage(MessageID messageID, uint64_t syncRequestID, PassOwnPtr<ArgumentEncoder> encoder, double timeout) +{ + // We only allow sending sync messages from the client run loop. + ASSERT(RunLoop::current() == m_clientRunLoop); + + if (!isValid()) + return 0; + + // Push the pending sync reply information on our stack. + { + MutexLocker locker(m_syncReplyStateMutex); + if (!m_shouldWaitForSyncReplies) + return 0; + + m_pendingSyncReplies.append(PendingSyncReply(syncRequestID)); + } + + // First send the message. + sendMessage(messageID, encoder); + + // Then wait for a reply. Waiting for a reply could involve dispatching incoming sync messages, so + // keep an extra reference to the connection here in case it's invalidated. + RefPtr<Connection> protect(this); + OwnPtr<ArgumentDecoder> reply = waitForSyncReply(syncRequestID, timeout); + + // Finally, pop the pending sync reply information. + { + MutexLocker locker(m_syncReplyStateMutex); + ASSERT(m_pendingSyncReplies.last().syncRequestID == syncRequestID); + m_pendingSyncReplies.removeLast(); + + if (m_pendingSyncReplies.isEmpty()) { + // This was the bottom-most sendSyncMessage call in the stack. If we have any pending incoming + // sync messages, they need to be dispatched. + if (!m_syncMessagesReceivedWhileWaitingForSyncReply.isEmpty()) { + // Add the messages. + MutexLocker locker(m_incomingMessagesLock); + m_incomingMessages.append(m_syncMessagesReceivedWhileWaitingForSyncReply); + m_syncMessagesReceivedWhileWaitingForSyncReply.clear(); + + // Schedule for the messages to be sent. + m_clientRunLoop->scheduleWork(WorkItem::create(this, &Connection::dispatchMessages)); + } + } + } + + return reply.release(); +} + +PassOwnPtr<ArgumentDecoder> Connection::waitForSyncReply(uint64_t syncRequestID, double timeout) +{ + double absoluteTime = currentTime() + timeout; + + bool timedOut = false; + while (!timedOut) { + { + MutexLocker locker(m_syncReplyStateMutex); + + // First, check if we have any incoming sync messages that we need to process. + Vector<IncomingMessage> syncMessagesReceivedWhileWaitingForSyncReply; + m_syncMessagesReceivedWhileWaitingForSyncReply.swap(syncMessagesReceivedWhileWaitingForSyncReply); + + if (!syncMessagesReceivedWhileWaitingForSyncReply.isEmpty()) { + // Make sure to unlock the mutex here because we're calling out to client code which could in turn send + // another sync message and we don't want that to deadlock. + m_syncReplyStateMutex.unlock(); + + for (size_t i = 0; i < syncMessagesReceivedWhileWaitingForSyncReply.size(); ++i) { + IncomingMessage& message = syncMessagesReceivedWhileWaitingForSyncReply[i]; + OwnPtr<ArgumentDecoder> arguments = message.releaseArguments(); + + dispatchSyncMessage(message.messageID(), arguments.get()); + } + m_syncReplyStateMutex.lock(); + } + + // Second, check if there is a sync reply at the top of the stack. + ASSERT(!m_pendingSyncReplies.isEmpty()); + + PendingSyncReply& pendingSyncReply = m_pendingSyncReplies.last(); + ASSERT(pendingSyncReply.syncRequestID == syncRequestID); + + // We found the sync reply, or the connection was closed. + if (pendingSyncReply.didReceiveReply || !m_shouldWaitForSyncReplies) + return pendingSyncReply.releaseReplyDecoder(); + } + + // We didn't find a sync reply yet, keep waiting. + timedOut = !m_waitForSyncReplySemaphore.wait(absoluteTime); + } + + // We timed out. + return 0; +} + +void Connection::processIncomingMessage(MessageID messageID, PassOwnPtr<ArgumentDecoder> arguments) +{ + // Check if this is a sync reply. + if (messageID == MessageID(CoreIPCMessage::SyncMessageReply)) { + MutexLocker locker(m_syncReplyStateMutex); + ASSERT(!m_pendingSyncReplies.isEmpty()); + + PendingSyncReply& pendingSyncReply = m_pendingSyncReplies.last(); + ASSERT(pendingSyncReply.syncRequestID == arguments->destinationID()); + + pendingSyncReply.replyDecoder = arguments.leakPtr(); + pendingSyncReply.didReceiveReply = true; + + m_waitForSyncReplySemaphore.signal(); + return; + } + + // Check if this is a sync message. If it is, and we're waiting for a sync reply this message + // needs to be dispatched. If we don't we'll end up with a deadlock where both sync message senders are + // stuck waiting for a reply. + if (messageID.isSync()) { + MutexLocker locker(m_syncReplyStateMutex); + if (!m_pendingSyncReplies.isEmpty()) { + m_syncMessagesReceivedWhileWaitingForSyncReply.append(IncomingMessage(messageID, arguments)); + + // The message has been added, now wake up the client thread. + m_waitForSyncReplySemaphore.signal(); + return; + } + } + + // Check if we're waiting for this message. + { + MutexLocker locker(m_waitForMessageMutex); + + HashMap<std::pair<unsigned, uint64_t>, ArgumentDecoder*>::iterator it = m_waitForMessageMap.find(std::make_pair(messageID.toInt(), arguments->destinationID())); + if (it != m_waitForMessageMap.end()) { + it->second = arguments.leakPtr(); + + m_waitForMessageCondition.signal(); + return; + } + } + + MutexLocker locker(m_incomingMessagesLock); + m_incomingMessages.append(IncomingMessage(messageID, arguments)); + + m_clientRunLoop->scheduleWork(WorkItem::create(this, &Connection::dispatchMessages)); +} + +void Connection::connectionDidClose() +{ + // The connection is now invalid. + platformInvalidate(); + + { + MutexLocker locker(m_syncReplyStateMutex); + + ASSERT(m_shouldWaitForSyncReplies); + m_shouldWaitForSyncReplies = false; + + if (!m_pendingSyncReplies.isEmpty()) + m_waitForSyncReplySemaphore.signal(); + } + + m_client->didCloseOnConnectionWorkQueue(&m_connectionQueue, this); + + m_clientRunLoop->scheduleWork(WorkItem::create(this, &Connection::dispatchConnectionDidClose)); +} + +void Connection::dispatchConnectionDidClose() +{ + // If the connection has been explicitly invalidated before dispatchConnectionDidClose was called, + // then the client will be null here. + if (!m_client) + return; + + + // Because we define a connection as being "valid" based on wheter it has a null client, we null out + // the client before calling didClose here. Otherwise, sendSync will try to send a message to the connection and + // will then wait indefinitely for a reply. + Client* client = m_client; + m_client = 0; + + client->didClose(this); +} + +bool Connection::canSendOutgoingMessages() const +{ + return m_isConnected && platformCanSendOutgoingMessages(); +} + +void Connection::sendOutgoingMessages() +{ + if (!canSendOutgoingMessages()) + return; + + while (true) { + OutgoingMessage message; + { + MutexLocker locker(m_outgoingMessagesLock); + if (m_outgoingMessages.isEmpty()) + break; + message = m_outgoingMessages.takeFirst(); + } + + if (!sendOutgoingMessage(message.messageID(), adoptPtr(message.arguments()))) + break; + } +} + +void Connection::dispatchSyncMessage(MessageID messageID, ArgumentDecoder* arguments) +{ + ASSERT(messageID.isSync()); + + // Decode the sync request ID. + uint64_t syncRequestID = 0; + + if (!arguments->decodeUInt64(syncRequestID) || !syncRequestID) { + // We received an invalid sync message. + arguments->markInvalid(); + return; + } + + // Create our reply encoder. + ArgumentEncoder* replyEncoder = ArgumentEncoder::create(syncRequestID).leakPtr(); + + // Hand off both the decoder and encoder to the client.. + SyncReplyMode syncReplyMode = m_client->didReceiveSyncMessage(this, messageID, arguments, replyEncoder); + + // FIXME: If the message was invalid, we should send back a SyncMessageError. + ASSERT(!arguments->isInvalid()); + + if (syncReplyMode == ManualReply) { + // The client will take ownership of the reply encoder and send it at some point in the future. + // We won't do anything here. + return; + } + + // Send the reply. + sendSyncReply(replyEncoder); +} + +void Connection::dispatchMessages() +{ + Vector<IncomingMessage> incomingMessages; + + { + MutexLocker locker(m_incomingMessagesLock); + m_incomingMessages.swap(incomingMessages); + } + + // Dispatch messages. + for (size_t i = 0; i < incomingMessages.size(); ++i) { + // If someone calls invalidate while we're invalidating messages, we should stop. + if (!m_client) + return; + + IncomingMessage& message = incomingMessages[i]; + OwnPtr<ArgumentDecoder> arguments = message.releaseArguments(); + + m_inDispatchMessageCount++; + + bool oldDidReceiveInvalidMessage = m_didReceiveInvalidMessage; + m_didReceiveInvalidMessage = false; + + if (message.messageID().isSync()) + dispatchSyncMessage(message.messageID(), arguments.get()); + else + m_client->didReceiveMessage(this, message.messageID(), arguments.get()); + + m_didReceiveInvalidMessage |= arguments->isInvalid(); + m_inDispatchMessageCount--; + + if (m_didReceiveInvalidMessage) + m_client->didReceiveInvalidMessage(this, message.messageID()); + + m_didReceiveInvalidMessage = oldDidReceiveInvalidMessage; + } +} + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/Connection.h b/Source/WebKit2/Platform/CoreIPC/Connection.h new file mode 100644 index 0000000..b7e5b0f --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/Connection.h @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * 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. + */ + +#ifndef Connection_h +#define Connection_h + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" +#include "Arguments.h" +#include "BinarySemaphore.h" +#include "MessageID.h" +#include "WorkQueue.h" +#include <wtf/HashMap.h> +#include <wtf/PassRefPtr.h> +#include <wtf/OwnPtr.h> +#include <wtf/Threading.h> + +#if PLATFORM(MAC) +#include <mach/mach_port.h> +#elif PLATFORM(WIN) +#include <string> +#elif PLATFORM(QT) +#include <QString> +class QLocalServer; +class QLocalSocket; +#endif + +class RunLoop; + +namespace CoreIPC { + +class MessageID; + +enum SyncReplyMode { + AutomaticReply, + ManualReply +}; + +#define MESSAGE_CHECK_BASE(assertion, connection) do \ + if (!(assertion)) { \ + ASSERT(assertion); \ + (connection)->markCurrentlyDispatchedMessageAsInvalid(); \ + return; \ + } \ +while (0) + +class Connection : public ThreadSafeShared<Connection> { +public: + class MessageReceiver { + protected: + virtual ~MessageReceiver() { } + + public: + virtual void didReceiveMessage(Connection*, MessageID, ArgumentDecoder*) = 0; + virtual SyncReplyMode didReceiveSyncMessage(Connection*, MessageID, ArgumentDecoder*, ArgumentEncoder*) { ASSERT_NOT_REACHED(); return AutomaticReply; } + }; + + class Client : public MessageReceiver { + protected: + virtual ~Client() { } + + public: + virtual void didClose(Connection*) = 0; + virtual void didReceiveInvalidMessage(Connection*, MessageID) = 0; + + // Called on the connection work queue when the connection is closed, before + // didCall is called on the client thread. + virtual void didCloseOnConnectionWorkQueue(WorkQueue*, Connection*) { } + }; + +#if PLATFORM(MAC) + typedef mach_port_t Identifier; +#elif PLATFORM(WIN) + typedef HANDLE Identifier; + static bool createServerAndClientIdentifiers(Identifier& serverIdentifier, Identifier& clientIdentifier); +#elif PLATFORM(QT) + typedef const QString Identifier; +#elif PLATFORM(GTK) + typedef int Identifier; +#endif + + static PassRefPtr<Connection> createServerConnection(Identifier, Client*, RunLoop* clientRunLoop); + static PassRefPtr<Connection> createClientConnection(Identifier, Client*, RunLoop* clientRunLoop); + ~Connection(); + +#if PLATFORM(MAC) + void setShouldCloseConnectionOnMachExceptions(); +#endif + + bool open(); + void invalidate(); + void markCurrentlyDispatchedMessageAsInvalid(); + + // FIXME: This variant of send is deprecated, all clients should move to the overload that takes a message. + template<typename E, typename T> bool send(E messageID, uint64_t destinationID, const T& arguments); + + template<typename T> bool send(const T& message, uint64_t destinationID); + + static const unsigned long long NoTimeout = 10000000000ULL; + // FIXME: This variant of sendSync is deprecated, all clients should move to the overload that takes a message. + template<typename E, typename T, typename U> bool sendSync(E messageID, uint64_t destinationID, const T& arguments, const U& reply, double timeout = NoTimeout); + + template<typename T> bool sendSync(const T& message, const typename T::Reply& reply, uint64_t destinationID, double timeout = NoTimeout); + + template<typename E> PassOwnPtr<ArgumentDecoder> waitFor(E messageID, uint64_t destinationID, double timeout); + + PassOwnPtr<ArgumentEncoder> createSyncMessageArgumentEncoder(uint64_t destinationID, uint64_t& syncRequestID); + bool sendMessage(MessageID, PassOwnPtr<ArgumentEncoder>); + bool sendSyncReply(PassOwnPtr<ArgumentEncoder>); + +private: + template<typename T> class Message { + public: + Message() + : m_arguments(0) + { + } + + Message(MessageID messageID, PassOwnPtr<T> arguments) + : m_messageID(messageID) + , m_arguments(arguments.leakPtr()) + { + } + + MessageID messageID() const { return m_messageID; } + T* arguments() const { return m_arguments; } + + PassOwnPtr<T> releaseArguments() + { + T* arguments = m_arguments; + m_arguments = 0; + + return arguments; + } + + private: + MessageID m_messageID; + T* m_arguments; + }; + +public: + typedef Message<ArgumentEncoder> OutgoingMessage; + +private: + Connection(Identifier, bool isServer, Client*, RunLoop* clientRunLoop); + void platformInitialize(Identifier); + void platformInvalidate(); + + bool isValid() const { return m_client; } + + PassOwnPtr<ArgumentDecoder> waitForMessage(MessageID, uint64_t destinationID, double timeout); + + PassOwnPtr<ArgumentDecoder> sendSyncMessage(MessageID, uint64_t syncRequestID, PassOwnPtr<ArgumentEncoder>, double timeout); + PassOwnPtr<ArgumentDecoder> waitForSyncReply(uint64_t syncRequestID, double timeout); + + // Called on the connection work queue. + void processIncomingMessage(MessageID, PassOwnPtr<ArgumentDecoder>); + bool canSendOutgoingMessages() const; + bool platformCanSendOutgoingMessages() const; + void sendOutgoingMessages(); + bool sendOutgoingMessage(MessageID, PassOwnPtr<ArgumentEncoder>); + void connectionDidClose(); + + // Called on the listener thread. + void dispatchConnectionDidClose(); + void dispatchMessages(); + void dispatchSyncMessage(MessageID, ArgumentDecoder*); + + Client* m_client; + bool m_isServer; + uint64_t m_syncRequestID; + + bool m_isConnected; + WorkQueue m_connectionQueue; + RunLoop* m_clientRunLoop; + + uint32_t m_inDispatchMessageCount; + bool m_didReceiveInvalidMessage; + + // Incoming messages. + typedef Message<ArgumentDecoder> IncomingMessage; + + Mutex m_incomingMessagesLock; + Vector<IncomingMessage> m_incomingMessages; + + // Outgoing messages. + Mutex m_outgoingMessagesLock; + Deque<OutgoingMessage> m_outgoingMessages; + + ThreadCondition m_waitForMessageCondition; + Mutex m_waitForMessageMutex; + HashMap<std::pair<unsigned, uint64_t>, ArgumentDecoder*> m_waitForMessageMap; + + // Represents a sync request for which we're waiting on a reply. + struct PendingSyncReply { + // The request ID. + uint64_t syncRequestID; + + // The reply decoder, will be null if there was an error processing the sync + // message on the other side. + ArgumentDecoder* replyDecoder; + + // Will be set to true once a reply has been received or an error occurred. + bool didReceiveReply; + + PendingSyncReply() + : syncRequestID(0) + , replyDecoder(0) + , didReceiveReply(false) + { + } + + explicit PendingSyncReply(uint64_t syncRequestID) + : syncRequestID(syncRequestID) + , replyDecoder(0) + , didReceiveReply(0) + { + } + + PassOwnPtr<ArgumentDecoder> releaseReplyDecoder() + { + OwnPtr<ArgumentDecoder> reply = adoptPtr(replyDecoder); + replyDecoder = 0; + + return reply.release(); + } + }; + + BinarySemaphore m_waitForSyncReplySemaphore; + + Mutex m_syncReplyStateMutex; + bool m_shouldWaitForSyncReplies; + Vector<PendingSyncReply> m_pendingSyncReplies; + Vector<IncomingMessage> m_syncMessagesReceivedWhileWaitingForSyncReply; + +#if PLATFORM(MAC) + // Called on the connection queue. + void receiveSourceEventHandler(); + void initializeDeadNameSource(); + void exceptionSourceEventHandler(); + + mach_port_t m_sendPort; + mach_port_t m_receivePort; + + // If setShouldCloseConnectionOnMachExceptions has been called, this has + // the exception port that exceptions from the other end will be sent on. + mach_port_t m_exceptionPort; + +#elif PLATFORM(WIN) + // Called on the connection queue. + void readEventHandler(); + void writeEventHandler(); + + Vector<uint8_t> m_readBuffer; + OVERLAPPED m_readState; + OwnPtr<ArgumentEncoder> m_pendingWriteArguments; + OVERLAPPED m_writeState; + HANDLE m_connectionPipe; +#elif PLATFORM(QT) + // Called on the connection queue. + void readyReadHandler(); + + Vector<uint8_t> m_readBuffer; + size_t m_currentMessageSize; + QLocalSocket* m_socket; + QString m_serverName; +#elif PLATFORM(GTK) + void readEventHandler(); + void processCompletedMessage(); + bool messageProcessingCompleted() { return !m_currentMessageSize; } + + int m_socket; + Vector<uint8_t> m_readBuffer; + size_t m_currentMessageSize; + size_t m_pendingBytes; +#endif +}; + +template<typename E, typename T> +bool Connection::send(E messageID, uint64_t destinationID, const T& arguments) +{ + OwnPtr<ArgumentEncoder> argumentEncoder = ArgumentEncoder::create(destinationID); + argumentEncoder->encode(arguments); + + return sendMessage(MessageID(messageID), argumentEncoder.release()); +} + +template<typename T> bool Connection::send(const T& message, uint64_t destinationID) +{ + OwnPtr<ArgumentEncoder> argumentEncoder = ArgumentEncoder::create(destinationID); + argumentEncoder->encode(message); + + return sendMessage(MessageID(T::messageID), argumentEncoder.release()); +} + +template<typename E, typename T, typename U> +inline bool Connection::sendSync(E messageID, uint64_t destinationID, const T& arguments, const U& reply, double timeout) +{ + uint64_t syncRequestID = 0; + OwnPtr<ArgumentEncoder> argumentEncoder = createSyncMessageArgumentEncoder(destinationID, syncRequestID); + + // Encode the input arguments. + argumentEncoder->encode(arguments); + + // Now send the message and wait for a reply. + OwnPtr<ArgumentDecoder> replyDecoder = sendSyncMessage(MessageID(messageID, MessageID::SyncMessage), syncRequestID, argumentEncoder.release(), timeout); + if (!replyDecoder) + return false; + + // Decode the reply. + return replyDecoder->decode(const_cast<U&>(reply)); +} + +template<typename T> bool Connection::sendSync(const T& message, const typename T::Reply& reply, uint64_t destinationID, double timeout) +{ + uint64_t syncRequestID = 0; + OwnPtr<ArgumentEncoder> argumentEncoder = createSyncMessageArgumentEncoder(destinationID, syncRequestID); + + // Encode the rest of the input arguments. + argumentEncoder->encode(message); + + // Now send the message and wait for a reply. + OwnPtr<ArgumentDecoder> replyDecoder = sendSyncMessage(MessageID(T::messageID, MessageID::SyncMessage), syncRequestID, argumentEncoder.release(), timeout); + if (!replyDecoder) + return false; + + // Decode the reply. + return replyDecoder->decode(const_cast<typename T::Reply&>(reply)); +} + +template<typename E> inline PassOwnPtr<ArgumentDecoder> Connection::waitFor(E messageID, uint64_t destinationID, double timeout) +{ + return waitForMessage(MessageID(messageID), destinationID, timeout); +} + +} // namespace CoreIPC + +#endif // Connection_h diff --git a/Source/WebKit2/Platform/CoreIPC/CoreIPCMessageKinds.h b/Source/WebKit2/Platform/CoreIPC/CoreIPCMessageKinds.h new file mode 100644 index 0000000..b2a2813 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/CoreIPCMessageKinds.h @@ -0,0 +1,51 @@ +/* + * 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 CoreIPCMessageKinds_h +#define CoreIPCMessageKinds_h + +#include "MessageID.h" + +namespace CoreIPC { + +namespace CoreIPCMessage { + +enum Kind { + InitializeConnection, + SyncMessageReply, +#if PLATFORM(MAC) + SetExceptionPort, +#endif +}; + +} // namespace CoreIPCMessage + +template<> struct MessageKindTraits<CoreIPCMessage::Kind> { + static const MessageClass messageClass = MessageClassCoreIPC; +}; + +} // namespace CoreIPC + +#endif // CoreIPCMessageKinds_h diff --git a/Source/WebKit2/Platform/CoreIPC/DataReference.cpp b/Source/WebKit2/Platform/CoreIPC/DataReference.cpp new file mode 100644 index 0000000..308fd6e --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/DataReference.cpp @@ -0,0 +1,45 @@ +/* + * 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 "DataReference.h" + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" + +namespace CoreIPC { + +void DataReference::encode(ArgumentEncoder* encoder) const +{ + encoder->encodeBytes(m_data, m_size); +} + +bool DataReference::decode(ArgumentDecoder* decoder, DataReference& dataReference) +{ + return decoder->decodeBytes(dataReference); +} + +} // namespace CoreIPC + + diff --git a/Source/WebKit2/Platform/CoreIPC/DataReference.h b/Source/WebKit2/Platform/CoreIPC/DataReference.h new file mode 100644 index 0000000..1657bea --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/DataReference.h @@ -0,0 +1,70 @@ +/* + * 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 DataReference_h +#define DataReference_h + +#include <inttypes.h> + +namespace CoreIPC { + +class ArgumentDecoder; +class ArgumentEncoder; + +class DataReference { +public: + DataReference() + : m_data(0) + , m_size(0) + { + } + + DataReference(const uint8_t* data, size_t size) + : m_data(data) + , m_size(size) + { + } + + bool isEmpty() const { return size() == 0; } + + size_t size() const { return m_size; } + const uint8_t* data() const + { + if (isEmpty()) + return 0; + return m_data; + } + + void encode(ArgumentEncoder* encoder) const; + static bool decode(ArgumentDecoder* decoder, DataReference& dataReference); + +private: + const uint8_t* m_data; + size_t m_size; +}; + +} // namespace CoreIPC + +#endif // DataReference_h diff --git a/Source/WebKit2/Platform/CoreIPC/HandleMessage.h b/Source/WebKit2/Platform/CoreIPC/HandleMessage.h new file mode 100644 index 0000000..534e825 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/HandleMessage.h @@ -0,0 +1,248 @@ +#ifndef HandleMessage_h +#define HandleMessage_h + +#include "Arguments.h" + +namespace CoreIPC { + +// Dispatch functions with no reply arguments. + +template<typename C, typename MF> +void callMemberFunction(const Arguments0&, C* object, MF function) +{ + (object->*function)(); +} + +template<typename C, typename MF, typename P1> +void callMemberFunction(const Arguments1<P1>& args, C* object, MF function) +{ + (object->*function)(args.argument1); +} + +template<typename C, typename MF, typename P1, typename P2> +void callMemberFunction(const Arguments2<P1, P2>& args, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3> +void callMemberFunction(const Arguments3<P1, P2, P3>& args, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4> +void callMemberFunction(const Arguments4<P1, P2, P3, P4>& args, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5> +void callMemberFunction(const Arguments5<P1, P2, P3, P4, P5>& args, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6> +void callMemberFunction(const Arguments6<P1, P2, P3, P4, P5, P6>& args, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5, args.argument6); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7> +void callMemberFunction(const Arguments7<P1, P2, P3, P4, P5, P6, P7>& args, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5, args.argument6, args.argument7); +} + +// Dispatch functions with reply arguments. + +template<typename C, typename MF> +void callMemberFunction(const Arguments0&, Arguments0&, C* object, MF function) +{ + (object->*function)(); +} + +template<typename C, typename MF, typename R1> +void callMemberFunction(const Arguments0&, Arguments1<R1>& replyArgs, C* object, MF function) +{ + (object->*function)(replyArgs.argument1); +} + +template<typename C, typename MF, typename R1, typename R2> +void callMemberFunction(const Arguments0&, Arguments2<R1, R2>& replyArgs, C* object, MF function) +{ + (object->*function)(replyArgs.argument1, replyArgs.argument2); +} + +template<typename C, typename MF, typename P1> +void callMemberFunction(const Arguments1<P1>& args, Arguments0&, C* object, MF function) +{ + (object->*function)(args.argument1); +} + +template<typename C, typename MF, typename P1, typename R1> +void callMemberFunction(const Arguments1<P1>& args, Arguments1<R1>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, replyArgs.argument1); +} + +template<typename C, typename MF, typename P1, typename R1, typename R2> +void callMemberFunction(const Arguments1<P1>& args, Arguments2<R1, R2>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, replyArgs.argument1, replyArgs.argument2); +} + +template<typename C, typename MF, typename P1, typename R1, typename R2, typename R3> +void callMemberFunction(const Arguments1<P1>& args, Arguments3<R1, R2, R3>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, replyArgs.argument1, replyArgs.argument2, replyArgs.argument3); +} + +template<typename C, typename MF, typename P1, typename P2> +void callMemberFunction(const Arguments2<P1, P2>& args, Arguments0&, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2); +} + +template<typename C, typename MF, typename P1, typename R1, typename R2, typename R3, typename R4> +void callMemberFunction(const Arguments1<P1>& args, Arguments4<R1, R2, R3, R4>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, replyArgs.argument1, replyArgs.argument2, replyArgs.argument3, replyArgs.argument4); +} + +template<typename C, typename MF, typename P1, typename P2, typename R1> +void callMemberFunction(const Arguments2<P1, P2>& args, Arguments1<R1>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, replyArgs.argument1); +} + +template<typename C, typename MF, typename P1, typename P2, typename R1, typename R2> +void callMemberFunction(const Arguments2<P1, P2>& args, Arguments2<R1, R2>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, replyArgs.argument1, replyArgs.argument2); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename R1> +void callMemberFunction(const Arguments3<P1, P2, P3>& args, Arguments1<R1>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, replyArgs.argument1); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename R1, typename R2> +void callMemberFunction(const Arguments3<P1, P2, P3>& args, Arguments2<R1, R2>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, replyArgs.argument1, replyArgs.argument2); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename R1> +void callMemberFunction(const Arguments4<P1, P2, P3, P4>& args, Arguments1<R1>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, replyArgs.argument1); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename R1> +void callMemberFunction(const Arguments7<P1, P2, P3, P4, P5, P6, P7>& args, Arguments1<R1>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5, args.argument6, args.argument7, replyArgs.argument1); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename R1, typename R2> +void callMemberFunction(const Arguments4<P1, P2, P3, P4>& args, Arguments2<R1, R2>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, replyArgs.argument1, replyArgs.argument2); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5, typename R1, typename R2> +void callMemberFunction(const Arguments5<P1, P2, P3, P4, P5>& args, Arguments2<R1, R2>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5, replyArgs.argument1, replyArgs.argument2); +} + + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename R1, typename R2, typename R3> +void callMemberFunction(const Arguments4<P1, P2, P3, P4>& args, Arguments3<R1, R2, R3>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, replyArgs.argument1, replyArgs.argument2, replyArgs.argument3); +} + +// Variadic dispatch functions. + +template<typename C, typename MF> +void callMemberFunction(const Arguments0&, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(argumentDecoder); +} + +template<typename C, typename MF, typename P1> +void callMemberFunction(const Arguments1<P1>& args, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(args.argument1, argumentDecoder); +} + +template<typename C, typename MF, typename P1, typename P2> +void callMemberFunction(const Arguments2<P1, P2>& args, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, argumentDecoder); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3> +void callMemberFunction(const Arguments3<P1, P2, P3>& args, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, argumentDecoder); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4> +void callMemberFunction(const Arguments4<P1, P2, P3, P4>& args, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, argumentDecoder); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5> +void callMemberFunction(const Arguments5<P1, P2, P3, P4, P5>& args, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5, argumentDecoder); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6> +void callMemberFunction(const Arguments6<P1, P2, P3, P4, P5, P6>& args, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5, args.argument6, argumentDecoder); +} + + +// Main dispatch functions + +template<typename T, typename C, typename MF> +void handleMessage(ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + typename T::DecodeType::ValueType arguments; + if (!argumentDecoder->decode(arguments)) + return; + callMemberFunction(arguments, object, function); +} + +template<typename T, typename C, typename MF> +void handleMessage(ArgumentDecoder* argumentDecoder, ArgumentEncoder* replyEncoder, C* object, MF function) +{ + typename T::DecodeType::ValueType arguments; + if (!argumentDecoder->decode(arguments)) + return; + + typename T::Reply::ValueType replyArguments; + callMemberFunction(arguments, replyArguments, object, function); + replyEncoder->encode(replyArguments); +} + +template<typename T, typename C, typename MF> +void handleMessageVariadic(ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + typename T::DecodeType::ValueType arguments; + if (!argumentDecoder->decode(arguments)) + return; + callMemberFunction(arguments, argumentDecoder, object, function); +} + +} // namespace CoreIPC + +#endif // HandleMessage_h diff --git a/Source/WebKit2/Platform/CoreIPC/MessageID.h b/Source/WebKit2/Platform/CoreIPC/MessageID.h new file mode 100644 index 0000000..724302c --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/MessageID.h @@ -0,0 +1,156 @@ +/* + * 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 MessageID_h +#define MessageID_h + +namespace CoreIPC { + +enum MessageClass { + MessageClassReserved = 0, + + // Messages sent by Core IPC. + MessageClassCoreIPC, + + // Messages sent by the UI process to the web process. + MessageClassAuthenticationManager, + MessageClassDrawingArea, + MessageClassDrawingAreaLegacy, + MessageClassInjectedBundle, + MessageClassWebDatabaseManager, + MessageClassWebGeolocationManagerProxy, + MessageClassWebInspector, + MessageClassWebPage, + MessageClassWebProcess, + + // Messages sent by the web process to the UI process. + MessageClassDownloadProxy, + MessageClassDrawingAreaProxy, + MessageClassDrawingAreaProxyLegacy, + MessageClassWebContext, + MessageClassWebContextLegacy, + MessageClassWebDatabaseManagerProxy, + MessageClassWebGeolocationManager, + MessageClassWebInspectorProxy, + MessageClassWebPageProxy, + MessageClassWebProcessProxy, + MessageClassWebProcessProxyLegacy, + + // Messages sent by the UI process to the plug-in process. + MessageClassPluginProcess, + + // Messages sent by the plug-in process to the UI process. + MessageClassPluginProcessProxy, + + // Messages sent by the web process to the plug-in process. + MessageClassWebProcessConnection, + MessageClassPluginControllerProxy, + + // Messages sent by the plug-in process to the web process. + MessageClassPluginProxy, + + // NPObject messages sent by both the plug-in process and the web process. + MessageClassNPObjectMessageReceiver, +}; + +template<typename> struct MessageKindTraits { }; + + +/* + MessageID Layout (the most significant bit is reserved and therefore always zero) + + --------- + | Flags | 7 bits + |-------| + | Class | 8 bits + |-------| + | Msg | 16 bits + | Kind | + --------- +*/ + +class MessageID { +public: + enum Flags { + SyncMessage = 1 << 0, + }; + + MessageID() + : m_messageID(0) + { + } + + template <typename EnumType> + explicit MessageID(EnumType messageKind, unsigned char flags = 0) + : m_messageID(stripMostSignificantBit(flags << 24 | (MessageKindTraits<EnumType>::messageClass) << 16 | messageKind)) + { + } + + template <typename EnumType> + EnumType get() const + { + ASSERT(getClass() == MessageKindTraits<EnumType>::messageClass); + return static_cast<EnumType>(m_messageID & 0xffff); + } + + template <MessageClass K> + bool is() const + { + return getClass() == K; + } + + template <typename EnumType> + bool operator==(EnumType messageKind) const + { + return m_messageID == MessageID(messageKind).m_messageID; + } + + static MessageID fromInt(unsigned i) + { + MessageID messageID; + messageID.m_messageID = stripMostSignificantBit(i); + + return messageID; + } + + unsigned toInt() const { return m_messageID; } + + bool isSync() const { return getFlags() & SyncMessage; } + +private: + static inline unsigned stripMostSignificantBit(unsigned value) + { + return value & 0x7fffffff; + } + + unsigned char getFlags() const { return (m_messageID & 0xff000000) >> 24; } + unsigned char getClass() const { return (m_messageID & 0x00ff0000) >> 16; } + + unsigned m_messageID; +}; + +} // namespace CoreIPC + +#endif // MessageID_h diff --git a/Source/WebKit2/Platform/CoreIPC/MessageSender.h b/Source/WebKit2/Platform/CoreIPC/MessageSender.h new file mode 100644 index 0000000..e2ba0b5 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/MessageSender.h @@ -0,0 +1,73 @@ +/* + * 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 MessageSender_h +#define MessageSender_h + +#include <wtf/Assertions.h> +#include "Connection.h" + +namespace CoreIPC { + +template<typename T> class MessageSender { +public: + template<typename U> bool send(const U& message) + { + return send(message, static_cast<T*>(this)->destinationID()); + } + + template<typename U> bool send(const U& message, uint64_t destinationID) + { + OwnPtr<ArgumentEncoder> argumentEncoder = ArgumentEncoder::create(destinationID); + argumentEncoder->encode(message); + + return static_cast<T*>(this)->sendMessage(MessageID(U::messageID), argumentEncoder.release()); + } + + bool sendMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> argumentEncoder) + { + Connection* connection = static_cast<T*>(this)->connection(); + ASSERT(connection); + + return connection->sendMessage(messageID, argumentEncoder); + } + + template<typename U> bool sendSync(const U& message, const typename U::Reply& reply, double timeout = Connection::NoTimeout) + { + return sendSync(message, reply, static_cast<T*>(this)->destinationID(), timeout); + } + + template<typename U> bool sendSync(const U& message, const typename U::Reply& reply, uint64_t destinationID, double timeout = Connection::NoTimeout) + { + Connection* connection = static_cast<T*>(this)->connection(); + ASSERT(connection); + + return connection->sendSync(message, reply, destinationID, timeout); + } +}; + +} // namespace CoreIPC + +#endif // MessageSender_h diff --git a/Source/WebKit2/Platform/CoreIPC/gtk/ConnectionGtk.cpp b/Source/WebKit2/Platform/CoreIPC/gtk/ConnectionGtk.cpp new file mode 100644 index 0000000..65b1254 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/gtk/ConnectionGtk.cpp @@ -0,0 +1,205 @@ +/* + * 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 "Connection.h" + +#include "ArgumentEncoder.h" +#include "WorkItem.h" +#include <errno.h> +#include <glib.h> +#include <sys/fcntl.h> + +using namespace std; + +namespace CoreIPC { + +static const size_t initialMessageBufferSize = 4096; + +static int readBytesFromSocket(int fileDescriptor, uint8_t* ptr, size_t length) +{ + ASSERT(fileDescriptor > 0); + ASSERT(buffer); + ASSERT(length > 0); + + ssize_t numberOfBytesRead = 0; + size_t pendingBytesToRead = length; + uint8_t* buffer = ptr; + + while (pendingBytesToRead > 0) { + if ((numberOfBytesRead = read(fileDescriptor, buffer, pendingBytesToRead)) < 0) { + if (errno == EINTR) + numberOfBytesRead = 0; + else if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + else + return 0; + } else if (!numberOfBytesRead) + break; + + buffer += numberOfBytesRead; + pendingBytesToRead -= numberOfBytesRead; + } + + return (length - pendingBytesToRead); +} + +static bool writeBytesToSocket(int fileDescriptor, uint8_t* ptr, size_t length) +{ + ASSERT(fileDescriptor > 0); + ASSERT(buffer); + ASSERT(length > 0); + + ssize_t numberOfBytesWritten = 0; + size_t pendingBytesToWrite = length; + uint8_t* buffer = ptr; + + // Keep writing to the socket till the complete message has been written. + while (pendingBytesToWrite > 0) { + if ((numberOfBytesWritten = write(fileDescriptor, buffer, pendingBytesToWrite)) < 0) { + if (errno == EINTR) + numberOfBytesWritten = 0; + else + return false; + } + buffer += numberOfBytesWritten; + pendingBytesToWrite -= numberOfBytesWritten; + } + + // Write operation failed if complete message is not written. + return !pendingBytesToWrite; +} + +void Connection::platformInitialize(Identifier identifier) +{ + m_currentMessageSize = 0; + m_pendingBytes = 0; + m_readBuffer.resize(initialMessageBufferSize); + m_socket = identifier; + m_isConnected = true; +} + +void Connection::platformInvalidate() +{ + if (!m_isConnected) + return; + + m_connectionQueue.unregisterEventSourceHandler(m_socket); + if (m_socket > 0) { + close(m_socket); + m_socket = -1; + } + + m_isConnected = false; +} + +void Connection::processCompletedMessage() +{ + size_t realBufferSize = m_currentMessageSize - sizeof(MessageID); + unsigned messageID = *reinterpret_cast<unsigned*>(m_readBuffer.data() + realBufferSize); + + processIncomingMessage(MessageID::fromInt(messageID), adoptPtr(new ArgumentDecoder(m_readBuffer.data(), realBufferSize))); + + // Prepare for the next message. + m_currentMessageSize = 0; + m_pendingBytes = 0; +} + +void Connection::readEventHandler() +{ + if (m_socket < 0) + return; + + // Handle any previously unprocessed message. + if (!messageProcessingCompleted()) { + if ((m_pendingBytes -= readBytesFromSocket(m_socket, (m_readBuffer.data() + (m_currentMessageSize - m_pendingBytes)), m_pendingBytes)) > 0) + return; + + // Message received completely. Process the message now. + processCompletedMessage(); + } + + // Prepare to read the next message. + uint8_t sizeBuffer[sizeof(size_t)]; + memset(sizeBuffer, 0, sizeof(size_t)); + + while (messageProcessingCompleted()) { + if (readBytesFromSocket(m_socket, sizeBuffer, sizeof(size_t))) + m_currentMessageSize = *reinterpret_cast<size_t*>(sizeBuffer); + + if (!m_currentMessageSize) + break; + + if (m_readBuffer.size() < m_currentMessageSize) + m_readBuffer.grow(m_currentMessageSize); + + m_pendingBytes = m_currentMessageSize - readBytesFromSocket(m_socket, m_readBuffer.data(), m_currentMessageSize); + if (m_pendingBytes > 0) // Message partially received. + break; + + // Message received completely. Process the message now. + processCompletedMessage(); + + memset(sizeBuffer, 0, sizeof(size_t)); + } +} + +bool Connection::open() +{ + int flags = fcntl(m_socket, F_GETFL, 0); + fcntl(m_socket, F_SETFL, flags | O_NONBLOCK); + + // Register callbacks for connection termination and input data on the WorkQueue. + m_connectionQueue.registerEventSourceHandler(m_socket, (G_IO_HUP | G_IO_ERR), WorkItem::create(this, &Connection::connectionDidClose)); + m_connectionQueue.registerEventSourceHandler(m_socket, G_IO_IN, WorkItem::create(this, &Connection::readEventHandler)); + return true; +} + +bool Connection::platformCanSendOutgoingMessages() const +{ + return (m_socket > 0); +} + +bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments) +{ + if (m_socket < 0) + return false; + + // We put the message ID last. + arguments->encodeUInt32(messageID.toInt()); + + size_t bufferSize = arguments->bufferSize(); + + // Send the message size first. + if (!writeBytesToSocket(m_socket, reinterpret_cast<uint8_t*>(&bufferSize), sizeof(size_t))) + return false; + + if (!writeBytesToSocket(m_socket, arguments->buffer(), arguments->bufferSize())) + return false; + + return true; +} + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/mac/ConnectionMac.cpp b/Source/WebKit2/Platform/CoreIPC/mac/ConnectionMac.cpp new file mode 100644 index 0000000..5e7bbbc --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/mac/ConnectionMac.cpp @@ -0,0 +1,424 @@ +/* + * 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 "Connection.h" + +#include "CoreIPCMessageKinds.h" +#include "MachPort.h" +#include "MachUtilities.h" +#include "RunLoop.h" +#include <mach/vm_map.h> + +using namespace std; + +namespace CoreIPC { + +static const size_t inlineMessageMaxSize = 4096; + +enum { + MessageBodyIsOOL = 1 << 31 +}; + +void Connection::platformInvalidate() +{ + if (!m_isConnected) + return; + + m_isConnected = false; + + ASSERT(m_sendPort); + ASSERT(m_receivePort); + + // Unregister our ports. + m_connectionQueue.unregisterMachPortEventHandler(m_sendPort); + m_sendPort = MACH_PORT_NULL; + + m_connectionQueue.unregisterMachPortEventHandler(m_receivePort); + m_receivePort = MACH_PORT_NULL; + + if (m_exceptionPort) { + m_connectionQueue.unregisterMachPortEventHandler(m_exceptionPort); + m_exceptionPort = MACH_PORT_NULL; + } +} + +void Connection::platformInitialize(Identifier identifier) +{ + m_exceptionPort = MACH_PORT_NULL; + + if (m_isServer) { + m_receivePort = identifier; + m_sendPort = MACH_PORT_NULL; + } else { + m_receivePort = MACH_PORT_NULL; + m_sendPort = identifier; + } +} + +bool Connection::open() +{ + if (m_isServer) { + ASSERT(m_receivePort); + ASSERT(!m_sendPort); + + } else { + ASSERT(!m_receivePort); + ASSERT(m_sendPort); + + // Create the receive port. + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_receivePort); + + m_isConnected = true; + + // Send the initialize message, which contains a send right for the server to use. + send(CoreIPCMessage::InitializeConnection, 0, MachPort(m_receivePort, MACH_MSG_TYPE_MAKE_SEND)); + + // Set the dead name handler for our send port. + initializeDeadNameSource(); + } + + // Change the message queue length for the receive port. + setMachPortQueueLength(m_receivePort, MACH_PORT_QLIMIT_LARGE); + + // Register the data available handler. + m_connectionQueue.registerMachPortEventHandler(m_receivePort, WorkQueue::MachPortDataAvailable, WorkItem::create(this, &Connection::receiveSourceEventHandler)); + + // If we have an exception port, register the data available handler and send over the port to the other end. + if (m_exceptionPort) { + m_connectionQueue.registerMachPortEventHandler(m_exceptionPort, WorkQueue::MachPortDataAvailable, WorkItem::create(this, &Connection::exceptionSourceEventHandler)); + + send(CoreIPCMessage::SetExceptionPort, 0, MachPort(m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND)); + } + + return true; +} + +static inline size_t machMessageSize(size_t bodySize, size_t numberOfPortDescriptors = 0, size_t numberOfOOLMemoryDescriptors = 0) +{ + size_t size = sizeof(mach_msg_header_t) + bodySize; + if (numberOfPortDescriptors || numberOfOOLMemoryDescriptors) { + size += sizeof(mach_msg_body_t); + if (numberOfPortDescriptors) + size += (numberOfPortDescriptors * sizeof(mach_msg_port_descriptor_t)); + if (numberOfOOLMemoryDescriptors) + size += (numberOfOOLMemoryDescriptors * sizeof(mach_msg_ool_ports_descriptor_t)); + } + return round_msg(size); +} + +bool Connection::platformCanSendOutgoingMessages() const +{ + return true; +} + +bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments) +{ + Vector<Attachment> attachments = arguments->releaseAttachments(); + + size_t numberOfPortDescriptors = 0; + size_t numberOfOOLMemoryDescriptors = 0; + for (size_t i = 0; i < attachments.size(); ++i) { + Attachment::Type type = attachments[i].type(); + if (type == Attachment::MachPortType) + numberOfPortDescriptors++; + else if (type == Attachment::MachOOLMemoryType) + numberOfOOLMemoryDescriptors++; + } + + size_t messageSize = machMessageSize(arguments->bufferSize(), numberOfPortDescriptors, numberOfOOLMemoryDescriptors); + char buffer[inlineMessageMaxSize]; + + bool messageBodyIsOOL = false; + if (messageSize > sizeof(buffer)) { + messageBodyIsOOL = true; + + attachments.append(Attachment(arguments->buffer(), arguments->bufferSize(), MACH_MSG_VIRTUAL_COPY, false)); + numberOfOOLMemoryDescriptors++; + messageSize = machMessageSize(0, numberOfPortDescriptors, numberOfOOLMemoryDescriptors); + } + + bool isComplex = (numberOfPortDescriptors + numberOfOOLMemoryDescriptors > 0); + + mach_msg_header_t* header = reinterpret_cast<mach_msg_header_t*>(&buffer); + header->msgh_bits = isComplex ? MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND | MACH_MSGH_BITS_COMPLEX, 0) : MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); + header->msgh_size = messageSize; + header->msgh_remote_port = m_sendPort; + header->msgh_local_port = MACH_PORT_NULL; + header->msgh_id = messageID.toInt(); + if (messageBodyIsOOL) + header->msgh_id |= MessageBodyIsOOL; + + uint8_t* messageData; + + if (isComplex) { + mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1); + body->msgh_descriptor_count = numberOfPortDescriptors + numberOfOOLMemoryDescriptors; + + uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1); + for (size_t i = 0; i < attachments.size(); ++i) { + Attachment attachment = attachments[i]; + + mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData); + switch (attachment.type()) { + case Attachment::MachPortType: + descriptor->port.name = attachment.port(); + descriptor->port.disposition = attachment.disposition(); + descriptor->port.type = MACH_MSG_PORT_DESCRIPTOR; + + descriptorData += sizeof(mach_msg_port_descriptor_t); + break; + case Attachment::MachOOLMemoryType: + descriptor->out_of_line.address = attachment.address(); + descriptor->out_of_line.size = attachment.size(); + descriptor->out_of_line.copy = attachment.copyOptions(); + descriptor->out_of_line.deallocate = attachment.deallocate(); + descriptor->out_of_line.type = MACH_MSG_OOL_DESCRIPTOR; + + descriptorData += sizeof(mach_msg_ool_descriptor_t); + break; + default: + ASSERT_NOT_REACHED(); + } + } + + messageData = descriptorData; + } else + messageData = (uint8_t*)(header + 1); + + // Copy the data if it is not being sent out-of-line. + if (!messageBodyIsOOL) + memcpy(messageData, arguments->buffer(), arguments->bufferSize()); + + ASSERT(m_sendPort); + + // Send the message. + kern_return_t kr = mach_msg(header, MACH_SEND_MSG, messageSize, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (kr != KERN_SUCCESS) { + // FIXME: What should we do here? + } + + return true; +} + +void Connection::initializeDeadNameSource() +{ + m_connectionQueue.registerMachPortEventHandler(m_sendPort, WorkQueue::MachPortDeadNameNotification, WorkItem::create(this, &Connection::connectionDidClose)); +} + +static PassOwnPtr<ArgumentDecoder> createArgumentDecoder(mach_msg_header_t* header) +{ + if (!(header->msgh_bits & MACH_MSGH_BITS_COMPLEX)) { + // We have a simple message. + size_t bodySize = header->msgh_size - sizeof(mach_msg_header_t); + uint8_t* body = reinterpret_cast<uint8_t*>(header + 1); + + return adoptPtr(new ArgumentDecoder(body, bodySize)); + } + + bool messageBodyIsOOL = header->msgh_id & MessageBodyIsOOL; + + mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1); + mach_msg_size_t numDescriptors = body->msgh_descriptor_count; + ASSERT(numDescriptors); + + // Build attachment list + Deque<Attachment> attachments; + uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1); + + // If the message body was sent out-of-line, don't treat the last descriptor + // as an attachment, since it is really the message body. + if (messageBodyIsOOL) + --numDescriptors; + + for (mach_msg_size_t i = 0; i < numDescriptors; ++i) { + mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData); + + switch (descriptor->type.type) { + case MACH_MSG_PORT_DESCRIPTOR: + attachments.append(Attachment(descriptor->port.name, descriptor->port.disposition)); + descriptorData += sizeof(mach_msg_port_descriptor_t); + break; + case MACH_MSG_OOL_DESCRIPTOR: + attachments.append(Attachment(descriptor->out_of_line.address, descriptor->out_of_line.size, + descriptor->out_of_line.copy, descriptor->out_of_line.deallocate)); + descriptorData += sizeof(mach_msg_ool_descriptor_t); + break; + default: + ASSERT(false && "Unhandled descriptor type"); + } + } + + if (messageBodyIsOOL) { + mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData); + ASSERT(descriptor->type.type == MACH_MSG_OOL_DESCRIPTOR); + Attachment messageBodyAttachment(descriptor->out_of_line.address, descriptor->out_of_line.size, + descriptor->out_of_line.copy, descriptor->out_of_line.deallocate); + + uint8_t* messageBody = static_cast<uint8_t*>(messageBodyAttachment.address()); + size_t messageBodySize = messageBodyAttachment.size(); + + ArgumentDecoder* argumentDecoder; + + if (attachments.isEmpty()) + argumentDecoder = new ArgumentDecoder(messageBody, messageBodySize); + else + argumentDecoder = new ArgumentDecoder(messageBody, messageBodySize, attachments); + + vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(messageBodyAttachment.address()), messageBodyAttachment.size()); + + return adoptPtr(argumentDecoder); + } + + uint8_t* messageBody = descriptorData; + size_t messageBodySize = header->msgh_size - (descriptorData - reinterpret_cast<uint8_t*>(header)); + + return adoptPtr(new ArgumentDecoder(messageBody, messageBodySize, attachments)); +} + +// The receive buffer size should always include the maximum trailer size. +static const size_t receiveBufferSize = inlineMessageMaxSize + MAX_TRAILER_SIZE; +typedef Vector<char, receiveBufferSize> ReceiveBuffer; + +static mach_msg_header_t* readFromMachPort(mach_port_t machPort, ReceiveBuffer& buffer) +{ + buffer.resize(receiveBufferSize); + + mach_msg_header_t* header = reinterpret_cast<mach_msg_header_t*>(buffer.data()); + kern_return_t kr = mach_msg(header, MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0, buffer.size(), machPort, 0, MACH_PORT_NULL); + if (kr == MACH_RCV_TIMED_OUT) + return 0; + + if (kr == MACH_RCV_TOO_LARGE) { + // The message was too large, resize the buffer and try again. + buffer.resize(header->msgh_size + MAX_TRAILER_SIZE); + header = reinterpret_cast<mach_msg_header_t*>(buffer.data()); + + kr = mach_msg(header, MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0, buffer.size(), machPort, 0, MACH_PORT_NULL); + ASSERT(kr != MACH_RCV_TOO_LARGE); + } + + if (kr != MACH_MSG_SUCCESS) { + ASSERT_NOT_REACHED(); + return 0; + } + + return header; +} + +void Connection::receiveSourceEventHandler() +{ + ReceiveBuffer buffer; + + mach_msg_header_t* header = readFromMachPort(m_receivePort, buffer); + if (!header) + return; + + MessageID messageID = MessageID::fromInt(header->msgh_id); + OwnPtr<ArgumentDecoder> arguments = createArgumentDecoder(header); + ASSERT(arguments); + + if (messageID == MessageID(CoreIPCMessage::InitializeConnection)) { + ASSERT(m_isServer); + ASSERT(!m_isConnected); + ASSERT(!m_sendPort); + + MachPort port; + if (!arguments->decode(port)) { + // FIXME: Disconnect. + return; + } + + m_sendPort = port.port(); + + // Set the dead name source if needed. + if (m_sendPort) + initializeDeadNameSource(); + + m_isConnected = true; + + // Send any pending outgoing messages. + sendOutgoingMessages(); + + return; + } + + if (messageID == MessageID(CoreIPCMessage::SetExceptionPort)) { + MachPort exceptionPort; + if (!arguments->decode(exceptionPort)) + return; + + setMachExceptionPort(exceptionPort.port()); + return; + } + + processIncomingMessage(messageID, arguments.release()); +} + +void Connection::exceptionSourceEventHandler() +{ + ReceiveBuffer buffer; + + mach_msg_header_t* header = readFromMachPort(m_exceptionPort, buffer); + if (!header) + return; + + // We've read the exception message. Now send it on to the real exception port. + + // The remote port should have a send once right. + ASSERT(MACH_MSGH_BITS_REMOTE(header->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE); + + // Now get the real exception port. + mach_port_t exceptionPort = machExceptionPort(); + + // First, get the complex bit from the source message. + mach_msg_bits_t messageBits = header->msgh_bits & MACH_MSGH_BITS_COMPLEX; + messageBits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE); + + header->msgh_bits = messageBits; + header->msgh_local_port = header->msgh_remote_port; + header->msgh_remote_port = exceptionPort; + + // Now send along the message. + kern_return_t kr = mach_msg(header, MACH_SEND_MSG, header->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (kr != KERN_SUCCESS) { + LOG_ERROR("Failed to send message to real exception port, error %x", kr); + ASSERT_NOT_REACHED(); + } + + connectionDidClose(); +} + +void Connection::setShouldCloseConnectionOnMachExceptions() +{ + ASSERT(m_exceptionPort == MACH_PORT_NULL); + + if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_exceptionPort) != KERN_SUCCESS) + ASSERT_NOT_REACHED(); + + if (mach_port_insert_right(mach_task_self(), m_exceptionPort, m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS) + ASSERT_NOT_REACHED(); +} + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/mac/MachPort.h b/Source/WebKit2/Platform/CoreIPC/mac/MachPort.h new file mode 100644 index 0000000..ecce16e --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/mac/MachPort.h @@ -0,0 +1,75 @@ +/* + * 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 MachPort_h +#define MachPort_h + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" +#include "Attachment.h" + +namespace CoreIPC { + +class MachPort { +public: + MachPort() + : m_port(MACH_PORT_NULL) + , m_disposition(0) + { + } + + MachPort(mach_port_name_t port, mach_msg_type_name_t disposition) + : m_port(port) + , m_disposition(disposition) + { + } + + void encode(ArgumentEncoder* encoder) const + { + encoder->encode(Attachment(m_port, m_disposition)); + } + + static bool decode(ArgumentDecoder* decoder, MachPort& p) + { + Attachment attachment; + if (!decoder->decode(attachment)) + return false; + + p.m_port = attachment.port(); + p.m_disposition = attachment.disposition(); + return true; + } + + mach_port_name_t port() const { return m_port; } + mach_msg_type_name_t disposition() const { return m_disposition; } + +private: + mach_port_name_t m_port; + mach_msg_type_name_t m_disposition; +}; + +} // namespace CoreIPC + +#endif // MachPort_h diff --git a/Source/WebKit2/Platform/CoreIPC/qt/ConnectionQt.cpp b/Source/WebKit2/Platform/CoreIPC/qt/ConnectionQt.cpp new file mode 100644 index 0000000..c0736b8 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/qt/ConnectionQt.cpp @@ -0,0 +1,142 @@ +/* + * 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 "Connection.h" + +#include "ArgumentEncoder.h" +#include "ProcessLauncher.h" +#include "WorkItem.h" +#include <QApplication> +#include <QLocalServer> +#include <QLocalSocket> + +using namespace std; + +namespace CoreIPC { + +// This is what other ports use... +static const size_t messageMaxSize = 4096; + +void Connection::platformInitialize(Identifier identifier) +{ + m_serverName = identifier; + m_socket = 0; + m_readBuffer.resize(messageMaxSize); + m_currentMessageSize = 0; +} + +void Connection::platformInvalidate() +{ + m_socket->disconnect(); + if (!m_isServer) + m_socket->deleteLater(); + m_socket = 0; +} + +void Connection::readyReadHandler() +{ + while (m_socket->bytesAvailable()) { + if (!m_currentMessageSize) { + size_t numberOfBytesRead = m_socket->read(reinterpret_cast<char*>(m_readBuffer.data()), sizeof(size_t)); + ASSERT_UNUSED(numberOfBytesRead, numberOfBytesRead); + m_currentMessageSize = *reinterpret_cast<size_t*>(m_readBuffer.data()); + } + + if (m_socket->bytesAvailable() < m_currentMessageSize) + return; + + if (m_readBuffer.size() < m_currentMessageSize) + m_readBuffer.grow(m_currentMessageSize); + + size_t numberOfBytesRead = m_socket->read(reinterpret_cast<char*>(m_readBuffer.data()), m_currentMessageSize); + ASSERT_UNUSED(numberOfBytesRead, numberOfBytesRead); + + // The messageID is encoded at the end of the buffer. + size_t realBufferSize = m_currentMessageSize - sizeof(uint32_t); + uint32_t messageID = *reinterpret_cast<uint32_t*>(m_readBuffer.data() + realBufferSize); + + processIncomingMessage(MessageID::fromInt(messageID), adoptPtr(new ArgumentDecoder(m_readBuffer.data(), realBufferSize))); + + m_currentMessageSize = 0; + } +} + +bool Connection::open() +{ + ASSERT(!m_socket); + + if (m_isServer) { + m_socket = WebKit::ProcessLauncher::takePendingConnection(); + m_isConnected = m_socket; + if (m_isConnected) { + m_connectionQueue.moveSocketToWorkThread(m_socket); + m_connectionQueue.connectSignal(m_socket, SIGNAL(readyRead()), WorkItem::create(this, &Connection::readyReadHandler)); + } + } else { + m_socket = new QLocalSocket(); + m_socket->connectToServer(m_serverName); + m_connectionQueue.moveSocketToWorkThread(m_socket); + m_connectionQueue.connectSignal(m_socket, SIGNAL(readyRead()), WorkItem::create(this, &Connection::readyReadHandler)); + m_connectionQueue.connectSignal(m_socket, SIGNAL(disconnected()), WorkItem::create(this, &Connection::connectionDidClose)); + m_isConnected = m_socket->waitForConnected(); + } + return m_isConnected; +} + +bool Connection::platformCanSendOutgoingMessages() const +{ + return m_socket; +} + +bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments) +{ + ASSERT(m_socket); + + // We put the message ID last. + arguments->encodeUInt32(messageID.toInt()); + + size_t bufferSize = arguments->bufferSize(); + + // Write message size first + // FIXME: Should just do a single write. + qint64 bytesWrittenForSize = m_socket->write(reinterpret_cast<char*>(&bufferSize), sizeof(bufferSize)); + if (bytesWrittenForSize != sizeof(bufferSize)) { + connectionDidClose(); + return false; + } + + qint64 bytesWrittenForBuffer = m_socket->write(reinterpret_cast<char*>(arguments->buffer()), arguments->bufferSize()); + if (bytesWrittenForBuffer != arguments->bufferSize()) { + connectionDidClose(); + return false; + } + + m_socket->flush(); + + return true; +} + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/win/ConnectionWin.cpp b/Source/WebKit2/Platform/CoreIPC/win/ConnectionWin.cpp new file mode 100644 index 0000000..695da78 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/win/ConnectionWin.cpp @@ -0,0 +1,315 @@ +/* + * 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 "Connection.h" + +#include "ArgumentEncoder.h" +#include "WorkItem.h" +#include <wtf/RandomNumber.h> +#include <wtf/text/WTFString.h> + +using namespace std; +// We explicitly don't use the WebCore namespace here because CoreIPC should only use WTF types and +// WTF::String is really in WTF. +using WTF::String; + +namespace CoreIPC { + +// FIXME: Rename this or use a different constant on windows. +static const size_t inlineMessageMaxSize = 4096; + +bool Connection::createServerAndClientIdentifiers(HANDLE& serverIdentifier, HANDLE& clientIdentifier) +{ + String pipeName; + + while (true) { + unsigned uniqueID = randomNumber() * std::numeric_limits<unsigned>::max(); + pipeName = String::format("\\\\.\\pipe\\com.apple.WebKit.%x", uniqueID); + + serverIdentifier = ::CreateNamedPipe(pipeName.charactersWithNullTermination(), + PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, inlineMessageMaxSize, inlineMessageMaxSize, + 0, 0); + if (!serverIdentifier && ::GetLastError() == ERROR_PIPE_BUSY) { + // There was already a pipe with this name, try again. + continue; + } + + break; + } + + if (!serverIdentifier) + return false; + + clientIdentifier = ::CreateFileW(pipeName.charactersWithNullTermination(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if (!clientIdentifier) { + ::CloseHandle(serverIdentifier); + return false; + } + + DWORD mode = PIPE_READMODE_MESSAGE; + if (!::SetNamedPipeHandleState(clientIdentifier, &mode, 0, 0)) { + ::CloseHandle(serverIdentifier); + ::CloseHandle(clientIdentifier); + return false; + } + + return true; +} + +void Connection::platformInitialize(Identifier identifier) +{ + memset(&m_readState, 0, sizeof(m_readState)); + m_readState.hEvent = ::CreateEventW(0, FALSE, FALSE, 0); + + memset(&m_writeState, 0, sizeof(m_writeState)); + m_writeState.hEvent = ::CreateEventW(0, FALSE, FALSE, 0); + + m_connectionPipe = identifier; + + // We connected the two ends of the pipe in createServerAndClientIdentifiers. + m_isConnected = true; +} + +void Connection::platformInvalidate() +{ + if (m_connectionPipe == INVALID_HANDLE_VALUE) + return; + + m_connectionQueue.unregisterAndCloseHandle(m_readState.hEvent); + m_readState.hEvent = 0; + + m_connectionQueue.unregisterAndCloseHandle(m_writeState.hEvent); + m_writeState.hEvent = 0; + + ::CloseHandle(m_connectionPipe); + m_connectionPipe = INVALID_HANDLE_VALUE; +} + +void Connection::readEventHandler() +{ + if (m_connectionPipe == INVALID_HANDLE_VALUE) + return; + + while (true) { + // Check if we got some data. + DWORD numberOfBytesRead = 0; + if (!::GetOverlappedResult(m_connectionPipe, &m_readState, &numberOfBytesRead, FALSE)) { + DWORD error = ::GetLastError(); + + switch (error) { + case ERROR_BROKEN_PIPE: + connectionDidClose(); + return; + case ERROR_MORE_DATA: { + // Read the rest of the message out of the pipe. + + DWORD bytesToRead = 0; + if (!::PeekNamedPipe(m_connectionPipe, 0, 0, 0, 0, &bytesToRead)) { + DWORD error = ::GetLastError(); + if (error == ERROR_BROKEN_PIPE) { + connectionDidClose(); + return; + } + ASSERT_NOT_REACHED(); + return; + } + + // ::GetOverlappedResult told us there's more data. ::PeekNamedPipe shouldn't + // contradict it! + ASSERT(bytesToRead); + if (!bytesToRead) + break; + + m_readBuffer.grow(m_readBuffer.size() + bytesToRead); + if (!::ReadFile(m_connectionPipe, m_readBuffer.data() + numberOfBytesRead, bytesToRead, 0, &m_readState)) { + DWORD error = ::GetLastError(); + ASSERT_NOT_REACHED(); + return; + } + continue; + } + + // FIXME: We should figure out why we're getting this error. + case ERROR_IO_INCOMPLETE: + return; + default: + ASSERT_NOT_REACHED(); + } + } + + if (!m_readBuffer.isEmpty()) { + // We have a message, let's dispatch it. + + // The messageID is encoded at the end of the buffer. + // Note that we assume here that the message is the same size as m_readBuffer. We can + // assume this because we always size m_readBuffer to exactly match the size of the message, + // either when receiving ERROR_MORE_DATA from ::GetOverlappedResult above or when + // ::PeekNamedPipe tells us the size below. We never set m_readBuffer to a size larger + // than the message. + ASSERT(m_readBuffer.size() >= sizeof(MessageID)); + size_t realBufferSize = m_readBuffer.size() - sizeof(MessageID); + + unsigned messageID = *reinterpret_cast<unsigned*>(m_readBuffer.data() + realBufferSize); + + processIncomingMessage(MessageID::fromInt(messageID), adoptPtr(new ArgumentDecoder(m_readBuffer.data(), realBufferSize))); + } + + // Find out the size of the next message in the pipe (if there is one) so that we can read + // it all in one operation. (This is just an optimization to avoid an extra pass through the + // loop (if we chose a buffer size that was too small) or allocating extra memory (if we + // chose a buffer size that was too large).) + DWORD bytesToRead = 0; + if (!::PeekNamedPipe(m_connectionPipe, 0, 0, 0, 0, &bytesToRead)) { + DWORD error = ::GetLastError(); + if (error == ERROR_BROKEN_PIPE) { + connectionDidClose(); + return; + } + ASSERT_NOT_REACHED(); + } + if (!bytesToRead) { + // There's no message waiting in the pipe. Schedule a read of the first byte of the + // next message. We'll find out the message's actual size when it arrives. (If we + // change this to read more than a single byte for performance reasons, we'll have to + // deal with m_readBuffer potentially being larger than the message we read after + // calling ::GetOverlappedResult above.) + bytesToRead = 1; + } + + m_readBuffer.resize(bytesToRead); + + // Either read the next available message (which should occur synchronously), or start an + // asynchronous read of the next message that becomes available. + BOOL result = ::ReadFile(m_connectionPipe, m_readBuffer.data(), m_readBuffer.size(), 0, &m_readState); + if (result) { + // There was already a message waiting in the pipe, and we read it synchronously. + // Process it. + continue; + } + + DWORD error = ::GetLastError(); + + if (error == ERROR_IO_PENDING) { + // There are no messages in the pipe currently. readEventHandler will be called again once there is a message. + return; + } + + if (error == ERROR_MORE_DATA) { + // Either a message is available when we didn't think one was, or the message is larger + // than ::PeekNamedPipe told us. The former seems far more likely. Probably the message + // became available between our calls to ::PeekNamedPipe and ::ReadFile above. Go back + // to the top of the loop to use ::GetOverlappedResult to retrieve the available data. + continue; + } + + // FIXME: We need to handle other errors here. + ASSERT_NOT_REACHED(); + } +} + +void Connection::writeEventHandler() +{ + if (m_connectionPipe == INVALID_HANDLE_VALUE) + return; + + DWORD numberOfBytesWritten = 0; + if (!::GetOverlappedResult(m_connectionPipe, &m_writeState, &numberOfBytesWritten, FALSE)) { + DWORD error = ::GetLastError(); + if (error == ERROR_IO_INCOMPLETE) { + // FIXME: We should figure out why we're getting this error. + return; + } + ASSERT_NOT_REACHED(); + } + + // The pending write has finished, so we are now done with its arguments. Clearing this member + // will allow us to send messages again. + m_pendingWriteArguments = 0; + + // Now that the pending write has finished, we can try to send a new message. + sendOutgoingMessages(); +} + +bool Connection::open() +{ + // Start listening for read and write state events. + m_connectionQueue.registerHandle(m_readState.hEvent, WorkItem::create(this, &Connection::readEventHandler)); + m_connectionQueue.registerHandle(m_writeState.hEvent, WorkItem::create(this, &Connection::writeEventHandler)); + + // Schedule a read. + m_connectionQueue.scheduleWork(WorkItem::create(this, &Connection::readEventHandler)); + + return true; +} + +bool Connection::platformCanSendOutgoingMessages() const +{ + // We only allow sending one asynchronous message at a time. If we wanted to send more than one + // at once, we'd have to use multiple OVERLAPPED structures and hold onto multiple pending + // ArgumentEncoders (one of each for each simultaneous asynchronous message). + return !m_pendingWriteArguments; +} + +bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments) +{ + ASSERT(!m_pendingWriteArguments); + + // Just bail if the handle has been closed. + if (m_connectionPipe == INVALID_HANDLE_VALUE) + return false; + + // We put the message ID last. + arguments->encodeUInt32(messageID.toInt()); + + // Write the outgoing message. + + if (::WriteFile(m_connectionPipe, arguments->buffer(), arguments->bufferSize(), 0, &m_writeState)) { + // We successfully sent this message. + return true; + } + + DWORD error = ::GetLastError(); + + if (error == ERROR_NO_DATA) { + // The pipe is being closed. + connectionDidClose(); + return false; + } + + if (error != ERROR_IO_PENDING) { + ASSERT_NOT_REACHED(); + return false; + } + + // The message will be sent soon. Hold onto the arguments so that they won't be destroyed + // before the write completes. + m_pendingWriteArguments = arguments; + + // We can only send one asynchronous message at a time (see comment in platformCanSendOutgoingMessages). + return false; +} + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/Logging.cpp b/Source/WebKit2/Platform/Logging.cpp new file mode 100644 index 0000000..ca312ef --- /dev/null +++ b/Source/WebKit2/Platform/Logging.cpp @@ -0,0 +1,53 @@ +/* + * 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 "Logging.h" + +#if !LOG_DISABLED + +WTFLogChannel LogSessionState = { 0x00000001, "WebKit2LogLevel", WTFLogChannelOff }; +WTFLogChannel LogContextMenu = { 0x00000002, "WebKit2LogLevel", WTFLogChannelOff }; +WTFLogChannel LogTextInput = { 0x00000004, "WebKit2LogLevel", WTFLogChannelOff }; +WTFLogChannel LogView = { 0x00000008, "WebKit2LogLevel", WTFLogChannelOff }; + +static inline void initializeLogChannel(WTFLogChannel* channel) +{ + // FIXME: This is a build fix. Each platform will need to define their own initializeLogChannel(). +} + +void initializeLogChannelsIfNecessary() +{ + static bool haveInitializedLogChannels = false; + if (haveInitializedLogChannels) + return; + haveInitializedLogChannels = true; + + initializeLogChannel(&LogContextMenu); + initializeLogChannel(&LogSessionState); + initializeLogChannel(&LogTextInput); + initializeLogChannel(&LogView); +} + +#endif // LOG_DISABLED diff --git a/Source/WebKit2/Platform/Logging.h b/Source/WebKit2/Platform/Logging.h new file mode 100644 index 0000000..b2cc391 --- /dev/null +++ b/Source/WebKit2/Platform/Logging.h @@ -0,0 +1,50 @@ +/* + * 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 Logging_h +#define Logging_h + +#include <wtf/Assertions.h> + +#if !LOG_DISABLED + +#ifndef LOG_CHANNEL_PREFIX +#define LOG_CHANNEL_PREFIX Log +#endif + +EXTERN_C_BEGIN + +extern WTFLogChannel LogContextMenu; +extern WTFLogChannel LogSessionState; +extern WTFLogChannel LogTextInput; +extern WTFLogChannel LogView; + +void initializeLogChannelsIfNecessary(void); + +EXTERN_C_END + +#endif // LOG_DISABLED + +#endif // Logging_h diff --git a/Source/WebKit2/Platform/Module.cpp b/Source/WebKit2/Platform/Module.cpp new file mode 100644 index 0000000..7a2def5 --- /dev/null +++ b/Source/WebKit2/Platform/Module.cpp @@ -0,0 +1,43 @@ +/* + * 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 "Module.h" + +namespace WebKit { + +Module::Module(const String& path) + : m_path(path) +#if PLATFORM(WIN) + , m_module(0) +#endif +{ +} + +Module::~Module() +{ + unload(); +} + +} diff --git a/Source/WebKit2/Platform/Module.h b/Source/WebKit2/Platform/Module.h new file mode 100644 index 0000000..0825bf6 --- /dev/null +++ b/Source/WebKit2/Platform/Module.h @@ -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. + */ + +#ifndef Module_h +#define Module_h + +#include <wtf/Noncopyable.h> +#include <wtf/text/WTFString.h> + +#if PLATFORM(MAC) +#include <wtf/RetainPtr.h> +#endif + +#if PLATFORM(QT) +#include <QLibrary> +#endif + +namespace WebKit { + +class Module : public Noncopyable { +public: + Module(const String& path); + ~Module(); + + bool load(); + // Note: On Mac this leaks the CFBundle to avoid crashes when a bundle is unloaded and there are + // live Objective-C objects whose methods come from that bundle. + void unload(); + + template<typename FunctionType> FunctionType functionPointer(const char* functionName) const; + +private: + void* platformFunctionPointer(const char* functionName) const; + + String m_path; +#if PLATFORM(MAC) + RetainPtr<CFBundleRef> m_bundle; +#elif PLATFORM(WIN) + HMODULE m_module; +#elif PLATFORM(QT) + QLibrary m_lib; +#endif +}; + +template<typename FunctionType> FunctionType Module::functionPointer(const char* functionName) const +{ + return reinterpret_cast<FunctionType>(platformFunctionPointer(functionName)); +} + +} + +#endif diff --git a/Source/WebKit2/Platform/PlatformProcessIdentifier.h b/Source/WebKit2/Platform/PlatformProcessIdentifier.h new file mode 100644 index 0000000..0363692 --- /dev/null +++ b/Source/WebKit2/Platform/PlatformProcessIdentifier.h @@ -0,0 +1,48 @@ +/* + * 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 PlatformProcessIdentifier_h +#define PlatformProcessIdentifier_h + +#if PLATFORM(QT) +class QProcess; +#endif + +namespace WebKit { + +#if PLATFORM(MAC) +typedef pid_t PlatformProcessIdentifier; +#elif PLATFORM(WIN) +typedef HANDLE PlatformProcessIdentifier; +#elif PLATFORM(QT) +typedef QProcess* PlatformProcessIdentifier; +#elif PLATFORM(GTK) +typedef pid_t PlatformProcessIdentifier; +#endif + +} // namespace WebKit + +#endif // PlatformProcessIdentifier_h diff --git a/Source/WebKit2/Platform/Region.cpp b/Source/WebKit2/Platform/Region.cpp new file mode 100644 index 0000000..a1cc24c --- /dev/null +++ b/Source/WebKit2/Platform/Region.cpp @@ -0,0 +1,454 @@ +/* + * 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 "Region.h" + +// A region class based on the paper "Scanline Coherent Shape Algebra" +// by Jonathan E. Steinhart from the book "Graphics Gems II". +// +// This implementation uses two vectors instead of linked list, and +// also compresses regions when possible. + +using namespace WebCore; + +namespace WebKit { + +Region::Region() +{ +} + +Region::Region(const IntRect& rect) + : m_bounds(rect) + , m_shape(rect) +{ +} + +Vector<IntRect> Region::rects() const +{ + Vector<IntRect> rects; + + for (Shape::SpanIterator span = m_shape.spans_begin(), end = m_shape.spans_end(); span != end && span + 1 != end; ++span) { + int y = span->y; + int height = (span + 1)->y - y; + + for (Shape::SegmentIterator segment = m_shape.segments_begin(span), end = m_shape.segments_end(span); segment != end && segment + 1 != end; segment += 2) { + int x = *segment; + int width = *(segment + 1) - x; + + rects.append(IntRect(x, y, width, height)); + } + } + + return rects; +} + +Region::Shape::Shape() +{ +} + +Region::Shape::Shape(const IntRect& rect) +{ + appendSpan(rect.y()); + appendSegment(rect.x()); + appendSegment(rect.right()); + appendSpan(rect.bottom()); +} + +void Region::Shape::appendSpan(int y) +{ + m_spans.append(Span(y, m_segments.size())); +} + +bool Region::Shape::canCoalesce(SegmentIterator begin, SegmentIterator end) +{ + if (m_spans.isEmpty()) + return false; + + SegmentIterator lastSpanBegin = m_segments.data() + m_spans.last().segmentIndex; + SegmentIterator lastSpanEnd = m_segments.data() + m_segments.size(); + + // Check if both spans have an equal number of segments. + if (lastSpanEnd - lastSpanBegin != end - begin) + return false; + + // Check if both spans are equal. + if (!std::equal(begin, end, lastSpanBegin)) + return false; + + // Since the segments are equal the second segment can just be ignored. + return true; +} + +void Region::Shape::appendSpan(int y, SegmentIterator begin, SegmentIterator end) +{ + if (canCoalesce(begin, end)) + return; + + appendSpan(y); + m_segments.appendRange(begin, end); +} + +void Region::Shape::appendSpans(const Shape& shape, SpanIterator begin, SpanIterator end) +{ + for (SpanIterator it = begin; it != end; ++it) + appendSpan(it->y, shape.segments_begin(it), shape.segments_end(it)); +} + +void Region::Shape::appendSegment(int x) +{ + m_segments.append(x); +} + +Region::Shape::SpanIterator Region::Shape::spans_begin() const +{ + return m_spans.data(); +} + +Region::Shape::SpanIterator Region::Shape::spans_end() const +{ + return m_spans.data() + m_spans.size(); +} + +Region::Shape::SegmentIterator Region::Shape::segments_begin(SpanIterator it) const +{ + ASSERT(it >= m_spans.data()); + ASSERT(it < m_spans.data() + m_spans.size()); + + // Check if this span has any segments. + if (it->segmentIndex == m_segments.size()) + return 0; + + return &m_segments[it->segmentIndex]; +} + +Region::Shape::SegmentIterator Region::Shape::segments_end(SpanIterator it) const +{ + ASSERT(it >= m_spans.data()); + ASSERT(it < m_spans.data() + m_spans.size()); + + // Check if this span has any segments. + if (it->segmentIndex == m_segments.size()) + return 0; + + ASSERT(it + 1 < m_spans.data() + m_spans.size()); + size_t segmentIndex = (it + 1)->segmentIndex; + + ASSERT(segmentIndex <= m_segments.size()); + return m_segments.data() + segmentIndex; +} + +#ifndef NDEBUG +void Region::Shape::dump() const +{ + for (Shape::SpanIterator span = spans_begin(), end = spans_end(); span != end; ++span) { + printf("%6d: (", span->y); + + for (Shape::SegmentIterator segment = segments_begin(span), end = segments_end(span); segment != end; ++segment) + printf("%d ", *segment); + printf(")\n"); + } + + printf("\n"); +} +#endif + +IntRect Region::Shape::bounds() const +{ + if (isEmpty()) + return IntRect(); + + SpanIterator span = spans_begin(); + int minY = span->y; + + SpanIterator lastSpan = spans_end() - 1; + int maxY = lastSpan->y; + + int minX = std::numeric_limits<int>::max(); + int maxX = std::numeric_limits<int>::min(); + + while (span != lastSpan) { + SegmentIterator firstSegment = segments_begin(span); + SegmentIterator lastSegment = segments_end(span) - 1; + + if (firstSegment && lastSegment) { + ASSERT(firstSegment != lastSegment); + + if (*firstSegment < minX) + minX = *firstSegment; + + if (*lastSegment > maxX) + maxX = *lastSegment; + } + + ++span; + } + + ASSERT(minX <= maxX); + ASSERT(minY <= maxY); + + return IntRect(minX, minY, maxX - minX, maxY - minY); +} + +void Region::Shape::translate(const IntSize& offset) +{ + for (size_t i = 0; i < m_segments.size(); ++i) + m_segments[i] += offset.width(); + for (size_t i = 0; i < m_spans.size(); ++i) + m_spans[i].y += offset.height(); +} + +void Region::Shape::swap(Shape& other) +{ + m_segments.swap(other.m_segments); + m_spans.swap(other.m_spans); +} + +enum { + Shape1, + Shape2, +}; + +template<typename Operation> +Region::Shape Region::Shape::shapeOperation(const Shape& shape1, const Shape& shape2) +{ + COMPILE_ASSERT(!(!Operation::shouldAddRemainingSegmentsFromSpan1 && Operation::shouldAddRemainingSegmentsFromSpan2), invalid_segment_combination); + COMPILE_ASSERT(!(!Operation::shouldAddRemainingSpansFromShape1 && Operation::shouldAddRemainingSpansFromShape2), invalid_span_combination); + + Shape result; + if (Operation::trySimpleOperation(shape1, shape2, result)) + return result; + + SpanIterator spans1 = shape1.spans_begin(); + SpanIterator spans1End = shape1.spans_end(); + + SpanIterator spans2 = shape2.spans_begin(); + SpanIterator spans2End = shape2.spans_end(); + + SegmentIterator segments1 = 0; + SegmentIterator segments1End = 0; + + SegmentIterator segments2 = 0; + SegmentIterator segments2End = 0; + + // Iterate over all spans. + while (spans1 != spans1End && spans2 != spans2End) { + int y; + int test = spans1->y - spans2->y; + + if (test <= 0) { + y = spans1->y; + + segments1 = shape1.segments_begin(spans1); + segments1End = shape1.segments_end(spans1); + ++spans1; + } + if (test >= 0) { + y = spans2->y; + + segments2 = shape2.segments_begin(spans2); + segments2End = shape2.segments_end(spans2); + ++spans2; + } + + int flag = 0; + int oldFlag = 0; + + SegmentIterator s1 = segments1; + SegmentIterator s2 = segments2; + + Vector<int> segments; + + // Now iterate over the segments in each span and construct a new vector of segments. + while (s1 != segments1End && s2 != segments2End) { + int test = *s1 - *s2; + int x; + + if (test <= 0) { + x = *s1; + flag = flag ^ 1; + ++s1; + } + if (test >= 0) { + x = *s2; + flag = flag ^ 2; + ++s2; + } + + if (flag == Operation::opCode || oldFlag == Operation::opCode) + segments.append(x); + + oldFlag = flag; + } + + // Add any remaining segments. + if (Operation::shouldAddRemainingSegmentsFromSpan1 && s1 != segments1End) + segments.appendRange(s1, segments1End); + else if (Operation::shouldAddRemainingSegmentsFromSpan2 && s2 != segments2End) + segments.appendRange(s2, segments2End); + + // Add the span. + if (!segments.isEmpty() || !result.isEmpty()) + result.appendSpan(y, segments.data(), segments.data() + segments.size()); + } + + // Add any remaining spans. + if (Operation::shouldAddRemainingSpansFromShape1 && spans1 != spans1End) + result.appendSpans(shape1, spans1, spans1End); + else if (Operation::shouldAddRemainingSpansFromShape2 && spans2 != spans2End) + result.appendSpans(shape2, spans2, spans2End); + + return result; +} + +struct Region::Shape::UnionOperation { + static bool trySimpleOperation(const Shape& shape1, const Shape& shape2, Shape& result) + { + if (shape1.isEmpty()) { + result = shape2; + return true; + } + + if (shape2.isEmpty()) { + result = shape1; + return true; + } + + return false; + } + + static const int opCode = 0; + + static const bool shouldAddRemainingSegmentsFromSpan1 = true; + static const bool shouldAddRemainingSegmentsFromSpan2 = true; + static const bool shouldAddRemainingSpansFromShape1 = true; + static const bool shouldAddRemainingSpansFromShape2 = true; +}; + +Region::Shape Region::Shape::unionShapes(const Shape& shape1, const Shape& shape2) +{ + return shapeOperation<UnionOperation>(shape1, shape2); +} + +struct Region::Shape::IntersectOperation { + static bool trySimpleOperation(const Shape& shape1, const Shape& shape2, Shape& result) + { + if (shape1.isEmpty()) { + result = Shape(); + return true; + } + + if (shape2.isEmpty()) { + result = shape1; + return true; + } + + return false; + } + + static const int opCode = 3; + + static const bool shouldAddRemainingSegmentsFromSpan1 = false; + static const bool shouldAddRemainingSegmentsFromSpan2 = false; + static const bool shouldAddRemainingSpansFromShape1 = false; + static const bool shouldAddRemainingSpansFromShape2 = false; +}; + +Region::Shape Region::Shape::intersectShapes(const Shape& shape1, const Shape& shape2) +{ + return shapeOperation<IntersectOperation>(shape1, shape2); +} + +struct Region::Shape::SubtractOperation { + static bool trySimpleOperation(const Shape& shape1, const Shape& shape2, Region::Shape& result) + { + + if (shape1.isEmpty() || shape2.isEmpty()) { + result = Shape(); + return true; + } + + return false; + } + + static const int opCode = 1; + + static const bool shouldAddRemainingSegmentsFromSpan1 = true; + static const bool shouldAddRemainingSegmentsFromSpan2 = false; + static const bool shouldAddRemainingSpansFromShape1 = true; + static const bool shouldAddRemainingSpansFromShape2 = false; +}; + +Region::Shape Region::Shape::subtractShapes(const Shape& shape1, const Shape& shape2) +{ + return shapeOperation<SubtractOperation>(shape1, shape2); +} + +#ifndef NDEBUG +void Region::dump() const +{ + printf("Bounds: (%d, %d, %d, %d)\n", + m_bounds.x(), m_bounds.y(), m_bounds.width(), m_bounds.height()); + m_shape.dump(); +} +#endif + +void Region::intersect(const Region& region) +{ + if (!m_bounds.intersects(region.m_bounds)) { + m_shape = Shape(); + m_bounds = IntRect(); + return; + } + + Shape intersectedShape = Shape::intersectShapes(m_shape, region.m_shape); + + m_shape.swap(intersectedShape); + m_bounds = m_shape.bounds(); +} + +void Region::unite(const Region& region) +{ + Shape unitedShape = Shape::unionShapes(m_shape, region.m_shape); + + m_shape.swap(unitedShape); + m_bounds.unite(region.m_bounds); +} + +void Region::subtract(const Region& region) +{ + Shape subtractedShape = Shape::subtractShapes(m_shape, region.m_shape); + + m_shape.swap(subtractedShape); + m_bounds = m_shape.bounds(); +} + +void Region::translate(const IntSize& offset) +{ + m_bounds.move(offset); + m_shape.translate(offset); +} + +} // namespace WebKit + diff --git a/Source/WebKit2/Platform/Region.h b/Source/WebKit2/Platform/Region.h new file mode 100644 index 0000000..b44519f --- /dev/null +++ b/Source/WebKit2/Platform/Region.h @@ -0,0 +1,144 @@ +/* + * 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 Region_h +#define Region_h + +#include <WebCore/IntRect.h> +#include <wtf/Vector.h> + +#include <vector> + +namespace WebKit { + +class Region { +public: + Region(); + Region(const WebCore::IntRect&); + + WebCore::IntRect bounds() const { return m_bounds; } + bool isEmpty() const { return m_bounds.isEmpty(); } + + Vector<WebCore::IntRect> rects() const; + + void unite(const Region&); + void intersect(const Region&); + void subtract(const Region&); + + void translate(const WebCore::IntSize&); + +#ifndef NDEBUG + void dump() const; +#endif + +private: + struct Span { + Span(int y, size_t segmentIndex) + : y(y), segmentIndex(segmentIndex) + { + } + + int y; + size_t segmentIndex; + }; + + class Shape { + public: + Shape(); + Shape(const WebCore::IntRect&); + + WebCore::IntRect bounds() const; + bool isEmpty() const { return m_spans.isEmpty(); } + + typedef const Span* SpanIterator; + SpanIterator spans_begin() const; + SpanIterator spans_end() const; + + typedef const int* SegmentIterator; + SegmentIterator segments_begin(SpanIterator) const; + SegmentIterator segments_end(SpanIterator) const; + + static Shape unionShapes(const Shape& shape1, const Shape& shape2); + static Shape intersectShapes(const Shape& shape1, const Shape& shape2); + static Shape subtractShapes(const Shape& shape1, const Shape& shape2); + + void translate(const WebCore::IntSize&); + void swap(Shape&); + +#ifndef NDEBUG + void dump() const; +#endif + + private: + struct UnionOperation; + struct IntersectOperation; + struct SubtractOperation; + + template<typename Operation> + static Shape shapeOperation(const Shape& shape1, const Shape& shape2); + + void appendSegment(int x); + void appendSpan(int y); + void appendSpan(int y, SegmentIterator begin, SegmentIterator end); + void appendSpans(const Shape&, SpanIterator begin, SpanIterator end); + + bool canCoalesce(SegmentIterator begin, SegmentIterator end); + + // FIXME: These vectors should have inline sizes. Figure out a good optimal value. + Vector<int> m_segments; + Vector<Span> m_spans; + }; + + WebCore::IntRect m_bounds; + Shape m_shape; +}; + +static inline Region intersect(const Region& a, const Region& b) +{ + Region result(a); + result.intersect(b); + + return result; +} + +static inline Region subtract(const Region& a, const Region& b) +{ + Region result(a); + result.subtract(b); + + return result; +} + +static inline Region translate(const Region& region, const WebCore::IntSize& offset) +{ + Region result(region); + result.translate(offset); + + return result; +} + +} // namespace WebKit + +#endif // Region_h diff --git a/Source/WebKit2/Platform/RunLoop.cpp b/Source/WebKit2/Platform/RunLoop.cpp new file mode 100644 index 0000000..606aba1 --- /dev/null +++ b/Source/WebKit2/Platform/RunLoop.cpp @@ -0,0 +1,72 @@ +/* + * 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 "RunLoop.h" + +#include "WorkItem.h" +#include <wtf/StdLibExtras.h> + +static RunLoop* s_mainRunLoop; + +void RunLoop::initializeMainRunLoop() +{ + if (s_mainRunLoop) + return; + s_mainRunLoop = RunLoop::current(); +} + +RunLoop* RunLoop::current() +{ + DEFINE_STATIC_LOCAL(WTF::ThreadSpecific<RunLoop>, runLoopData, ()); + return &*runLoopData; +} + +RunLoop* RunLoop::main() +{ + ASSERT(s_mainRunLoop); + return s_mainRunLoop; +} + +void RunLoop::performWork() +{ + Vector<WorkItem*> workItemQueue; + { + MutexLocker locker(m_workItemQueueLock); + m_workItemQueue.swap(workItemQueue); + } + + for (size_t i = 0; i < workItemQueue.size(); ++i) { + OwnPtr<WorkItem> item(workItemQueue[i]); + item->execute(); + } +} + +void RunLoop::scheduleWork(PassOwnPtr<WorkItem> item) +{ + MutexLocker locker(m_workItemQueueLock); + m_workItemQueue.append(item.leakPtr()); + + wakeUp(); +} diff --git a/Source/WebKit2/Platform/RunLoop.h b/Source/WebKit2/Platform/RunLoop.h new file mode 100644 index 0000000..aa87506 --- /dev/null +++ b/Source/WebKit2/Platform/RunLoop.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * 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. + */ + +#ifndef RunLoop_h +#define RunLoop_h + +#include <wtf/HashMap.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/ThreadSpecific.h> +#include <wtf/Threading.h> +#include <wtf/Vector.h> +#if PLATFORM(GTK) +typedef struct _GSource GSource; +typedef struct _GMainLoop GMainLoop; +typedef struct _GMainContext GMainContext; +typedef int gboolean; +#endif + +class WorkItem; + +class RunLoop { +public: + // Must be called from the main thread. + static void initializeMainRunLoop(); + + static RunLoop* current(); + static RunLoop* main(); + + void scheduleWork(PassOwnPtr<WorkItem>); + + static void run(); + void stop(); + + class TimerBase { + friend class RunLoop; + public: + TimerBase(RunLoop*); + virtual ~TimerBase(); + + void startRepeating(double repeatInterval) { start(repeatInterval, true); } + void startOneShot(double interval) { start(interval, false); } + + void stop(); + bool isActive() const; + + virtual void fired() = 0; + + private: + void start(double nextFireInterval, bool repeat); + + RunLoop* m_runLoop; + +#if PLATFORM(WIN) + static void timerFired(RunLoop*, uint64_t ID); + uint64_t m_ID; + bool m_isRepeating; +#elif PLATFORM(MAC) + static void timerFired(CFRunLoopTimerRef, void*); + CFRunLoopTimerRef m_timer; +#elif PLATFORM(QT) + static void timerFired(RunLoop*, int ID); + int m_ID; + bool m_isRepeating; +#elif PLATFORM(GTK) + static gboolean oneShotTimerFired(RunLoop::TimerBase*); + static gboolean repeatingTimerFired(RunLoop::TimerBase*); + void resetTimerSource(); + GSource* m_timerSource; +#endif + }; + + template <typename TimerFiredClass> + class Timer : public TimerBase { + public: + typedef void (TimerFiredClass::*TimerFiredFunction)(); + + Timer(RunLoop* runLoop, TimerFiredClass* o, TimerFiredFunction f) + : TimerBase(runLoop) + , m_object(o) + , m_function(f) + { + } + + private: + virtual void fired() { (m_object->*m_function)(); } + + TimerFiredClass* m_object; + TimerFiredFunction m_function; + }; + +private: + friend class WTF::ThreadSpecific<RunLoop>; + + RunLoop(); + ~RunLoop(); + + void performWork(); + void wakeUp(); + + Mutex m_workItemQueueLock; + Vector<WorkItem*> m_workItemQueue; + +#if PLATFORM(WIN) + static bool registerRunLoopMessageWindowClass(); + static LRESULT CALLBACK RunLoopWndProc(HWND, UINT, WPARAM, LPARAM); + LRESULT wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + HWND m_runLoopMessageWindow; + + typedef HashMap<uint64_t, TimerBase*> TimerMap; + TimerMap m_activeTimers; +#elif PLATFORM(MAC) + static void performWork(void*); + CFRunLoopRef m_runLoop; + CFRunLoopSourceRef m_runLoopSource; +#elif PLATFORM(QT) + typedef HashMap<int, TimerBase*> TimerMap; + TimerMap m_activeTimers; + class TimerObject; + TimerObject* m_timerObject; +#elif PLATFORM(GTK) +public: + static gboolean queueWork(RunLoop*); + GMainLoop* mainLoop(); +private: + GMainContext* m_runLoopContext; + GMainLoop* m_runLoopMain; +#endif +}; + +#endif // RunLoop_h diff --git a/Source/WebKit2/Platform/SharedMemory.h b/Source/WebKit2/Platform/SharedMemory.h new file mode 100644 index 0000000..05dc0dd --- /dev/null +++ b/Source/WebKit2/Platform/SharedMemory.h @@ -0,0 +1,105 @@ +/* + * 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 SharedMemory_h +#define SharedMemory_h + +#include <wtf/Noncopyable.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +#if PLATFORM(QT) +#include <QtGlobal> +QT_BEGIN_NAMESPACE +class QSharedMemory; +QT_END_NAMESPACE +#include <wtf/text/WTFString.h> +#endif + +namespace CoreIPC { + class ArgumentDecoder; + class ArgumentEncoder; +} + +namespace WebKit { + +class SharedMemory : public RefCounted<SharedMemory> { +public: + enum Protection { + ReadOnly, + ReadWrite + }; + + class Handle : Noncopyable { + public: + Handle(); + ~Handle(); + + bool isNull() const; + + void encode(CoreIPC::ArgumentEncoder*) const; + static bool decode(CoreIPC::ArgumentDecoder*, Handle&); + + private: + friend class SharedMemory; +#if PLATFORM(MAC) + mutable mach_port_t m_port; +#elif PLATFORM(WIN) + mutable HANDLE m_handle; +#elif PLATFORM(QT) + mutable String m_key; +#endif + size_t m_size; + }; + + // Create a shared memory object with the given size. Will return 0 on failure. + static PassRefPtr<SharedMemory> create(size_t); + + // Create a shared memory object from the given handle and the requested protection. Will return 0 on failure. + static PassRefPtr<SharedMemory> create(const Handle&, Protection); + + ~SharedMemory(); + + bool createHandle(Handle&, Protection); + + size_t size() const { return m_size; } + void* data() const { return m_data; } + + // Return the system page size in bytes. + static unsigned systemPageSize(); + +private: + size_t m_size; + void* m_data; +#if PLATFORM(WIN) + HANDLE m_handle; +#elif PLATFORM(QT) + QSharedMemory* m_impl; +#endif +}; + +}; + +#endif // SharedMemory_h diff --git a/Source/WebKit2/Platform/WorkItem.h b/Source/WebKit2/Platform/WorkItem.h new file mode 100644 index 0000000..64bff58 --- /dev/null +++ b/Source/WebKit2/Platform/WorkItem.h @@ -0,0 +1,187 @@ +/* + * 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 WorkItem_h +#define WorkItem_h + +#include <wtf/PassOwnPtr.h> + +class WorkItem { +public: + template<typename C> + static PassOwnPtr<WorkItem> create(C*, void (C::*)()); + + template<typename C, typename T0> + static PassOwnPtr<WorkItem> create(C*, void (C::*)(T0), T0); + + template<typename C, typename T0, typename T1> + static PassOwnPtr<WorkItem> create(C*, void (C::*)(T0, T1), T0, T1); + + static PassOwnPtr<WorkItem> create(void (*)()); + + virtual ~WorkItem() { } + virtual void execute() = 0; + +protected: + WorkItem() { } + +private: + WorkItem(const WorkItem&); + WorkItem& operator=(const WorkItem&); +}; + +template <typename C> +class MemberFunctionWorkItem0 : private WorkItem { + // We only allow WorkItem to create this. + friend class WorkItem; + + typedef void (C::*FunctionType)(); + + MemberFunctionWorkItem0(C* ptr, FunctionType function) + : m_ptr(ptr) + , m_function(function) + { + m_ptr->ref(); + } + + ~MemberFunctionWorkItem0() + { + m_ptr->deref(); + } + + virtual void execute() + { + (m_ptr->*m_function)(); + } + + C* m_ptr; + FunctionType m_function; +}; + +template<typename C, typename T0> +class MemberFunctionWorkItem1 : private WorkItem { + // We only allow WorkItem to create this. + friend class WorkItem; + + typedef void (C::*FunctionType)(T0); + + MemberFunctionWorkItem1(C* ptr, FunctionType function, T0 t0) + : m_ptr(ptr) + , m_function(function) + , m_t0(t0) + { + m_ptr->ref(); + } + + ~MemberFunctionWorkItem1() + { + m_ptr->deref(); + } + + virtual void execute() + { + (m_ptr->*m_function)(m_t0); + } + + C* m_ptr; + FunctionType m_function; + T0 m_t0; +}; + +template<typename C, typename T0, typename T1> +class MemberFunctionWorkItem2 : private WorkItem { + // We only allow WorkItem to create this. + friend class WorkItem; + + typedef void (C::*FunctionType)(T0, T1); + + MemberFunctionWorkItem2(C* ptr, FunctionType function, T0 t0, T1 t1) + : m_ptr(ptr) + , m_function(function) + , m_t0(t0) + , m_t1(t1) + { + m_ptr->ref(); + } + + ~MemberFunctionWorkItem2() + { + m_ptr->deref(); + } + + virtual void execute() + { + (m_ptr->*m_function)(m_t0, m_t1); + } + + C* m_ptr; + FunctionType m_function; + T0 m_t0; + T1 m_t1; +}; + +template<typename C> +PassOwnPtr<WorkItem> WorkItem::create(C* ptr, void (C::*function)()) +{ + return adoptPtr(static_cast<WorkItem*>(new MemberFunctionWorkItem0<C>(ptr, function))); +} + +template<typename C, typename T0> +PassOwnPtr<WorkItem> WorkItem::create(C* ptr, void (C::*function)(T0), T0 t0) +{ + return adoptPtr(static_cast<WorkItem*>(new MemberFunctionWorkItem1<C, T0>(ptr, function, t0))); +} + +template<typename C, typename T0, typename T1> +PassOwnPtr<WorkItem> WorkItem::create(C* ptr, void (C::*function)(T0, T1), T0 t0, T1 t1) +{ + return adoptPtr(static_cast<WorkItem*>(new MemberFunctionWorkItem2<C, T0, T1>(ptr, function, t0, t1))); +} + +class FunctionWorkItem0 : private WorkItem { + // We only allow WorkItem to create this. + friend class WorkItem; + + typedef void (*FunctionType)(); + + FunctionWorkItem0(FunctionType function) + : m_function(function) + { + } + + virtual void execute() + { + (*m_function)(); + } + + FunctionType m_function; +}; + +inline PassOwnPtr<WorkItem> WorkItem::create(void (*function)()) +{ + return adoptPtr(static_cast<WorkItem*>(new FunctionWorkItem0(function))); +} + +#endif // WorkItem_h diff --git a/Source/WebKit2/Platform/WorkQueue.cpp b/Source/WebKit2/Platform/WorkQueue.cpp new file mode 100644 index 0000000..de82c80 --- /dev/null +++ b/Source/WebKit2/Platform/WorkQueue.cpp @@ -0,0 +1,50 @@ +/* + * 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 "WorkQueue.h" + +WorkQueue::WorkQueue(const char* name) + : m_isValid(true) +{ + platformInitialize(name); +} + +WorkQueue::~WorkQueue() +{ +#if !ASSERT_DISABLED + MutexLocker locker(m_isValidMutex); + ASSERT(!m_isValid); +#endif +} + +void WorkQueue::invalidate() +{ + { + MutexLocker locker(m_isValidMutex); + m_isValid = false; + } + + platformInvalidate(); +} diff --git a/Source/WebKit2/Platform/WorkQueue.h b/Source/WebKit2/Platform/WorkQueue.h new file mode 100644 index 0000000..78fa8b7 --- /dev/null +++ b/Source/WebKit2/Platform/WorkQueue.h @@ -0,0 +1,176 @@ +/* + * 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. + */ + +#ifndef WorkQueue_h +#define WorkQueue_h + +#if PLATFORM(MAC) +#if HAVE(DISPATCH_H) +#include <dispatch/dispatch.h> +#endif +#endif + +#include "WorkItem.h" +#include <wtf/HashMap.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Threading.h> +#include <wtf/Vector.h> + +#if PLATFORM(QT) +class QLocalSocket; +class QObject; +class QThread; +#elif PLATFORM(GTK) +typedef struct _GMainContext GMainContext; +typedef struct _GMainLoop GMainLoop; +#endif + +class WorkQueue { +public: + explicit WorkQueue(const char* name); + ~WorkQueue(); + + // Will schedule the given work item to run as soon as possible. + void scheduleWork(PassOwnPtr<WorkItem>); + + // Will schedule the given work item to run after the given delay (in seconds). + void scheduleWorkAfterDelay(PassOwnPtr<WorkItem>, double delay); + + void invalidate(); + +#if PLATFORM(MAC) + enum MachPortEventType { + // Fired when there is data on the given receive right. + MachPortDataAvailable, + + // Fired when the receive right for this send right has been destroyed. + MachPortDeadNameNotification + }; + + // Will execute the given work item whenever the given mach port event fires. + // Note that this will adopt the mach port and destroy it when the work queue is invalidated. + void registerMachPortEventHandler(mach_port_t, MachPortEventType, PassOwnPtr<WorkItem>); + void unregisterMachPortEventHandler(mach_port_t); +#elif PLATFORM(WIN) + void registerHandle(HANDLE, PassOwnPtr<WorkItem>); + void unregisterAndCloseHandle(HANDLE); +#elif PLATFORM(QT) + void connectSignal(QObject*, const char* signal, PassOwnPtr<WorkItem>); + void disconnectSignal(QObject*, const char* signal); + + void moveSocketToWorkThread(QLocalSocket*); +#elif PLATFORM(GTK) + void registerEventSourceHandler(int, int, PassOwnPtr<WorkItem>); + void unregisterEventSourceHandler(int); +#endif + +private: + // FIXME: Use an atomic boolean here instead. + Mutex m_isValidMutex; + bool m_isValid; + + void platformInitialize(const char* name); + void platformInvalidate(); + +#if PLATFORM(MAC) +#if HAVE(DISPATCH_H) + static void executeWorkItem(void*); + Mutex m_eventSourcesMutex; + class EventSource; + HashMap<mach_port_t, EventSource*> m_eventSources; + dispatch_queue_t m_dispatchQueue; +#endif +#elif PLATFORM(WIN) + class WorkItemWin : public ThreadSafeShared<WorkItemWin> { + public: + static PassRefPtr<WorkItemWin> create(PassOwnPtr<WorkItem>, WorkQueue*); + virtual ~WorkItemWin(); + + WorkItem* item() const { return m_item.get(); } + WorkQueue* queue() const { return m_queue; } + + protected: + WorkItemWin(PassOwnPtr<WorkItem>, WorkQueue*); + + private: + OwnPtr<WorkItem> m_item; + WorkQueue* m_queue; + }; + + class HandleWorkItem : public WorkItemWin { + public: + static PassRefPtr<HandleWorkItem> createByAdoptingHandle(HANDLE, PassOwnPtr<WorkItem>, WorkQueue*); + virtual ~HandleWorkItem(); + + void setWaitHandle(HANDLE waitHandle) { m_waitHandle = waitHandle; } + HANDLE waitHandle() const { return m_waitHandle; } + + private: + HandleWorkItem(HANDLE, PassOwnPtr<WorkItem>, WorkQueue*); + + HANDLE m_handle; + HANDLE m_waitHandle; + }; + + static void CALLBACK handleCallback(void* context, BOOLEAN timerOrWaitFired); + static DWORD WINAPI workThreadCallback(void* context); + + bool tryRegisterAsWorkThread(); + void unregisterAsWorkThread(); + void performWorkOnRegisteredWorkThread(); + + static void unregisterWaitAndDestroyItemSoon(PassRefPtr<HandleWorkItem>); + static DWORD WINAPI unregisterWaitAndDestroyItemCallback(void* context); + + volatile LONG m_isWorkThreadRegistered; + + Mutex m_workItemQueueLock; + Vector<RefPtr<WorkItemWin> > m_workItemQueue; + + Mutex m_handlesLock; + HashMap<HANDLE, RefPtr<HandleWorkItem> > m_handles; +#elif PLATFORM(QT) + class WorkItemQt; + HashMap<QObject*, WorkItemQt*> m_signalListeners; + QThread* m_workThread; + friend class WorkItemQt; +#elif PLATFORM(GTK) + static void* startWorkQueueThread(WorkQueue*); + void workQueueThreadBody(); + + ThreadIdentifier m_workQueueThread; + GMainContext* m_eventContext; + Mutex m_eventLoopLock; + GMainLoop* m_eventLoop; + Mutex m_eventSourcesLock; + class EventSource; + HashMap<int, Vector<EventSource*> > m_eventSources; + typedef HashMap<int, Vector<EventSource*> >::iterator EventSourceIterator; +#endif +}; + +#endif // WorkQueue_h diff --git a/Source/WebKit2/Platform/cg/CGUtilities.cpp b/Source/WebKit2/Platform/cg/CGUtilities.cpp new file mode 100644 index 0000000..1e5dd33 --- /dev/null +++ b/Source/WebKit2/Platform/cg/CGUtilities.cpp @@ -0,0 +1,64 @@ +/* + * 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 "CGUtilities.h" + +#include <wtf/RetainPtr.h> + +namespace WebKit { + +void paintBitmapContext(CGContextRef context, CGContextRef bitmapContext, CGPoint destination, CGRect source) +{ + void* bitmapData = CGBitmapContextGetData(bitmapContext); + ASSERT(bitmapData); + + size_t imageWidth = CGBitmapContextGetWidth(bitmapContext); + size_t imageHeight = CGBitmapContextGetHeight(bitmapContext); + + size_t bytesPerRow = CGBitmapContextGetBytesPerRow(bitmapContext); + + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithData(0, bitmapData, bytesPerRow * imageHeight, 0)); + RetainPtr<CGImageRef> image(AdoptCF, CGImageCreate(imageWidth, imageHeight, + CGBitmapContextGetBitsPerComponent(bitmapContext), + CGBitmapContextGetBitsPerPixel(bitmapContext), + bytesPerRow, + CGBitmapContextGetColorSpace(bitmapContext), + CGBitmapContextGetBitmapInfo(bitmapContext), + dataProvider.get(), 0, false, kCGRenderingIntentDefault)); + + CGContextSaveGState(context); + + CGContextClipToRect(context, CGRectMake(destination.x, destination.y, source.size.width, source.size.height)); + CGContextScaleCTM(context, 1, -1); + + CGFloat destX = destination.x - source.origin.x; + CGFloat destY = -static_cast<CGFloat>(imageHeight) - destination.y + source.origin.y; + + CGContextDrawImage(context, CGRectMake(destX, destY, imageWidth, imageHeight), image.get()); + CGContextRestoreGState(context); +} + +} // namespace WebKit + diff --git a/Source/WebKit2/Platform/cg/CGUtilities.h b/Source/WebKit2/Platform/cg/CGUtilities.h new file mode 100644 index 0000000..3dca654 --- /dev/null +++ b/Source/WebKit2/Platform/cg/CGUtilities.h @@ -0,0 +1,35 @@ +/* + * 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 CGUtilities_h +#define CGUtilities_h + +namespace WebKit { + +void paintBitmapContext(CGContextRef, CGContextRef bitmapContext, CGPoint destination, CGRect source); + +} // namespace WebKit + +#endif // CGUtilities_h diff --git a/Source/WebKit2/Platform/gtk/RunLoopGtk.cpp b/Source/WebKit2/Platform/gtk/RunLoopGtk.cpp new file mode 100644 index 0000000..2c183fa --- /dev/null +++ b/Source/WebKit2/Platform/gtk/RunLoopGtk.cpp @@ -0,0 +1,135 @@ +/* + * 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 "RunLoop.h" + +#include "WKBase.h" +#include <glib.h> + +RunLoop::RunLoop() +{ + m_runLoopContext = g_main_context_default(); + ASSERT(m_runLoopContext); + m_runLoopMain = g_main_loop_new(m_runLoopContext, FALSE); + ASSERT(m_runLoopMain); +} + +RunLoop::~RunLoop() +{ + if (m_runLoopMain) { + g_main_loop_quit(m_runLoopMain); + g_main_loop_unref(m_runLoopMain); + } + + if (m_runLoopContext) + g_main_context_unref(m_runLoopContext); +} + +void RunLoop::run() +{ + g_main_loop_run(RunLoop::main()->mainLoop()); +} + +GMainLoop* RunLoop::mainLoop() +{ + return m_runLoopMain; +} + +void RunLoop::stop() +{ + g_main_loop_quit(m_runLoopMain); +} + +gboolean RunLoop::queueWork(RunLoop* runLoop) +{ + runLoop->performWork(); + return FALSE; +} + +void RunLoop::wakeUp() +{ + GSource* source = g_timeout_source_new(0); + g_source_set_callback(source, reinterpret_cast<GSourceFunc>(&RunLoop::queueWork), this, 0); + g_source_attach(source, m_runLoopContext); + + g_main_context_wakeup(m_runLoopContext); +} + +RunLoop::TimerBase::TimerBase(RunLoop* runLoop) + : m_runLoop(runLoop) + , m_timerSource(0) +{ +} + +RunLoop::TimerBase::~TimerBase() +{ + stop(); +} + +void RunLoop::TimerBase::resetTimerSource() +{ + m_timerSource = 0; +} + +gboolean RunLoop::TimerBase::oneShotTimerFired(RunLoop::TimerBase* timer) +{ + timer->fired(); + timer->resetTimerSource(); + return FALSE; +} + +gboolean RunLoop::TimerBase::repeatingTimerFired(RunLoop::TimerBase* timer) +{ + timer->fired(); + return TRUE; +} + +void RunLoop::TimerBase::start(double fireInterval, bool repeat) +{ + if (m_timerSource) + stop(); + + m_timerSource = g_timeout_source_new(static_cast<guint>(fireInterval)); + if (repeat) + g_source_set_callback(m_timerSource, reinterpret_cast<GSourceFunc>(&RunLoop::TimerBase::repeatingTimerFired), this, 0); + else + g_source_set_callback(m_timerSource, reinterpret_cast<GSourceFunc>(&RunLoop::TimerBase::oneShotTimerFired), this, 0); + g_source_attach(m_timerSource, m_runLoop->m_runLoopContext); +} + +void RunLoop::TimerBase::stop() +{ + if (!m_timerSource) + return; + + g_source_destroy(m_timerSource); + m_timerSource = 0; +} + +bool RunLoop::TimerBase::isActive() const +{ + return m_timerSource; +} diff --git a/Source/WebKit2/Platform/gtk/SharedMemoryGtk.cpp b/Source/WebKit2/Platform/gtk/SharedMemoryGtk.cpp new file mode 100644 index 0000000..93fda95 --- /dev/null +++ b/Source/WebKit2/Platform/gtk/SharedMemoryGtk.cpp @@ -0,0 +1,84 @@ +/* + * 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 "SharedMemory.h" + +#include "NotImplemented.h" + +namespace WebKit { + +SharedMemory::Handle::Handle() +{ + notImplemented(); +} + +SharedMemory::Handle::~Handle() +{ + notImplemented(); +} + +void SharedMemory::Handle::encode(CoreIPC::ArgumentEncoder* encoder) const +{ + notImplemented(); +} + +bool SharedMemory::Handle::decode(CoreIPC::ArgumentDecoder* decoder, Handle& handle) +{ + notImplemented(); + return false; +} + +PassRefPtr<SharedMemory> SharedMemory::create(size_t size) +{ + notImplemented(); + return 0; +} + +PassRefPtr<SharedMemory> SharedMemory::create(const Handle& handle, Protection protection) +{ + notImplemented(); + return 0; +} + +SharedMemory::~SharedMemory() +{ + notImplemented(); +} + +bool SharedMemory::createHandle(Handle& handle, Protection protection) +{ + notImplemented(); + return false; +} + +unsigned SharedMemory::systemPageSize() +{ + unsigned pageSize = 0; + + return pageSize; +} + +} diff --git a/Source/WebKit2/Platform/gtk/WorkQueueGtk.cpp b/Source/WebKit2/Platform/gtk/WorkQueueGtk.cpp new file mode 100644 index 0000000..995b531 --- /dev/null +++ b/Source/WebKit2/Platform/gtk/WorkQueueGtk.cpp @@ -0,0 +1,202 @@ +/* + * 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 "WorkQueue.h" + +#include "NotImplemented.h" +#include "WKBase.h" +#include <glib.h> + +// WorkQueue::EventSource +class WorkQueue::EventSource { +public: + EventSource(GSource* dispatchSource, PassOwnPtr<WorkItem> workItem, WorkQueue* workQueue) + : m_dispatchSource(dispatchSource) + , m_workItem(workItem) + , m_workQueue(workQueue) + { + } + + GSource* dispatchSource() { return m_dispatchSource; } + + static gboolean performWorkOnce(EventSource* eventSource) + { + ASSERT(eventSource); + WorkQueue* queue = eventSource->m_workQueue; + { + MutexLocker locker(queue->m_isValidMutex); + if (!queue->m_isValid) + return FALSE; + } + + eventSource->m_workItem->execute(); + return FALSE; + } + + static gboolean performWork(GIOChannel* channel, GIOCondition condition, EventSource* eventSource) + { + ASSERT(eventSource); + + if (!(condition & G_IO_IN) && !(condition & G_IO_HUP) && !(condition & G_IO_ERR)) + return FALSE; + + WorkQueue* queue = eventSource->m_workQueue; + { + MutexLocker locker(queue->m_isValidMutex); + if (!queue->m_isValid) + return FALSE; + } + + eventSource->m_workItem->execute(); + + if ((condition & G_IO_HUP) || (condition & G_IO_ERR)) + return FALSE; + + return TRUE; + } + + static void deleteEventSource(EventSource* eventSource) + { + ASSERT(eventSource); + delete eventSource; + } + +public: + GSource* m_dispatchSource; + PassOwnPtr<WorkItem> m_workItem; + WorkQueue* m_workQueue; +}; + +// WorkQueue +void WorkQueue::platformInitialize(const char* name) +{ + m_eventContext = g_main_context_new(); + ASSERT(m_eventContext); + m_eventLoop = g_main_loop_new(m_eventContext, FALSE); + ASSERT(m_eventLoop); + m_workQueueThread = createThread(reinterpret_cast<WTF::ThreadFunction>(&WorkQueue::startWorkQueueThread), this, name); +} + +void WorkQueue::platformInvalidate() +{ + MutexLocker locker(m_eventLoopLock); + + if (m_eventLoop) { + if (g_main_loop_is_running(m_eventLoop)) + g_main_loop_quit(m_eventLoop); + + g_main_loop_unref(m_eventLoop); + m_eventLoop = 0; + } + + if (m_eventContext) { + g_main_context_unref(m_eventContext); + m_eventContext = 0; + } +} + +void* WorkQueue::startWorkQueueThread(WorkQueue* workQueue) +{ + workQueue->workQueueThreadBody(); + return 0; +} + +void WorkQueue::workQueueThreadBody() +{ + g_main_loop_run(m_eventLoop); +} + +void WorkQueue::registerEventSourceHandler(int fileDescriptor, int condition, PassOwnPtr<WorkItem> item) +{ + GIOChannel* channel = g_io_channel_unix_new(fileDescriptor); + ASSERT(channel); + GSource* dispatchSource = g_io_create_watch(channel, static_cast<GIOCondition>(condition)); + ASSERT(dispatchSource); + EventSource* eventSource = new EventSource(dispatchSource, item, this); + ASSERT(eventSource); + + g_source_set_callback(dispatchSource, reinterpret_cast<GSourceFunc>(&WorkQueue::EventSource::performWork), + eventSource, reinterpret_cast<GDestroyNotify>(&WorkQueue::EventSource::deleteEventSource)); + + // Set up the event sources under the mutex since this is shared across multiple threads. + { + MutexLocker locker(m_eventSourcesLock); + ASSERT(!m_eventSources.contains(fileDescriptor)); + Vector<EventSource*> sources; + EventSourceIterator it = m_eventSources.find(fileDescriptor); + if (it != m_eventSources.end()) + sources = it->second; + + sources.append(eventSource); + m_eventSources.set(fileDescriptor, sources); + } + + // Attach the event source to the GMainContext under the mutex since this is shared across multiple threads. + { + MutexLocker locker(m_eventLoopLock); + g_source_attach(dispatchSource, m_eventContext); + } +} + +void WorkQueue::unregisterEventSourceHandler(int fileDescriptor) +{ + ASSERT(fileDescriptor); + + MutexLocker locker(m_eventSourcesLock); + + EventSourceIterator it = m_eventSources.find(fileDescriptor); + ASSERT(it != m_eventSources.end()); + ASSERT(m_eventSources.contains(fileDescriptor)); + + if (it != m_eventSources.end()) { + Vector<EventSource*> sources = it->second; + for (unsigned i = 0; i < sources.size(); i++) + g_source_destroy(sources[i]->dispatchSource()); + + m_eventSources.remove(it); + } +} + +void WorkQueue::scheduleWork(PassOwnPtr<WorkItem> item) +{ + GSource* dispatchSource = g_timeout_source_new(0); + ASSERT(dispatchSource); + EventSource* eventSource = new EventSource(dispatchSource, item, this); + + g_source_set_callback(dispatchSource, + reinterpret_cast<GSourceFunc>(&WorkQueue::EventSource::performWorkOnce), + eventSource, + reinterpret_cast<GDestroyNotify>(&WorkQueue::EventSource::deleteEventSource)); + { + MutexLocker locker(m_eventLoopLock); + g_source_attach(dispatchSource, m_eventContext); + } +} + +void WorkQueue::scheduleWorkAfterDelay(PassOwnPtr<WorkItem>, double) +{ + notImplemented(); +} diff --git a/Source/WebKit2/Platform/mac/MachUtilities.cpp b/Source/WebKit2/Platform/mac/MachUtilities.cpp new file mode 100644 index 0000000..edb17dc --- /dev/null +++ b/Source/WebKit2/Platform/mac/MachUtilities.cpp @@ -0,0 +1,67 @@ +/* + * 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 "MachUtilities.h" + +#include <mach/task.h> + +void setMachPortQueueLength(mach_port_t receivePort, mach_port_msgcount_t queueLength) +{ + mach_port_limits_t portLimits; + portLimits.mpl_qlimit = queueLength; + + mach_port_set_attributes(mach_task_self(), receivePort, MACH_PORT_LIMITS_INFO, reinterpret_cast<mach_port_info_t>(&portLimits), MACH_PORT_LIMITS_INFO_COUNT); +} + +mach_port_t machExceptionPort() +{ + exception_mask_t exceptionMasks[EXC_TYPES_COUNT]; + exception_port_t exceptionHandlers[EXC_TYPES_COUNT]; + exception_behavior_t exceptionBehaviors[EXC_TYPES_COUNT]; + thread_state_flavor_t exceptionFlavors[EXC_TYPES_COUNT]; + mach_msg_type_number_t numExceptionMasks; + + kern_return_t kr = task_get_exception_ports(mach_task_self(), EXC_MASK_CRASH, exceptionMasks, &numExceptionMasks, exceptionHandlers, exceptionBehaviors, exceptionFlavors); + if (kr != KERN_SUCCESS) { + ASSERT_NOT_REACHED(); + return MACH_PORT_NULL; + } + + // We're just interested in the first exception handler. + return exceptionHandlers[0]; +} + +void setMachExceptionPort(mach_port_t exceptionPort) +{ + // Assert that we dont try to call setMachExceptionPort more than once per process. +#if !ASSERT_DISABLED + static mach_port_t taskExceptionPort = MACH_PORT_NULL; + ASSERT(taskExceptionPort == MACH_PORT_NULL); + taskExceptionPort = exceptionPort; +#endif + + if (task_set_exception_ports(mach_task_self(), EXC_MASK_CRASH, exceptionPort, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, MACHINE_THREAD_STATE) != KERN_SUCCESS) + ASSERT_NOT_REACHED(); +} diff --git a/Source/WebKit2/Platform/mac/MachUtilities.h b/Source/WebKit2/Platform/mac/MachUtilities.h new file mode 100644 index 0000000..a8d0d6f --- /dev/null +++ b/Source/WebKit2/Platform/mac/MachUtilities.h @@ -0,0 +1,36 @@ +/* + * 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 MachUtilities_h +#define MachUtilities_h + +#include <mach/mach_port.h> + +void setMachPortQueueLength(mach_port_t, mach_port_msgcount_t queueLength); + +mach_port_t machExceptionPort(); +void setMachExceptionPort(mach_port_t exceptionPort); + +#endif // MachUtilities_h diff --git a/Source/WebKit2/Platform/mac/ModuleMac.mm b/Source/WebKit2/Platform/mac/ModuleMac.mm new file mode 100644 index 0000000..fa38745 --- /dev/null +++ b/Source/WebKit2/Platform/mac/ModuleMac.mm @@ -0,0 +1,62 @@ +/* + * 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 "Module.h" + +namespace WebKit { + +bool Module::load() +{ + RetainPtr<CFStringRef> bundlePath(AdoptCF, m_path.createCFString()); + RetainPtr<CFURLRef> bundleURL(AdoptCF, CFURLCreateWithFileSystemPath(kCFAllocatorDefault, bundlePath.get(), kCFURLPOSIXPathStyle, FALSE)); + if (!bundleURL) + return false; + + RetainPtr<CFBundleRef> bundle(AdoptCF, CFBundleCreate(kCFAllocatorDefault, bundleURL.get())); + if (!bundle) + return false; + + if (!CFBundleLoadExecutable(bundle.get())) + return false; + + m_bundle.adoptCF(bundle.releaseRef()); + return true; +} + +void Module::unload() +{ + // See the comment in Module.h for why we leak the bundle here. + m_bundle.releaseRef(); +} + +void* Module::platformFunctionPointer(const char* functionName) const +{ + if (!m_bundle) + return 0; + RetainPtr<CFStringRef> functionNameString(AdoptCF, CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, functionName, kCFStringEncodingASCII, kCFAllocatorNull)); + return CFBundleGetFunctionPointerForName(m_bundle.get(), functionNameString.get()); +} + +} diff --git a/Source/WebKit2/Platform/mac/RunLoopMac.mm b/Source/WebKit2/Platform/mac/RunLoopMac.mm new file mode 100644 index 0000000..ca044f3 --- /dev/null +++ b/Source/WebKit2/Platform/mac/RunLoopMac.mm @@ -0,0 +1,131 @@ +/* + * 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 "RunLoop.h" + +#include "WorkItem.h" + +void RunLoop::performWork(void* context) +{ + static_cast<RunLoop*>(context)->performWork(); +} + +RunLoop::RunLoop() +{ + m_runLoop = CFRunLoopGetCurrent(); + + CFRunLoopSourceContext context = { 0, this, 0, 0, 0, 0, 0, 0, 0, performWork }; + m_runLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); + CFRunLoopAddSource(m_runLoop, m_runLoopSource, kCFRunLoopCommonModes); +} + +RunLoop::~RunLoop() +{ + // FIXME: Tear down the work item queue here. + CFRunLoopSourceInvalidate(m_runLoopSource); + CFRelease(m_runLoopSource); +} + +void RunLoop::run() +{ + if (current() == main()) { + // Use -[NSApplication run] for the main run loop. + [NSApp run]; + } else { + // Otherwise, use NSRunLoop. We do this because it sets up an autorelease pool for us. + [[NSRunLoop currentRunLoop] run]; + } +} + +void RunLoop::stop() +{ + ASSERT(m_runLoop == CFRunLoopGetCurrent()); + + if (m_runLoop == main()->m_runLoop) { + [NSApp stop:nil]; + NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined + location:NSMakePoint(0, 0) + modifierFlags:0 + timestamp:0.0 + windowNumber:0 + context:nil + subtype: 0 + data1:0 + data2:0]; + [NSApp postEvent:event atStart:true]; + } else + CFRunLoopStop(m_runLoop); +} + +void RunLoop::wakeUp() +{ + CFRunLoopSourceSignal(m_runLoopSource); + CFRunLoopWakeUp(m_runLoop); +} + +// RunLoop::Timer + +void RunLoop::TimerBase::timerFired(CFRunLoopTimerRef, void* context) +{ + TimerBase* timer = static_cast<TimerBase*>(context); + timer->fired(); +} + +RunLoop::TimerBase::TimerBase(RunLoop* runLoop) + : m_runLoop(runLoop) + , m_timer(0) +{ +} + +RunLoop::TimerBase::~TimerBase() +{ + stop(); +} + +void RunLoop::TimerBase::start(double nextFireInterval, bool repeat) +{ + if (m_timer) + stop(); + + CFRunLoopTimerContext context = { 0, this, 0, 0, 0 }; + CFTimeInterval repeatInterval = repeat ? nextFireInterval : 0; + m_timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + nextFireInterval, repeatInterval, 0, 0, timerFired, &context); + CFRunLoopAddTimer(m_runLoop->m_runLoop, m_timer, kCFRunLoopCommonModes); +} + +void RunLoop::TimerBase::stop() +{ + if (!m_timer) + return; + + CFRunLoopTimerInvalidate(m_timer); + CFRelease(m_timer); + m_timer = 0; +} + +bool RunLoop::TimerBase::isActive() const +{ + return m_timer && CFRunLoopTimerIsValid(m_timer); +} diff --git a/Source/WebKit2/Platform/mac/SharedMemoryMac.cpp b/Source/WebKit2/Platform/mac/SharedMemoryMac.cpp new file mode 100644 index 0000000..07f942c --- /dev/null +++ b/Source/WebKit2/Platform/mac/SharedMemoryMac.cpp @@ -0,0 +1,171 @@ +/* + * 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 "SharedMemory.h" + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" +#include "Arguments.h" +#include "MachPort.h" +#include <mach/mach_port.h> +#include <mach/mach_vm.h> +#include <mach/vm_map.h> +#include <wtf/RefPtr.h> + +namespace WebKit { + +SharedMemory::Handle::Handle() + : m_port(MACH_PORT_NULL) + , m_size(0) +{ +} + +SharedMemory::Handle::~Handle() +{ + if (m_port) + mach_port_deallocate(mach_task_self(), m_port); +} + +bool SharedMemory::Handle::isNull() const +{ + return !m_port; +} + +void SharedMemory::Handle::encode(CoreIPC::ArgumentEncoder* encoder) const +{ + encoder->encodeUInt64(m_size); + encoder->encode(CoreIPC::MachPort(m_port, MACH_MSG_TYPE_COPY_SEND)); + m_port = MACH_PORT_NULL; +} + +bool SharedMemory::Handle::decode(CoreIPC::ArgumentDecoder* decoder, Handle& handle) +{ + ASSERT(!handle.m_port); + ASSERT(!handle.m_size); + + uint64_t size; + if (!decoder->decodeUInt64(size)) + return false; + + CoreIPC::MachPort machPort; + if (!decoder->decode(CoreIPC::Out(machPort))) + return false; + + handle.m_size = size; + handle.m_port = machPort.port(); + return true; +} + +static inline void* toPointer(mach_vm_address_t address) +{ + return reinterpret_cast<void*>(static_cast<uintptr_t>(address)); +} + +static inline mach_vm_address_t toVMAddress(void* pointer) +{ + return static_cast<mach_vm_address_t>(reinterpret_cast<uintptr_t>(pointer)); +} + +PassRefPtr<SharedMemory> SharedMemory::create(size_t size) +{ + mach_vm_address_t address; + kern_return_t kr = mach_vm_allocate(mach_task_self(), &address, round_page(size), VM_FLAGS_ANYWHERE); + if (kr != KERN_SUCCESS) + return 0; + + RefPtr<SharedMemory> sharedMemory(adoptRef(new SharedMemory)); + sharedMemory->m_size = size; + sharedMemory->m_data = toPointer(address); + + return sharedMemory.release(); +} + +static inline vm_prot_t machProtection(SharedMemory::Protection protection) +{ + switch (protection) { + case SharedMemory::ReadOnly: + return VM_PROT_READ; + case SharedMemory::ReadWrite: + return VM_PROT_READ | VM_PROT_WRITE; + } + + ASSERT_NOT_REACHED(); + return VM_PROT_NONE; +} + +PassRefPtr<SharedMemory> SharedMemory::create(const Handle& handle, Protection protection) +{ + if (handle.isNull()) + return 0; + + // Map the memory. + vm_prot_t vmProtection = machProtection(protection); + mach_vm_address_t mappedAddress = 0; + kern_return_t kr = mach_vm_map(mach_task_self(), &mappedAddress, handle.m_size, 0, VM_FLAGS_ANYWHERE, handle.m_port, 0, false, vmProtection, vmProtection, VM_INHERIT_NONE); + if (kr != KERN_SUCCESS) + return 0; + + RefPtr<SharedMemory> sharedMemory(adoptRef(new SharedMemory)); + sharedMemory->m_size = handle.m_size; + sharedMemory->m_data = toPointer(mappedAddress); + + return sharedMemory.release(); +} + +SharedMemory::~SharedMemory() +{ + if (!m_data) + return; + + kern_return_t kr = mach_vm_deallocate(mach_task_self(), toVMAddress(m_data), round_page(m_size)); + ASSERT_UNUSED(kr, kr == KERN_SUCCESS); +} + +bool SharedMemory::createHandle(Handle& handle, Protection protection) +{ + ASSERT(!handle.m_port); + ASSERT(!handle.m_size); + + mach_vm_address_t address = toVMAddress(m_data); + memory_object_size_t size = round_page(m_size); + + // Create a mach port that represents the shared memory. + mach_port_t port; + kern_return_t kr = mach_make_memory_entry_64(mach_task_self(), &size, address, machProtection(protection), &port, MACH_PORT_NULL); + if (kr != KERN_SUCCESS) + return false; + + handle.m_port = port; + handle.m_size = size; + + return true; +} + +unsigned SharedMemory::systemPageSize() +{ + return vm_page_size; +} + +} // namespace WebKit diff --git a/Source/WebKit2/Platform/mac/WorkQueueMac.cpp b/Source/WebKit2/Platform/mac/WorkQueueMac.cpp new file mode 100644 index 0000000..3651f8c --- /dev/null +++ b/Source/WebKit2/Platform/mac/WorkQueueMac.cpp @@ -0,0 +1,202 @@ +/* + * 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 "WorkQueue.h" + +#include <mach/mach_port.h> +#include <wtf/PassOwnPtr.h> + +#if HAVE(DISPATCH_H) + +void WorkQueue::executeWorkItem(void* item) +{ + WorkQueue* queue = static_cast<WorkQueue*>(dispatch_get_context(dispatch_get_current_queue())); + OwnPtr<WorkItem> workItem(static_cast<WorkItem*>(item)); + + { + MutexLocker locker(queue->m_isValidMutex); + if (!queue->m_isValid) + return; + } + + workItem->execute(); +} + +void WorkQueue::scheduleWork(PassOwnPtr<WorkItem> item) +{ + dispatch_async_f(m_dispatchQueue, item.leakPtr(), executeWorkItem); +} + +void WorkQueue::scheduleWorkAfterDelay(PassOwnPtr<WorkItem> item, double delay) +{ + dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC); + + dispatch_after_f(delayTime, m_dispatchQueue, item.leakPtr(), executeWorkItem); +} + +class WorkQueue::EventSource { +public: + EventSource(MachPortEventType eventType, dispatch_source_t dispatchSource, PassOwnPtr<WorkItem> workItem) + : m_eventType(eventType) + , m_dispatchSource(dispatchSource) + , m_workItem(workItem) + { + } + + dispatch_source_t dispatchSource() const { return m_dispatchSource; } + + static void eventHandler(void* source) + { + EventSource* eventSource = static_cast<EventSource*>(source); + + eventSource->m_workItem->execute(); + } + + static void cancelHandler(void* source) + { + EventSource* eventSource = static_cast<EventSource*>(source); + + mach_port_t machPort = dispatch_source_get_handle(eventSource->m_dispatchSource); + + switch (eventSource->m_eventType) { + case MachPortDataAvailable: + // Release our receive right. + mach_port_mod_refs(mach_task_self(), machPort, MACH_PORT_RIGHT_RECEIVE, -1); + break; + case MachPortDeadNameNotification: + // Release our send right. + mach_port_deallocate(mach_task_self(), machPort); + break; + } + } + + static void finalizeHandler(void* source) + { + EventSource* eventSource = static_cast<EventSource*>(source); + + delete eventSource; + } + +private: + MachPortEventType m_eventType; + + // This is a weak reference, since m_dispatchSource references the event source. + dispatch_source_t m_dispatchSource; + + OwnPtr<WorkItem> m_workItem; +}; + +void WorkQueue::registerMachPortEventHandler(mach_port_t machPort, MachPortEventType eventType, PassOwnPtr<WorkItem> workItem) +{ + dispatch_source_type_t sourceType = 0; + switch (eventType) { + case MachPortDataAvailable: + sourceType = DISPATCH_SOURCE_TYPE_MACH_RECV; + break; + case MachPortDeadNameNotification: + sourceType = DISPATCH_SOURCE_TYPE_MACH_SEND; + break; + } + + dispatch_source_t dispatchSource = dispatch_source_create(sourceType, machPort, 0, m_dispatchQueue); + + EventSource* eventSource = new EventSource(eventType, dispatchSource, workItem); + dispatch_set_context(dispatchSource, eventSource); + + dispatch_source_set_event_handler_f(dispatchSource, &EventSource::eventHandler); + dispatch_source_set_cancel_handler_f(dispatchSource, &EventSource::cancelHandler); + dispatch_set_finalizer_f(dispatchSource, &EventSource::finalizeHandler); + + // Add the source to our set of sources. + { + MutexLocker locker(m_eventSourcesMutex); + + ASSERT(!m_eventSources.contains(machPort)); + + m_eventSources.set(machPort, eventSource); + + // And start it! + dispatch_resume(dispatchSource); + } +} + +void WorkQueue::unregisterMachPortEventHandler(mach_port_t machPort) +{ + ASSERT(machPort); + + MutexLocker locker(m_eventSourcesMutex); + + HashMap<mach_port_t, EventSource*>::iterator it = m_eventSources.find(machPort); + ASSERT(it != m_eventSources.end()); + + ASSERT(m_eventSources.contains(machPort)); + + EventSource* eventSource = it->second; + // Cancel and release the source. It will be deleted in its finalize handler. + dispatch_source_cancel(eventSource->dispatchSource()); + dispatch_release(eventSource->dispatchSource()); + + m_eventSources.remove(it); +} + +void WorkQueue::platformInitialize(const char* name) +{ + m_dispatchQueue = dispatch_queue_create(name, 0); + dispatch_set_context(m_dispatchQueue, this); +} + +void WorkQueue::platformInvalidate() +{ +#if !ASSERT_DISABLED + MutexLocker locker(m_eventSourcesMutex); + ASSERT(m_eventSources.isEmpty()); +#endif + + dispatch_release(m_dispatchQueue); +} + +#else /* !HAVE(DISPATCH_H) */ + +void WorkQueue::scheduleWork(PassOwnPtr<WorkItem> item) +{ +} + +void WorkQueue::registerMachPortEventHandler(mach_port_t, MachPortEventType, PassOwnPtr<WorkItem>) +{ +} + +void WorkQueue::unregisterMachPortEventHandler(mach_port_t) +{ +} + +void WorkQueue::platformInitialize(const char*) +{ +} + +void WorkQueue::platformInvalidate() +{ +} + +#endif diff --git a/Source/WebKit2/Platform/qt/MappedMemoryPool.cpp b/Source/WebKit2/Platform/qt/MappedMemoryPool.cpp new file mode 100644 index 0000000..d36d82b --- /dev/null +++ b/Source/WebKit2/Platform/qt/MappedMemoryPool.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010 University of Szeged + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR + * 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 "MappedMemoryPool.h" + +#include "CleanupHandler.h" +#include "StdLibExtras.h" +#include <QDir> +#include <QIODevice> +#include <QTemporaryFile> + +namespace WebKit { + +MappedMemoryPool* MappedMemoryPool::theInstance = 0; + +MappedMemoryPool* MappedMemoryPool::instance() +{ + if (!theInstance) { + theInstance = new MappedMemoryPool; + + // Do not leave mapping files on the disk. + CleanupHandler::instance()->markForCleanup(theInstance); + } + + return theInstance; +} + +MappedMemoryPool::~MappedMemoryPool() +{ + CleanupHandler::instance()->unmark(theInstance); + + for (unsigned n = 0; n < m_pool.size(); ++n) { + MappedMemory& current = m_pool.at(n); + if (!current.file) + continue; + current.file->remove(); + delete current.file; + } + m_pool.clear(); +} + +MappedMemory* MappedMemoryPool::mapMemory(size_t size) +{ + for (unsigned n = 0; n < m_pool.size(); ++n) { + MappedMemory& current = m_pool.at(n); + if (current.dataSize >= size && current.isFree()) { + current.markUsed(); + return ¤t; + } + } + + MappedMemory newMap; + newMap.dataSize = size; + newMap.file = new QTemporaryFile(QDir::tempPath() + "/WebKit2UpdateChunk"); + newMap.file->open(QIODevice::ReadWrite); + newMap.fileName = newMap.file->fileName(); + newMap.file->resize(newMap.mapSize()); + newMap.mappedBytes = newMap.file->map(0, newMap.mapSize()); + newMap.file->close(); + newMap.markUsed(); + m_pool.append(newMap); + return &m_pool.last(); +} + +MappedMemory* MappedMemoryPool::mapFile(QString fileName, size_t size) +{ + for (unsigned n = 0; n < m_pool.size(); ++n) { + MappedMemory& current = m_pool.at(n); + if (current.fileName == fileName) { + ASSERT(!current.isFree()); + return ¤t; + } + } + + MappedMemory newMap; + newMap.file = new QFile(fileName); + newMap.fileName = fileName; + newMap.dataSize = size; + ASSERT(newMap.file->exists()); + ASSERT(newMap.file->size() >= newMap.mapSize()); + newMap.file->open(QIODevice::ReadWrite); + newMap.mappedBytes = newMap.file->map(0, newMap.mapSize()); + ASSERT(newMap.mappedBytes); + ASSERT(!newMap.isFree()); + newMap.file->close(); + m_pool.append(newMap); + return &m_pool.last(); +} + +} // namespace WebKit diff --git a/Source/WebKit2/Platform/qt/MappedMemoryPool.h b/Source/WebKit2/Platform/qt/MappedMemoryPool.h new file mode 100644 index 0000000..8d6af8c --- /dev/null +++ b/Source/WebKit2/Platform/qt/MappedMemoryPool.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2010 University of Szeged + * + * 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 MappedMemoryPool_h +#define MappedMemoryPool_h + +#include <QFile> +#include <QObject> +#include <wtf/StdLibExtras.h> +#include <wtf/Vector.h> + +namespace WebKit { + +class MappedMemoryPool; + +struct MappedMemory { + + QString mappedFileName() const + { + ASSERT(file); + ASSERT(mappedBytes); + return fileName; + } + + void markFree() + { + ASSERT(mappedBytes); + dataPtr->isFree = true; + } + + uchar* data() const + { + ASSERT(mappedBytes); + return dataPtr->bytes; + } + +private: + friend class MappedMemoryPool; + + MappedMemory() + : file(0) + , mappedBytes(0) + , dataSize(0) + { + } + + void markUsed() { dataPtr->isFree = false; } + + size_t mapSize() const { return dataSize + sizeof(Data); } + bool isFree() const { return dataPtr->isFree; } + + struct Data { + uint32_t isFree; // keep bytes aligned + uchar bytes[]; + }; + + QFile* file; + QString fileName; + union { + uchar* mappedBytes; + Data* dataPtr; + }; + size_t dataSize; +}; + +class MappedMemoryPool : QObject { + Q_OBJECT +public: + static MappedMemoryPool* instance(); + + MappedMemory* mapMemory(size_t size); + MappedMemory* mapFile(QString fileName, size_t size); + +private: + MappedMemoryPool() { } + ~MappedMemoryPool(); + + static MappedMemoryPool* theInstance; + + Vector<MappedMemory> m_pool; +}; + +} // namespace WebKit + +#endif // MappedMemoryPool_h diff --git a/Source/WebKit2/Platform/qt/ModuleQt.cpp b/Source/WebKit2/Platform/qt/ModuleQt.cpp new file mode 100644 index 0000000..8a68cf4 --- /dev/null +++ b/Source/WebKit2/Platform/qt/ModuleQt.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 University of Szeged. + * + * 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 "Module.h" + +namespace WebKit { + +bool Module::load() +{ + m_lib.setFileName(static_cast<QString>(m_path)); + return m_lib.load(); +} + +void Module::unload() +{ + m_lib.unload(); +} + +void* Module::platformFunctionPointer(const char* functionName) const +{ + // Unfortunately QLibrary::resolve is not const. + return const_cast<QLibrary*>(&m_lib)->resolve(functionName); +} + +} diff --git a/Source/WebKit2/Platform/qt/RunLoopQt.cpp b/Source/WebKit2/Platform/qt/RunLoopQt.cpp new file mode 100644 index 0000000..d7d859d --- /dev/null +++ b/Source/WebKit2/Platform/qt/RunLoopQt.cpp @@ -0,0 +1,145 @@ +/* + * 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 "RunLoop.h" + +#include "WorkItem.h" + +#include <QApplication> +#include <QAbstractEventDispatcher> +#include <QObject> +#include <QMetaMethod> +#include <QMetaObject> +#include <QTimerEvent> + +class RunLoop::TimerObject : public QObject +{ + Q_OBJECT +public: + TimerObject(RunLoop* runLoop) : m_runLoop(runLoop) + { + int methodIndex = metaObject()->indexOfMethod("performWork()"); + m_method = metaObject()->method(methodIndex); + } + + Q_SLOT void performWork() { m_runLoop->performWork(); } + inline void wakeUp() { m_method.invoke(this, Qt::QueuedConnection); } + +protected: + virtual void timerEvent(QTimerEvent* event) + { + RunLoop::TimerBase::timerFired(m_runLoop, event->timerId()); + } + +private: + RunLoop* m_runLoop; + QMetaMethod m_method; +}; + +void RunLoop::run() +{ + QCoreApplication::exec(); +} + +void RunLoop::stop() +{ + QCoreApplication::exit(); +} + +RunLoop::RunLoop() + : m_timerObject(new TimerObject(this)) +{ +} + +RunLoop::~RunLoop() +{ + delete m_timerObject; +} + +void RunLoop::wakeUp() +{ + m_timerObject->wakeUp(); +} + +// RunLoop::Timer + +void RunLoop::TimerBase::timerFired(RunLoop* runLoop, int ID) +{ + TimerMap::iterator it = runLoop->m_activeTimers.find(ID); + ASSERT(it != runLoop->m_activeTimers.end()); + TimerBase* timer = it->second; + + if (!timer->m_isRepeating) { + // Stop the timer (calling stop would need another hash table lookup). + runLoop->m_activeTimers.remove(it); + runLoop->m_timerObject->killTimer(timer->m_ID); + timer->m_ID = 0; + } + + timer->fired(); +} + +RunLoop::TimerBase::TimerBase(RunLoop* runLoop) + : m_runLoop(runLoop) + , m_ID(0) + , m_isRepeating(false) +{ +} + +RunLoop::TimerBase::~TimerBase() +{ + stop(); +} + +void RunLoop::TimerBase::start(double nextFireInterval, bool repeat) +{ + stop(); + int millis = static_cast<int>(nextFireInterval * 1000); + m_isRepeating = repeat; + m_ID = m_runLoop->m_timerObject->startTimer(millis); + ASSERT(m_ID); + m_runLoop->m_activeTimers.set(m_ID, this); +} + +void RunLoop::TimerBase::stop() +{ + if (!m_ID) + return; + TimerMap::iterator it = m_runLoop->m_activeTimers.find(m_ID); + if (it == m_runLoop->m_activeTimers.end()) + return; + + m_runLoop->m_activeTimers.remove(it); + m_runLoop->m_timerObject->killTimer(m_ID); + m_ID = 0; +} + +bool RunLoop::TimerBase::isActive() const +{ + return m_ID; +} + +#include "RunLoopQt.moc" diff --git a/Source/WebKit2/Platform/qt/SharedMemoryQt.cpp b/Source/WebKit2/Platform/qt/SharedMemoryQt.cpp new file mode 100644 index 0000000..f5fecfc --- /dev/null +++ b/Source/WebKit2/Platform/qt/SharedMemoryQt.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2010 University of Szeged + * 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 "SharedMemory.h" + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" +#include "CleanupHandler.h" +#include "WebCoreArgumentCoders.h" +#include <unistd.h> +#include <QCoreApplication> +#include <QLatin1String> +#include <QSharedMemory> +#include <QString> +#include <QUuid> +#include <wtf/Assertions.h> +#include <wtf/CurrentTime.h> + +namespace WebKit { + +SharedMemory::Handle::Handle() + : m_key() + , m_size(0) +{ +} + +SharedMemory::Handle::~Handle() +{ +} + +bool SharedMemory::Handle::isNull() const +{ + return m_key.isNull(); +} + +void SharedMemory::Handle::encode(CoreIPC::ArgumentEncoder* encoder) const +{ + encoder->encodeUInt64(m_size); + encoder->encode(m_key); + m_key = String(); +} + +bool SharedMemory::Handle::decode(CoreIPC::ArgumentDecoder* decoder, Handle& handle) +{ + ASSERT_ARG(handle, !handle.m_size); + ASSERT_ARG(handle, handle.m_key.isNull()); + + uint64_t size; + if (!decoder->decodeUInt64(size)) + return false; + + String key; + if (!decoder->decode(key)) + return false; + + handle.m_size = size; + handle.m_key = key; + + return true; +} + +static QString createUniqueKey() +{ + return QLatin1String("QWKSharedMemoryKey") + QUuid::createUuid().toString(); +} + +PassRefPtr<SharedMemory> SharedMemory::create(size_t size) +{ + RefPtr<SharedMemory> sharedMemory(adoptRef(new SharedMemory)); + QSharedMemory* impl = new QSharedMemory(createUniqueKey()); + bool created = impl->create(size); + ASSERT_UNUSED(created, created); + + sharedMemory->m_impl = impl; + sharedMemory->m_size = size; + sharedMemory->m_data = impl->data(); + + // Do not leave the shared memory segment behind. + CleanupHandler::instance()->markForCleanup(impl); + + return sharedMemory.release(); +} + +static inline QSharedMemory::AccessMode accessMode(SharedMemory::Protection protection) +{ + switch (protection) { + case SharedMemory::ReadOnly: + return QSharedMemory::ReadOnly; + case SharedMemory::ReadWrite: + return QSharedMemory::ReadWrite; + } + + ASSERT_NOT_REACHED(); + return QSharedMemory::ReadWrite; +} + +PassRefPtr<SharedMemory> SharedMemory::create(const Handle& handle, Protection protection) +{ + if (handle.isNull()) + return 0; + + QSharedMemory* impl = new QSharedMemory(QString(handle.m_key)); + bool attached = impl->attach(accessMode(protection)); + if (!attached) { + delete impl; + return 0; + } + + RefPtr<SharedMemory> sharedMemory(adoptRef(new SharedMemory)); + sharedMemory->m_impl = impl; + ASSERT(handle.m_size == impl->size()); + sharedMemory->m_size = handle.m_size; + sharedMemory->m_data = impl->data(); + + // Do not leave the shared memory segment behind. + CleanupHandler::instance()->markForCleanup(impl); + + return sharedMemory.release(); +} + +SharedMemory::~SharedMemory() +{ + if (CleanupHandler::instance()->hasStartedDeleting()) + return; + + CleanupHandler::instance()->unmark(m_impl); + delete m_impl; +} + +bool SharedMemory::createHandle(Handle& handle, Protection protection) +{ + ASSERT_ARG(handle, handle.m_key.isNull()); + ASSERT_ARG(handle, !handle.m_size); + + QString key = m_impl->key(); + if (key.isNull()) + return false; + handle.m_key = String(key); + handle.m_size = m_size; + + return true; +} + +unsigned SharedMemory::systemPageSize() +{ + static unsigned pageSize = 0; + + if (!pageSize) + pageSize = getpagesize(); + + return pageSize; +} + +} // namespace WebKit diff --git a/Source/WebKit2/Platform/qt/WorkQueueQt.cpp b/Source/WebKit2/Platform/qt/WorkQueueQt.cpp new file mode 100644 index 0000000..271984f --- /dev/null +++ b/Source/WebKit2/Platform/qt/WorkQueueQt.cpp @@ -0,0 +1,132 @@ +/* + * 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 "WorkQueue.h" + +#include <QLocalSocket> +#include <QObject> +#include <QThread> +#include <wtf/Threading.h> +#include "NotImplemented.h" + +class WorkQueue::WorkItemQt : public QObject { + Q_OBJECT +public: + WorkItemQt(WorkQueue* workQueue, WorkItem* workItem) + : m_queue(workQueue) + , m_source(0) + , m_signal(0) + , m_workItem(workItem) + { + } + + WorkItemQt(WorkQueue* workQueue, QObject* source, const char* signal, WorkItem* workItem) + : m_queue(workQueue) + , m_source(source) + , m_signal(signal) + , m_workItem(workItem) + { + connect(m_source, m_signal, SLOT(execute()), Qt::QueuedConnection); + } + + ~WorkItemQt() + { + delete m_workItem; + } + + Q_SLOT void execute() + { + if (m_queue->m_isValid) + m_workItem->execute(); + } + + virtual void timerEvent(QTimerEvent*) + { + execute(); + delete this; + } + + WorkQueue* m_queue; + QObject* m_source; + const char* m_signal; + WorkItem* m_workItem; +}; + +void WorkQueue::connectSignal(QObject* o, const char* signal, PassOwnPtr<WorkItem> workItem) +{ + WorkQueue::WorkItemQt* itemQt = new WorkQueue::WorkItemQt(this, o, signal, workItem.leakPtr()); + itemQt->moveToThread(m_workThread); + m_signalListeners.add(o, itemQt); +} + +void WorkQueue::disconnectSignal(QObject* o, const char* name) +{ + HashMap<QObject*, WorkItemQt*>::iterator it = m_signalListeners.find(o); + for (; it != m_signalListeners.end(); ++it) { + if (strcmp(it->second->m_signal, name)) + continue; + delete it->second; + m_signalListeners.remove(it); + return; + } +} + +void WorkQueue::moveSocketToWorkThread(QLocalSocket* socket) +{ + ASSERT(m_workThread); + ASSERT(socket); + + socket->setParent(0); + socket->moveToThread(m_workThread); +} + +void WorkQueue::platformInitialize(const char*) +{ + m_workThread = new QThread(); + m_workThread->start(); +} + +void WorkQueue::platformInvalidate() +{ + m_workThread->exit(); + m_workThread->wait(); + delete m_workThread; + deleteAllValues(m_signalListeners); +} + +void WorkQueue::scheduleWork(PassOwnPtr<WorkItem> item) +{ + WorkQueue::WorkItemQt* itemQt = new WorkQueue::WorkItemQt(this, item.leakPtr()); + itemQt->startTimer(0); + itemQt->moveToThread(m_workThread); +} + +void WorkQueue::scheduleWorkAfterDelay(PassOwnPtr<WorkItem>, double) +{ + notImplemented(); +} + +#include "WorkQueueQt.moc" diff --git a/Source/WebKit2/Platform/win/ModuleWin.cpp b/Source/WebKit2/Platform/win/ModuleWin.cpp new file mode 100644 index 0000000..2c2250d --- /dev/null +++ b/Source/WebKit2/Platform/win/ModuleWin.cpp @@ -0,0 +1,55 @@ +/* + * 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 "Module.h" + +#include <shlwapi.h> + +namespace WebKit { + +bool Module::load() +{ + ASSERT(!::PathIsRelativeW(m_path.charactersWithNullTermination())); + m_module = ::LoadLibraryExW(m_path.charactersWithNullTermination(), 0, LOAD_WITH_ALTERED_SEARCH_PATH); + return m_module; +} + +void Module::unload() +{ + if (!m_module) + return; + ::FreeLibrary(m_module); + m_module = 0; +} + +void* Module::platformFunctionPointer(const char* functionName) const +{ + if (!m_module) + return 0; + + return ::GetProcAddress(m_module, functionName); +} + +} // namespace WebKit diff --git a/Source/WebKit2/Platform/win/RunLoopWin.cpp b/Source/WebKit2/Platform/win/RunLoopWin.cpp new file mode 100644 index 0000000..4dfb4b5 --- /dev/null +++ b/Source/WebKit2/Platform/win/RunLoopWin.cpp @@ -0,0 +1,170 @@ +/* + * 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 "RunLoop.h" + +#include "WorkItem.h" + +static const UINT PerformWorkMessage = WM_USER + 1; +static const LPWSTR kRunLoopMessageWindowClassName = L"RunLoopMessageWindow"; + +LRESULT CALLBACK RunLoop::RunLoopWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + LONG_PTR longPtr = ::GetWindowLongPtr(hWnd, 0); + + if (RunLoop* runLoop = reinterpret_cast<RunLoop*>(longPtr)) + return runLoop->wndProc(hWnd, message, wParam, lParam); + + if (message == WM_CREATE) { + LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam); + + // Associate the RunLoop with the window. + ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams); + return 0; + } + + return ::DefWindowProc(hWnd, message, wParam, lParam); +} + +LRESULT RunLoop::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case PerformWorkMessage: + performWork(); + return 0; + case WM_TIMER: + RunLoop::TimerBase::timerFired(this, wParam); + return 0; + } + + return ::DefWindowProc(hWnd, message, wParam, lParam); +} + +void RunLoop::run() +{ + MSG message; + while (BOOL result = ::GetMessage(&message, 0, 0, 0)) { + if (result == -1) + break; + ::TranslateMessage(&message); + ::DispatchMessage(&message); + } +} + +void RunLoop::stop() +{ + ::PostQuitMessage(0); +} + +bool RunLoop::registerRunLoopMessageWindowClass() +{ + // FIXME: This really only needs to be called once. + + WNDCLASSEX windowClass = { 0 }; + windowClass.cbSize = sizeof(windowClass); + windowClass.lpfnWndProc = RunLoop::RunLoopWndProc; + windowClass.cbWndExtra = sizeof(RunLoop*); + windowClass.lpszClassName = kRunLoopMessageWindowClassName; + + return !!::RegisterClassEx(&windowClass); +} + +RunLoop::RunLoop() +{ + registerRunLoopMessageWindowClass(); + + m_runLoopMessageWindow = ::CreateWindow(kRunLoopMessageWindowClassName, 0, 0, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + HWND_MESSAGE, 0, 0, this); + ASSERT(::IsWindow(m_runLoopMessageWindow)); +} + +RunLoop::~RunLoop() +{ + // FIXME: Tear down the work item queue here. +} + +void RunLoop::wakeUp() +{ + // FIXME: No need to wake up the run loop if we've already called scheduleWork + // before the run loop has had the time to respond. + ::PostMessage(m_runLoopMessageWindow, PerformWorkMessage, reinterpret_cast<WPARAM>(this), 0); +} + +// RunLoop::Timer + +void RunLoop::TimerBase::timerFired(RunLoop* runLoop, uint64_t ID) +{ + TimerMap::iterator it = runLoop->m_activeTimers.find(ID); + ASSERT(it != runLoop->m_activeTimers.end()); + TimerBase* timer = it->second; + + if (!timer->m_isRepeating) { + runLoop->m_activeTimers.remove(it); + ::KillTimer(runLoop->m_runLoopMessageWindow, ID); + } + + timer->fired(); +} + +static uint64_t generateTimerID() +{ + static uint64_t uniqueTimerID = 1; + return uniqueTimerID++; +} + +RunLoop::TimerBase::TimerBase(RunLoop* runLoop) + : m_runLoop(runLoop) + , m_ID(generateTimerID()) + , m_isRepeating(false) +{ +} + +RunLoop::TimerBase::~TimerBase() +{ + stop(); +} + +void RunLoop::TimerBase::start(double nextFireInterval, bool repeat) +{ + m_isRepeating = repeat; + m_runLoop->m_activeTimers.set(m_ID, this); + ::SetTimer(m_runLoop->m_runLoopMessageWindow, m_ID, nextFireInterval, 0); +} + +void RunLoop::TimerBase::stop() +{ + TimerMap::iterator it = m_runLoop->m_activeTimers.find(m_ID); + if (it == m_runLoop->m_activeTimers.end()) + return; + + m_runLoop->m_activeTimers.remove(it); + ::KillTimer(m_runLoop->m_runLoopMessageWindow, m_ID); +} + +bool RunLoop::TimerBase::isActive() const +{ + return m_runLoop->m_activeTimers.contains(m_ID); +} diff --git a/Source/WebKit2/Platform/win/SharedMemoryWin.cpp b/Source/WebKit2/Platform/win/SharedMemoryWin.cpp new file mode 100644 index 0000000..260783a --- /dev/null +++ b/Source/WebKit2/Platform/win/SharedMemoryWin.cpp @@ -0,0 +1,188 @@ +/* + * 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 "SharedMemory.h" + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" +#include <wtf/RefPtr.h> + +namespace WebKit { + +SharedMemory::Handle::Handle() + : m_handle(0) + , m_size(0) +{ +} + +SharedMemory::Handle::~Handle() +{ + if (!m_handle) + return; + + ::CloseHandle(m_handle); +} + +void SharedMemory::Handle::encode(CoreIPC::ArgumentEncoder* encoder) const +{ + encoder->encodeUInt64(m_size); + + // Hand off ownership of our HANDLE to the receiving process. It will close it for us. + // FIXME: If the receiving process crashes before it receives the memory, the memory will be + // leaked. See <http://webkit.org/b/47502>. + encoder->encodeUInt64(reinterpret_cast<uint64_t>(m_handle)); + m_handle = 0; + + // Send along our PID so that the receiving process can duplicate the HANDLE for its own use. + encoder->encodeUInt32(::GetCurrentProcessId()); +} + +bool SharedMemory::Handle::decode(CoreIPC::ArgumentDecoder* decoder, Handle& handle) +{ + ASSERT_ARG(handle, !handle.m_handle); + ASSERT_ARG(handle, !handle.m_size); + + uint64_t size; + if (!decoder->decodeUInt64(size)) + return false; + + uint64_t sourceHandle; + if (!decoder->decodeUInt64(sourceHandle)) + return false; + + uint32_t sourcePID; + if (!decoder->decodeUInt32(sourcePID)) + return false; + + HANDLE sourceProcess = ::OpenProcess(PROCESS_DUP_HANDLE, FALSE, sourcePID); + if (!sourceProcess) + return false; + + // Copy the handle into our process and close the handle that the sending process created for us. + HANDLE duplicatedHandle; + BOOL success = ::DuplicateHandle(sourceProcess, reinterpret_cast<HANDLE>(sourceHandle), ::GetCurrentProcess(), &duplicatedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + ::CloseHandle(sourceProcess); + + if (!success) + return false; + + handle.m_handle = duplicatedHandle; + handle.m_size = size; + return true; +} + +PassRefPtr<SharedMemory> SharedMemory::create(size_t size) +{ + HANDLE handle = ::CreateFileMappingW(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size, 0); + if (!handle) + return 0; + + void* baseAddress = ::MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, size); + if (!baseAddress) { + ::CloseHandle(handle); + return 0; + } + + RefPtr<SharedMemory> memory = adoptRef(new SharedMemory); + memory->m_size = size; + memory->m_data = baseAddress; + memory->m_handle = handle; + + return memory.release(); +} + +static DWORD accessRights(SharedMemory::Protection protection) +{ + switch (protection) { + case SharedMemory::ReadOnly: + return FILE_MAP_READ; + case SharedMemory::ReadWrite: + // FILE_MAP_WRITE implies read access, too. + return FILE_MAP_WRITE; + } + + ASSERT_NOT_REACHED(); + return 0; +} + +PassRefPtr<SharedMemory> SharedMemory::create(const Handle& handle, Protection protection) +{ + DWORD desiredAccess = accessRights(protection); + + void* baseAddress = ::MapViewOfFile(handle.m_handle, desiredAccess, 0, 0, handle.m_size); + if (!baseAddress) + return 0; + + RefPtr<SharedMemory> memory = adoptRef(new SharedMemory); + memory->m_size = handle.m_size; + memory->m_data = baseAddress; + + // Adopt the HANDLE. + memory->m_handle = handle.m_handle; + handle.m_handle = 0; + + return memory.release(); +} + +SharedMemory::~SharedMemory() +{ + ASSERT(m_data); + ASSERT(m_handle); + + ::UnmapViewOfFile(m_data); + ::CloseHandle(m_handle); +} + +bool SharedMemory::createHandle(Handle& handle, Protection protection) +{ + ASSERT_ARG(handle, !handle.m_handle); + ASSERT_ARG(handle, !handle.m_size); + + HANDLE processHandle = ::GetCurrentProcess(); + + HANDLE duplicatedHandle; + if (!::DuplicateHandle(processHandle, m_handle, processHandle, &duplicatedHandle, accessRights(protection), FALSE, 0)) + return false; + + handle.m_handle = duplicatedHandle; + handle.m_size = m_size; + return true; +} + +unsigned SharedMemory::systemPageSize() +{ + static unsigned pageSize = 0; + + if (!pageSize) { + SYSTEM_INFO systemInfo; + ::GetSystemInfo(&systemInfo); + pageSize = systemInfo.dwPageSize; + } + + return pageSize; +} + +} // namespace WebKit diff --git a/Source/WebKit2/Platform/win/WorkQueueWin.cpp b/Source/WebKit2/Platform/win/WorkQueueWin.cpp new file mode 100644 index 0000000..f527432 --- /dev/null +++ b/Source/WebKit2/Platform/win/WorkQueueWin.cpp @@ -0,0 +1,234 @@ +/* + * 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 "WorkQueue.h" + +#include <wtf/Threading.h> +#include "NotImplemented.h" + +inline WorkQueue::WorkItemWin::WorkItemWin(PassOwnPtr<WorkItem> item, WorkQueue* queue) + : m_item(item) + , m_queue(queue) +{ +} + +PassRefPtr<WorkQueue::WorkItemWin> WorkQueue::WorkItemWin::create(PassOwnPtr<WorkItem> item, WorkQueue* queue) +{ + return adoptRef(new WorkItemWin(item, queue)); +} + +WorkQueue::WorkItemWin::~WorkItemWin() +{ +} + +inline WorkQueue::HandleWorkItem::HandleWorkItem(HANDLE handle, PassOwnPtr<WorkItem> item, WorkQueue* queue) + : WorkItemWin(item, queue) + , m_handle(handle) + , m_waitHandle(0) +{ + ASSERT_ARG(handle, handle); +} + +PassRefPtr<WorkQueue::HandleWorkItem> WorkQueue::HandleWorkItem::createByAdoptingHandle(HANDLE handle, PassOwnPtr<WorkItem> item, WorkQueue* queue) +{ + return adoptRef(new HandleWorkItem(handle, item, queue)); +} + +WorkQueue::HandleWorkItem::~HandleWorkItem() +{ + ::CloseHandle(m_handle); +} + +void WorkQueue::handleCallback(void* context, BOOLEAN timerOrWaitFired) +{ + ASSERT_ARG(context, context); + ASSERT_ARG(timerOrWaitFired, !timerOrWaitFired); + + WorkItemWin* item = static_cast<WorkItemWin*>(context); + WorkQueue* queue = item->queue(); + + { + MutexLocker lock(queue->m_workItemQueueLock); + queue->m_workItemQueue.append(item); + + // If no other thread is performing work, we can do it on this thread. + if (!queue->tryRegisterAsWorkThread()) { + // Some other thread is performing work. Since we hold the queue lock, we can be sure + // that the work thread is not exiting due to an empty queue and will process the work + // item we just added to it. If we weren't holding the lock we'd have to signal + // m_performWorkEvent to make sure the work item got picked up. + return; + } + } + + queue->performWorkOnRegisteredWorkThread(); +} + +void WorkQueue::registerHandle(HANDLE handle, PassOwnPtr<WorkItem> item) +{ + RefPtr<HandleWorkItem> handleItem = HandleWorkItem::createByAdoptingHandle(handle, item, this); + + { + MutexLocker lock(m_handlesLock); + ASSERT_ARG(handle, !m_handles.contains(handle)); + m_handles.set(handle, handleItem); + } + + HANDLE waitHandle; + if (!::RegisterWaitForSingleObject(&waitHandle, handle, handleCallback, handleItem.get(), INFINITE, WT_EXECUTEDEFAULT)) { + DWORD error = ::GetLastError(); + ASSERT_NOT_REACHED(); + } + handleItem->setWaitHandle(waitHandle); +} + +void WorkQueue::unregisterAndCloseHandle(HANDLE handle) +{ + RefPtr<HandleWorkItem> item; + { + MutexLocker locker(m_handlesLock); + ASSERT_ARG(handle, m_handles.contains(handle)); + item = m_handles.take(handle); + } + + unregisterWaitAndDestroyItemSoon(item.release()); +} + +DWORD WorkQueue::workThreadCallback(void* context) +{ + ASSERT_ARG(context, context); + + WorkQueue* queue = static_cast<WorkQueue*>(context); + + if (!queue->tryRegisterAsWorkThread()) + return 0; + + queue->performWorkOnRegisteredWorkThread(); + return 0; +} + +void WorkQueue::performWorkOnRegisteredWorkThread() +{ + ASSERT(m_isWorkThreadRegistered); + + bool isValid = true; + + m_workItemQueueLock.lock(); + + while (isValid && !m_workItemQueue.isEmpty()) { + Vector<RefPtr<WorkItemWin> > workItemQueue; + m_workItemQueue.swap(workItemQueue); + + // Allow more work to be scheduled while we're not using the queue directly. + m_workItemQueueLock.unlock(); + for (size_t i = 0; i < workItemQueue.size(); ++i) { + MutexLocker locker(m_isValidMutex); + isValid = m_isValid; + if (!isValid) + break; + workItemQueue[i]->item()->execute(); + } + m_workItemQueueLock.lock(); + } + + // One invariant we maintain is that any work scheduled while a work thread is registered will + // be handled by that work thread. Unregister as the work thread while the queue lock is still + // held so that no work can be scheduled while we're still registered. + unregisterAsWorkThread(); + + m_workItemQueueLock.unlock(); +} + +void WorkQueue::platformInitialize(const char* name) +{ + m_isWorkThreadRegistered = 0; +} + +bool WorkQueue::tryRegisterAsWorkThread() +{ + LONG result = ::InterlockedCompareExchange(&m_isWorkThreadRegistered, 1, 0); + ASSERT(!result || result == 1); + return !result; +} + +void WorkQueue::unregisterAsWorkThread() +{ + LONG result = ::InterlockedCompareExchange(&m_isWorkThreadRegistered, 0, 1); + ASSERT_UNUSED(result, result == 1); +} + +void WorkQueue::platformInvalidate() +{ +#if !ASSERT_DISABLED + MutexLocker lock(m_handlesLock); + ASSERT(m_handles.isEmpty()); +#endif +} + +void WorkQueue::scheduleWork(PassOwnPtr<WorkItem> item) +{ + MutexLocker locker(m_workItemQueueLock); + + m_workItemQueue.append(WorkItemWin::create(item, this)); + + // Spawn a work thread to perform the work we just added. As an optimization, we avoid + // spawning the thread if a work thread is already registered. This prevents multiple work + // threads from being spawned in most cases. (Note that when a work thread has been spawned but + // hasn't registered itself yet, m_isWorkThreadRegistered will be false and we'll end up + // spawning a second work thread here. But work thread registration process will ensure that + // only one thread actually ends up performing work.) + if (!m_isWorkThreadRegistered) + ::QueueUserWorkItem(workThreadCallback, this, WT_EXECUTEDEFAULT); +} + +void WorkQueue::scheduleWorkAfterDelay(PassOwnPtr<WorkItem>, double) +{ + notImplemented(); +} + +void WorkQueue::unregisterWaitAndDestroyItemSoon(PassRefPtr<HandleWorkItem> item) +{ + // We're going to make a blocking call to ::UnregisterWaitEx before closing the handle. (The + // blocking version of ::UnregisterWaitEx is much simpler than the non-blocking version.) If we + // do this on the current thread, we'll deadlock if we're currently in a callback function for + // the wait we're unregistering. So instead we do it asynchronously on some other worker thread. + + ::QueueUserWorkItem(unregisterWaitAndDestroyItemCallback, item.leakRef(), WT_EXECUTEDEFAULT); +} + +DWORD WINAPI WorkQueue::unregisterWaitAndDestroyItemCallback(void* context) +{ + ASSERT_ARG(context, context); + RefPtr<HandleWorkItem> item = adoptRef(static_cast<HandleWorkItem*>(context)); + + // Now that we know we're not in a callback function for the wait we're unregistering, we can + // make a blocking call to ::UnregisterWaitEx. + if (!::UnregisterWaitEx(item->waitHandle(), INVALID_HANDLE_VALUE)) { + DWORD error = ::GetLastError(); + ASSERT_NOT_REACHED(); + } + + return 0; +} |