diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebKit2/Platform | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebKit2/Platform')
43 files changed, 2141 insertions, 2058 deletions
diff --git a/Source/WebKit2/Platform/IPC/ArgumentCoder.h b/Source/WebKit2/Platform/IPC/ArgumentCoder.h index 2af313c42..5df6c1b0b 100644 --- a/Source/WebKit2/Platform/IPC/ArgumentCoder.h +++ b/Source/WebKit2/Platform/IPC/ArgumentCoder.h @@ -28,16 +28,16 @@ namespace IPC { -class ArgumentDecoder; -class ArgumentEncoder; +class Decoder; +class Encoder; template<typename T> struct ArgumentCoder { - static void encode(ArgumentEncoder& encoder, const T& t) + static void encode(Encoder& encoder, const T& t) { t.encode(encoder); } - static bool decode(ArgumentDecoder& decoder, T& t) + static bool decode(Decoder& decoder, T& t) { return T::decode(decoder, t); } diff --git a/Source/WebKit2/Platform/IPC/ArgumentCoders.cpp b/Source/WebKit2/Platform/IPC/ArgumentCoders.cpp index 5ca064108..0c986425a 100644 --- a/Source/WebKit2/Platform/IPC/ArgumentCoders.cpp +++ b/Source/WebKit2/Platform/IPC/ArgumentCoders.cpp @@ -32,12 +32,27 @@ namespace IPC { -void ArgumentCoder<AtomicString>::encode(ArgumentEncoder& encoder, const AtomicString& atomicString) +void ArgumentCoder<std::chrono::system_clock::time_point>::encode(IPC::Encoder& encoder, const std::chrono::system_clock::time_point& timePoint) +{ + encoder << static_cast<int64_t>(timePoint.time_since_epoch().count()); +} + +bool ArgumentCoder<std::chrono::system_clock::time_point>::decode(Decoder& decoder, std::chrono::system_clock::time_point& result) +{ + int64_t time; + if (!decoder.decode(time)) + return false; + + result = std::chrono::system_clock::time_point(std::chrono::system_clock::duration(static_cast<std::chrono::system_clock::rep>(time))); + return true; +} + +void ArgumentCoder<AtomicString>::encode(Encoder& encoder, const AtomicString& atomicString) { encoder << atomicString.string(); } -bool ArgumentCoder<AtomicString>::decode(ArgumentDecoder& decoder, AtomicString& atomicString) +bool ArgumentCoder<AtomicString>::decode(Decoder& decoder, AtomicString& atomicString) { String string; if (!decoder.decode(string)) @@ -47,7 +62,7 @@ bool ArgumentCoder<AtomicString>::decode(ArgumentDecoder& decoder, AtomicString& return true; } -void ArgumentCoder<CString>::encode(ArgumentEncoder& encoder, const CString& string) +void ArgumentCoder<CString>::encode(Encoder& encoder, const CString& string) { // Special case the null string. if (string.isNull()) { @@ -60,7 +75,7 @@ void ArgumentCoder<CString>::encode(ArgumentEncoder& encoder, const CString& str encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(string.data()), length, 1); } -bool ArgumentCoder<CString>::decode(ArgumentDecoder& decoder, CString& result) +bool ArgumentCoder<CString>::decode(Decoder& decoder, CString& result) { uint32_t length; if (!decoder.decode(length)) @@ -88,7 +103,7 @@ bool ArgumentCoder<CString>::decode(ArgumentDecoder& decoder, CString& result) } -void ArgumentCoder<String>::encode(ArgumentEncoder& encoder, const String& string) +void ArgumentCoder<String>::encode(Encoder& encoder, const String& string) { // Special case the null string. if (string.isNull()) { @@ -108,7 +123,7 @@ void ArgumentCoder<String>::encode(ArgumentEncoder& encoder, const String& strin } template <typename CharacterType> -static inline bool decodeStringText(ArgumentDecoder& decoder, uint32_t length, String& result) +static inline bool decodeStringText(Decoder& decoder, uint32_t length, String& result) { // Before allocating the string, make sure that the decoder buffer is big enough. if (!decoder.bufferIsLargeEnoughToContain<CharacterType>(length)) { @@ -125,7 +140,7 @@ static inline bool decodeStringText(ArgumentDecoder& decoder, uint32_t length, S return true; } -bool ArgumentCoder<String>::decode(ArgumentDecoder& decoder, String& result) +bool ArgumentCoder<String>::decode(Decoder& decoder, String& result) { uint32_t length; if (!decoder.decode(length)) @@ -147,4 +162,15 @@ bool ArgumentCoder<String>::decode(ArgumentDecoder& decoder, String& result) return decodeStringText<UChar>(decoder, length, result); } + +void ArgumentCoder<SHA1::Digest>::encode(Encoder& encoder, const SHA1::Digest& digest) +{ + encoder.encodeFixedLengthData(digest.data(), sizeof(digest), 1); +} + +bool ArgumentCoder<SHA1::Digest>::decode(Decoder& decoder, SHA1::Digest& digest) +{ + return decoder.decodeFixedLengthData(digest.data(), sizeof(digest), 1); +} + } // namespace IPC diff --git a/Source/WebKit2/Platform/IPC/ArgumentCoders.h b/Source/WebKit2/Platform/IPC/ArgumentCoders.h index c04b7a989..86166c843 100644 --- a/Source/WebKit2/Platform/IPC/ArgumentCoders.h +++ b/Source/WebKit2/Platform/IPC/ArgumentCoders.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,38 +23,92 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SimpleArgumentCoder_h -#define SimpleArgumentCoder_h +#pragma once -#include "ArgumentDecoder.h" -#include "ArgumentEncoder.h" +#include "Decoder.h" +#include "Encoder.h" #include <utility> #include <wtf/Forward.h> +#include <wtf/HashCountedSet.h> #include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/OptionSet.h> +#include <wtf/Optional.h> +#include <wtf/SHA1.h> +#include <wtf/Variant.h> #include <wtf/Vector.h> namespace IPC { // An argument coder works on POD types template<typename T> struct SimpleArgumentCoder { - static void encode(ArgumentEncoder& encoder, const T& t) + static void encode(Encoder& encoder, const T& t) { encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(&t), sizeof(T), alignof(T)); } - static bool decode(ArgumentDecoder& decoder, T& t) + static bool decode(Decoder& decoder, T& t) { return decoder.decodeFixedLengthData(reinterpret_cast<uint8_t*>(&t), sizeof(T), alignof(T)); } }; +template<typename T> struct ArgumentCoder<OptionSet<T>> { + static void encode(Encoder& encoder, const OptionSet<T>& optionSet) + { + encoder << (static_cast<uint64_t>(optionSet.toRaw())); + } + + static bool decode(Decoder& decoder, OptionSet<T>& optionSet) + { + uint64_t value; + if (!decoder.decode(value)) + return false; + + optionSet = OptionSet<T>::fromRaw(value); + return true; + } +}; + +template<typename T> struct ArgumentCoder<std::optional<T>> { + static void encode(Encoder& encoder, const std::optional<T>& optional) + { + if (!optional) { + encoder << false; + return; + } + + encoder << true; + encoder << optional.value(); + } + + static bool decode(Decoder& decoder, std::optional<T>& optional) + { + bool isEngaged; + if (!decoder.decode(isEngaged)) + return false; + + if (!isEngaged) { + optional = std::nullopt; + return true; + } + + T value; + if (!decoder.decode(value)) + return false; + + optional = WTFMove(value); + return true; + } +}; + template<typename T, typename U> struct ArgumentCoder<std::pair<T, U>> { - static void encode(ArgumentEncoder& encoder, const std::pair<T, U>& pair) + static void encode(Encoder& encoder, const std::pair<T, U>& pair) { encoder << pair.first << pair.second; } - static bool decode(ArgumentDecoder& decoder, std::pair<T, U>& pair) + static bool decode(Decoder& decoder, std::pair<T, U>& pair) { T first; if (!decoder.decode(first)) @@ -70,13 +124,71 @@ template<typename T, typename U> struct ArgumentCoder<std::pair<T, U>> { } }; +template<size_t index, typename... Elements> +struct TupleCoder { + static void encode(Encoder& encoder, const std::tuple<Elements...>& tuple) + { + encoder << std::get<sizeof...(Elements) - index>(tuple); + TupleCoder<index - 1, Elements...>::encode(encoder, tuple); + } + + static bool decode(Decoder& decoder, std::tuple<Elements...>& tuple) + { + if (!decoder.decode(std::get<sizeof...(Elements) - index>(tuple))) + return false; + return TupleCoder<index - 1, Elements...>::decode(decoder, tuple); + } +}; + +template<typename... Elements> +struct TupleCoder<0, Elements...> { + static void encode(Encoder&, const std::tuple<Elements...>&) + { + } + + static bool decode(Decoder&, std::tuple<Elements...>&) + { + return true; + } +}; + +template<typename... Elements> struct ArgumentCoder<std::tuple<Elements...>> { + static void encode(Encoder& encoder, const std::tuple<Elements...>& tuple) + { + TupleCoder<sizeof...(Elements), Elements...>::encode(encoder, tuple); + } + + static bool decode(Decoder& decoder, std::tuple<Elements...>& tuple) + { + return TupleCoder<sizeof...(Elements), Elements...>::decode(decoder, tuple); + } +}; + + +template<typename Rep, typename Period> struct ArgumentCoder<std::chrono::duration<Rep, Period>> { + static void encode(Encoder& encoder, const std::chrono::duration<Rep, Period>& duration) + { + static_assert(std::is_integral<Rep>::value && std::is_signed<Rep>::value && sizeof(Rep) <= sizeof(int64_t), "Serialization of this Rep type is not supported yet. Only signed integer type which can be fit in an int64_t is currently supported."); + encoder << static_cast<int64_t>(duration.count()); + } + + static bool decode(Decoder& decoder, std::chrono::duration<Rep, Period>& result) + { + int64_t count; + if (!decoder.decode(count)) + return false; + result = std::chrono::duration<Rep, Period>(static_cast<Rep>(count)); + return true; + } +}; + template<typename KeyType, typename ValueType> struct ArgumentCoder<WTF::KeyValuePair<KeyType, ValueType>> { - static void encode(ArgumentEncoder& encoder, const WTF::KeyValuePair<KeyType, ValueType>& pair) + static void encode(Encoder& encoder, const WTF::KeyValuePair<KeyType, ValueType>& pair) { encoder << pair.key << pair.value; } - static bool decode(ArgumentDecoder& decoder, WTF::KeyValuePair<KeyType, ValueType>& pair) + static bool decode(Decoder& decoder, WTF::KeyValuePair<KeyType, ValueType>& pair) { KeyType key; if (!decoder.decode(key)) @@ -92,29 +204,29 @@ template<typename KeyType, typename ValueType> struct ArgumentCoder<WTF::KeyValu } }; -template<bool fixedSizeElements, typename T> struct VectorArgumentCoder; +template<bool fixedSizeElements, typename T, size_t inlineCapacity> struct VectorArgumentCoder; -template<typename T> struct VectorArgumentCoder<false, T> { - static void encode(ArgumentEncoder& encoder, const Vector<T>& vector) +template<typename T, size_t inlineCapacity> struct VectorArgumentCoder<false, T, inlineCapacity> { + static void encode(Encoder& encoder, const Vector<T, inlineCapacity>& vector) { encoder << static_cast<uint64_t>(vector.size()); for (size_t i = 0; i < vector.size(); ++i) encoder << vector[i]; } - static bool decode(ArgumentDecoder& decoder, Vector<T>& vector) + static bool decode(Decoder& decoder, Vector<T, inlineCapacity>& vector) { uint64_t size; if (!decoder.decode(size)) return false; - Vector<T> tmp; + Vector<T, inlineCapacity> tmp; for (size_t i = 0; i < size; ++i) { T element; if (!decoder.decode(element)) return false; - tmp.append(element); + tmp.append(WTFMove(element)); } tmp.shrinkToFit(); @@ -123,14 +235,14 @@ template<typename T> struct VectorArgumentCoder<false, T> { } }; -template<typename T> struct VectorArgumentCoder<true, T> { - static void encode(ArgumentEncoder& encoder, const Vector<T>& vector) +template<typename T, size_t inlineCapacity> struct VectorArgumentCoder<true, T, inlineCapacity> { + static void encode(Encoder& encoder, const Vector<T, inlineCapacity>& vector) { encoder << static_cast<uint64_t>(vector.size()); encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(vector.data()), vector.size() * sizeof(T), alignof(T)); } - static bool decode(ArgumentDecoder& decoder, Vector<T>& vector) + static bool decode(Decoder& decoder, Vector<T, inlineCapacity>& vector) { uint64_t size; if (!decoder.decode(size)) @@ -144,7 +256,7 @@ template<typename T> struct VectorArgumentCoder<true, T> { return false; } - Vector<T> temp; + Vector<T, inlineCapacity> temp; temp.resize(size); decoder.decodeFixedLengthData(reinterpret_cast<uint8_t*>(temp.data()), size * sizeof(T), alignof(T)); @@ -154,19 +266,19 @@ template<typename T> struct VectorArgumentCoder<true, T> { } }; -template<typename T> struct ArgumentCoder<Vector<T>> : VectorArgumentCoder<std::is_arithmetic<T>::value, T> { }; +template<typename T, size_t inlineCapacity> struct ArgumentCoder<Vector<T, inlineCapacity>> : VectorArgumentCoder<std::is_arithmetic<T>::value, T, inlineCapacity> { }; 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) + static void encode(Encoder& encoder, const HashMapType& hashMap) { encoder << static_cast<uint64_t>(hashMap.size()); for (typename HashMapType::const_iterator it = hashMap.begin(), end = hashMap.end(); it != end; ++it) encoder << *it; } - static bool decode(ArgumentDecoder& decoder, HashMapType& hashMap) + static bool decode(Decoder& decoder, HashMapType& hashMap) { uint64_t hashMapSize; if (!decoder.decode(hashMapSize)) @@ -193,21 +305,104 @@ template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTrai } }; +template<typename KeyArg, typename HashArg, typename KeyTraitsArg> struct ArgumentCoder<HashSet<KeyArg, HashArg, KeyTraitsArg>> { + typedef HashSet<KeyArg, HashArg, KeyTraitsArg> HashSetType; + + static void encode(Encoder& encoder, const HashSetType& hashSet) + { + encoder << static_cast<uint64_t>(hashSet.size()); + for (typename HashSetType::const_iterator it = hashSet.begin(), end = hashSet.end(); it != end; ++it) + encoder << *it; + } + + static bool decode(Decoder& decoder, HashSetType& hashSet) + { + uint64_t hashSetSize; + if (!decoder.decode(hashSetSize)) + return false; + + HashSetType tempHashSet; + for (uint64_t i = 0; i < hashSetSize; ++i) { + KeyArg key; + if (!decoder.decode(key)) + return false; + + if (!tempHashSet.add(key).isNewEntry) { + // The hash map already has the specified key, bail. + decoder.markInvalid(); + return false; + } + } + + hashSet.swap(tempHashSet); + return true; + } +}; + +template<typename KeyArg, typename HashArg, typename KeyTraitsArg> struct ArgumentCoder<HashCountedSet<KeyArg, HashArg, KeyTraitsArg>> { + typedef HashCountedSet<KeyArg, HashArg, KeyTraitsArg> HashCountedSetType; + + static void encode(Encoder& encoder, const HashCountedSetType& hashCountedSet) + { + encoder << static_cast<uint64_t>(hashCountedSet.size()); + + for (auto entry : hashCountedSet) { + encoder << entry.key; + encoder << entry.value; + } + } + + static bool decode(Decoder& decoder, HashCountedSetType& hashCountedSet) + { + uint64_t hashCountedSetSize; + if (!decoder.decode(hashCountedSetSize)) + return false; + + HashCountedSetType tempHashCountedSet; + for (uint64_t i = 0; i < hashCountedSetSize; ++i) { + KeyArg key; + if (!decoder.decode(key)) + return false; + + unsigned count; + if (!decoder.decode(count)) + return false; + + if (!tempHashCountedSet.add(key, count).isNewEntry) { + // The hash counted set already has the specified key, bail. + decoder.markInvalid(); + return false; + } + } + + hashCountedSet.swap(tempHashCountedSet); + return true; + } +}; + +template<> struct ArgumentCoder<std::chrono::system_clock::time_point> { + static void encode(Encoder&, const std::chrono::system_clock::time_point&); + static bool decode(Decoder&, std::chrono::system_clock::time_point&); +}; + template<> struct ArgumentCoder<AtomicString> { - static void encode(ArgumentEncoder&, const AtomicString&); - static bool decode(ArgumentDecoder&, AtomicString&); + static void encode(Encoder&, const AtomicString&); + static bool decode(Decoder&, AtomicString&); }; template<> struct ArgumentCoder<CString> { - static void encode(ArgumentEncoder&, const CString&); - static bool decode(ArgumentDecoder&, CString&); + static void encode(Encoder&, const CString&); + static bool decode(Decoder&, CString&); }; template<> struct ArgumentCoder<String> { - static void encode(ArgumentEncoder&, const String&); - static bool decode(ArgumentDecoder&, String&); + static void encode(Encoder&, const String&); + static bool decode(Decoder&, String&); }; -} // namespace IPC +template<> struct ArgumentCoder<SHA1::Digest> { + static void encode(Encoder&, const SHA1::Digest&); + static bool decode(Decoder&, SHA1::Digest&); +}; -#endif // ArgumentCoders_h +} // namespace IPC diff --git a/Source/WebKit2/Platform/IPC/Arguments.h b/Source/WebKit2/Platform/IPC/Arguments.h deleted file mode 100644 index 7921e1a33..000000000 --- a/Source/WebKit2/Platform/IPC/Arguments.h +++ /dev/null @@ -1,391 +0,0 @@ -/* - * 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" - -namespace IPC { - -template<size_t index, typename... Elements> -struct TupleCoder { - static void encode(ArgumentEncoder& encoder, const std::tuple<Elements...>& tuple) - { - encoder << std::get<sizeof...(Elements) - index>(tuple); - TupleCoder<index - 1, Elements...>::encode(encoder, tuple); - } - - static bool decode(ArgumentDecoder& decoder, std::tuple<Elements...>& tuple) - { - if (!decoder.decode(std::get<sizeof...(Elements) - index>(tuple))) - return false; - return TupleCoder<index - 1, Elements...>::decode(decoder, tuple); - } -}; - -template<typename... Elements> -struct TupleCoder<0, Elements...> { - static void encode(ArgumentEncoder&, const std::tuple<Elements...>&) - { - } - - static bool decode(ArgumentDecoder&, std::tuple<Elements...>&) - { - return true; - } -}; - -template<typename... Elements> struct ArgumentCoder<std::tuple<Elements...>> { - static void encode(ArgumentEncoder& encoder, const std::tuple<Elements...>& tuple) - { - TupleCoder<sizeof...(Elements), Elements...>::encode(encoder, tuple); - } - - static bool decode(ArgumentDecoder& decoder, std::tuple<Elements...>& tuple) - { - return TupleCoder<sizeof...(Elements), Elements...>::decode(decoder, tuple); - } -}; - -struct Arguments0 { - typedef std::tuple<> ValueType; - - void encode(ArgumentEncoder&) const - { - } - - static bool decode(ArgumentDecoder&, Arguments0&) - { - return true; - } -}; - -template<typename T1> struct Arguments1 { - typedef std::tuple<typename std::remove_const<typename std::remove_reference<T1>::type>::type> ValueType; - - Arguments1() - { - } - - Arguments1(T1 t1) - : argument1(t1) - { - } - - void encode(ArgumentEncoder& encoder) const - { - encoder << argument1; - } - - static bool decode(ArgumentDecoder& decoder, Arguments1& result) - { - return decoder.decode(result.argument1); - } - - T1 argument1; -}; - -template<typename T1, typename T2> struct Arguments2 : Arguments1<T1> { - typedef std::tuple<typename std::remove_const<typename std::remove_reference<T1>::type>::type, - typename std::remove_const<typename std::remove_reference<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 << 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, typename T3> struct Arguments3 : Arguments2<T1, T2> { - typedef std::tuple<typename std::remove_const<typename std::remove_reference<T1>::type>::type, - typename std::remove_const<typename std::remove_reference<T2>::type>::type, - typename std::remove_const<typename std::remove_reference<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 << 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, typename T4> struct Arguments4 : Arguments3<T1, T2, T3> { - typedef std::tuple<typename std::remove_const<typename std::remove_reference<T1>::type>::type, - typename std::remove_const<typename std::remove_reference<T2>::type>::type, - typename std::remove_const<typename std::remove_reference<T3>::type>::type, - typename std::remove_const<typename std::remove_reference<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 << 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, typename T5> struct Arguments5 : Arguments4<T1, T2, T3, T4> { - typedef std::tuple<typename std::remove_const<typename std::remove_reference<T1>::type>::type, - typename std::remove_const<typename std::remove_reference<T2>::type>::type, - typename std::remove_const<typename std::remove_reference<T3>::type>::type, - typename std::remove_const<typename std::remove_reference<T4>::type>::type, - typename std::remove_const<typename std::remove_reference<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 << 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, typename T6> struct Arguments6 : Arguments5<T1, T2, T3, T4, T5> { - typedef std::tuple<typename std::remove_const<typename std::remove_reference<T1>::type>::type, - typename std::remove_const<typename std::remove_reference<T2>::type>::type, - typename std::remove_const<typename std::remove_reference<T3>::type>::type, - typename std::remove_const<typename std::remove_reference<T4>::type>::type, - typename std::remove_const<typename std::remove_reference<T5>::type>::type, - typename std::remove_const<typename std::remove_reference<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 << 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, typename T7> struct Arguments7 : Arguments6<T1, T2, T3, T4, T5, T6> { - typedef std::tuple<typename std::remove_const<typename std::remove_reference<T1>::type>::type, - typename std::remove_const<typename std::remove_reference<T2>::type>::type, - typename std::remove_const<typename std::remove_reference<T3>::type>::type, - typename std::remove_const<typename std::remove_reference<T4>::type>::type, - typename std::remove_const<typename std::remove_reference<T5>::type>::type, - typename std::remove_const<typename std::remove_reference<T6>::type>::type, - typename std::remove_const<typename std::remove_reference<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 << 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, typename T8> struct Arguments8 : Arguments7<T1, T2, T3, T4, T5, T6, T7> { - typedef std::tuple<typename std::remove_const<typename std::remove_reference<T1>::type>::type, - typename std::remove_const<typename std::remove_reference<T2>::type>::type, - typename std::remove_const<typename std::remove_reference<T3>::type>::type, - typename std::remove_const<typename std::remove_reference<T4>::type>::type, - typename std::remove_const<typename std::remove_reference<T5>::type>::type, - typename std::remove_const<typename std::remove_reference<T6>::type>::type, - typename std::remove_const<typename std::remove_reference<T7>::type>::type, - typename std::remove_const<typename std::remove_reference<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 << 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, typename T9, typename T10> struct Arguments10 : Arguments8<T1, T2, T3, T4, T5, T6, T7, T8> { - typedef std::tuple<typename std::remove_const<typename std::remove_reference<T1>::type>::type, - typename std::remove_const<typename std::remove_reference<T2>::type>::type, - typename std::remove_const<typename std::remove_reference<T3>::type>::type, - typename std::remove_const<typename std::remove_reference<T4>::type>::type, - typename std::remove_const<typename std::remove_reference<T5>::type>::type, - typename std::remove_const<typename std::remove_reference<T6>::type>::type, - typename std::remove_const<typename std::remove_reference<T7>::type>::type, - typename std::remove_const<typename std::remove_reference<T8>::type>::type, - typename std::remove_const<typename std::remove_reference<T9>::type>::type, - typename std::remove_const<typename std::remove_reference<T10>::type>::type> ValueType; - - Arguments10() { } - - Arguments10(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10) - : Arguments8<T1, T2, T3, T4, T5, T6, T7, T8>(t1, t2, t3, t4, t5, t6, t7, t8) - , argument9(t9) - , argument10(t10) - { - } - - void encode(ArgumentEncoder& encoder) const - { - Arguments8<T1, T2, T3, T4, T5, T6, T7, T8>::encode(encoder); - encoder << argument9; - encoder << argument10; - } - - static bool decode(ArgumentDecoder& decoder, Arguments10& result) - { - if (!Arguments8<T1, T2, T3, T4, T5, T6, T7, T8>::decode(decoder, result)) - return false; - - decoder.decode(result.argument9); - return decoder.decode(result.argument10); - } - - T9 argument9; - T10 argument10; -}; - -} // namespace IPC - -#endif // Arguments_h diff --git a/Source/WebKit2/Platform/IPC/Attachment.cpp b/Source/WebKit2/Platform/IPC/Attachment.cpp index 9367b1ad2..2c5ce0e7b 100644 --- a/Source/WebKit2/Platform/IPC/Attachment.cpp +++ b/Source/WebKit2/Platform/IPC/Attachment.cpp @@ -26,8 +26,8 @@ #include "config.h" #include "Attachment.h" -#include "ArgumentDecoder.h" -#include "ArgumentEncoder.h" +#include "Decoder.h" +#include "Encoder.h" namespace IPC { @@ -36,7 +36,7 @@ Attachment::Attachment() { } -#if OS(DARWIN) +#if OS(DARWIN) && !USE(UNIX_DOMAIN_SOCKETS) Attachment::Attachment(mach_port_name_t port, mach_msg_type_name_t disposition) : m_type(MachPortType) , m_port(port) @@ -50,12 +50,12 @@ void Attachment::release() } #endif -void Attachment::encode(ArgumentEncoder& encoder) const +void Attachment::encode(Encoder& encoder) const { - encoder.addAttachment(*this); + encoder.addAttachment(WTFMove(*const_cast<Attachment*>(this))); } -bool Attachment::decode(ArgumentDecoder& decoder, Attachment& attachment) +bool Attachment::decode(Decoder& decoder, Attachment& attachment) { if (!decoder.removeAttachment(attachment)) return false; diff --git a/Source/WebKit2/Platform/IPC/Attachment.h b/Source/WebKit2/Platform/IPC/Attachment.h index b0f1dce20..a684c0d91 100644 --- a/Source/WebKit2/Platform/IPC/Attachment.h +++ b/Source/WebKit2/Platform/IPC/Attachment.h @@ -26,15 +26,15 @@ #ifndef Attachment_h #define Attachment_h -#if OS(DARWIN) +#if OS(DARWIN) && !USE(UNIX_DOMAIN_SOCKETS) #include <mach/mach_init.h> #include <mach/mach_traps.h> #endif namespace IPC { -class ArgumentDecoder; -class ArgumentEncoder; +class Decoder; +class Encoder; class Attachment { public: @@ -42,51 +42,51 @@ public: enum Type { Uninitialized, -#if OS(DARWIN) - MachPortType, -#elif USE(UNIX_DOMAIN_SOCKETS) +#if USE(UNIX_DOMAIN_SOCKETS) SocketType, - MappedMemoryType + MappedMemoryType, +#elif OS(DARWIN) + MachPortType #endif }; -#if OS(DARWIN) - Attachment(mach_port_name_t port, mach_msg_type_name_t disposition); -#elif USE(UNIX_DOMAIN_SOCKETS) +#if USE(UNIX_DOMAIN_SOCKETS) + Attachment(Attachment&&); + Attachment& operator=(Attachment&&); Attachment(int fileDescriptor, size_t); Attachment(int fileDescriptor); + ~Attachment(); +#elif OS(DARWIN) + Attachment(mach_port_name_t, mach_msg_type_name_t disposition); #endif Type type() const { return m_type; } -#if OS(DARWIN) - void release(); - - // MachPortType - mach_port_name_t port() const { return m_port; } - mach_msg_type_name_t disposition() const { return m_disposition; } - -#elif USE(UNIX_DOMAIN_SOCKETS) +#if USE(UNIX_DOMAIN_SOCKETS) size_t size() const { return m_size; } int releaseFileDescriptor() { int temp = m_fileDescriptor; m_fileDescriptor = -1; return temp; } int fileDescriptor() const { return m_fileDescriptor; } +#elif OS(DARWIN) + void release(); - void dispose(); + // MachPortType + mach_port_name_t port() const { return m_port; } + mach_msg_type_name_t disposition() const { return m_disposition; } #endif - void encode(ArgumentEncoder&) const; - static bool decode(ArgumentDecoder&, Attachment&); + void encode(Encoder&) const; + static bool decode(Decoder&, Attachment&); private: Type m_type; -#if OS(DARWIN) +#if USE(UNIX_DOMAIN_SOCKETS) + int m_fileDescriptor { -1 }; + size_t m_size; +#elif OS(DARWIN) mach_port_name_t m_port; mach_msg_type_name_t m_disposition; -#elif USE(UNIX_DOMAIN_SOCKETS) - int m_fileDescriptor; - size_t m_size; #endif }; diff --git a/Source/WebKit2/Platform/IPC/Connection.cpp b/Source/WebKit2/Platform/IPC/Connection.cpp index 615e707ba..39a504b9b 100644 --- a/Source/WebKit2/Platform/IPC/Connection.cpp +++ b/Source/WebKit2/Platform/IPC/Connection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,6 +26,8 @@ #include "config.h" #include "Connection.h" +#include "Logging.h" +#include <memory> #include <wtf/CurrentTime.h> #include <wtf/HashSet.h> #include <wtf/NeverDestroyed.h> @@ -33,121 +35,116 @@ #include <wtf/text/WTFString.h> #include <wtf/threads/BinarySemaphore.h> +#if PLATFORM(COCOA) +#include "MachMessage.h" +#endif + +#if USE(UNIX_DOMAIN_SOCKETS) +#include "UnixMessage.h" +#endif + namespace IPC { -class Connection::SyncMessageState : public ThreadSafeRefCounted<Connection::SyncMessageState> { +struct Connection::ReplyHandler { + RefPtr<FunctionDispatcher> dispatcher; + Function<void (std::unique_ptr<Decoder>)> handler; +}; + +struct Connection::WaitForMessageState { + WaitForMessageState(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID, OptionSet<WaitForOption> waitForOptions) + : messageReceiverName(messageReceiverName) + , messageName(messageName) + , destinationID(destinationID) + , waitForOptions(waitForOptions) + { + } + + StringReference messageReceiverName; + StringReference messageName; + uint64_t destinationID; + + OptionSet<WaitForOption> waitForOptions; + bool messageWaitingInterrupted = false; + + std::unique_ptr<Decoder> decoder; +}; + +class Connection::SyncMessageState { public: - static PassRefPtr<SyncMessageState> getOrCreate(RunLoop*); - ~SyncMessageState(); + static SyncMessageState& singleton(); + + SyncMessageState(); + ~SyncMessageState() = delete; void wakeUpClientRunLoop() { m_waitForSyncReplySemaphore.signal(); } - bool wait(double absoluteTime) + bool wait(TimeWithDynamicClockType absoluteTime) { return m_waitForSyncReplySemaphore.wait(absoluteTime); } // Returns true if this message will be handled on a client thread that is currently // waiting for a reply to a synchronous message. - bool processIncomingMessage(Connection*, std::unique_ptr<MessageDecoder>&); + bool processIncomingMessage(Connection&, std::unique_ptr<Decoder>&); // Dispatch pending sync messages. if allowedConnection is not null, will only dispatch messages // from that connection and put the other messages back in the queue. void dispatchMessages(Connection* allowedConnection); private: - explicit SyncMessageState(RunLoop*); - - typedef HashMap<RunLoop*, SyncMessageState*> SyncMessageStateMap; - static SyncMessageStateMap& syncMessageStateMap() - { - static NeverDestroyed<SyncMessageStateMap> syncMessageStateMap; - return syncMessageStateMap; - } + void dispatchMessageAndResetDidScheduleDispatchMessagesForConnection(Connection&); - static Mutex& syncMessageStateMapMutex() - { - static NeverDestroyed<Mutex> syncMessageStateMapMutex; - return syncMessageStateMapMutex; - } - - void dispatchMessageAndResetDidScheduleDispatchMessagesForConnection(Connection*); - - RunLoop* m_runLoop; BinarySemaphore m_waitForSyncReplySemaphore; // Protects m_didScheduleDispatchMessagesWorkSet and m_messagesToDispatchWhileWaitingForSyncReply. - Mutex m_mutex; + Lock m_mutex; // The set of connections for which we've scheduled a call to dispatchMessageAndResetDidScheduleDispatchMessagesForConnection. HashSet<RefPtr<Connection>> m_didScheduleDispatchMessagesWorkSet; struct ConnectionAndIncomingMessage { - RefPtr<Connection> connection; - std::unique_ptr<MessageDecoder> message; + Ref<Connection> connection; + std::unique_ptr<Decoder> message; }; Vector<ConnectionAndIncomingMessage> m_messagesToDispatchWhileWaitingForSyncReply; }; -class Connection::SecondaryThreadPendingSyncReply { -public: - // The reply decoder, will be null if there was an error processing the sync message on the other side. - std::unique_ptr<MessageDecoder> replyDecoder; - - BinarySemaphore semaphore; -}; - - -PassRefPtr<Connection::SyncMessageState> Connection::SyncMessageState::getOrCreate(RunLoop* runLoop) +Connection::SyncMessageState& Connection::SyncMessageState::singleton() { - MutexLocker locker(syncMessageStateMapMutex()); - SyncMessageStateMap::AddResult result = syncMessageStateMap().add(runLoop, nullptr); - - if (!result.isNewEntry) { - ASSERT(result.iterator->value); - return result.iterator->value; - } - - RefPtr<SyncMessageState> syncMessageState = adoptRef(new SyncMessageState(runLoop)); - result.iterator->value = syncMessageState.get(); + static std::once_flag onceFlag; + static LazyNeverDestroyed<SyncMessageState> syncMessageState; - return syncMessageState.release(); -} + std::call_once(onceFlag, [] { + syncMessageState.construct(); + }); -Connection::SyncMessageState::SyncMessageState(RunLoop* runLoop) - : m_runLoop(runLoop) -{ + return syncMessageState; } -Connection::SyncMessageState::~SyncMessageState() +Connection::SyncMessageState::SyncMessageState() { - MutexLocker locker(syncMessageStateMapMutex()); - - ASSERT(syncMessageStateMap().contains(m_runLoop)); - syncMessageStateMap().remove(m_runLoop); - - ASSERT(m_messagesToDispatchWhileWaitingForSyncReply.isEmpty()); } -bool Connection::SyncMessageState::processIncomingMessage(Connection* connection, std::unique_ptr<MessageDecoder>& message) +bool Connection::SyncMessageState::processIncomingMessage(Connection& connection, std::unique_ptr<Decoder>& message) { if (!message->shouldDispatchMessageWhenWaitingForSyncReply()) return false; - ConnectionAndIncomingMessage connectionAndIncomingMessage; - connectionAndIncomingMessage.connection = connection; - connectionAndIncomingMessage.message = std::move(message); + ConnectionAndIncomingMessage connectionAndIncomingMessage { connection, WTFMove(message) }; { - MutexLocker locker(m_mutex); + std::lock_guard<Lock> lock(m_mutex); - if (m_didScheduleDispatchMessagesWorkSet.add(connection).isNewEntry) - m_runLoop->dispatch(bind(&SyncMessageState::dispatchMessageAndResetDidScheduleDispatchMessagesForConnection, this, RefPtr<Connection>(connection))); + if (m_didScheduleDispatchMessagesWorkSet.add(&connection).isNewEntry) { + RunLoop::main().dispatch([this, protectedConnection = Ref<Connection>(connection)]() mutable { + dispatchMessageAndResetDidScheduleDispatchMessagesForConnection(protectedConnection); + }); + } - m_messagesToDispatchWhileWaitingForSyncReply.append(std::move(connectionAndIncomingMessage)); + m_messagesToDispatchWhileWaitingForSyncReply.append(WTFMove(connectionAndIncomingMessage)); } wakeUpClientRunLoop(); @@ -157,12 +154,12 @@ bool Connection::SyncMessageState::processIncomingMessage(Connection* connection void Connection::SyncMessageState::dispatchMessages(Connection* allowedConnection) { - ASSERT(m_runLoop == RunLoop::current()); + ASSERT(RunLoop::isMain()); Vector<ConnectionAndIncomingMessage> messagesToDispatchWhileWaitingForSyncReply; { - MutexLocker locker(m_mutex); + std::lock_guard<Lock> lock(m_mutex); m_messagesToDispatchWhileWaitingForSyncReply.swap(messagesToDispatchWhileWaitingForSyncReply); } @@ -171,46 +168,66 @@ void Connection::SyncMessageState::dispatchMessages(Connection* allowedConnectio for (size_t i = 0; i < messagesToDispatchWhileWaitingForSyncReply.size(); ++i) { ConnectionAndIncomingMessage& connectionAndIncomingMessage = messagesToDispatchWhileWaitingForSyncReply[i]; - if (allowedConnection && allowedConnection != connectionAndIncomingMessage.connection) { + if (allowedConnection && allowedConnection != connectionAndIncomingMessage.connection.ptr()) { // This incoming message belongs to another connection and we don't want to dispatch it now // so mark it to be put back in the message queue. - messagesToPutBack.append(std::move(connectionAndIncomingMessage)); + messagesToPutBack.append(WTFMove(connectionAndIncomingMessage)); continue; } - connectionAndIncomingMessage.connection->dispatchMessage(std::move(connectionAndIncomingMessage.message)); + connectionAndIncomingMessage.connection->dispatchMessage(WTFMove(connectionAndIncomingMessage.message)); } if (!messagesToPutBack.isEmpty()) { - MutexLocker locker(m_mutex); + std::lock_guard<Lock> lock(m_mutex); for (auto& message : messagesToPutBack) - m_messagesToDispatchWhileWaitingForSyncReply.append(std::move(message)); + m_messagesToDispatchWhileWaitingForSyncReply.append(WTFMove(message)); } } -void Connection::SyncMessageState::dispatchMessageAndResetDidScheduleDispatchMessagesForConnection(Connection* connection) +void Connection::SyncMessageState::dispatchMessageAndResetDidScheduleDispatchMessagesForConnection(Connection& connection) { { - MutexLocker locker(m_mutex); - ASSERT(m_didScheduleDispatchMessagesWorkSet.contains(connection)); - m_didScheduleDispatchMessagesWorkSet.remove(connection); + std::lock_guard<Lock> lock(m_mutex); + ASSERT(m_didScheduleDispatchMessagesWorkSet.contains(&connection)); + m_didScheduleDispatchMessagesWorkSet.remove(&connection); } - dispatchMessages(connection); + dispatchMessages(&connection); } -PassRefPtr<Connection> Connection::createServerConnection(Identifier identifier, Client* client, RunLoop* clientRunLoop) +// Represents a sync request for which we're waiting on a reply. +struct Connection::PendingSyncReply { + // The request ID. + uint64_t syncRequestID { 0 }; + + // The reply decoder, will be null if there was an error processing the sync + // message on the other side. + std::unique_ptr<Decoder> replyDecoder; + + // Will be set to true once a reply has been received. + bool didReceiveReply { false }; + + PendingSyncReply() = default; + + explicit PendingSyncReply(uint64_t syncRequestID) + : syncRequestID(syncRequestID) + { + } +}; + +Ref<Connection> Connection::createServerConnection(Identifier identifier, Client& client) { - return adoptRef(new Connection(identifier, true, client, clientRunLoop)); + return adoptRef(*new Connection(identifier, true, client)); } -PassRefPtr<Connection> Connection::createClientConnection(Identifier identifier, Client* client, RunLoop* clientRunLoop) +Ref<Connection> Connection::createClientConnection(Identifier identifier, Client& client) { - return adoptRef(new Connection(identifier, false, client, clientRunLoop)); + return adoptRef(*new Connection(identifier, false, client)); } -Connection::Connection(Identifier identifier, bool isServer, Client* client, RunLoop* clientRunLoop) +Connection::Connection(Identifier identifier, bool isServer, Client& client) : m_client(client) , m_isServer(isServer) , m_syncRequestID(0) @@ -219,17 +236,21 @@ Connection::Connection(Identifier identifier, bool isServer, Client* client, Run , m_didCloseOnConnectionWorkQueueCallback(0) , m_isConnected(false) , m_connectionQueue(WorkQueue::create("com.apple.IPC.ReceiveQueue")) - , m_clientRunLoop(clientRunLoop) , m_inSendSyncCount(0) , m_inDispatchMessageCount(0) , m_inDispatchMessageMarkedDispatchWhenWaitingForSyncReplyCount(0) , m_didReceiveInvalidMessage(false) - , m_syncMessageState(SyncMessageState::getOrCreate(clientRunLoop)) + , m_waitingForMessage(nullptr) , m_shouldWaitForSyncReplies(true) { - ASSERT(m_client); + ASSERT(RunLoop::isMain()); platformInitialize(identifier); + +#if HAVE(QOS_CLASSES) + ASSERT(pthread_main_np()); + m_mainThread = pthread_self(); +#endif } Connection::~Connection() @@ -251,63 +272,52 @@ void Connection::setShouldExitOnSyncMessageSendFailure(bool shouldExitOnSyncMess m_shouldExitOnSyncMessageSendFailure = shouldExitOnSyncMessageSendFailure; } -void Connection::addWorkQueueMessageReceiver(StringReference messageReceiverName, WorkQueue* workQueue, WorkQueueMessageReceiver* workQueueMessageReceiver) +void Connection::addWorkQueueMessageReceiver(StringReference messageReceiverName, WorkQueue& workQueue, WorkQueueMessageReceiver* workQueueMessageReceiver) { - ASSERT(RunLoop::current() == m_clientRunLoop); - ASSERT(!m_isConnected); + ASSERT(RunLoop::isMain()); - m_connectionQueue->dispatch(bind(&Connection::addWorkQueueMessageReceiverOnConnectionWorkQueue, this, messageReceiverName, RefPtr<WorkQueue>(workQueue), RefPtr<WorkQueueMessageReceiver>(workQueueMessageReceiver))); -} + m_connectionQueue->dispatch([protectedThis = makeRef(*this), messageReceiverName = WTFMove(messageReceiverName), workQueue = &workQueue, workQueueMessageReceiver]() mutable { + ASSERT(!protectedThis->m_workQueueMessageReceivers.contains(messageReceiverName)); -void Connection::removeWorkQueueMessageReceiver(StringReference messageReceiverName) -{ - ASSERT(RunLoop::current() == m_clientRunLoop); - - m_connectionQueue->dispatch(bind(&Connection::removeWorkQueueMessageReceiverOnConnectionWorkQueue, this, messageReceiverName)); + protectedThis->m_workQueueMessageReceivers.add(messageReceiverName, std::make_pair(workQueue, workQueueMessageReceiver)); + }); } -void Connection::addWorkQueueMessageReceiverOnConnectionWorkQueue(StringReference messageReceiverName, WorkQueue* workQueue, WorkQueueMessageReceiver* workQueueMessageReceiver) +void Connection::removeWorkQueueMessageReceiver(StringReference messageReceiverName) { - ASSERT(workQueue); - ASSERT(workQueueMessageReceiver); - ASSERT(!m_workQueueMessageReceivers.contains(messageReceiverName)); - - m_workQueueMessageReceivers.add(messageReceiverName, std::make_pair(workQueue, workQueueMessageReceiver)); -} + ASSERT(RunLoop::isMain()); -void Connection::removeWorkQueueMessageReceiverOnConnectionWorkQueue(StringReference messageReceiverName) -{ - ASSERT(m_workQueueMessageReceivers.contains(messageReceiverName)); - m_workQueueMessageReceivers.remove(messageReceiverName); + m_connectionQueue->dispatch([protectedThis = makeRef(*this), messageReceiverName = WTFMove(messageReceiverName)]() mutable { + ASSERT(protectedThis->m_workQueueMessageReceivers.contains(messageReceiverName)); + protectedThis->m_workQueueMessageReceivers.remove(messageReceiverName); + }); } -void Connection::dispatchWorkQueueMessageReceiverMessage(WorkQueueMessageReceiver* workQueueMessageReceiver, MessageDecoder* incomingMessageDecoder) +void Connection::dispatchWorkQueueMessageReceiverMessage(WorkQueueMessageReceiver& workQueueMessageReceiver, Decoder& decoder) { - OwnPtr<MessageDecoder> decoder = adoptPtr(incomingMessageDecoder); - - if (!decoder->isSyncMessage()) { - workQueueMessageReceiver->didReceiveMessage(this, *decoder); + if (!decoder.isSyncMessage()) { + workQueueMessageReceiver.didReceiveMessage(*this, decoder); return; } uint64_t syncRequestID = 0; - if (!decoder->decode(syncRequestID) || !syncRequestID) { + if (!decoder.decode(syncRequestID) || !syncRequestID) { // We received an invalid sync message. // FIXME: Handle this. - decoder->markInvalid(); + decoder.markInvalid(); return; } - auto replyEncoder = std::make_unique<MessageEncoder>("IPC", "SyncMessageReply", syncRequestID); + auto replyEncoder = std::make_unique<Encoder>("IPC", "SyncMessageReply", syncRequestID); // Hand off both the decoder and encoder to the work queue message receiver. - workQueueMessageReceiver->didReceiveSyncMessage(this, *decoder, replyEncoder); + workQueueMessageReceiver.didReceiveSyncMessage(*this, decoder, replyEncoder); // FIXME: If the message was invalid, we should send back a SyncMessageError. - ASSERT(!decoder->isInvalid()); + ASSERT(!decoder.isInvalid()); if (replyEncoder) - sendSyncReply(std::move(replyEncoder)); + sendSyncReply(WTFMove(replyEncoder)); } void Connection::setDidCloseOnConnectionWorkQueueCallback(DidCloseOnConnectionWorkQueueCallback callback) @@ -319,15 +329,29 @@ void Connection::setDidCloseOnConnectionWorkQueueCallback(DidCloseOnConnectionWo void Connection::invalidate() { + ASSERT(RunLoop::isMain()); + if (!isValid()) { // Someone already called invalidate(). return; } - // Reset the client. - m_client = 0; + m_isValid = false; - m_connectionQueue->dispatch(WTF::bind(&Connection::platformInvalidate, this)); + { + std::lock_guard<Lock> lock(m_replyHandlersLock); + for (auto& replyHandler : m_replyHandlers.values()) { + replyHandler.dispatcher->dispatch([handler = WTFMove(replyHandler.handler)] { + handler(nullptr); + }); + } + + m_replyHandlers.clear(); + } + + m_connectionQueue->dispatch([protectedThis = makeRef(*this)]() mutable { + protectedThis->platformInvalidate(); + }); } void Connection::markCurrentlyDispatchedMessageAsInvalid() @@ -338,9 +362,9 @@ void Connection::markCurrentlyDispatchedMessageAsInvalid() m_didReceiveInvalidMessage = true; } -std::unique_ptr<MessageEncoder> Connection::createSyncMessageEncoder(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID, uint64_t& syncRequestID) +std::unique_ptr<Encoder> Connection::createSyncMessageEncoder(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID, uint64_t& syncRequestID) { - auto encoder = std::make_unique<MessageEncoder>(messageReceiverName, messageName, destinationID); + auto encoder = std::make_unique<Encoder>(messageReceiverName, messageName, destinationID); encoder->setIsSyncMessage(true); // Encode the sync request ID. @@ -350,78 +374,126 @@ std::unique_ptr<MessageEncoder> Connection::createSyncMessageEncoder(StringRefer return encoder; } -bool Connection::sendMessage(std::unique_ptr<MessageEncoder> encoder, unsigned messageSendFlags) +bool Connection::sendMessage(std::unique_ptr<Encoder> encoder, OptionSet<SendOption> sendOptions) { if (!isValid()) return false; - if (messageSendFlags & DispatchMessageEvenWhenWaitingForSyncReply + if (RunLoop::isMain() && m_inDispatchMessageMarkedToUseFullySynchronousModeForTesting && !encoder->isSyncMessage() && !(encoder->messageReceiverName() == "IPC")) { + uint64_t syncRequestID; + auto wrappedMessage = createSyncMessageEncoder("IPC", "WrappedAsyncMessageForTesting", encoder->destinationID(), syncRequestID); + wrappedMessage->setFullySynchronousModeForTesting(); + wrappedMessage->wrapForTesting(WTFMove(encoder)); + return static_cast<bool>(sendSyncMessage(syncRequestID, WTFMove(wrappedMessage), Seconds::infinity(), { })); + } + + if (sendOptions.contains(SendOption::DispatchMessageEvenWhenWaitingForSyncReply) && (!m_onlySendMessagesAsDispatchWhenWaitingForSyncReplyWhenProcessingSuchAMessage || m_inDispatchMessageMarkedDispatchWhenWaitingForSyncReplyCount)) encoder->setShouldDispatchMessageWhenWaitingForSyncReply(true); { - MutexLocker locker(m_outgoingMessagesLock); - m_outgoingMessages.append(std::move(encoder)); + std::lock_guard<Lock> lock(m_outgoingMessagesMutex); + m_outgoingMessages.append(WTFMove(encoder)); } // FIXME: We should add a boolean flag so we don't call this when work has already been scheduled. - m_connectionQueue->dispatch(WTF::bind(&Connection::sendOutgoingMessages, this)); + m_connectionQueue->dispatch([protectedThis = makeRef(*this)]() mutable { + protectedThis->sendOutgoingMessages(); + }); return true; } -bool Connection::sendSyncReply(std::unique_ptr<MessageEncoder> encoder) +void Connection::sendMessageWithReply(uint64_t requestID, std::unique_ptr<Encoder> encoder, FunctionDispatcher& replyDispatcher, Function<void (std::unique_ptr<Decoder>)>&& replyHandler) { - return sendMessage(std::move(encoder)); + { + std::lock_guard<Lock> lock(m_replyHandlersLock); + + if (!isValid()) { + replyDispatcher.dispatch([replyHandler = WTFMove(replyHandler)] { + replyHandler(nullptr); + }); + return; + } + + ASSERT(!m_replyHandlers.contains(requestID)); + m_replyHandlers.set(requestID, ReplyHandler { &replyDispatcher, WTFMove(replyHandler) }); + } + + sendMessage(WTFMove(encoder), { }); +} + +bool Connection::sendSyncReply(std::unique_ptr<Encoder> encoder) +{ + return sendMessage(WTFMove(encoder), { }); } -std::unique_ptr<MessageDecoder> Connection::waitForMessage(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID, std::chrono::milliseconds timeout) +Seconds Connection::timeoutRespectingIgnoreTimeoutsForTesting(Seconds timeout) const { + return m_ignoreTimeoutsForTesting ? Seconds::infinity() : timeout; +} + +std::unique_ptr<Decoder> Connection::waitForMessage(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID, Seconds timeout, OptionSet<WaitForOption> waitForOptions) +{ + ASSERT(RunLoop::isMain()); + + timeout = timeoutRespectingIgnoreTimeoutsForTesting(timeout); + + bool hasIncomingSynchronousMessage = false; + // First, check if this message is already in the incoming messages queue. { - MutexLocker locker(m_incomingMessagesLock); + std::lock_guard<Lock> lock(m_incomingMessagesMutex); for (auto it = m_incomingMessages.begin(), end = m_incomingMessages.end(); it != end; ++it) { - std::unique_ptr<MessageDecoder>& message = *it; + std::unique_ptr<Decoder>& message = *it; if (message->messageReceiverName() == messageReceiverName && message->messageName() == messageName && message->destinationID() == destinationID) { - std::unique_ptr<MessageDecoder> returnedMessage = std::move(message); + std::unique_ptr<Decoder> returnedMessage = WTFMove(message); m_incomingMessages.remove(it); return returnedMessage; } + + if (message->isSyncMessage()) + hasIncomingSynchronousMessage = true; } } - std::pair<std::pair<StringReference, StringReference>, uint64_t> messageAndDestination(std::make_pair(std::make_pair(messageReceiverName, messageName), destinationID)); - + // Don't even start waiting if we have InterruptWaitingIfSyncMessageArrives and there's a sync message already in the queue. + if (hasIncomingSynchronousMessage && waitForOptions.contains(WaitForOption::InterruptWaitingIfSyncMessageArrives)) { + m_waitingForMessage = nullptr; + return nullptr; + } + + WaitForMessageState waitingForMessage(messageReceiverName, messageName, destinationID, waitForOptions); + { - std::lock_guard<std::mutex> lock(m_waitForMessageMutex); + std::lock_guard<Lock> lock(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, nullptr); + // We don't support having multiple clients waiting for messages. + ASSERT(!m_waitingForMessage); + + m_waitingForMessage = &waitingForMessage; } - + + MonotonicTime absoluteTimeout = MonotonicTime::now() + timeout; + // Now wait for it to be set. while (true) { - std::unique_lock<std::mutex> lock(m_waitForMessageMutex); - - auto it = m_waitForMessageMap.find(messageAndDestination); - if (it->value) { - std::unique_ptr<MessageDecoder> decoder = std::move(it->value); - m_waitForMessageMap.remove(it); + std::unique_lock<Lock> lock(m_waitForMessageMutex); + if (m_waitingForMessage->decoder) { + auto decoder = WTFMove(m_waitingForMessage->decoder); + m_waitingForMessage = nullptr; return decoder; } // Now we wait. - if (m_waitForMessageCondition.wait_for(lock, timeout) == std::cv_status::timeout) { - // We timed out, now remove the pending wait. - m_waitForMessageMap.remove(messageAndDestination); - + bool didTimeout = !m_waitForMessageCondition.waitUntil(lock, absoluteTimeout); + // We timed out, lost our connection, or a sync message came in with InterruptWaitingIfSyncMessageArrives, so stop waiting. + if (didTimeout || m_waitingForMessage->messageWaitingInterrupted) { + m_waitingForMessage = nullptr; break; } } @@ -429,13 +501,9 @@ std::unique_ptr<MessageDecoder> Connection::waitForMessage(StringReference messa return nullptr; } -std::unique_ptr<MessageDecoder> Connection::sendSyncMessage(uint64_t syncRequestID, std::unique_ptr<MessageEncoder> encoder, std::chrono::milliseconds timeout, unsigned syncSendFlags) +std::unique_ptr<Decoder> Connection::sendSyncMessage(uint64_t syncRequestID, std::unique_ptr<Encoder> encoder, Seconds timeout, OptionSet<SendSyncOption> sendSyncOptions) { - if (RunLoop::current() != m_clientRunLoop) { - // No flags are supported for synchronous messages sent from secondary threads. - ASSERT(!syncSendFlags); - return sendSyncMessageFromSecondaryThread(syncRequestID, std::move(encoder), timeout); - } + ASSERT(RunLoop::isMain()); if (!isValid()) { didFailToSendSyncMessage(); @@ -444,7 +512,7 @@ std::unique_ptr<MessageDecoder> Connection::sendSyncMessage(uint64_t syncRequest // Push the pending sync reply information on our stack. { - MutexLocker locker(m_syncReplyStateMutex); + LockHolder locker(m_syncReplyStateMutex); if (!m_shouldWaitForSyncReplies) { didFailToSendSyncMessage(); return nullptr; @@ -456,18 +524,18 @@ std::unique_ptr<MessageDecoder> Connection::sendSyncMessage(uint64_t syncRequest ++m_inSendSyncCount; // First send the message. - sendMessage(std::move(encoder), DispatchMessageEvenWhenWaitingForSyncReply); + sendMessage(WTFMove(encoder), IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply); // 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. Ref<Connection> protect(*this); - std::unique_ptr<MessageDecoder> reply = waitForSyncReply(syncRequestID, timeout, syncSendFlags); + std::unique_ptr<Decoder> reply = waitForSyncReply(syncRequestID, timeout, sendSyncOptions); --m_inSendSyncCount; // Finally, pop the pending sync reply information. { - MutexLocker locker(m_syncReplyStateMutex); + LockHolder locker(m_syncReplyStateMutex); ASSERT(m_pendingSyncReplies.last().syncRequestID == syncRequestID); m_pendingSyncReplies.removeLast(); } @@ -478,50 +546,20 @@ std::unique_ptr<MessageDecoder> Connection::sendSyncMessage(uint64_t syncRequest return reply; } -std::unique_ptr<MessageDecoder> Connection::sendSyncMessageFromSecondaryThread(uint64_t syncRequestID, std::unique_ptr<MessageEncoder> encoder, std::chrono::milliseconds timeout) -{ - ASSERT(RunLoop::current() != m_clientRunLoop); - - if (!isValid()) - return nullptr; - - SecondaryThreadPendingSyncReply pendingReply; - - // Push the pending sync reply information on our stack. - { - MutexLocker locker(m_syncReplyStateMutex); - if (!m_shouldWaitForSyncReplies) - return nullptr; - - ASSERT(!m_secondaryThreadPendingSyncReplyMap.contains(syncRequestID)); - m_secondaryThreadPendingSyncReplyMap.add(syncRequestID, &pendingReply); - } - - sendMessage(std::move(encoder), 0); - - pendingReply.semaphore.wait(currentTime() + (timeout.count() / 1000.0)); - - // Finally, pop the pending sync reply information. - { - MutexLocker locker(m_syncReplyStateMutex); - ASSERT(m_secondaryThreadPendingSyncReplyMap.contains(syncRequestID)); - m_secondaryThreadPendingSyncReplyMap.remove(syncRequestID); - } - - return std::move(pendingReply.replyDecoder); -} - -std::unique_ptr<MessageDecoder> Connection::waitForSyncReply(uint64_t syncRequestID, std::chrono::milliseconds timeout, unsigned syncSendFlags) +std::unique_ptr<Decoder> Connection::waitForSyncReply(uint64_t syncRequestID, Seconds timeout, OptionSet<SendSyncOption> sendSyncOptions) { - double absoluteTime = currentTime() + (timeout.count() / 1000.0); + timeout = timeoutRespectingIgnoreTimeoutsForTesting(timeout); + WallTime absoluteTime = WallTime::now() + timeout; + willSendSyncMessage(sendSyncOptions); + bool timedOut = false; while (!timedOut) { // First, check if we have any messages that we need to process. - m_syncMessageState->dispatchMessages(0); + SyncMessageState::singleton().dispatchMessages(nullptr); { - MutexLocker locker(m_syncReplyStateMutex); + LockHolder locker(m_syncReplyStateMutex); // Second, check if there is a sync reply at the top of the stack. ASSERT(!m_pendingSyncReplies.isEmpty()); @@ -530,129 +568,192 @@ std::unique_ptr<MessageDecoder> Connection::waitForSyncReply(uint64_t syncReques ASSERT_UNUSED(syncRequestID, pendingSyncReply.syncRequestID == syncRequestID); // We found the sync reply, or the connection was closed. - if (pendingSyncReply.didReceiveReply || !m_shouldWaitForSyncReplies) - return std::move(pendingSyncReply.replyDecoder); + if (pendingSyncReply.didReceiveReply || !m_shouldWaitForSyncReplies) { + didReceiveSyncReply(sendSyncOptions); + return WTFMove(pendingSyncReply.replyDecoder); + } } // Processing a sync message could cause the connection to be invalidated. // (If the handler ends up calling Connection::invalidate). // If that happens, we need to stop waiting, or we'll hang since we won't get // any more incoming messages. - if (!isValid()) + if (!isValid()) { + RELEASE_LOG_ERROR(IPC, "Connection::waitForSyncReply: Connection no longer valid, id = %" PRIu64, syncRequestID); + didReceiveSyncReply(sendSyncOptions); return nullptr; + } // We didn't find a sync reply yet, keep waiting. // This allows the WebProcess to still serve clients while waiting for the message to return. // Notably, it can continue to process accessibility requests, which are on the main thread. - if (syncSendFlags & SpinRunLoopWhileWaitingForReply) { -#if PLATFORM(MAC) - // FIXME: Although we run forever, any events incoming will cause us to drop out and exit out. This however doesn't - // account for a timeout value passed in. Timeout is always NoTimeout in these cases, but that could change. - RunLoop::current()->runForDuration(1e10); - timedOut = currentTime() >= absoluteTime; -#endif - } else - timedOut = !m_syncMessageState->wait(absoluteTime); - + timedOut = !SyncMessageState::singleton().wait(absoluteTime); } + RELEASE_LOG_ERROR(IPC, "Connection::waitForSyncReply: Timed-out while waiting for reply, id = %" PRIu64, syncRequestID); + didReceiveSyncReply(sendSyncOptions); + return nullptr; } -void Connection::processIncomingSyncReply(std::unique_ptr<MessageDecoder> decoder) +void Connection::processIncomingSyncReply(std::unique_ptr<Decoder> decoder) { - MutexLocker locker(m_syncReplyStateMutex); + { + LockHolder locker(m_syncReplyStateMutex); - // Go through the stack of sync requests that have pending replies and see which one - // this reply is for. - for (size_t i = m_pendingSyncReplies.size(); i > 0; --i) { - PendingSyncReply& pendingSyncReply = m_pendingSyncReplies[i - 1]; + // Go through the stack of sync requests that have pending replies and see which one + // this reply is for. + for (size_t i = m_pendingSyncReplies.size(); i > 0; --i) { + PendingSyncReply& pendingSyncReply = m_pendingSyncReplies[i - 1]; - if (pendingSyncReply.syncRequestID != decoder->destinationID()) - continue; + if (pendingSyncReply.syncRequestID != decoder->destinationID()) + continue; - ASSERT(!pendingSyncReply.replyDecoder); + ASSERT(!pendingSyncReply.replyDecoder); - pendingSyncReply.replyDecoder = std::move(decoder); - pendingSyncReply.didReceiveReply = true; + pendingSyncReply.replyDecoder = WTFMove(decoder); + pendingSyncReply.didReceiveReply = true; - // We got a reply to the last send message, wake up the client run loop so it can be processed. - if (i == m_pendingSyncReplies.size()) - m_syncMessageState->wakeUpClientRunLoop(); + // We got a reply to the last send message, wake up the client run loop so it can be processed. + if (i == m_pendingSyncReplies.size()) + SyncMessageState::singleton().wakeUpClientRunLoop(); - return; + return; + } } - // If it's not a reply to any primary thread message, check if it is a reply to a secondary thread one. - SecondaryThreadPendingSyncReplyMap::iterator secondaryThreadReplyMapItem = m_secondaryThreadPendingSyncReplyMap.find(decoder->destinationID()); - if (secondaryThreadReplyMapItem != m_secondaryThreadPendingSyncReplyMap.end()) { - SecondaryThreadPendingSyncReply* reply = secondaryThreadReplyMapItem->value; - ASSERT(!reply->replyDecoder); - reply->replyDecoder = std::move(decoder); - reply->semaphore.signal(); + { + LockHolder locker(m_replyHandlersLock); + + auto replyHandler = m_replyHandlers.take(decoder->destinationID()); + if (replyHandler.dispatcher) { + replyHandler.dispatcher->dispatch([protectedThis = makeRef(*this), handler = WTFMove(replyHandler.handler), decoder = WTFMove(decoder)] () mutable { + if (!protectedThis->isValid()) { + handler(nullptr); + return; + } + + handler(WTFMove(decoder)); + }); + } } // If we get here, it means we got a reply for a message that wasn't in the sync request stack or map. // This can happen if the send timed out, so it's fine to ignore. } -void Connection::processIncomingMessage(std::unique_ptr<MessageDecoder> message) +void Connection::processIncomingMessage(std::unique_ptr<Decoder> message) { ASSERT(!message->messageReceiverName().isEmpty()); ASSERT(!message->messageName().isEmpty()); if (message->messageReceiverName() == "IPC" && message->messageName() == "SyncMessageReply") { - processIncomingSyncReply(std::move(message)); + processIncomingSyncReply(WTFMove(message)); return; } if (!m_workQueueMessageReceivers.isValidKey(message->messageReceiverName())) { - if (message->messageReceiverName().isEmpty() && message->messageName().isEmpty()) { - // Something went wrong when decoding the message. Encode the message length so we can figure out if this - // happens for certain message lengths. - CString messageReceiverName = "<unknown message>"; - CString messageName = String::format("<message length: %zu bytes>", message->length()).utf8(); - - m_clientRunLoop->dispatch(bind(&Connection::dispatchDidReceiveInvalidMessage, this, messageReceiverName, messageName)); - return; - } - - m_clientRunLoop->dispatch(bind(&Connection::dispatchDidReceiveInvalidMessage, this, message->messageReceiverName().toString(), message->messageName().toString())); + RefPtr<Connection> protectedThis(this); + StringReference messageReceiverNameReference = message->messageReceiverName(); + String messageReceiverName(messageReceiverNameReference.isEmpty() ? "<unknown message receiver>" : String(messageReceiverNameReference.data(), messageReceiverNameReference.size())); + StringReference messageNameReference = message->messageName(); + String messageName(messageNameReference.isEmpty() ? "<unknown message>" : String(messageNameReference.data(), messageNameReference.size())); + + RunLoop::main().dispatch([protectedThis = makeRef(*this), messageReceiverName = WTFMove(messageReceiverName), messageName = WTFMove(messageName)]() mutable { + protectedThis->dispatchDidReceiveInvalidMessage(messageReceiverName.utf8(), messageName.utf8()); + }); return; } auto it = m_workQueueMessageReceivers.find(message->messageReceiverName()); if (it != m_workQueueMessageReceivers.end()) { - it->value.first->dispatch(bind(&Connection::dispatchWorkQueueMessageReceiverMessage, this, it->value.second, message.release())); + it->value.first->dispatch([protectedThis = makeRef(*this), workQueueMessageReceiver = it->value.second, decoder = WTFMove(message)]() mutable { + protectedThis->dispatchWorkQueueMessageReceiverMessage(*workQueueMessageReceiver, *decoder); + }); return; } +#if HAVE(QOS_CLASSES) + if (message->isSyncMessage() && m_shouldBoostMainThreadOnSyncMessage) { + pthread_override_t override = pthread_override_qos_class_start_np(m_mainThread, adjustedQOSClass(QOS_CLASS_USER_INTERACTIVE), 0); + message->setQOSClassOverride(override); + } +#endif + + if (message->isSyncMessage()) { + std::lock_guard<Lock> lock(m_incomingSyncMessageCallbackMutex); + + for (auto& callback : m_incomingSyncMessageCallbacks.values()) + m_incomingSyncMessageCallbackQueue->dispatch(WTFMove(callback)); + + m_incomingSyncMessageCallbacks.clear(); + } + // Check if this is a sync message or if it's a message that should be dispatched even when waiting for // a sync reply. 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 (m_syncMessageState->processIncomingMessage(this, message)) + if (SyncMessageState::singleton().processIncomingMessage(*this, message)) return; // Check if we're waiting for this message. { - std::lock_guard<std::mutex> lock(m_waitForMessageMutex); + std::lock_guard<Lock> lock(m_waitForMessageMutex); + + if (m_waitingForMessage && !m_waitingForMessage->decoder) { + if (m_waitingForMessage->messageReceiverName == message->messageReceiverName() && m_waitingForMessage->messageName == message->messageName() && m_waitingForMessage->destinationID == message->destinationID()) { + m_waitingForMessage->decoder = WTFMove(message); + ASSERT(m_waitingForMessage->decoder); + m_waitForMessageCondition.notifyOne(); + return; + } - auto it = m_waitForMessageMap.find(std::make_pair(std::make_pair(message->messageReceiverName(), message->messageName()), message->destinationID())); - if (it != m_waitForMessageMap.end()) { - it->value = std::move(message); - ASSERT(it->value); - - m_waitForMessageCondition.notify_one(); - return; + if (m_waitingForMessage->waitForOptions.contains(WaitForOption::InterruptWaitingIfSyncMessageArrives) && message->isSyncMessage()) { + m_waitingForMessage->messageWaitingInterrupted = true; + m_waitForMessageCondition.notifyOne(); + } } } - enqueueIncomingMessage(std::move(message)); + enqueueIncomingMessage(WTFMove(message)); +} + +uint64_t Connection::installIncomingSyncMessageCallback(std::function<void ()> callback) +{ + std::lock_guard<Lock> lock(m_incomingSyncMessageCallbackMutex); + + m_nextIncomingSyncMessageCallbackID++; + + if (!m_incomingSyncMessageCallbackQueue) + m_incomingSyncMessageCallbackQueue = WorkQueue::create("com.apple.WebKit.IPC.IncomingSyncMessageCallbackQueue"); + + m_incomingSyncMessageCallbacks.add(m_nextIncomingSyncMessageCallbackID, callback); + + return m_nextIncomingSyncMessageCallbackID; +} + +void Connection::uninstallIncomingSyncMessageCallback(uint64_t callbackID) +{ + std::lock_guard<Lock> lock(m_incomingSyncMessageCallbackMutex); + m_incomingSyncMessageCallbacks.remove(callbackID); +} + +bool Connection::hasIncomingSyncMessage() +{ + std::lock_guard<Lock> lock(m_incomingMessagesMutex); + + for (auto& message : m_incomingMessages) { + if (message->isSyncMessage()) + return true; + } + + return false; } void Connection::postConnectionDidCloseOnConnectionWorkQueue() { - m_connectionQueue->dispatch(WTF::bind(&Connection::connectionDidClose, this)); + m_connectionQueue->dispatch([protectedThis = makeRef(*this)]() mutable { + protectedThis->connectionDidClose(); + }); } void Connection::connectionDidClose() @@ -661,38 +762,48 @@ void Connection::connectionDidClose() platformInvalidate(); { - MutexLocker locker(m_syncReplyStateMutex); + LockHolder locker(m_replyHandlersLock); + for (auto& replyHandler : m_replyHandlers.values()) { + replyHandler.dispatcher->dispatch([handler = WTFMove(replyHandler.handler)] { + handler(nullptr); + }); + } + + m_replyHandlers.clear(); + } + + { + LockHolder locker(m_syncReplyStateMutex); ASSERT(m_shouldWaitForSyncReplies); m_shouldWaitForSyncReplies = false; if (!m_pendingSyncReplies.isEmpty()) - m_syncMessageState->wakeUpClientRunLoop(); + SyncMessageState::singleton().wakeUpClientRunLoop(); + } - for (SecondaryThreadPendingSyncReplyMap::iterator iter = m_secondaryThreadPendingSyncReplyMap.begin(); iter != m_secondaryThreadPendingSyncReplyMap.end(); ++iter) - iter->value->semaphore.signal(); + { + std::lock_guard<Lock> lock(m_waitForMessageMutex); + if (m_waitingForMessage) + m_waitingForMessage->messageWaitingInterrupted = true; } + m_waitForMessageCondition.notifyAll(); if (m_didCloseOnConnectionWorkQueueCallback) m_didCloseOnConnectionWorkQueueCallback(this); - m_clientRunLoop->dispatch(WTF::bind(&Connection::dispatchConnectionDidClose, this)); -} + RunLoop::main().dispatch([protectedThis = makeRef(*this)]() mutable { + // If the connection has been explicitly invalidated before dispatchConnectionDidClose was called, + // then the the connection will be invalid here. + if (!protectedThis->isValid()) + return; -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; + // Set m_isValid to false before calling didClose, otherwise, sendSync will try to send a message + // to the connection and will then wait indefinitely for a reply. + protectedThis->m_isValid = false; - // 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); + protectedThis->m_client.didClose(protectedThis.get()); + }); } bool Connection::canSendOutgoingMessages() const @@ -706,21 +817,21 @@ void Connection::sendOutgoingMessages() return; while (true) { - std::unique_ptr<MessageEncoder> message; + std::unique_ptr<Encoder> message; { - MutexLocker locker(m_outgoingMessagesLock); + std::lock_guard<Lock> lock(m_outgoingMessagesMutex); if (m_outgoingMessages.isEmpty()) break; message = m_outgoingMessages.takeFirst(); } - if (!sendOutgoingMessage(std::move(message))) + if (!sendOutgoingMessage(WTFMove(message))) break; } } -void Connection::dispatchSyncMessage(MessageDecoder& decoder) +void Connection::dispatchSyncMessage(Decoder& decoder) { ASSERT(decoder.isSyncMessage()); @@ -731,26 +842,38 @@ void Connection::dispatchSyncMessage(MessageDecoder& decoder) return; } - auto replyEncoder = std::make_unique<MessageEncoder>("IPC", "SyncMessageReply", syncRequestID); + auto replyEncoder = std::make_unique<Encoder>("IPC", "SyncMessageReply", syncRequestID); - // Hand off both the decoder and encoder to the client. - m_client->didReceiveSyncMessage(this, decoder, replyEncoder); + if (decoder.messageReceiverName() == "IPC" && decoder.messageName() == "WrappedAsyncMessageForTesting") { + if (!m_fullySynchronousModeIsAllowedForTesting) { + decoder.markInvalid(); + return; + } + std::unique_ptr<Decoder> unwrappedDecoder = Decoder::unwrapForTesting(decoder); + RELEASE_ASSERT(unwrappedDecoder); + processIncomingMessage(WTFMove(unwrappedDecoder)); + + SyncMessageState::singleton().dispatchMessages(nullptr); + } else { + // Hand off both the decoder and encoder to the client. + m_client.didReceiveSyncMessage(*this, decoder, replyEncoder); + } // FIXME: If the message was invalid, we should send back a SyncMessageError. ASSERT(!decoder.isInvalid()); if (replyEncoder) - sendSyncReply(std::move(replyEncoder)); + sendSyncReply(WTFMove(replyEncoder)); } void Connection::dispatchDidReceiveInvalidMessage(const CString& messageReceiverNameString, const CString& messageNameString) { - ASSERT(RunLoop::current() == m_clientRunLoop); + ASSERT(RunLoop::isMain()); - if (!m_client) + if (!isValid()) return; - m_client->didReceiveInvalidMessage(this, StringReference(messageReceiverNameString.data(), messageReceiverNameString.length()), StringReference(messageNameString.data(), messageNameString.length())); + m_client.didReceiveInvalidMessage(*this, StringReference(messageReceiverNameString.data(), messageReceiverNameString.length()), StringReference(messageNameString.data(), messageNameString.length())); } void Connection::didFailToSendSyncMessage() @@ -761,28 +884,36 @@ void Connection::didFailToSendSyncMessage() exit(0); } -void Connection::enqueueIncomingMessage(std::unique_ptr<MessageDecoder> incomingMessage) +void Connection::enqueueIncomingMessage(std::unique_ptr<Decoder> incomingMessage) { { - MutexLocker locker(m_incomingMessagesLock); - m_incomingMessages.append(std::move(incomingMessage)); + std::lock_guard<Lock> lock(m_incomingMessagesMutex); + m_incomingMessages.append(WTFMove(incomingMessage)); } - m_clientRunLoop->dispatch(WTF::bind(&Connection::dispatchOneMessage, this)); + RunLoop::main().dispatch([protectedThis = makeRef(*this)]() mutable { + protectedThis->dispatchOneMessage(); + }); } -void Connection::dispatchMessage(MessageDecoder& decoder) +void Connection::dispatchMessage(Decoder& decoder) { - m_client->didReceiveMessage(this, decoder); + m_client.didReceiveMessage(*this, decoder); } -void Connection::dispatchMessage(std::unique_ptr<MessageDecoder> message) +void Connection::dispatchMessage(std::unique_ptr<Decoder> message) { - // If there's no client, return. We do this after calling releaseArguments so that - // the ArgumentDecoder message will be freed. - if (!m_client) + if (!isValid()) return; + if (message->shouldUseFullySynchronousModeForTesting()) { + if (!m_fullySynchronousModeIsAllowedForTesting) { + m_client.didReceiveInvalidMessage(*this, message->messageReceiverName(), message->messageName()); + return; + } + m_inDispatchMessageMarkedToUseFullySynchronousModeForTesting++; + } + m_inDispatchMessageCount++; if (message->shouldDispatchMessageWhenWaitingForSyncReply()) @@ -799,33 +930,38 @@ void Connection::dispatchMessage(std::unique_ptr<MessageDecoder> message) m_didReceiveInvalidMessage |= message->isInvalid(); m_inDispatchMessageCount--; + // FIXME: For Delayed synchronous messages, we should not decrement the counter until we send a response. + // Otherwise, we would deadlock if processing the message results in a sync message back after we exit this function. if (message->shouldDispatchMessageWhenWaitingForSyncReply()) m_inDispatchMessageMarkedDispatchWhenWaitingForSyncReplyCount--; - if (m_didReceiveInvalidMessage && m_client) - m_client->didReceiveInvalidMessage(this, message->messageReceiverName(), message->messageName()); + if (message->shouldUseFullySynchronousModeForTesting()) + m_inDispatchMessageMarkedToUseFullySynchronousModeForTesting--; + + if (m_didReceiveInvalidMessage && isValid()) + m_client.didReceiveInvalidMessage(*this, message->messageReceiverName(), message->messageName()); m_didReceiveInvalidMessage = oldDidReceiveInvalidMessage; } void Connection::dispatchOneMessage() { - std::unique_ptr<MessageDecoder> message; + std::unique_ptr<Decoder> message; { - MutexLocker locker(m_incomingMessagesLock); + std::lock_guard<Lock> lock(m_incomingMessagesMutex); if (m_incomingMessages.isEmpty()) return; message = m_incomingMessages.takeFirst(); } - dispatchMessage(std::move(message)); + dispatchMessage(WTFMove(message)); } void Connection::wakeUpRunLoop() { - m_clientRunLoop->wakeUp(); + RunLoop::main().wakeUp(); } } // namespace IPC diff --git a/Source/WebKit2/Platform/IPC/Connection.h b/Source/WebKit2/Platform/IPC/Connection.h index 92df2689c..a5a8ad7b4 100644 --- a/Source/WebKit2/Platform/IPC/Connection.h +++ b/Source/WebKit2/Platform/IPC/Connection.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010-2016 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. * @@ -25,48 +25,51 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef Connection_h -#define Connection_h +#pragma once -#include "Arguments.h" -#include "MessageDecoder.h" -#include "MessageEncoder.h" +#include "Decoder.h" +#include "Encoder.h" +#include "HandleMessage.h" #include "MessageReceiver.h" -#include "WorkQueue.h" #include <atomic> -#include <condition_variable> +#include <wtf/Condition.h> #include <wtf/Deque.h> #include <wtf/Forward.h> -#include <wtf/PassRefPtr.h> -#include <wtf/OwnPtr.h> +#include <wtf/HashMap.h> +#include <wtf/Lock.h> +#include <wtf/OptionSet.h> +#include <wtf/WorkQueue.h> #include <wtf/text/CString.h> -#if OS(DARWIN) +#if OS(DARWIN) && !USE(UNIX_DOMAIN_SOCKETS) #include <mach/mach_port.h> -#include <xpc/xpc.h> +#include <wtf/OSObjectPtr.h> +#include <wtf/spi/darwin/XPCSPI.h> #endif -#if PLATFORM(GTK) || PLATFORM(EFL) -#include "PlatformProcessIdentifier.h" +#if PLATFORM(GTK) +#include "GSocketMonitor.h" #endif -namespace WTF { -class RunLoop; -} - namespace IPC { -enum MessageSendFlags { +enum class SendOption { // Whether this message should be dispatched when waiting for a sync reply. // This is the default for synchronous messages. DispatchMessageEvenWhenWaitingForSyncReply = 1 << 0, }; -enum SyncMessageSendFlags { - // Will allow events to continue being handled while waiting for the sync reply. - SpinRunLoopWhileWaitingForReply = 1 << 0, +enum class SendSyncOption { + // Use this to inform that this sync call will suspend this process until the user responds with input. + InformPlatformProcessWillSuspend = 1 << 0, + UseFullySynchronousModeForTesting = 1 << 1, }; - + +enum class WaitForOption { + // Use this to make waitForMessage be interrupted immediately by any incoming sync messages. + InterruptWaitingIfSyncMessageArrives = 1 << 0, +}; + #define MESSAGE_CHECK_BASE(assertion, connection) do \ if (!(assertion)) { \ ASSERT(assertion); \ @@ -75,12 +78,15 @@ enum SyncMessageSendFlags { } \ while (0) +class MachMessage; +class UnixMessage; + class Connection : public ThreadSafeRefCounted<Connection> { public: class Client : public MessageReceiver { public: - virtual void didClose(Connection*) = 0; - virtual void didReceiveInvalidMessage(Connection*, StringReference messageReceiverName, StringReference messageName) = 0; + virtual void didClose(Connection&) = 0; + virtual void didReceiveInvalidMessage(Connection&, StringReference messageReceiverName, StringReference messageName) = 0; protected: virtual ~Client() { } @@ -89,54 +95,55 @@ public: class WorkQueueMessageReceiver : public MessageReceiver, public ThreadSafeRefCounted<WorkQueueMessageReceiver> { }; -#if OS(DARWIN) +#if USE(UNIX_DOMAIN_SOCKETS) + typedef int Identifier; + static bool identifierIsNull(Identifier identifier) { return identifier == -1; } + + struct SocketPair { + int client; + int server; + }; + + enum ConnectionOptions { + SetCloexecOnClient = 1 << 0, + SetCloexecOnServer = 1 << 1, + }; + + static Connection::SocketPair createPlatformConnection(unsigned options = SetCloexecOnClient | SetCloexecOnServer); +#elif OS(DARWIN) struct Identifier { Identifier() : port(MACH_PORT_NULL) - , xpcConnection(0) { } Identifier(mach_port_t port) : port(port) - , xpcConnection(0) { } - Identifier(mach_port_t port, xpc_connection_t xpcConnection) + Identifier(mach_port_t port, OSObjectPtr<xpc_connection_t> xpcConnection) : port(port) - , xpcConnection(xpcConnection) + , xpcConnection(WTFMove(xpcConnection)) { } mach_port_t port; - xpc_connection_t xpcConnection; + OSObjectPtr<xpc_connection_t> xpcConnection; }; static bool identifierIsNull(Identifier identifier) { return identifier.port == MACH_PORT_NULL; } -#elif USE(UNIX_DOMAIN_SOCKETS) - typedef int Identifier; - static bool identifierIsNull(Identifier identifier) { return !identifier; } - - struct SocketPair { - int client; - int server; - }; - - enum ConnectionOptions { - SetCloexecOnClient = 1 << 0, - SetCloexecOnServer = 1 << 1, - }; - - static Connection::SocketPair createPlatformConnection(unsigned options = SetCloexecOnClient | SetCloexecOnServer); + xpc_connection_t xpcConnection() const { return m_xpcConnection.get(); } + bool getAuditToken(audit_token_t&); + pid_t remoteProcessID() const; #endif - static PassRefPtr<Connection> createServerConnection(Identifier, Client*, WTF::RunLoop* clientRunLoop); - static PassRefPtr<Connection> createClientConnection(Identifier, Client*, WTF::RunLoop* clientRunLoop); + static Ref<Connection> createServerConnection(Identifier, Client&); + static Ref<Connection> createClientConnection(Identifier, Client&); ~Connection(); - Client* client() const { return m_client; } + Client& client() const { return m_client; } -#if OS(DARWIN) +#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED <= 101000 void setShouldCloseConnectionOnMachExceptions(); #endif @@ -151,7 +158,7 @@ public: typedef void (*DidCloseOnConnectionWorkQueueCallback)(Connection*); void setDidCloseOnConnectionWorkQueueCallback(DidCloseOnConnectionWorkQueueCallback callback); - void addWorkQueueMessageReceiver(StringReference messageReceiverName, WorkQueue*, WorkQueueMessageReceiver*); + void addWorkQueueMessageReceiver(StringReference messageReceiverName, WorkQueue&, WorkQueueMessageReceiver*); void removeWorkQueueMessageReceiver(StringReference messageReceiverName); bool open(); @@ -160,15 +167,16 @@ public: void postConnectionDidCloseOnConnectionWorkQueue(); - template<typename T> bool send(T&& message, uint64_t destinationID, unsigned messageSendFlags = 0); - template<typename T> bool sendSync(T&& message, typename T::Reply&& reply, uint64_t destinationID, std::chrono::milliseconds timeout = std::chrono::milliseconds::max(), unsigned syncSendFlags = 0); - template<typename T> bool waitForAndDispatchImmediately(uint64_t destinationID, std::chrono::milliseconds timeout); + template<typename T> bool send(T&& message, uint64_t destinationID, OptionSet<SendOption> sendOptions = { }); + template<typename T> void sendWithReply(T&& message, uint64_t destinationID, FunctionDispatcher& replyDispatcher, Function<void (std::optional<typename CodingType<typename T::Reply>::Type>)>&& replyHandler); + template<typename T> bool sendSync(T&& message, typename T::Reply&& reply, uint64_t destinationID, Seconds timeout = Seconds::infinity(), OptionSet<SendSyncOption> sendSyncOptions = { }); + template<typename T> bool waitForAndDispatchImmediately(uint64_t destinationID, Seconds timeout, OptionSet<WaitForOption> waitForOptions = { }); - std::unique_ptr<MessageEncoder> createSyncMessageEncoder(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID, uint64_t& syncRequestID); - bool sendMessage(std::unique_ptr<MessageEncoder>, unsigned messageSendFlags = 0); - std::unique_ptr<MessageDecoder> sendSyncMessage(uint64_t syncRequestID, std::unique_ptr<MessageEncoder>, std::chrono::milliseconds timeout, unsigned syncSendFlags = 0); - std::unique_ptr<MessageDecoder> sendSyncMessageFromSecondaryThread(uint64_t syncRequestID, std::unique_ptr<MessageEncoder>, std::chrono::milliseconds timeout); - bool sendSyncReply(std::unique_ptr<MessageEncoder>); + bool sendMessage(std::unique_ptr<Encoder>, OptionSet<SendOption> sendOptions); + void sendMessageWithReply(uint64_t requestID, std::unique_ptr<Encoder>, FunctionDispatcher& replyDispatcher, Function<void (std::unique_ptr<Decoder>)>&& replyHandler); + std::unique_ptr<Encoder> createSyncMessageEncoder(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID, uint64_t& syncRequestID); + std::unique_ptr<Decoder> sendSyncMessage(uint64_t syncRequestID, std::unique_ptr<Encoder>, Seconds timeout, OptionSet<SendSyncOption> sendSyncOptions); + bool sendSyncReply(std::unique_ptr<Encoder>); void wakeUpRunLoop(); @@ -177,45 +185,71 @@ public: bool inSendSync() const { return m_inSendSyncCount; } + Identifier identifier() const; + +#if PLATFORM(COCOA) + bool kill(); + void terminateSoon(double intervalInSeconds); +#endif + + bool isValid() const { return m_isValid; } + +#if HAVE(QOS_CLASSES) + void setShouldBoostMainThreadOnSyncMessage(bool b) { m_shouldBoostMainThreadOnSyncMessage = b; } +#endif + + uint64_t installIncomingSyncMessageCallback(std::function<void ()>); + void uninstallIncomingSyncMessageCallback(uint64_t); + bool hasIncomingSyncMessage(); + + void allowFullySynchronousModeForTesting() { m_fullySynchronousModeIsAllowedForTesting = true; } + + void ignoreTimeoutsForTesting() { m_ignoreTimeoutsForTesting = true; } + private: - Connection(Identifier, bool isServer, Client*, WTF::RunLoop* clientRunLoop); + Connection(Identifier, bool isServer, Client&); void platformInitialize(Identifier); void platformInvalidate(); - bool isValid() const { return m_client; } + std::unique_ptr<Decoder> waitForMessage(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID, Seconds timeout, OptionSet<WaitForOption>); - std::unique_ptr<MessageDecoder> waitForMessage(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID, std::chrono::milliseconds timeout); - - std::unique_ptr<MessageDecoder> waitForSyncReply(uint64_t syncRequestID, std::chrono::milliseconds timeout, unsigned syncSendFlags); + std::unique_ptr<Decoder> waitForSyncReply(uint64_t syncRequestID, Seconds timeout, OptionSet<SendSyncOption>); // Called on the connection work queue. - void processIncomingMessage(std::unique_ptr<MessageDecoder>); - void processIncomingSyncReply(std::unique_ptr<MessageDecoder>); + void processIncomingMessage(std::unique_ptr<Decoder>); + void processIncomingSyncReply(std::unique_ptr<Decoder>); - void addWorkQueueMessageReceiverOnConnectionWorkQueue(StringReference messageReceiverName, WorkQueue*, WorkQueueMessageReceiver*); - void removeWorkQueueMessageReceiverOnConnectionWorkQueue(StringReference messageReceiverName); - void dispatchWorkQueueMessageReceiverMessage(WorkQueueMessageReceiver*, MessageDecoder*); + void dispatchWorkQueueMessageReceiverMessage(WorkQueueMessageReceiver&, Decoder&); bool canSendOutgoingMessages() const; bool platformCanSendOutgoingMessages() const; void sendOutgoingMessages(); - bool sendOutgoingMessage(std::unique_ptr<MessageEncoder>); + bool sendOutgoingMessage(std::unique_ptr<Encoder>); void connectionDidClose(); // Called on the listener thread. - void dispatchConnectionDidClose(); void dispatchOneMessage(); - void dispatchMessage(std::unique_ptr<MessageDecoder>); - void dispatchMessage(MessageDecoder&); - void dispatchSyncMessage(MessageDecoder&); + void dispatchMessage(std::unique_ptr<Decoder>); + void dispatchMessage(Decoder&); + void dispatchSyncMessage(Decoder&); void dispatchDidReceiveInvalidMessage(const CString& messageReceiverNameString, const CString& messageNameString); void didFailToSendSyncMessage(); // Can be called on any thread. - void enqueueIncomingMessage(std::unique_ptr<MessageDecoder>); + void enqueueIncomingMessage(std::unique_ptr<Decoder>); + + void willSendSyncMessage(OptionSet<SendSyncOption>); + void didReceiveSyncReply(OptionSet<SendSyncOption>); - Client* m_client; + Seconds timeoutRespectingIgnoreTimeoutsForTesting(Seconds) const; + +#if PLATFORM(COCOA) + bool sendMessage(std::unique_ptr<MachMessage>); +#endif + + Client& m_client; bool m_isServer; + std::atomic<bool> m_isValid { true }; std::atomic<uint64_t> m_syncRequestID; bool m_onlySendMessagesAsDispatchWhenWaitingForSyncReplyWhenProcessingSuchAMessage; @@ -223,119 +257,143 @@ private: DidCloseOnConnectionWorkQueueCallback m_didCloseOnConnectionWorkQueueCallback; bool m_isConnected; - RefPtr<WorkQueue> m_connectionQueue; - WTF::RunLoop* m_clientRunLoop; + Ref<WorkQueue> m_connectionQueue; HashMap<StringReference, std::pair<RefPtr<WorkQueue>, RefPtr<WorkQueueMessageReceiver>>> m_workQueueMessageReceivers; unsigned m_inSendSyncCount; unsigned m_inDispatchMessageCount; unsigned m_inDispatchMessageMarkedDispatchWhenWaitingForSyncReplyCount; + unsigned m_inDispatchMessageMarkedToUseFullySynchronousModeForTesting { 0 }; + bool m_fullySynchronousModeIsAllowedForTesting { false }; + bool m_ignoreTimeoutsForTesting { false }; bool m_didReceiveInvalidMessage; // Incoming messages. - Mutex m_incomingMessagesLock; - Deque<std::unique_ptr<MessageDecoder>> m_incomingMessages; + Lock m_incomingMessagesMutex; + Deque<std::unique_ptr<Decoder>> m_incomingMessages; // Outgoing messages. - Mutex m_outgoingMessagesLock; - Deque<std::unique_ptr<MessageEncoder>> m_outgoingMessages; + Lock m_outgoingMessagesMutex; + Deque<std::unique_ptr<Encoder>> m_outgoingMessages; - std::condition_variable m_waitForMessageCondition; - std::mutex m_waitForMessageMutex; - HashMap<std::pair<std::pair<StringReference, StringReference>, uint64_t>, std::unique_ptr<MessageDecoder>> m_waitForMessageMap; + Condition m_waitForMessageCondition; + Lock m_waitForMessageMutex; - // Represents a sync request for which we're waiting on a reply. - struct PendingSyncReply { - // The request ID. - uint64_t syncRequestID; + struct ReplyHandler; - // The reply decoder, will be null if there was an error processing the sync - // message on the other side. - std::unique_ptr<MessageDecoder> replyDecoder; + Lock m_replyHandlersLock; + HashMap<uint64_t, ReplyHandler> m_replyHandlers; - // Will be set to true once a reply has been received. - bool didReceiveReply; - - PendingSyncReply() - : syncRequestID(0) - , didReceiveReply(false) - { - } - - explicit PendingSyncReply(uint64_t syncRequestID) - : syncRequestID(syncRequestID) - , didReceiveReply(0) - { - } - }; + struct WaitForMessageState; + WaitForMessageState* m_waitingForMessage; class SyncMessageState; - friend class SyncMessageState; - RefPtr<SyncMessageState> m_syncMessageState; - Mutex m_syncReplyStateMutex; + Lock m_syncReplyStateMutex; bool m_shouldWaitForSyncReplies; + struct PendingSyncReply; Vector<PendingSyncReply> m_pendingSyncReplies; - class SecondaryThreadPendingSyncReply; - typedef HashMap<uint64_t, SecondaryThreadPendingSyncReply*> SecondaryThreadPendingSyncReplyMap; - SecondaryThreadPendingSyncReplyMap m_secondaryThreadPendingSyncReplyMap; + Lock m_incomingSyncMessageCallbackMutex; + HashMap<uint64_t, std::function<void ()>> m_incomingSyncMessageCallbacks; + RefPtr<WorkQueue> m_incomingSyncMessageCallbackQueue; + uint64_t m_nextIncomingSyncMessageCallbackID { 0 }; + +#if HAVE(QOS_CLASSES) + pthread_t m_mainThread { 0 }; + bool m_shouldBoostMainThreadOnSyncMessage { false }; +#endif -#if OS(DARWIN) +#if USE(UNIX_DOMAIN_SOCKETS) + // Called on the connection queue. + void readyReadHandler(); + bool processMessage(); + bool sendOutputMessage(UnixMessage&); + + Vector<uint8_t> m_readBuffer; + Vector<int> m_fileDescriptors; + int m_socketDescriptor; + std::unique_ptr<UnixMessage> m_pendingOutputMessage; +#if PLATFORM(GTK) + GRefPtr<GSocket> m_socket; + GSocketMonitor m_readSocketMonitor; + GSocketMonitor m_writeSocketMonitor; +#endif +#elif OS(DARWIN) // Called on the connection queue. void receiveSourceEventHandler(); - void initializeDeadNameSource(); - void exceptionSourceEventHandler(); + void initializeSendSource(); mach_port_t m_sendPort; - dispatch_source_t m_deadNameSource; + dispatch_source_t m_sendSource; mach_port_t m_receivePort; - dispatch_source_t m_receivePortDataAvailableSource; + dispatch_source_t m_receiveSource; + + std::unique_ptr<MachMessage> m_pendingOutgoingMachMessage; +#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED <= 101000 + void exceptionSourceEventHandler(); // 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; dispatch_source_t m_exceptionPortDataAvailableSource; +#endif - xpc_connection_t m_xpcConnection; - -#elif USE(UNIX_DOMAIN_SOCKETS) - // Called on the connection queue. - void readyReadHandler(); - bool processMessage(); - - Vector<uint8_t> m_readBuffer; - size_t m_readBufferSize; - Vector<int> m_fileDescriptors; - size_t m_fileDescriptorsSize; - int m_socketDescriptor; + OSObjectPtr<xpc_connection_t> m_xpcConnection; #endif }; -template<typename T> bool Connection::send(T&& message, uint64_t destinationID, unsigned messageSendFlags) +template<typename T> +bool Connection::send(T&& message, uint64_t destinationID, OptionSet<SendOption> sendOptions) { COMPILE_ASSERT(!T::isSync, AsyncMessageExpected); - auto encoder = std::make_unique<MessageEncoder>(T::receiverName(), T::name(), destinationID); + auto encoder = std::make_unique<Encoder>(T::receiverName(), T::name(), destinationID); encoder->encode(message.arguments()); - return sendMessage(std::move(encoder), messageSendFlags); + return sendMessage(WTFMove(encoder), sendOptions); +} + +template<typename T> +void Connection::sendWithReply(T&& message, uint64_t destinationID, FunctionDispatcher& replyDispatcher, Function<void (std::optional<typename CodingType<typename T::Reply>::Type>)>&& replyHandler) +{ + uint64_t requestID = 0; + std::unique_ptr<Encoder> encoder = createSyncMessageEncoder(T::receiverName(), T::name(), destinationID, requestID); + + encoder->encode(message.arguments()); + + sendMessageWithReply(requestID, WTFMove(encoder), replyDispatcher, [replyHandler = WTFMove(replyHandler)](std::unique_ptr<Decoder> decoder) { + if (decoder) { + typename CodingType<typename T::Reply>::Type reply; + if (decoder->decode(reply)) { + replyHandler(WTFMove(reply)); + return; + } + } + + replyHandler(std::nullopt); + }); } -template<typename T> bool Connection::sendSync(T&& message, typename T::Reply&& reply, uint64_t destinationID, std::chrono::milliseconds timeout, unsigned syncSendFlags) +template<typename T> bool Connection::sendSync(T&& message, typename T::Reply&& reply, uint64_t destinationID, Seconds timeout, OptionSet<SendSyncOption> sendSyncOptions) { COMPILE_ASSERT(T::isSync, SyncMessageExpected); uint64_t syncRequestID = 0; - std::unique_ptr<MessageEncoder> encoder = createSyncMessageEncoder(T::receiverName(), T::name(), destinationID, syncRequestID); - + std::unique_ptr<Encoder> encoder = createSyncMessageEncoder(T::receiverName(), T::name(), destinationID, syncRequestID); + + if (sendSyncOptions.contains(SendSyncOption::UseFullySynchronousModeForTesting)) { + encoder->setFullySynchronousModeForTesting(); + m_fullySynchronousModeIsAllowedForTesting = true; + } + // Encode the rest of the input arguments. encoder->encode(message.arguments()); // Now send the message and wait for a reply. - std::unique_ptr<MessageDecoder> replyDecoder = sendSyncMessage(syncRequestID, std::move(encoder), timeout, syncSendFlags); + std::unique_ptr<Decoder> replyDecoder = sendSyncMessage(syncRequestID, WTFMove(encoder), timeout, sendSyncOptions); if (!replyDecoder) return false; @@ -343,17 +401,15 @@ template<typename T> bool Connection::sendSync(T&& message, typename T::Reply&& return replyDecoder->decode(reply); } -template<typename T> bool Connection::waitForAndDispatchImmediately(uint64_t destinationID, std::chrono::milliseconds timeout) +template<typename T> bool Connection::waitForAndDispatchImmediately(uint64_t destinationID, Seconds timeout, OptionSet<WaitForOption> waitForOptions) { - std::unique_ptr<MessageDecoder> decoder = waitForMessage(T::receiverName(), T::name(), destinationID, timeout); + std::unique_ptr<Decoder> decoder = waitForMessage(T::receiverName(), T::name(), destinationID, timeout, waitForOptions); if (!decoder) return false; ASSERT(decoder->destinationID() == destinationID); - m_client->didReceiveMessage(this, *decoder); + m_client.didReceiveMessage(*this, *decoder); return true; } } // namespace IPC - -#endif // Connection_h diff --git a/Source/WebKit2/Platform/IPC/DataReference.cpp b/Source/WebKit2/Platform/IPC/DataReference.cpp index 0047022e9..9bdec4ff4 100644 --- a/Source/WebKit2/Platform/IPC/DataReference.cpp +++ b/Source/WebKit2/Platform/IPC/DataReference.cpp @@ -26,19 +26,34 @@ #include "config.h" #include "DataReference.h" -#include "ArgumentDecoder.h" -#include "ArgumentEncoder.h" +#include "Decoder.h" +#include "Encoder.h" namespace IPC { -void DataReference::encode(ArgumentEncoder& encoder) const +void DataReference::encode(Encoder& encoder) const { encoder.encodeVariableLengthByteArray(*this); } -bool DataReference::decode(ArgumentDecoder& decoder, DataReference& dataReference) +bool DataReference::decode(Decoder& decoder, DataReference& dataReference) { return decoder.decodeVariableLengthByteArray(dataReference); } +void SharedBufferDataReference::encode(Encoder& encoder) const +{ + uint64_t bufferSize = static_cast<uint64_t>(m_buffer->size()); + encoder.reserve(bufferSize + sizeof(uint64_t)); + encoder << bufferSize; + + const char* partialData; + unsigned position = 0; + while (position < bufferSize) { + unsigned bytesToWrite = m_buffer->getSomeData(partialData, position); + encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(partialData), bytesToWrite, 1); + position += bytesToWrite; + } +} + } // namespace IPC diff --git a/Source/WebKit2/Platform/IPC/DataReference.h b/Source/WebKit2/Platform/IPC/DataReference.h index 66c3761e4..fb57591db 100644 --- a/Source/WebKit2/Platform/IPC/DataReference.h +++ b/Source/WebKit2/Platform/IPC/DataReference.h @@ -26,12 +26,13 @@ #ifndef DataReference_h #define DataReference_h +#include <WebCore/SharedBuffer.h> #include <wtf/Vector.h> namespace IPC { -class ArgumentDecoder; -class ArgumentEncoder; +class Decoder; +class Encoder; class DataReference { public: @@ -72,14 +73,40 @@ public: return result; } - void encode(ArgumentEncoder&) const; - static bool decode(ArgumentDecoder&, DataReference&); + virtual void encode(Encoder&) const; + static bool decode(Decoder&, DataReference&); + + virtual ~DataReference() { } private: const uint8_t* m_data; size_t m_size; }; +class SharedBufferDataReference : public DataReference { +public: + // FIXME: This class doesn't handle null, so the argument should be a reference or PassRef. + SharedBufferDataReference(WebCore::SharedBuffer* buffer) + : m_buffer(buffer) + { + } + +private: + // FIXME: It is a bad idea to violate the Liskov Substitution Principle as we do here. + // Since we are using DataReference as a polymoprhic base class in this fashion, + // then we need it to be a base class that does not have functions such as isEmpty, + // size, data, and vector, all of which will do the wrong thing if they are called. + // Deleting these functions here does not prevent them from being called. + bool isEmpty() const = delete; + size_t size() const = delete; + const uint8_t* data() const = delete; + Vector<uint8_t> vector() const = delete; + + void encode(Encoder&) const override; + + RefPtr<WebCore::SharedBuffer> m_buffer; +}; + } // namespace IPC #endif // DataReference_h diff --git a/Source/WebKit2/Platform/IPC/ArgumentDecoder.cpp b/Source/WebKit2/Platform/IPC/Decoder.cpp index 6d396beee..740a0cced 100644 --- a/Source/WebKit2/Platform/IPC/ArgumentDecoder.cpp +++ b/Source/WebKit2/Platform/IPC/Decoder.cpp @@ -24,56 +24,111 @@ */ #include "config.h" -#include "ArgumentDecoder.h" +#include "Decoder.h" #include "DataReference.h" +#include "MessageFlags.h" #include <stdio.h> +#if PLATFORM(MAC) +#include "ImportanceAssertion.h" +#endif + namespace IPC { -ArgumentDecoder::ArgumentDecoder(const uint8_t* buffer, size_t bufferSize) +static const uint8_t* copyBuffer(const uint8_t* buffer, size_t bufferSize) { - initialize(buffer, bufferSize); + auto bufferCopy = static_cast<uint8_t*>(fastMalloc(bufferSize)); + memcpy(bufferCopy, buffer, bufferSize); + + return bufferCopy; } -ArgumentDecoder::ArgumentDecoder(const uint8_t* buffer, size_t bufferSize, Vector<Attachment> attachments) +Decoder::Decoder(const uint8_t* buffer, size_t bufferSize, void (*bufferDeallocator)(const uint8_t*, size_t), Vector<Attachment> attachments) + : m_buffer { bufferDeallocator ? buffer : copyBuffer(buffer, bufferSize) } + , m_bufferPos { m_buffer } + , m_bufferEnd { m_buffer + bufferSize } + , m_bufferDeallocator { bufferDeallocator } + , m_attachments { WTFMove(attachments) } { - initialize(buffer, bufferSize); + ASSERT(!(reinterpret_cast<uintptr_t>(m_buffer) % alignof(uint64_t))); + + if (!decode(m_messageFlags)) + return; - m_attachments = std::move(attachments); + if (!decode(m_messageReceiverName)) + return; + + if (!decode(m_messageName)) + return; + + if (!decode(m_destinationID)) + return; } -ArgumentDecoder::~ArgumentDecoder() +Decoder::~Decoder() { ASSERT(m_buffer); - free(m_buffer); -#if !USE(UNIX_DOMAIN_SOCKETS) + + if (m_bufferDeallocator) + m_bufferDeallocator(m_buffer, m_bufferEnd - m_buffer); + else + fastFree(const_cast<uint8_t*>(m_buffer)); + // FIXME: We need to dispose of the mach ports in cases of failure. -#else - Vector<Attachment>::iterator end = m_attachments.end(); - for (Vector<Attachment>::iterator it = m_attachments.begin(); it != end; ++it) - it->dispose(); + +#if HAVE(QOS_CLASSES) + if (m_qosClassOverride) + pthread_override_qos_class_end_np(m_qosClassOverride); #endif } -static inline uint8_t* roundUpToAlignment(uint8_t* ptr, unsigned alignment) +bool Decoder::isSyncMessage() const { - // Assert that the alignment is a power of 2. - ASSERT(alignment && !(alignment & (alignment - 1))); + return m_messageFlags & SyncMessage; +} - uintptr_t alignmentMask = alignment - 1; - return reinterpret_cast<uint8_t*>((reinterpret_cast<uintptr_t>(ptr) + alignmentMask) & ~alignmentMask); +bool Decoder::shouldDispatchMessageWhenWaitingForSyncReply() const +{ + return m_messageFlags & DispatchMessageWhenWaitingForSyncReply; } -void ArgumentDecoder::initialize(const uint8_t* buffer, size_t bufferSize) +bool Decoder::shouldUseFullySynchronousModeForTesting() const { - m_buffer = static_cast<uint8_t*>(malloc(bufferSize)); + return m_messageFlags & UseFullySynchronousModeForTesting; +} - ASSERT(!(reinterpret_cast<uintptr_t>(m_buffer) % alignof(uint64_t))); +#if PLATFORM(MAC) +void Decoder::setImportanceAssertion(std::unique_ptr<ImportanceAssertion> assertion) +{ + m_importanceAssertion = WTFMove(assertion); +} +#endif + +std::unique_ptr<Decoder> Decoder::unwrapForTesting(Decoder& decoder) +{ + ASSERT(decoder.isSyncMessage()); + + Vector<Attachment> attachments; + Attachment attachment; + while (decoder.removeAttachment(attachment)) + attachments.append(WTFMove(attachment)); + attachments.reverse(); + + DataReference wrappedMessage; + if (!decoder.decode(wrappedMessage)) + return nullptr; - m_bufferPos = m_buffer; - m_bufferEnd = m_buffer + bufferSize; - memcpy(m_buffer, buffer, bufferSize); + return std::make_unique<Decoder>(wrappedMessage.data(), wrappedMessage.size(), nullptr, WTFMove(attachments)); +} + +static inline const uint8_t* roundUpToAlignment(const uint8_t* ptr, unsigned alignment) +{ + // Assert that the alignment is a power of 2. + ASSERT(alignment && !(alignment & (alignment - 1))); + + uintptr_t alignmentMask = alignment - 1; + return reinterpret_cast<uint8_t*>((reinterpret_cast<uintptr_t>(ptr) + alignmentMask) & ~alignmentMask); } static inline bool alignedBufferIsLargeEnoughToContain(const uint8_t* alignedPosition, const uint8_t* bufferEnd, size_t size) @@ -81,9 +136,9 @@ static inline bool alignedBufferIsLargeEnoughToContain(const uint8_t* alignedPos return bufferEnd >= alignedPosition && static_cast<size_t>(bufferEnd - alignedPosition) >= size; } -bool ArgumentDecoder::alignBufferPosition(unsigned alignment, size_t size) +bool Decoder::alignBufferPosition(unsigned alignment, size_t size) { - uint8_t* alignedPosition = roundUpToAlignment(m_bufferPos, alignment); + const uint8_t* alignedPosition = roundUpToAlignment(m_bufferPos, alignment); if (!alignedBufferIsLargeEnoughToContain(alignedPosition, m_bufferEnd, size)) { // We've walked off the end of this buffer. markInvalid(); @@ -94,12 +149,12 @@ bool ArgumentDecoder::alignBufferPosition(unsigned alignment, size_t size) return true; } -bool ArgumentDecoder::bufferIsLargeEnoughToContain(unsigned alignment, size_t size) const +bool Decoder::bufferIsLargeEnoughToContain(unsigned alignment, size_t size) const { return alignedBufferIsLargeEnoughToContain(roundUpToAlignment(m_bufferPos, alignment), m_bufferEnd, size); } -bool ArgumentDecoder::decodeFixedLengthData(uint8_t* data, size_t size, unsigned alignment) +bool Decoder::decodeFixedLengthData(uint8_t* data, size_t size, unsigned alignment) { if (!alignBufferPosition(alignment, size)) return false; @@ -110,7 +165,7 @@ bool ArgumentDecoder::decodeFixedLengthData(uint8_t* data, size_t size, unsigned return true; } -bool ArgumentDecoder::decodeVariableLengthByteArray(DataReference& dataReference) +bool Decoder::decodeVariableLengthByteArray(DataReference& dataReference) { uint64_t size; if (!decode(size)) @@ -119,7 +174,7 @@ bool ArgumentDecoder::decodeVariableLengthByteArray(DataReference& dataReference if (!alignBufferPosition(1, size)) return false; - uint8_t* data = m_bufferPos; + const uint8_t* data = m_bufferPos; m_bufferPos += size; dataReference = DataReference(data, size); @@ -127,13 +182,13 @@ bool ArgumentDecoder::decodeVariableLengthByteArray(DataReference& dataReference } template<typename Type> -static void decodeValueFromBuffer(Type& value, uint8_t*& bufferPosition) +static void decodeValueFromBuffer(Type& value, const uint8_t*& bufferPosition) { memcpy(&value, bufferPosition, sizeof(value)); bufferPosition += sizeof(Type); } -bool ArgumentDecoder::decode(bool& result) +bool Decoder::decode(bool& result) { if (!alignBufferPosition(sizeof(result), sizeof(result))) return false; @@ -142,7 +197,7 @@ bool ArgumentDecoder::decode(bool& result) return true; } -bool ArgumentDecoder::decode(uint8_t& result) +bool Decoder::decode(uint8_t& result) { if (!alignBufferPosition(sizeof(result), sizeof(result))) return false; @@ -151,7 +206,7 @@ bool ArgumentDecoder::decode(uint8_t& result) return true; } -bool ArgumentDecoder::decode(uint16_t& result) +bool Decoder::decode(uint16_t& result) { if (!alignBufferPosition(sizeof(result), sizeof(result))) return false; @@ -160,7 +215,7 @@ bool ArgumentDecoder::decode(uint16_t& result) return true; } -bool ArgumentDecoder::decode(uint32_t& result) +bool Decoder::decode(uint32_t& result) { if (!alignBufferPosition(sizeof(result), sizeof(result))) return false; @@ -169,7 +224,7 @@ bool ArgumentDecoder::decode(uint32_t& result) return true; } -bool ArgumentDecoder::decode(uint64_t& result) +bool Decoder::decode(uint64_t& result) { if (!alignBufferPosition(sizeof(result), sizeof(result))) return false; @@ -178,7 +233,7 @@ bool ArgumentDecoder::decode(uint64_t& result) return true; } -bool ArgumentDecoder::decode(int32_t& result) +bool Decoder::decode(int32_t& result) { if (!alignBufferPosition(sizeof(result), sizeof(result))) return false; @@ -187,7 +242,7 @@ bool ArgumentDecoder::decode(int32_t& result) return true; } -bool ArgumentDecoder::decode(int64_t& result) +bool Decoder::decode(int64_t& result) { if (!alignBufferPosition(sizeof(result), sizeof(result))) return false; @@ -196,7 +251,7 @@ bool ArgumentDecoder::decode(int64_t& result) return true; } -bool ArgumentDecoder::decode(float& result) +bool Decoder::decode(float& result) { if (!alignBufferPosition(sizeof(result), sizeof(result))) return false; @@ -205,7 +260,7 @@ bool ArgumentDecoder::decode(float& result) return true; } -bool ArgumentDecoder::decode(double& result) +bool Decoder::decode(double& result) { if (!alignBufferPosition(sizeof(result), sizeof(result))) return false; @@ -214,13 +269,12 @@ bool ArgumentDecoder::decode(double& result) return true; } -bool ArgumentDecoder::removeAttachment(Attachment& attachment) +bool Decoder::removeAttachment(Attachment& attachment) { if (m_attachments.isEmpty()) return false; - attachment = m_attachments.last(); - m_attachments.removeLast(); + attachment = m_attachments.takeLast(); return true; } diff --git a/Source/WebKit2/Platform/IPC/ArgumentDecoder.h b/Source/WebKit2/Platform/IPC/Decoder.h index b35ce3f9c..5a30c4258 100644 --- a/Source/WebKit2/Platform/IPC/ArgumentDecoder.h +++ b/Source/WebKit2/Platform/IPC/Decoder.h @@ -23,21 +23,49 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ArgumentDecoder_h -#define ArgumentDecoder_h +#pragma once #include "ArgumentCoder.h" #include "Attachment.h" +#include "StringReference.h" +#include <wtf/EnumTraits.h> #include <wtf/Vector.h> +#if HAVE(QOS_CLASSES) +#include <pthread/qos.h> +#endif + namespace IPC { class DataReference; - -class ArgumentDecoder { +class ImportanceAssertion; + +class Decoder { + WTF_MAKE_FAST_ALLOCATED; public: - ArgumentDecoder(const uint8_t* buffer, size_t bufferSize); - virtual ~ArgumentDecoder(); + Decoder(const uint8_t* buffer, size_t bufferSize, void (*bufferDeallocator)(const uint8_t*, size_t), Vector<Attachment>); + ~Decoder(); + + Decoder(const Decoder&) = delete; + Decoder(Decoder&&) = delete; + + StringReference messageReceiverName() const { return m_messageReceiverName; } + StringReference messageName() const { return m_messageName; } + uint64_t destinationID() const { return m_destinationID; } + + bool isSyncMessage() const; + bool shouldDispatchMessageWhenWaitingForSyncReply() const; + bool shouldUseFullySynchronousModeForTesting() const; + +#if PLATFORM(MAC) + void setImportanceAssertion(std::unique_ptr<ImportanceAssertion>); +#endif + +#if HAVE(QOS_CLASSES) + void setQOSClassOverride(pthread_override_t override) { m_qosClassOverride = override; } +#endif + + static std::unique_ptr<Decoder> unwrapForTesting(Decoder&); size_t length() const { return m_bufferEnd - m_buffer; } @@ -59,6 +87,19 @@ public: bool decode(float&); bool decode(double&); + template<typename E> + auto decode(E& e) -> std::enable_if_t<std::is_enum<E>::value, bool> + { + uint64_t value; + if (!decode(value)) + return false; + if (!isValidEnum<E>(value)) + return false; + + e = static_cast<E>(value); + return true; + } + template<typename T> bool decodeEnum(T& result) { static_assert(sizeof(T) <= 8, "Enum type T must not be larger than 64 bits!"); @@ -82,30 +123,40 @@ public: return bufferIsLargeEnoughToContain(alignof(T), numElements * sizeof(T)); } - // Generic type decode function. - template<typename T> bool decode(T& t) + template<typename T> + auto decode(T& t) -> std::enable_if_t<!std::is_enum<T>::value, bool> { return ArgumentCoder<T>::decode(*this, t); } bool removeAttachment(Attachment&); -protected: - ArgumentDecoder(const uint8_t* buffer, size_t bufferSize, Vector<Attachment>); - - void initialize(const uint8_t* buffer, size_t bufferSize); - - bool alignBufferPosition(unsigned alignment, size_t size); - bool bufferIsLargeEnoughToContain(unsigned alignment, size_t size) const; + static const bool isIPCDecoder = true; private: - uint8_t* m_buffer; - uint8_t* m_bufferPos; - uint8_t* m_bufferEnd; + bool alignBufferPosition(unsigned alignment, size_t); + bool bufferIsLargeEnoughToContain(unsigned alignment, size_t) const; + + const uint8_t* m_buffer; + const uint8_t* m_bufferPos; + const uint8_t* m_bufferEnd; + void (*m_bufferDeallocator)(const uint8_t*, size_t); Vector<Attachment> m_attachments; + + uint8_t m_messageFlags; + StringReference m_messageReceiverName; + StringReference m_messageName; + + uint64_t m_destinationID; + +#if PLATFORM(MAC) + std::unique_ptr<ImportanceAssertion> m_importanceAssertion; +#endif + +#if HAVE(QOS_CLASSES) + pthread_override_t m_qosClassOverride { nullptr }; +#endif }; } // namespace IPC - -#endif // ArgumentDecoder_h diff --git a/Source/WebKit2/Platform/IPC/ArgumentEncoder.cpp b/Source/WebKit2/Platform/IPC/Encoder.cpp index ee8563034..6cd7471d1 100644 --- a/Source/WebKit2/Platform/IPC/ArgumentEncoder.cpp +++ b/Source/WebKit2/Platform/IPC/Encoder.cpp @@ -24,9 +24,10 @@ */ #include "config.h" -#include "ArgumentEncoder.h" +#include "Encoder.h" #include "DataReference.h" +#include "MessageFlags.h" #include <algorithm> #include <stdio.h> @@ -36,12 +37,17 @@ namespace IPC { -static inline void* allocBuffer(size_t size) +static const uint8_t defaultMessageFlags = 0; + +template <typename T> +static inline bool allocBuffer(T*& buffer, size_t size) { #if OS(DARWIN) - return mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + buffer = static_cast<T*>(mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0)); + return buffer != MAP_FAILED; #else - return fastMalloc(size); + buffer = static_cast<T*>(fastMalloc(size)); + return !!buffer; #endif } @@ -55,25 +61,69 @@ static inline void freeBuffer(void* addr, size_t size) #endif } -ArgumentEncoder::ArgumentEncoder() - : m_buffer(m_inlineBuffer) +Encoder::Encoder(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID) + : m_messageReceiverName(messageReceiverName) + , m_messageName(messageName) + , m_destinationID(destinationID) + , m_buffer(m_inlineBuffer) , m_bufferPointer(m_inlineBuffer) , m_bufferSize(0) , m_bufferCapacity(sizeof(m_inlineBuffer)) { + encodeHeader(); } -ArgumentEncoder::~ArgumentEncoder() +Encoder::~Encoder() { if (m_buffer != m_inlineBuffer) freeBuffer(m_buffer, m_bufferCapacity); - -#if !USE(UNIX_DOMAIN_SOCKETS) // FIXME: We need to dispose of the attachments in cases of failure. -#else - for (size_t i = 0; i < m_attachments.size(); ++i) - m_attachments[i].dispose(); -#endif +} + +bool Encoder::isSyncMessage() const +{ + return *buffer() & SyncMessage; +} + +bool Encoder::shouldDispatchMessageWhenWaitingForSyncReply() const +{ + return *buffer() & DispatchMessageWhenWaitingForSyncReply; +} + +void Encoder::setIsSyncMessage(bool isSyncMessage) +{ + if (isSyncMessage) + *buffer() |= SyncMessage; + else + *buffer() &= ~SyncMessage; +} + +void Encoder::setShouldDispatchMessageWhenWaitingForSyncReply(bool shouldDispatchMessageWhenWaitingForSyncReply) +{ + if (shouldDispatchMessageWhenWaitingForSyncReply) + *buffer() |= DispatchMessageWhenWaitingForSyncReply; + else + *buffer() &= ~DispatchMessageWhenWaitingForSyncReply; +} + +void Encoder::setFullySynchronousModeForTesting() +{ + *buffer() |= UseFullySynchronousModeForTesting; +} + +void Encoder::wrapForTesting(std::unique_ptr<Encoder> original) +{ + ASSERT(isSyncMessage()); + ASSERT(!original->isSyncMessage()); + + original->setShouldDispatchMessageWhenWaitingForSyncReply(true); + + encodeVariableLengthByteArray(DataReference(original->buffer(), original->bufferSize())); + + Vector<Attachment> attachments = original->releaseAttachments(); + reserve(attachments.size()); + for (Attachment& attachment : attachments) + addAttachment(WTFMove(attachment)); } static inline size_t roundUpToAlignment(size_t value, unsigned alignment) @@ -81,27 +131,42 @@ 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) +void Encoder::reserve(size_t size) { - size_t alignedSize = roundUpToAlignment(m_bufferSize, alignment); - - if (alignedSize + size > m_bufferCapacity) { - size_t newCapacity = roundUpToAlignment(m_bufferCapacity * 2, 4096); - while (newCapacity < alignedSize + size) - newCapacity *= 2; + if (size <= m_bufferCapacity) + return; - uint8_t* newBuffer = static_cast<uint8_t*>(allocBuffer(newCapacity)); - if (!newBuffer) - CRASH(); + size_t newCapacity = roundUpToAlignment(m_bufferCapacity * 2, 4096); + while (newCapacity < size) + newCapacity *= 2; - memcpy(newBuffer, m_buffer, m_bufferSize); + uint8_t* newBuffer; + if (!allocBuffer(newBuffer, newCapacity)) + CRASH(); - if (m_buffer != m_inlineBuffer) - freeBuffer(m_buffer, m_bufferCapacity); + memcpy(newBuffer, m_buffer, m_bufferSize); - m_buffer = newBuffer; - m_bufferCapacity = newCapacity; - } + if (m_buffer != m_inlineBuffer) + freeBuffer(m_buffer, m_bufferCapacity); + + m_buffer = newBuffer; + m_bufferCapacity = newCapacity; +} + +void Encoder::encodeHeader() +{ + ASSERT(!m_messageReceiverName.isEmpty()); + + *this << defaultMessageFlags; + *this << m_messageReceiverName; + *this << m_messageName; + *this << m_destinationID; +} + +uint8_t* Encoder::grow(unsigned alignment, size_t size) +{ + size_t alignedSize = roundUpToAlignment(m_bufferSize, alignment); + reserve(alignedSize + size); m_bufferSize = alignedSize + size; m_bufferPointer = m_buffer + alignedSize + size; @@ -109,7 +174,7 @@ uint8_t* ArgumentEncoder::grow(unsigned alignment, size_t size) return m_buffer + alignedSize; } -void ArgumentEncoder::encodeFixedLengthData(const uint8_t* data, size_t size, unsigned alignment) +void Encoder::encodeFixedLengthData(const uint8_t* data, size_t size, unsigned alignment) { ASSERT(!(reinterpret_cast<uintptr_t>(data) % alignment)); @@ -117,7 +182,7 @@ void ArgumentEncoder::encodeFixedLengthData(const uint8_t* data, size_t size, un memcpy(buffer, data, size); } -void ArgumentEncoder::encodeVariableLengthByteArray(const DataReference& dataReference) +void Encoder::encodeVariableLengthByteArray(const DataReference& dataReference) { encode(static_cast<uint64_t>(dataReference.size())); encodeFixedLengthData(dataReference.data(), dataReference.size(), 1); @@ -129,70 +194,68 @@ static void copyValueToBuffer(Type value, uint8_t* bufferPosition) memcpy(bufferPosition, &value, sizeof(Type)); } -void ArgumentEncoder::encode(bool n) +void Encoder::encode(bool n) { uint8_t* buffer = grow(sizeof(n), sizeof(n)); copyValueToBuffer(n, buffer); } -void ArgumentEncoder::encode(uint8_t n) +void Encoder::encode(uint8_t n) { uint8_t* buffer = grow(sizeof(n), sizeof(n)); copyValueToBuffer(n, buffer); } -void ArgumentEncoder::encode(uint16_t n) +void Encoder::encode(uint16_t n) { uint8_t* buffer = grow(sizeof(n), sizeof(n)); copyValueToBuffer(n, buffer); } -void ArgumentEncoder::encode(uint32_t n) +void Encoder::encode(uint32_t n) { uint8_t* buffer = grow(sizeof(n), sizeof(n)); copyValueToBuffer(n, buffer); } -void ArgumentEncoder::encode(uint64_t n) +void Encoder::encode(uint64_t n) { uint8_t* buffer = grow(sizeof(n), sizeof(n)); copyValueToBuffer(n, buffer); } -void ArgumentEncoder::encode(int32_t n) +void Encoder::encode(int32_t n) { uint8_t* buffer = grow(sizeof(n), sizeof(n)); copyValueToBuffer(n, buffer); } -void ArgumentEncoder::encode(int64_t n) +void Encoder::encode(int64_t n) { uint8_t* buffer = grow(sizeof(n), sizeof(n)); copyValueToBuffer(n, buffer); } -void ArgumentEncoder::encode(float n) +void Encoder::encode(float n) { uint8_t* buffer = grow(sizeof(n), sizeof(n)); copyValueToBuffer(n, buffer); } -void ArgumentEncoder::encode(double n) +void Encoder::encode(double n) { uint8_t* buffer = grow(sizeof(n), sizeof(n)); copyValueToBuffer(n, buffer); } -void ArgumentEncoder::addAttachment(const Attachment& attachment) +void Encoder::addAttachment(Attachment&& attachment) { - m_attachments.append(attachment); + m_attachments.append(WTFMove(attachment)); } -Vector<Attachment> ArgumentEncoder::releaseAttachments() +Vector<Attachment> Encoder::releaseAttachments() { - Vector<Attachment> newList; - newList.swap(m_attachments); - return newList; + return WTFMove(m_attachments); } } // namespace IPC diff --git a/Source/WebKit2/Platform/IPC/ArgumentEncoder.h b/Source/WebKit2/Platform/IPC/Encoder.h index 424291570..92f9ba256 100644 --- a/Source/WebKit2/Platform/IPC/ArgumentEncoder.h +++ b/Source/WebKit2/Platform/IPC/Encoder.h @@ -23,22 +23,37 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ArgumentEncoder_h -#define ArgumentEncoder_h +#pragma once #include "ArgumentCoder.h" #include "Attachment.h" +#include "StringReference.h" +#include <wtf/EnumTraits.h> #include <wtf/Vector.h> namespace IPC { -class ArgumentEncoder; class DataReference; -class ArgumentEncoder { +class Encoder final { + WTF_MAKE_FAST_ALLOCATED; public: - ArgumentEncoder(); - virtual ~ArgumentEncoder(); + Encoder(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID); + ~Encoder(); + + StringReference messageReceiverName() const { return m_messageReceiverName; } + StringReference messageName() const { return m_messageName; } + uint64_t destinationID() const { return m_destinationID; } + + void setIsSyncMessage(bool); + bool isSyncMessage() const; + + void setShouldDispatchMessageWhenWaitingForSyncReply(bool); + bool shouldDispatchMessageWhenWaitingForSyncReply() const; + + void setFullySynchronousModeForTesting(); + + void wrapForTesting(std::unique_ptr<Encoder>); void encodeFixedLengthData(const uint8_t*, size_t, unsigned alignment); void encodeVariableLengthByteArray(const DataReference&); @@ -50,24 +65,30 @@ public: encode(static_cast<uint64_t>(t)); } - template<typename T> void encode(const T& t) + template<typename T> + auto encode(T&& t) -> std::enable_if_t<!std::is_enum<typename std::remove_const_t<std::remove_reference_t<T>>>::value> { - ArgumentCoder<T>::encode(*this, t); + ArgumentCoder<typename std::remove_const<typename std::remove_reference<T>::type>::type>::encode(*this, std::forward<T>(t)); } - template<typename T> ArgumentEncoder& operator<<(const T& t) + template<typename T> Encoder& operator<<(T&& t) { - encode(t); + encode(std::forward<T>(t)); return *this; } uint8_t* buffer() const { return m_buffer; } size_t bufferSize() const { return m_bufferSize; } - void addAttachment(const Attachment&); + void addAttachment(Attachment&&); Vector<Attachment> releaseAttachments(); + void reserve(size_t); + + static const bool isIPCEncoder = true; private: + uint8_t* grow(unsigned alignment, size_t); + void encode(bool); void encode(uint8_t); void encode(uint16_t); @@ -78,7 +99,20 @@ private: void encode(float); void encode(double); - uint8_t* grow(unsigned alignment, size_t size); + template<typename E> + auto encode(E value) -> std::enable_if_t<std::is_enum<E>::value> + { + static_assert(sizeof(E) <= sizeof(uint64_t), "Enum type must not be larger than 64 bits."); + + ASSERT(isValidEnum<E>(static_cast<uint64_t>(value))); + encode(static_cast<uint64_t>(value)); + } + + void encodeHeader(); + + StringReference m_messageReceiverName; + StringReference m_messageName; + uint64_t m_destinationID; uint8_t m_inlineBuffer[512]; @@ -92,5 +126,3 @@ private: }; } // namespace IPC - -#endif // ArgumentEncoder_h diff --git a/Source/WebKit2/Platform/IPC/HandleMessage.h b/Source/WebKit2/Platform/IPC/HandleMessage.h index 7f32bf38f..13b94413a 100644 --- a/Source/WebKit2/Platform/IPC/HandleMessage.h +++ b/Source/WebKit2/Platform/IPC/HandleMessage.h @@ -1,19 +1,43 @@ -#ifndef HandleMessage_h -#define HandleMessage_h - -#include "Arguments.h" -#include "MessageDecoder.h" -#include "MessageEncoder.h" +/* + * Copyright (C) 2010-2016 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. + */ + +#pragma once + +#include "ArgumentCoders.h" #include <wtf/StdLibExtras.h> namespace IPC { +class Connection; + // Dispatch functions with no reply arguments. template <typename C, typename MF, typename ArgsTuple, size_t... ArgsIndex> void callMemberFunctionImpl(C* object, MF function, ArgsTuple&& args, std::index_sequence<ArgsIndex...>) { - (object->*function)(std::get<ArgsIndex>(args)...); + (object->*function)(std::get<ArgsIndex>(std::forward<ArgsTuple>(args))...); } template<typename C, typename MF, typename ArgsTuple, typename ArgsIndicies = std::make_index_sequence<std::tuple_size<ArgsTuple>::value>> @@ -39,27 +63,27 @@ void callMemberFunction(ArgsTuple&& args, ReplyArgsTuple& replyArgs, C* object, // Dispatch functions with delayed reply arguments. template <typename C, typename MF, typename R, typename ArgsTuple, size_t... ArgsIndex> -void callMemberFunctionImpl(C* object, MF function, PassRefPtr<R> delayedReply, ArgsTuple&& args, std::index_sequence<ArgsIndex...>) +void callMemberFunctionImpl(C* object, MF function, Ref<R>&& delayedReply, ArgsTuple&& args, std::index_sequence<ArgsIndex...>) { - (object->*function)(std::get<ArgsIndex>(args)..., delayedReply); + (object->*function)(std::get<ArgsIndex>(args)..., WTFMove(delayedReply)); } template<typename C, typename MF, typename R, typename ArgsTuple, typename ArgsIndicies = std::make_index_sequence<std::tuple_size<ArgsTuple>::value>> -void callMemberFunction(ArgsTuple&& args, PassRefPtr<R> delayedReply, C* object, MF function) +void callMemberFunction(ArgsTuple&& args, Ref<R>&& delayedReply, C* object, MF function) { - callMemberFunctionImpl(object, function, delayedReply, std::forward<ArgsTuple>(args), ArgsIndicies()); + callMemberFunctionImpl(object, function, WTFMove(delayedReply), std::forward<ArgsTuple>(args), ArgsIndicies()); } // Dispatch functions with connection parameter with no reply arguments. template <typename C, typename MF, typename ArgsTuple, size_t... ArgsIndex> -void callMemberFunctionImpl(C* object, MF function, Connection* connection, ArgsTuple&& args, std::index_sequence<ArgsIndex...>) +void callMemberFunctionImpl(C* object, MF function, Connection& connection, ArgsTuple&& args, std::index_sequence<ArgsIndex...>) { - (object->*function)(connection, std::get<ArgsIndex>(args)...); + (object->*function)(connection, std::get<ArgsIndex>(std::forward<ArgsTuple>(args))...); } template<typename C, typename MF, typename ArgsTuple, typename ArgsIndicies = std::make_index_sequence<std::tuple_size<ArgsTuple>::value>> -void callMemberFunction(Connection* connection, ArgsTuple&& args, C* object, MF function) +void callMemberFunction(Connection& connection, ArgsTuple&& args, C* object, MF function) { callMemberFunctionImpl(object, function, connection, std::forward<ArgsTuple>(args), ArgsIndicies()); } @@ -67,121 +91,91 @@ void callMemberFunction(Connection* connection, ArgsTuple&& args, C* object, MF // Dispatch functions with connection parameter with reply arguments. template <typename C, typename MF, typename ArgsTuple, size_t... ArgsIndex, typename ReplyArgsTuple, size_t... ReplyArgsIndex> -void callMemberFunctionImpl(C* object, MF function, Connection* connection, ArgsTuple&& args, ReplyArgsTuple& replyArgs, std::index_sequence<ArgsIndex...>, std::index_sequence<ReplyArgsIndex...>) +void callMemberFunctionImpl(C* object, MF function, Connection& connection, ArgsTuple&& args, ReplyArgsTuple& replyArgs, std::index_sequence<ArgsIndex...>, std::index_sequence<ReplyArgsIndex...>) { (object->*function)(connection, std::get<ArgsIndex>(std::forward<ArgsTuple>(args))..., std::get<ReplyArgsIndex>(replyArgs)...); } template <typename C, typename MF, typename ArgsTuple, typename ArgsIndicies = std::make_index_sequence<std::tuple_size<ArgsTuple>::value>, typename ReplyArgsTuple, typename ReplyArgsIndicies = std::make_index_sequence<std::tuple_size<ReplyArgsTuple>::value>> -void callMemberFunction(Connection* connection, ArgsTuple&& args, ReplyArgsTuple& replyArgs, C* object, MF function) +void callMemberFunction(Connection& connection, ArgsTuple&& args, ReplyArgsTuple& replyArgs, C* object, MF function) { callMemberFunctionImpl(object, function, connection, std::forward<ArgsTuple>(args), replyArgs, ArgsIndicies(), ReplyArgsIndicies()); } -// Variadic dispatch functions. - -template <typename C, typename MF, typename ArgsTuple, size_t... ArgsIndex> -void callMemberFunctionImpl(C* object, MF function, MessageDecoder& decoder, ArgsTuple&& args, std::index_sequence<ArgsIndex...>) -{ - (object->*function)(std::get<ArgsIndex>(args)..., decoder); -} - -template<typename C, typename MF, typename ArgsTuple, typename ArgsIndicies = std::make_index_sequence<std::tuple_size<ArgsTuple>::value>> -void callMemberFunction(ArgsTuple&& args, MessageDecoder& decoder, C* object, MF function) -{ - callMemberFunctionImpl(object, function, decoder, std::forward<ArgsTuple>(args), ArgsIndicies()); -} - -// Variadic dispatch functions with non-variadic reply arguments. - -template <typename C, typename MF, typename ArgsTuple, size_t... ArgsIndex, typename ReplyArgsTuple, size_t... ReplyArgsIndex> -void callMemberFunctionImpl(C* object, MF function, MessageDecoder& decoder, ArgsTuple&& args, ReplyArgsTuple& replyArgs, std::index_sequence<ArgsIndex...>, std::index_sequence<ReplyArgsIndex...>) -{ - (object->*function)(std::get<ArgsIndex>(std::forward<ArgsTuple>(args))..., decoder, std::get<ReplyArgsIndex>(replyArgs)...); -} - -template <typename C, typename MF, typename ArgsTuple, typename ArgsIndicies = std::make_index_sequence<std::tuple_size<ArgsTuple>::value>, typename ReplyArgsTuple, typename ReplyArgsIndicies = std::make_index_sequence<std::tuple_size<ReplyArgsTuple>::value>> -void callMemberFunction(ArgsTuple&& args, MessageDecoder& decoder, ReplyArgsTuple& replyArgs, C* object, MF function) -{ - callMemberFunctionImpl(object, function, decoder, std::forward<ArgsTuple>(args), replyArgs, ArgsIndicies(), ReplyArgsIndicies()); -} - // Main dispatch functions -template<typename T, typename C, typename MF> -void handleMessage(MessageDecoder& decoder, C* object, MF function) -{ - typename T::DecodeType arguments; - if (!decoder.decode(arguments)) - return; - callMemberFunction(std::move(arguments), object, function); -} +template<typename T> +struct CodingType { + typedef std::remove_const_t<std::remove_reference_t<T>> Type; +}; + +template<typename... Ts> +struct CodingType<std::tuple<Ts...>> { + typedef std::tuple<typename CodingType<Ts>::Type...> Type; +}; template<typename T, typename C, typename MF> -void handleMessage(MessageDecoder& decoder, MessageEncoder& replyEncoder, C* object, MF function) +void handleMessage(Decoder& decoder, C* object, MF function) { - typename T::DecodeType arguments; - if (!decoder.decode(arguments)) + typename CodingType<typename T::Arguments>::Type arguments; + if (!decoder.decode(arguments)) { + ASSERT(decoder.isInvalid()); return; + } - typename T::Reply::ValueType replyArguments; - callMemberFunction(std::move(arguments), replyArguments, object, function); - replyEncoder << replyArguments; + callMemberFunction(WTFMove(arguments), object, function); } template<typename T, typename C, typename MF> -void handleMessage(Connection* connection, MessageDecoder& decoder, MessageEncoder& replyEncoder, C* object, MF function) +void handleMessage(Decoder& decoder, Encoder& replyEncoder, C* object, MF function) { - typename T::DecodeType arguments; - if (!decoder.decode(arguments)) + typename CodingType<typename T::Arguments>::Type arguments; + if (!decoder.decode(arguments)) { + ASSERT(decoder.isInvalid()); return; + } - typename T::Reply::ValueType replyArguments; - callMemberFunction(connection, std::move(arguments), replyArguments, object, function); + typename CodingType<typename T::Reply>::Type replyArguments; + callMemberFunction(WTFMove(arguments), replyArguments, object, function); replyEncoder << replyArguments; } template<typename T, typename C, typename MF> -void handleMessage(Connection* connection, MessageDecoder& decoder, C* object, MF function) +void handleMessage(Connection& connection, Decoder& decoder, Encoder& replyEncoder, C* object, MF function) { - typename T::DecodeType arguments; - if (!decoder.decode(arguments)) + typename CodingType<typename T::Arguments>::Type arguments; + if (!decoder.decode(arguments)) { + ASSERT(decoder.isInvalid()); return; - callMemberFunction(connection, std::move(arguments), object, function); -} + } -template<typename T, typename C, typename MF> -void handleMessageVariadic(MessageDecoder& decoder, C* object, MF function) -{ - typename T::DecodeType arguments; - if (!decoder.decode(arguments)) - return; - callMemberFunction(std::move(arguments), decoder, object, function); + typename CodingType<typename T::Reply>::Type replyArguments; + callMemberFunction(connection, WTFMove(arguments), replyArguments, object, function); + replyEncoder << replyArguments; } template<typename T, typename C, typename MF> -void handleMessageVariadic(MessageDecoder& decoder, MessageEncoder& replyEncoder, C* object, MF function) +void handleMessage(Connection& connection, Decoder& decoder, C* object, MF function) { - typename T::DecodeType arguments; - if (!decoder.decode(arguments)) + typename CodingType<typename T::Arguments>::Type arguments; + if (!decoder.decode(arguments)) { + ASSERT(decoder.isInvalid()); return; - - typename T::Reply::ValueType replyArguments; - callMemberFunction(std::move(arguments), decoder, replyArguments, object, function); - replyEncoder << replyArguments; + } + callMemberFunction(connection, WTFMove(arguments), object, function); } template<typename T, typename C, typename MF> -void handleMessageDelayed(Connection* connection, MessageDecoder& decoder, std::unique_ptr<MessageEncoder>& replyEncoder, C* object, MF function) +void handleMessageDelayed(Connection& connection, Decoder& decoder, std::unique_ptr<Encoder>& replyEncoder, C* object, MF function) { - typename T::DecodeType arguments; - if (!decoder.decode(arguments)) + typename CodingType<typename T::Arguments>::Type arguments; + if (!decoder.decode(arguments)) { + ASSERT(decoder.isInvalid()); return; + } - RefPtr<typename T::DelayedReply> delayedReply = adoptRef(new typename T::DelayedReply(connection, std::move(replyEncoder))); - callMemberFunction(std::move(arguments), delayedReply.release(), object, function); + Ref<typename T::DelayedReply> delayedReply = adoptRef(*new typename T::DelayedReply(connection, WTFMove(replyEncoder))); + callMemberFunction(WTFMove(arguments), WTFMove(delayedReply), object, function); } } // namespace IPC - -#endif // HandleMessage_h diff --git a/Source/WebKit2/Platform/IPC/MessageDecoder.h b/Source/WebKit2/Platform/IPC/MessageDecoder.h deleted file mode 100644 index 0b09baad7..000000000 --- a/Source/WebKit2/Platform/IPC/MessageDecoder.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef MessageDecoder_h -#define MessageDecoder_h - -#include "ArgumentDecoder.h" -#include "StringReference.h" - -namespace IPC { - -class DataReference; -class ImportanceAssertion; - -class MessageDecoder : public ArgumentDecoder { -public: - MessageDecoder(const DataReference& buffer, Vector<Attachment>); - virtual ~MessageDecoder(); - - StringReference messageReceiverName() const { return m_messageReceiverName; } - StringReference messageName() const { return m_messageName; } - uint64_t destinationID() const { return m_destinationID; } - - bool isSyncMessage() const; - bool shouldDispatchMessageWhenWaitingForSyncReply() const; - -#if PLATFORM(IOS) || PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 - void setImportanceAssertion(std::unique_ptr<ImportanceAssertion>); -#endif - -private: - uint8_t m_messageFlags; - StringReference m_messageReceiverName; - StringReference m_messageName; - - uint64_t m_destinationID; - -#if PLATFORM(IOS) || PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 - std::unique_ptr<ImportanceAssertion> m_importanceAssertion; -#endif -}; - -} // namespace IPC - -#endif // MessageDecoder_h diff --git a/Source/WebKit2/Platform/IPC/MessageEncoder.cpp b/Source/WebKit2/Platform/IPC/MessageEncoder.cpp deleted file mode 100644 index d2e4efe9a..000000000 --- a/Source/WebKit2/Platform/IPC/MessageEncoder.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "MessageEncoder.h" - -#include "ArgumentCoders.h" -#include "MessageFlags.h" -#include "StringReference.h" - -namespace IPC { - -static uint8_t defaultMessageFlags = 0; - -MessageEncoder::MessageEncoder(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID) -{ - ASSERT(!messageReceiverName.isEmpty()); - - *this << defaultMessageFlags; - *this << messageReceiverName; - *this << messageName; - *this << destinationID; -} - -MessageEncoder::~MessageEncoder() -{ -} - -void MessageEncoder::setIsSyncMessage(bool isSyncMessage) -{ - if (isSyncMessage) - *buffer() |= SyncMessage; - else - *buffer() &= ~SyncMessage; -} - -void MessageEncoder::setShouldDispatchMessageWhenWaitingForSyncReply(bool shouldDispatchMessageWhenWaitingForSyncReply) -{ - if (shouldDispatchMessageWhenWaitingForSyncReply) - *buffer() |= DispatchMessageWhenWaitingForSyncReply; - else - *buffer() &= ~DispatchMessageWhenWaitingForSyncReply; -} - -} // namespace IPC diff --git a/Source/WebKit2/Platform/IPC/MessageFlags.h b/Source/WebKit2/Platform/IPC/MessageFlags.h index 187ca981b..e8d3e5e37 100644 --- a/Source/WebKit2/Platform/IPC/MessageFlags.h +++ b/Source/WebKit2/Platform/IPC/MessageFlags.h @@ -31,6 +31,7 @@ namespace IPC { enum MessageFlags { SyncMessage = 1 << 0, DispatchMessageWhenWaitingForSyncReply = 1 << 1, + UseFullySynchronousModeForTesting = 1 << 2, }; } // namespace IPC diff --git a/Source/WebKit2/Platform/IPC/MessageReceiver.h b/Source/WebKit2/Platform/IPC/MessageReceiver.h index 331b7c33a..ef890c146 100644 --- a/Source/WebKit2/Platform/IPC/MessageReceiver.h +++ b/Source/WebKit2/Platform/IPC/MessageReceiver.h @@ -23,29 +23,50 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MessageReceiver_h -#define MessageReceiver_h +#pragma once #include <wtf/Assertions.h> -#include <wtf/OwnPtr.h> namespace IPC { -class MessageDecoder; -class MessageEncoder; class Connection; +class Decoder; +class Encoder; class MessageReceiver { public: - virtual ~MessageReceiver() { } + virtual ~MessageReceiver() + { + ASSERT(!m_messageReceiverMapCount); + } - virtual void didReceiveMessage(Connection*, MessageDecoder&) = 0; - virtual void didReceiveSyncMessage(Connection*, MessageDecoder&, std::unique_ptr<MessageEncoder>&) + virtual void didReceiveMessage(Connection&, Decoder&) = 0; + virtual void didReceiveSyncMessage(Connection&, Decoder&, std::unique_ptr<Encoder>&) { ASSERT_NOT_REACHED(); } + +private: + friend class MessageReceiverMap; + + void willBeAddedToMessageReceiverMap() + { +#if !ASSERT_DISABLED + m_messageReceiverMapCount++; +#endif + } + + void willBeRemovedFromMessageReceiverMap() + { + ASSERT(m_messageReceiverMapCount); +#if !ASSERT_DISABLED + m_messageReceiverMapCount--; +#endif + } + +#if !ASSERT_DISABLED + unsigned m_messageReceiverMapCount { 0 }; +#endif }; } // namespace IPC - -#endif // MessageReceiver_h diff --git a/Source/WebKit2/Platform/IPC/MessageReceiverMap.cpp b/Source/WebKit2/Platform/IPC/MessageReceiverMap.cpp index da6d7c5b3..aa5eba8df 100644 --- a/Source/WebKit2/Platform/IPC/MessageReceiverMap.cpp +++ b/Source/WebKit2/Platform/IPC/MessageReceiverMap.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "MessageReceiverMap.h" -#include "MessageDecoder.h" +#include "Decoder.h" #include "MessageReceiver.h" namespace IPC { @@ -42,6 +42,8 @@ MessageReceiverMap::~MessageReceiverMap() void MessageReceiverMap::addMessageReceiver(StringReference messageReceiverName, MessageReceiver& messageReceiver) { ASSERT(!m_globalMessageReceivers.contains(messageReceiverName)); + + messageReceiver.willBeAddedToMessageReceiverMap(); m_globalMessageReceivers.set(messageReceiverName, &messageReceiver); } @@ -51,6 +53,7 @@ void MessageReceiverMap::addMessageReceiver(StringReference messageReceiverName, ASSERT(!m_messageReceivers.contains(std::make_pair(messageReceiverName, destinationID))); ASSERT(!m_globalMessageReceivers.contains(messageReceiverName)); + messageReceiver.willBeAddedToMessageReceiverMap(); m_messageReceivers.set(std::make_pair(messageReceiverName, destinationID), &messageReceiver); } @@ -58,23 +61,56 @@ void MessageReceiverMap::removeMessageReceiver(StringReference messageReceiverNa { ASSERT(m_globalMessageReceivers.contains(messageReceiverName)); - m_globalMessageReceivers.remove(messageReceiverName); + auto it = m_globalMessageReceivers.find(messageReceiverName); + it->value->willBeRemovedFromMessageReceiverMap(); + + m_globalMessageReceivers.remove(it); } void MessageReceiverMap::removeMessageReceiver(StringReference messageReceiverName, uint64_t destinationID) { ASSERT(m_messageReceivers.contains(std::make_pair(messageReceiverName, destinationID))); - m_messageReceivers.remove(std::make_pair(messageReceiverName, destinationID)); + auto it = m_messageReceivers.find(std::make_pair(messageReceiverName, destinationID)); + it->value->willBeRemovedFromMessageReceiverMap(); + + m_messageReceivers.remove(it); +} + +void MessageReceiverMap::removeMessageReceiver(MessageReceiver& messageReceiver) +{ + Vector<StringReference> globalReceiversToRemove; + for (auto& nameAndReceiver : m_globalMessageReceivers) { + if (nameAndReceiver.value == &messageReceiver) + globalReceiversToRemove.append(nameAndReceiver.key); + } + + for (auto& globalReceiverToRemove : globalReceiversToRemove) + removeMessageReceiver(globalReceiverToRemove); + + Vector<std::pair<StringReference, uint64_t>> receiversToRemove; + for (auto& nameAndIdAndReceiver : m_messageReceivers) { + if (nameAndIdAndReceiver.value == &messageReceiver) + receiversToRemove.append(std::make_pair(nameAndIdAndReceiver.key.first, nameAndIdAndReceiver.key.second)); + } + + for (auto& receiverToRemove : receiversToRemove) + removeMessageReceiver(receiverToRemove.first, receiverToRemove.second); } void MessageReceiverMap::invalidate() { + for (auto& messageReceiver : m_globalMessageReceivers.values()) + messageReceiver->willBeRemovedFromMessageReceiverMap(); m_globalMessageReceivers.clear(); + + + for (auto& messageReceiver : m_messageReceivers.values()) + messageReceiver->willBeRemovedFromMessageReceiverMap(); m_messageReceivers.clear(); } -bool MessageReceiverMap::dispatchMessage(Connection* connection, MessageDecoder& decoder) +bool MessageReceiverMap::dispatchMessage(Connection& connection, Decoder& decoder) { if (MessageReceiver* messageReceiver = m_globalMessageReceivers.get(decoder.messageReceiverName())) { ASSERT(!decoder.destinationID()); @@ -91,7 +127,7 @@ bool MessageReceiverMap::dispatchMessage(Connection* connection, MessageDecoder& return false; } -bool MessageReceiverMap::dispatchSyncMessage(Connection* connection, MessageDecoder& decoder, std::unique_ptr<MessageEncoder>& replyEncoder) +bool MessageReceiverMap::dispatchSyncMessage(Connection& connection, Decoder& decoder, std::unique_ptr<Encoder>& replyEncoder) { if (MessageReceiver* messageReceiver = m_globalMessageReceivers.get(decoder.messageReceiverName())) { ASSERT(!decoder.destinationID()); diff --git a/Source/WebKit2/Platform/IPC/MessageReceiverMap.h b/Source/WebKit2/Platform/IPC/MessageReceiverMap.h index b00d3646d..4fc751281 100644 --- a/Source/WebKit2/Platform/IPC/MessageReceiverMap.h +++ b/Source/WebKit2/Platform/IPC/MessageReceiverMap.h @@ -33,8 +33,8 @@ namespace IPC { class Connection; -class MessageDecoder; -class MessageEncoder; +class Encoder; +class Decoder; class MessageReceiver; class MessageReceiverMap { @@ -47,11 +47,12 @@ public: void removeMessageReceiver(StringReference messageReceiverName); void removeMessageReceiver(StringReference messageReceiverName, uint64_t destinationID); + void removeMessageReceiver(MessageReceiver&); void invalidate(); - bool dispatchMessage(Connection*, MessageDecoder&); - bool dispatchSyncMessage(Connection*, MessageDecoder&, std::unique_ptr<MessageEncoder>&); + bool dispatchMessage(Connection&, Decoder&); + bool dispatchSyncMessage(Connection&, Decoder&, std::unique_ptr<Encoder>&); private: // Message receivers that don't require a destination ID. diff --git a/Source/WebKit2/Platform/IPC/MessageSender.cpp b/Source/WebKit2/Platform/IPC/MessageSender.cpp index a3f3ef1ae..da1044aed 100644 --- a/Source/WebKit2/Platform/IPC/MessageSender.cpp +++ b/Source/WebKit2/Platform/IPC/MessageSender.cpp @@ -32,11 +32,11 @@ MessageSender::~MessageSender() { } -bool MessageSender::sendMessage(std::unique_ptr<MessageEncoder> encoder, unsigned messageSendFlags) +bool MessageSender::sendMessage(std::unique_ptr<Encoder> encoder, OptionSet<SendOption> sendOptions) { ASSERT(messageSenderConnection()); - return messageSenderConnection()->sendMessage(std::move(encoder), messageSendFlags); + return messageSenderConnection()->sendMessage(WTFMove(encoder), sendOptions); } } // namespace IPC diff --git a/Source/WebKit2/Platform/IPC/MessageSender.h b/Source/WebKit2/Platform/IPC/MessageSender.h index 638bdeebe..f216229b4 100644 --- a/Source/WebKit2/Platform/IPC/MessageSender.h +++ b/Source/WebKit2/Platform/IPC/MessageSender.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,8 +23,7 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MessageSender_h -#define MessageSender_h +#pragma once #include <wtf/Assertions.h> #include "Connection.h" @@ -37,36 +36,36 @@ public: template<typename U> bool send(const U& message) { - return send(message, messageSenderDestinationID(), 0); + return send(message, messageSenderDestinationID(), { }); } - template<typename U> bool send(const U& message, uint64_t destinationID, unsigned messageSendFlags = 0) + template<typename U> bool send(const U& message, uint64_t destinationID, OptionSet<SendOption> sendOptions = { }) { static_assert(!U::isSync, "Message is sync!"); - auto encoder = std::make_unique<MessageEncoder>(U::receiverName(), U::name(), destinationID); + auto encoder = std::make_unique<Encoder>(U::receiverName(), U::name(), destinationID); encoder->encode(message.arguments()); - return sendMessage(std::move(encoder), messageSendFlags); + return sendMessage(WTFMove(encoder), sendOptions); } template<typename T> - bool sendSync(T&& message, typename T::Reply&& reply, std::chrono::milliseconds timeout = std::chrono::milliseconds::max(), unsigned syncSendFlags = 0) + bool sendSync(T&& message, typename T::Reply&& reply, Seconds timeout = Seconds::infinity(), OptionSet<SendSyncOption> sendSyncOptions = { }) { static_assert(T::isSync, "Message is not sync!"); - return sendSync(std::forward<T>(message), std::move(reply), messageSenderDestinationID(), timeout, syncSendFlags); + return sendSync(std::forward<T>(message), WTFMove(reply), messageSenderDestinationID(), timeout, sendSyncOptions); } template<typename T> - bool sendSync(T&& message, typename T::Reply&& reply, uint64_t destinationID, std::chrono::milliseconds timeout = std::chrono::milliseconds::max(), unsigned syncSendFlags = 0) + bool sendSync(T&& message, typename T::Reply&& reply, uint64_t destinationID, Seconds timeout = Seconds::infinity(), OptionSet<SendSyncOption> sendSyncOptions = { }) { ASSERT(messageSenderConnection()); - return messageSenderConnection()->sendSync(std::move(message), std::move(reply), destinationID, timeout, syncSendFlags); + return messageSenderConnection()->sendSync(WTFMove(message), WTFMove(reply), destinationID, timeout, sendSyncOptions); } - virtual bool sendMessage(std::unique_ptr<MessageEncoder>, unsigned messageSendFlags); + virtual bool sendMessage(std::unique_ptr<Encoder>, OptionSet<SendOption>); private: virtual Connection* messageSenderConnection() = 0; @@ -74,5 +73,3 @@ private: }; } // namespace IPC - -#endif // MessageSender_h diff --git a/Source/WebKit2/Platform/IPC/StringReference.cpp b/Source/WebKit2/Platform/IPC/StringReference.cpp index 258b7cdd2..852ef43e0 100644 --- a/Source/WebKit2/Platform/IPC/StringReference.cpp +++ b/Source/WebKit2/Platform/IPC/StringReference.cpp @@ -26,10 +26,10 @@ #include "config.h" #include "StringReference.h" -#include "ArgumentDecoder.h" -#include "ArgumentEncoder.h" #include "DataReference.h" -#include <wtf/StringHasher.h> +#include "Decoder.h" +#include "Encoder.h" +#include <wtf/Hasher.h> #include <wtf/text/CString.h> namespace IPC { @@ -39,12 +39,12 @@ CString StringReference::toString() const return WTF::CString(m_data, m_size); } -void StringReference::encode(ArgumentEncoder& encoder) const +void StringReference::encode(Encoder& encoder) const { encoder << DataReference(reinterpret_cast<const uint8_t*>(m_data), m_size); } -bool StringReference::decode(ArgumentDecoder& decoder, StringReference& result) +bool StringReference::decode(Decoder& decoder, StringReference& result) { DataReference dataReference; if (!decoder.decode(dataReference)) diff --git a/Source/WebKit2/Platform/IPC/StringReference.h b/Source/WebKit2/Platform/IPC/StringReference.h index 3403bbc84..e98e91119 100644 --- a/Source/WebKit2/Platform/IPC/StringReference.h +++ b/Source/WebKit2/Platform/IPC/StringReference.h @@ -32,8 +32,8 @@ namespace IPC { -class ArgumentEncoder; -class ArgumentDecoder; +class Encoder; +class Decoder; class StringReference { public: @@ -68,8 +68,8 @@ public: return a.m_size == b.m_size && !memcmp(a.m_data, b.m_data, a.m_size); } - void encode(ArgumentEncoder&) const; - static bool decode(ArgumentDecoder&, StringReference&); + void encode(Encoder&) const; + static bool decode(Decoder&, StringReference&); struct Hash { static unsigned hash(const StringReference& a); diff --git a/Source/WebKit2/Platform/IPC/MessageDecoder.cpp b/Source/WebKit2/Platform/IPC/glib/GSocketMonitor.cpp index 5dfda2194..14329b938 100644 --- a/Source/WebKit2/Platform/IPC/MessageDecoder.cpp +++ b/Source/WebKit2/Platform/IPC/glib/GSocketMonitor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2015 Igalia S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,53 +24,46 @@ */ #include "config.h" -#include "MessageDecoder.h" +#include "GSocketMonitor.h" -#include "ArgumentCoders.h" -#include "DataReference.h" -#include "MessageFlags.h" -#include "StringReference.h" - -#if PLATFORM(IOS) || PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 -#include "ImportanceAssertion.h" -#endif +#include <gio/gio.h> namespace IPC { -MessageDecoder::~MessageDecoder() +GSocketMonitor::~GSocketMonitor() { + stop(); } -MessageDecoder::MessageDecoder(const DataReference& buffer, Vector<Attachment> attachments) - : ArgumentDecoder(buffer.data(), buffer.size(), attachments) +gboolean GSocketMonitor::socketSourceCallback(GSocket*, GIOCondition condition, GSocketMonitor* monitor) { - if (!decode(m_messageFlags)) - return; - - if (!decode(m_messageReceiverName)) - return; - - if (!decode(m_messageName)) - return; - - decode(m_destinationID); + if (g_cancellable_is_cancelled(monitor->m_cancellable.get())) + return G_SOURCE_REMOVE; + return monitor->m_callback(condition); } -bool MessageDecoder::isSyncMessage() const +void GSocketMonitor::start(GSocket* socket, GIOCondition condition, RunLoop& runLoop, Function<gboolean (GIOCondition)>&& callback) { - return m_messageFlags & SyncMessage; -} + stop(); -bool MessageDecoder::shouldDispatchMessageWhenWaitingForSyncReply() const -{ - return m_messageFlags & DispatchMessageWhenWaitingForSyncReply; + m_cancellable = adoptGRef(g_cancellable_new()); + m_source = adoptGRef(g_socket_create_source(socket, condition, m_cancellable.get())); + g_source_set_name(m_source.get(), "[WebKit] Socket monitor"); + m_callback = WTFMove(callback); + g_source_set_callback(m_source.get(), reinterpret_cast<GSourceFunc>(socketSourceCallback), this, nullptr); + g_source_attach(m_source.get(), runLoop.mainContext()); } -#if PLATFORM(IOS) || PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 -void MessageDecoder::setImportanceAssertion(std::unique_ptr<ImportanceAssertion> assertion) +void GSocketMonitor::stop() { - m_importanceAssertion = std::move(assertion); + if (!m_source) + return; + + g_cancellable_cancel(m_cancellable.get()); + m_cancellable = nullptr; + g_source_destroy(m_source.get()); + m_source = nullptr; + m_callback = nullptr; } -#endif } // namespace IPC diff --git a/Source/WebKit2/Platform/IPC/MessageEncoder.h b/Source/WebKit2/Platform/IPC/glib/GSocketMonitor.h index 524e5e1d4..ff37bf9e5 100644 --- a/Source/WebKit2/Platform/IPC/MessageEncoder.h +++ b/Source/WebKit2/Platform/IPC/glib/GSocketMonitor.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2015 Igalia S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,25 +23,37 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MessageEncoder_h -#define MessageEncoder_h +#ifndef GSocketMonitor_h +#define GSocketMonitor_h -#include "ArgumentEncoder.h" +#include <functional> +#include <glib.h> #include <wtf/Forward.h> +#include <wtf/Noncopyable.h> +#include <wtf/RunLoop.h> +#include <wtf/glib/GRefPtr.h> -namespace IPC { +typedef struct _GSocket GSocket; -class StringReference; +namespace IPC { -class MessageEncoder : public ArgumentEncoder { +class GSocketMonitor { + WTF_MAKE_NONCOPYABLE(GSocketMonitor); public: - MessageEncoder(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID); - virtual ~MessageEncoder(); + GSocketMonitor() = default; + ~GSocketMonitor(); + + void start(GSocket*, GIOCondition, RunLoop&, Function<gboolean (GIOCondition)>&&); + void stop(); + +private: + static gboolean socketSourceCallback(GSocket*, GIOCondition, GSocketMonitor*); - void setIsSyncMessage(bool); - void setShouldDispatchMessageWhenWaitingForSyncReply(bool); + GRefPtr<GSource> m_source; + GRefPtr<GCancellable> m_cancellable; + Function<gboolean (GIOCondition)> m_callback; }; } // namespace IPC -#endif // MessageEncoder_h +#endif // GSocketMonitor_h diff --git a/Source/WebKit2/Platform/IPC/unix/AttachmentUnix.cpp b/Source/WebKit2/Platform/IPC/unix/AttachmentUnix.cpp index 022c72d41..218711645 100644 --- a/Source/WebKit2/Platform/IPC/unix/AttachmentUnix.cpp +++ b/Source/WebKit2/Platform/IPC/unix/AttachmentUnix.cpp @@ -45,7 +45,29 @@ Attachment::Attachment(int fileDescriptor) { } -void Attachment::dispose() +Attachment::Attachment(Attachment&& attachment) + : m_type(attachment.m_type) + , m_fileDescriptor(attachment.m_fileDescriptor) + , m_size(attachment.m_size) +{ + attachment.m_type = Uninitialized; + attachment.m_fileDescriptor = -1; + attachment.m_size = 0; +} + +Attachment& Attachment::operator=(Attachment&& attachment) +{ + m_type = attachment.m_type; + attachment.m_type = Uninitialized; + m_fileDescriptor = attachment.m_fileDescriptor; + attachment.m_fileDescriptor = -1; + m_size = attachment.m_size; + attachment.m_size = 0; + + return *this; +} + +Attachment::~Attachment() { if (m_fileDescriptor != -1) closeWithRetry(m_fileDescriptor); diff --git a/Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp b/Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp index dbadd26a3..7d564a449 100644 --- a/Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp +++ b/Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp @@ -30,21 +30,23 @@ #include "DataReference.h" #include "SharedMemory.h" +#include "UnixMessage.h" #include <sys/socket.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <poll.h> #include <wtf/Assertions.h> -#include <wtf/Functional.h> #include <wtf/StdLibExtras.h> #include <wtf/UniStdExtras.h> #if PLATFORM(GTK) -#include <glib.h> +#include <gio/gio.h> #endif -#ifdef SOCK_SEQPACKET +// Although it's available on Darwin, SOCK_SEQPACKET seems to work differently +// than in traditional Unix so fallback to STREAM on that platform. +#if defined(SOCK_SEQPACKET) && !OS(DARWIN) #define SOCKET_TYPE SOCK_SEQPACKET #else #if PLATFORM(GTK) @@ -59,59 +61,20 @@ namespace IPC { static const size_t messageMaxSize = 4096; static const size_t attachmentMaxAmount = 255; -enum { - MessageBodyIsOutOfLine = 1U << 31 -}; - -class MessageInfo { -public: - MessageInfo() { } - - MessageInfo(size_t bodySize, size_t initialAttachmentCount) - : m_bodySize(bodySize) - , m_attachmentCount(initialAttachmentCount) - , m_isMessageBodyOutOfLine(false) - { - } - - void setMessageBodyIsOutOfLine() - { - ASSERT(!isMessageBodyIsOutOfLine()); - - m_isMessageBodyOutOfLine = true; - m_attachmentCount++; - } - - bool isMessageBodyIsOutOfLine() const { return m_isMessageBodyOutOfLine; } - - size_t bodySize() const { return m_bodySize; } - - size_t attachmentCount() const { return m_attachmentCount; } - -private: - size_t m_bodySize; - size_t m_attachmentCount; - bool m_isMessageBodyOutOfLine; -}; - class AttachmentInfo { + WTF_MAKE_FAST_ALLOCATED; public: - AttachmentInfo() - : m_type(Attachment::Uninitialized) - , m_size(0) - , m_isNull(false) - { - } + AttachmentInfo() = default; void setType(Attachment::Type type) { m_type = type; } - Attachment::Type getType() { return m_type; } + Attachment::Type type() const { return m_type; } void setSize(size_t size) { ASSERT(m_type == Attachment::MappedMemoryType); m_size = size; } - size_t getSize() + size_t size() const { ASSERT(m_type == Attachment::MappedMemoryType); return m_size; @@ -119,27 +82,30 @@ public: // The attachment is not null unless explicitly set. void setNull() { m_isNull = true; } - bool isNull() { return m_isNull; } + bool isNull() const { return m_isNull; } private: - Attachment::Type m_type; - size_t m_size; - bool m_isNull; + Attachment::Type m_type { Attachment::Uninitialized }; + size_t m_size { 0 }; + bool m_isNull { false }; }; void Connection::platformInitialize(Identifier identifier) { m_socketDescriptor = identifier; - m_readBuffer.resize(messageMaxSize); - m_readBufferSize = 0; - m_fileDescriptors.resize(attachmentMaxAmount); - m_fileDescriptorsSize = 0; +#if PLATFORM(GTK) + m_socket = adoptGRef(g_socket_new_from_fd(m_socketDescriptor, nullptr)); +#endif + m_readBuffer.reserveInitialCapacity(messageMaxSize); + m_fileDescriptors.reserveInitialCapacity(attachmentMaxAmount); } void Connection::platformInvalidate() { - // In GTK+ platform the socket is closed by the work queue. -#if !PLATFORM(GTK) +#if PLATFORM(GTK) + // In GTK+ platform the socket descriptor is owned by GSocket. + m_socket = nullptr; +#else if (m_socketDescriptor != -1) closeWithRetry(m_socketDescriptor); #endif @@ -147,34 +113,18 @@ void Connection::platformInvalidate() if (!m_isConnected) return; -#if PLATFORM(GTK) || PLATFORM(EFL) - m_connectionQueue->unregisterSocketEventHandler(m_socketDescriptor); +#if PLATFORM(GTK) + m_readSocketMonitor.stop(); + m_writeSocketMonitor.stop(); #endif m_socketDescriptor = -1; m_isConnected = false; } -template<class T, class iterator> -class AttachmentResourceGuard { -public: - AttachmentResourceGuard(T& attachments) - : m_attachments(attachments) - { - } - ~AttachmentResourceGuard() - { - iterator end = m_attachments.end(); - for (iterator i = m_attachments.begin(); i != end; ++i) - i->dispose(); - } -private: - T& m_attachments; -}; - bool Connection::processMessage() { - if (m_readBufferSize < sizeof(MessageInfo)) + if (m_readBuffer.size() < sizeof(MessageInfo)) return false; uint8_t* messageData = m_readBuffer.data(); @@ -182,8 +132,13 @@ bool Connection::processMessage() memcpy(&messageInfo, messageData, sizeof(messageInfo)); messageData += sizeof(messageInfo); - size_t messageLength = sizeof(MessageInfo) + messageInfo.attachmentCount() * sizeof(AttachmentInfo) + (messageInfo.isMessageBodyIsOutOfLine() ? 0 : messageInfo.bodySize()); - if (m_readBufferSize < messageLength) + if (messageInfo.attachmentCount() > attachmentMaxAmount || (!messageInfo.isBodyOutOfLine() && messageInfo.bodySize() > messageMaxSize)) { + ASSERT_NOT_REACHED(); + return false; + } + + size_t messageLength = sizeof(MessageInfo) + messageInfo.attachmentCount() * sizeof(AttachmentInfo) + (messageInfo.isBodyOutOfLine() ? 0 : messageInfo.bodySize()); + if (m_readBuffer.size() < messageLength) return false; size_t attachmentFileDescriptorCount = 0; @@ -196,7 +151,7 @@ bool Connection::processMessage() messageData += sizeof(AttachmentInfo) * attachmentCount; for (size_t i = 0; i < attachmentCount; ++i) { - switch (attachmentInfo[i].getType()) { + switch (attachmentInfo[i].type()) { case Attachment::MappedMemoryType: case Attachment::SocketType: if (!attachmentInfo[i].isNull()) @@ -204,27 +159,25 @@ bool Connection::processMessage() break; case Attachment::Uninitialized: default: - ASSERT_NOT_REACHED(); break; } } - if (messageInfo.isMessageBodyIsOutOfLine()) + if (messageInfo.isBodyOutOfLine()) attachmentCount--; } Vector<Attachment> attachments(attachmentCount); - AttachmentResourceGuard<Vector<Attachment>, Vector<Attachment>::iterator> attachementDisposer(attachments); RefPtr<WebKit::SharedMemory> oolMessageBody; size_t fdIndex = 0; for (size_t i = 0; i < attachmentCount; ++i) { int fd = -1; - switch (attachmentInfo[i].getType()) { + switch (attachmentInfo[i].type()) { case Attachment::MappedMemoryType: if (!attachmentInfo[i].isNull()) fd = m_fileDescriptors[fdIndex++]; - attachments[attachmentCount - i - 1] = Attachment(fd, attachmentInfo[i].getSize()); + attachments[attachmentCount - i - 1] = Attachment(fd, attachmentInfo[i].size()); break; case Attachment::SocketType: if (!attachmentInfo[i].isNull()) @@ -238,54 +191,53 @@ bool Connection::processMessage() } } - if (messageInfo.isMessageBodyIsOutOfLine()) { + if (messageInfo.isBodyOutOfLine()) { ASSERT(messageInfo.bodySize()); - if (attachmentInfo[attachmentCount].isNull()) { + if (attachmentInfo[attachmentCount].isNull() || attachmentInfo[attachmentCount].size() != messageInfo.bodySize()) { ASSERT_NOT_REACHED(); return false; } WebKit::SharedMemory::Handle handle; - handle.adoptFromAttachment(m_fileDescriptors[attachmentFileDescriptorCount - 1], attachmentInfo[attachmentCount].getSize()); + handle.adoptAttachment(IPC::Attachment(m_fileDescriptors[attachmentFileDescriptorCount - 1], attachmentInfo[attachmentCount].size())); - oolMessageBody = WebKit::SharedMemory::create(handle, WebKit::SharedMemory::ReadOnly); + oolMessageBody = WebKit::SharedMemory::map(handle, WebKit::SharedMemory::Protection::ReadOnly); if (!oolMessageBody) { ASSERT_NOT_REACHED(); return false; } } - ASSERT(attachments.size() == (messageInfo.isMessageBodyIsOutOfLine() ? messageInfo.attachmentCount() - 1 : messageInfo.attachmentCount())); + ASSERT(attachments.size() == (messageInfo.isBodyOutOfLine() ? messageInfo.attachmentCount() - 1 : messageInfo.attachmentCount())); uint8_t* messageBody = messageData; - if (messageInfo.isMessageBodyIsOutOfLine()) + if (messageInfo.isBodyOutOfLine()) messageBody = reinterpret_cast<uint8_t*>(oolMessageBody->data()); - auto decoder = std::make_unique<MessageDecoder>(DataReference(messageBody, messageInfo.bodySize()), std::move(attachments)); + auto decoder = std::make_unique<Decoder>(messageBody, messageInfo.bodySize(), nullptr, WTFMove(attachments)); - processIncomingMessage(std::move(decoder)); + processIncomingMessage(WTFMove(decoder)); - if (m_readBufferSize > messageLength) { - memmove(m_readBuffer.data(), m_readBuffer.data() + messageLength, m_readBufferSize - messageLength); - m_readBufferSize -= messageLength; + if (m_readBuffer.size() > messageLength) { + memmove(m_readBuffer.data(), m_readBuffer.data() + messageLength, m_readBuffer.size() - messageLength); + m_readBuffer.shrink(m_readBuffer.size() - messageLength); } else - m_readBufferSize = 0; + m_readBuffer.shrink(0); if (attachmentFileDescriptorCount) { - if (m_fileDescriptorsSize > attachmentFileDescriptorCount) { - size_t fileDescriptorsLength = attachmentFileDescriptorCount * sizeof(int); - memmove(m_fileDescriptors.data(), m_fileDescriptors.data() + fileDescriptorsLength, m_fileDescriptorsSize - fileDescriptorsLength); - m_fileDescriptorsSize -= fileDescriptorsLength; + if (m_fileDescriptors.size() > attachmentFileDescriptorCount) { + memmove(m_fileDescriptors.data(), m_fileDescriptors.data() + attachmentFileDescriptorCount, (m_fileDescriptors.size() - attachmentFileDescriptorCount) * sizeof(int)); + m_fileDescriptors.shrink(m_fileDescriptors.size() - attachmentFileDescriptorCount); } else - m_fileDescriptorsSize = 0; + m_fileDescriptors.shrink(0); } return true; } -static ssize_t readBytesFromSocket(int socketDescriptor, uint8_t* buffer, int count, int* fileDescriptors, size_t* fileDescriptorsCount) +static ssize_t readBytesFromSocket(int socketDescriptor, Vector<uint8_t>& buffer, Vector<int>& fileDescriptors) { struct msghdr message; memset(&message, 0, sizeof(message)); @@ -294,12 +246,14 @@ static ssize_t readBytesFromSocket(int socketDescriptor, uint8_t* buffer, int co memset(&iov, 0, sizeof(iov)); message.msg_controllen = CMSG_SPACE(sizeof(int) * attachmentMaxAmount); - auto attachmentDescriptorBuffer = std::make_unique<char[]>(message.msg_controllen); - memset(attachmentDescriptorBuffer.get(), 0, message.msg_controllen); + MallocPtr<char> attachmentDescriptorBuffer = MallocPtr<char>::malloc(sizeof(char) * message.msg_controllen); + memset(attachmentDescriptorBuffer.get(), 0, sizeof(char) * message.msg_controllen); message.msg_control = attachmentDescriptorBuffer.get(); - iov[0].iov_base = buffer; - iov[0].iov_len = count; + size_t previousBufferSize = buffer.size(); + buffer.grow(buffer.capacity()); + iov[0].iov_base = buffer.data() + previousBufferSize; + iov[0].iov_len = buffer.size() - previousBufferSize; message.msg_iov = iov; message.msg_iovlen = 1; @@ -311,33 +265,33 @@ static ssize_t readBytesFromSocket(int socketDescriptor, uint8_t* buffer, int co if (errno == EINTR) continue; + buffer.shrink(previousBufferSize); return -1; } - bool found = false; struct cmsghdr* controlMessage; for (controlMessage = CMSG_FIRSTHDR(&message); controlMessage; controlMessage = CMSG_NXTHDR(&message, controlMessage)) { if (controlMessage->cmsg_level == SOL_SOCKET && controlMessage->cmsg_type == SCM_RIGHTS) { - *fileDescriptorsCount = (controlMessage->cmsg_len - CMSG_LEN(0)) / sizeof(int); - memcpy(fileDescriptors, CMSG_DATA(controlMessage), sizeof(int) * *fileDescriptorsCount); - - for (size_t i = 0; i < *fileDescriptorsCount; ++i) { - while (fcntl(fileDescriptors[i], F_SETFD, FD_CLOEXEC) == -1) { - if (errno != EINTR) { - ASSERT_NOT_REACHED(); - break; - } + if (controlMessage->cmsg_len < CMSG_LEN(0) || controlMessage->cmsg_len > attachmentMaxAmount) { + ASSERT_NOT_REACHED(); + break; + } + size_t previousFileDescriptorsSize = fileDescriptors.size(); + size_t fileDescriptorsCount = (controlMessage->cmsg_len - CMSG_LEN(0)) / sizeof(int); + fileDescriptors.grow(fileDescriptors.size() + fileDescriptorsCount); + memcpy(fileDescriptors.data() + previousFileDescriptorsSize, CMSG_DATA(controlMessage), sizeof(int) * fileDescriptorsCount); + + for (size_t i = 0; i < fileDescriptorsCount; ++i) { + if (!setCloseOnExec(fileDescriptors[previousFileDescriptorsSize + i])) { + ASSERT_NOT_REACHED(); + break; } } - - found = true; break; } } - if (!found) - *fileDescriptorsCount = 0; - + buffer.shrink(previousBufferSize + bytesRead); return bytesRead; } @@ -347,24 +301,20 @@ static ssize_t readBytesFromSocket(int socketDescriptor, uint8_t* buffer, int co void Connection::readyReadHandler() { while (true) { - size_t fileDescriptorsCount = 0; - size_t bytesToRead = m_readBuffer.size() - m_readBufferSize; - ssize_t bytesRead = readBytesFromSocket(m_socketDescriptor, m_readBuffer.data() + m_readBufferSize, bytesToRead, - m_fileDescriptors.data() + m_fileDescriptorsSize, &fileDescriptorsCount); + ssize_t bytesRead = readBytesFromSocket(m_socketDescriptor, m_readBuffer, m_fileDescriptors); if (bytesRead < 0) { // EINTR was already handled by readBytesFromSocket. if (errno == EAGAIN || errno == EWOULDBLOCK) return; - WTFLogAlways("Error receiving IPC message on socket %d in process %d: %s", m_socketDescriptor, getpid(), strerror(errno)); - connectionDidClose(); + if (m_isConnected) { + WTFLogAlways("Error receiving IPC message on socket %d in process %d: %s", m_socketDescriptor, getpid(), strerror(errno)); + connectionDidClose(); + } return; } - m_readBufferSize += bytesRead; - m_fileDescriptorsSize += fileDescriptorsCount; - if (!bytesRead) { connectionDidClose(); return; @@ -388,66 +338,73 @@ bool Connection::open() } } + RefPtr<Connection> protectedThis(this); m_isConnected = true; #if PLATFORM(GTK) - RefPtr<Connection> protector(this); - m_connectionQueue->registerSocketEventHandler(m_socketDescriptor, - [=] { - protector->readyReadHandler(); - }, - [=] { - protector->connectionDidClose(); - }); -#elif PLATFORM(EFL) - RefPtr<Connection> protector(this); - m_connectionQueue->registerSocketEventHandler(m_socketDescriptor, - [protector] { - protector->readyReadHandler(); - }); + m_readSocketMonitor.start(m_socket.get(), G_IO_IN, m_connectionQueue->runLoop(), [protectedThis] (GIOCondition condition) -> gboolean { + if (condition & G_IO_HUP || condition & G_IO_ERR || condition & G_IO_NVAL) { + protectedThis->connectionDidClose(); + return G_SOURCE_REMOVE; + } + + if (condition & G_IO_IN) { + protectedThis->readyReadHandler(); + return G_SOURCE_CONTINUE; + } + + ASSERT_NOT_REACHED(); + return G_SOURCE_REMOVE; + }); #endif - // Schedule a call to readyReadHandler. Data may have arrived before installation of the signal - // handler. - m_connectionQueue->dispatch(WTF::bind(&Connection::readyReadHandler, this)); + // Schedule a call to readyReadHandler. Data may have arrived before installation of the signal handler. + m_connectionQueue->dispatch([protectedThis] { + protectedThis->readyReadHandler(); + }); return true; } bool Connection::platformCanSendOutgoingMessages() const { - return m_isConnected; + return !m_pendingOutputMessage; } -bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder) +bool Connection::sendOutgoingMessage(std::unique_ptr<Encoder> encoder) { COMPILE_ASSERT(sizeof(MessageInfo) + attachmentMaxAmount * sizeof(size_t) <= messageMaxSize, AttachmentsFitToMessageInline); - Vector<Attachment> attachments = encoder->releaseAttachments(); - AttachmentResourceGuard<Vector<Attachment>, Vector<Attachment>::iterator> attachementDisposer(attachments); - - if (attachments.size() > (attachmentMaxAmount - 1)) { + UnixMessage outputMessage(*encoder); + if (outputMessage.attachments().size() > (attachmentMaxAmount - 1)) { ASSERT_NOT_REACHED(); return false; } - MessageInfo messageInfo(encoder->bufferSize(), attachments.size()); - size_t messageSizeWithBodyInline = sizeof(messageInfo) + (attachments.size() * sizeof(AttachmentInfo)) + encoder->bufferSize(); - if (messageSizeWithBodyInline > messageMaxSize && encoder->bufferSize()) { - RefPtr<WebKit::SharedMemory> oolMessageBody = WebKit::SharedMemory::create(encoder->bufferSize()); + size_t messageSizeWithBodyInline = sizeof(MessageInfo) + (outputMessage.attachments().size() * sizeof(AttachmentInfo)) + outputMessage.bodySize(); + if (messageSizeWithBodyInline > messageMaxSize && outputMessage.bodySize()) { + RefPtr<WebKit::SharedMemory> oolMessageBody = WebKit::SharedMemory::allocate(encoder->bufferSize()); if (!oolMessageBody) return false; WebKit::SharedMemory::Handle handle; - if (!oolMessageBody->createHandle(handle, WebKit::SharedMemory::ReadOnly)) + if (!oolMessageBody->createHandle(handle, WebKit::SharedMemory::Protection::ReadOnly)) return false; - messageInfo.setMessageBodyIsOutOfLine(); + outputMessage.messageInfo().setBodyOutOfLine(); - memcpy(oolMessageBody->data(), encoder->buffer(), encoder->bufferSize()); + memcpy(oolMessageBody->data(), outputMessage.body(), outputMessage.bodySize()); - attachments.append(handle.releaseToAttachment()); + outputMessage.appendAttachment(handle.releaseAttachment()); } + return sendOutputMessage(outputMessage); +} + +bool Connection::sendOutputMessage(UnixMessage& outputMessage) +{ + ASSERT(!m_pendingOutputMessage); + + auto& messageInfo = outputMessage.messageInfo(); struct msghdr message; memset(&message, 0, sizeof(message)); @@ -460,21 +417,21 @@ bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder) iov[0].iov_base = reinterpret_cast<void*>(&messageInfo); iov[0].iov_len = sizeof(messageInfo); - auto attachmentInfo = std::make_unique<AttachmentInfo[]>(attachments.size()); - - size_t attachmentFDBufferLength = 0; - if (!attachments.isEmpty()) { - for (size_t i = 0; i < attachments.size(); ++i) { - if (attachments[i].fileDescriptor() != -1) - attachmentFDBufferLength++; - } - } - auto attachmentFDBuffer = std::make_unique<char[]>(CMSG_SPACE(sizeof(int) * attachmentFDBufferLength)); + std::unique_ptr<AttachmentInfo[]> attachmentInfo; + MallocPtr<char> attachmentFDBuffer; + auto& attachments = outputMessage.attachments(); if (!attachments.isEmpty()) { int* fdPtr = 0; + size_t attachmentFDBufferLength = std::count_if(attachments.begin(), attachments.end(), + [](const Attachment& attachment) { + return attachment.fileDescriptor() != -1; + }); + if (attachmentFDBufferLength) { + attachmentFDBuffer = MallocPtr<char>::malloc(sizeof(char) * CMSG_SPACE(sizeof(int) * attachmentFDBufferLength)); + message.msg_control = attachmentFDBuffer.get(); message.msg_controllen = CMSG_SPACE(sizeof(int) * attachmentFDBufferLength); memset(message.msg_control, 0, message.msg_controllen); @@ -487,6 +444,7 @@ bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder) fdPtr = reinterpret_cast<int*>(CMSG_DATA(cmsg)); } + attachmentInfo = std::make_unique<AttachmentInfo[]>(attachments.size()); int fdIndex = 0; for (size_t i = 0; i < attachments.size(); ++i) { attachmentInfo[i].setType(attachments[i].type()); @@ -513,19 +471,37 @@ bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder) ++iovLength; } - if (!messageInfo.isMessageBodyIsOutOfLine() && encoder->bufferSize()) { - iov[iovLength].iov_base = reinterpret_cast<void*>(encoder->buffer()); - iov[iovLength].iov_len = encoder->bufferSize(); + if (!messageInfo.isBodyOutOfLine() && outputMessage.bodySize()) { + iov[iovLength].iov_base = reinterpret_cast<void*>(outputMessage.body()); + iov[iovLength].iov_len = outputMessage.bodySize(); ++iovLength; } message.msg_iovlen = iovLength; - int bytesSent = 0; - while ((bytesSent = sendmsg(m_socketDescriptor, &message, 0)) == -1) { + while (sendmsg(m_socketDescriptor, &message, 0) == -1) { if (errno == EINTR) continue; if (errno == EAGAIN || errno == EWOULDBLOCK) { +#if PLATFORM(GTK) + m_pendingOutputMessage = std::make_unique<UnixMessage>(WTFMove(outputMessage)); + m_writeSocketMonitor.start(m_socket.get(), G_IO_OUT, m_connectionQueue->runLoop(), [this, protectedThis = makeRef(*this)] (GIOCondition condition) -> gboolean { + if (condition & G_IO_OUT) { + ASSERT(m_pendingOutputMessage); + // We can't stop the monitor from this lambda, because stop destroys the lambda. + m_connectionQueue->dispatch([this, protectedThis = makeRef(*this)] { + m_writeSocketMonitor.stop(); + auto message = WTFMove(m_pendingOutputMessage); + if (m_isConnected) { + sendOutputMessage(*message); + sendOutgoingMessages(); + } + }); + } + return G_SOURCE_REMOVE; + }); + return false; +#else struct pollfd pollfd; pollfd.fd = m_socketDescriptor; @@ -533,9 +509,11 @@ bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder) pollfd.revents = 0; poll(&pollfd, 1, -1); continue; +#endif } - WTFLogAlways("Error sending IPC message: %s", strerror(errno)); + if (m_isConnected) + WTFLogAlways("Error sending IPC message: %s", strerror(errno)); return false; } return true; @@ -548,18 +526,26 @@ Connection::SocketPair Connection::createPlatformConnection(unsigned options) if (options & SetCloexecOnServer) { // Don't expose the child socket to the parent process. - while (fcntl(sockets[1], F_SETFD, FD_CLOEXEC) == -1) - RELEASE_ASSERT(errno != EINTR); + if (!setCloseOnExec(sockets[1])) + RELEASE_ASSERT_NOT_REACHED(); } if (options & SetCloexecOnClient) { // Don't expose the parent socket to potential future children. - while (fcntl(sockets[0], F_SETFD, FD_CLOEXEC) == -1) - RELEASE_ASSERT(errno != EINTR); + if (!setCloseOnExec(sockets[0])) + RELEASE_ASSERT_NOT_REACHED(); } SocketPair socketPair = { sockets[0], sockets[1] }; return socketPair; } +void Connection::willSendSyncMessage(OptionSet<SendSyncOption>) +{ +} + +void Connection::didReceiveSyncReply(OptionSet<SendSyncOption>) +{ +} + } // namespace IPC diff --git a/Source/WebKit2/Platform/IPC/unix/UnixMessage.h b/Source/WebKit2/Platform/IPC/unix/UnixMessage.h new file mode 100644 index 000000000..6e98a7374 --- /dev/null +++ b/Source/WebKit2/Platform/IPC/unix/UnixMessage.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2011,2017 Igalia S.L. + * + * 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. + */ + +#pragma once + +#include "Attachment.h" +#include <wtf/Vector.h> + +namespace IPC { + +class MessageInfo { +public: + MessageInfo() = default; + + MessageInfo(size_t bodySize, size_t initialAttachmentCount) + : m_bodySize(bodySize) + , m_attachmentCount(initialAttachmentCount) + { + } + + void setBodyOutOfLine() + { + ASSERT(!isBodyOutOfLine()); + + m_isBodyOutOfLine = true; + m_attachmentCount++; + } + + bool isBodyOutOfLine() const { return m_isBodyOutOfLine; } + size_t bodySize() const { return m_bodySize; } + size_t attachmentCount() const { return m_attachmentCount; } + +private: + size_t m_bodySize { 0 }; + size_t m_attachmentCount { 0 }; + bool m_isBodyOutOfLine { false }; +}; + +class UnixMessage { + WTF_MAKE_FAST_ALLOCATED; +public: + UnixMessage(Encoder& encoder) + : m_attachments(encoder.releaseAttachments()) + , m_messageInfo(encoder.bufferSize(), m_attachments.size()) + , m_body(encoder.buffer()) + { + } + + UnixMessage(UnixMessage&& other) + { + m_attachments = WTFMove(other.m_attachments); + m_messageInfo = WTFMove(other.m_messageInfo); + if (other.m_bodyOwned) { + std::swap(m_body, other.m_body); + std::swap(m_bodyOwned, other.m_bodyOwned); + } else if (!m_messageInfo.isBodyOutOfLine()) { + m_body = static_cast<uint8_t*>(fastMalloc(m_messageInfo.bodySize())); + memcpy(m_body, other.m_body, m_messageInfo.bodySize()); + m_bodyOwned = true; + other.m_body = nullptr; + other.m_bodyOwned = false; + } + } + + ~UnixMessage() + { + if (m_bodyOwned) + fastFree(m_body); + } + + const Vector<Attachment>& attachments() const { return m_attachments; } + MessageInfo& messageInfo() { return m_messageInfo; } + + uint8_t* body() const { return m_body; } + size_t bodySize() const { return m_messageInfo.bodySize(); } + + void appendAttachment(Attachment&& attachment) + { + m_attachments.append(WTFMove(attachment)); + } + +private: + Vector<Attachment> m_attachments; + MessageInfo m_messageInfo; + uint8_t* m_body { nullptr }; + bool m_bodyOwned { false }; +}; + +} // namespace IPC diff --git a/Source/WebKit2/Platform/WorkQueue.cpp b/Source/WebKit2/Platform/LogInitialization.h index 184825c27..c55b6cae1 100644 --- a/Source/WebKit2/Platform/WorkQueue.cpp +++ b/Source/WebKit2/Platform/LogInitialization.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2013, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,20 +23,17 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#include "WorkQueue.h" +#pragma once -PassRefPtr<WorkQueue> WorkQueue::create(const char* name) -{ - return adoptRef(new WorkQueue(name)); -} +#include <wtf/text/WTFString.h> -WorkQueue::WorkQueue(const char* name) -{ - platformInitialize(name); -} +#if !LOG_DISABLED || !RELEASE_LOG_DISABLED -WorkQueue::~WorkQueue() -{ - platformInvalidate(); -} +namespace WebKit { + +void initializeLogChannelsIfNecessary(void); +String logLevelString(); + +} // namespace WebKit + +#endif // !LOG_DISABLED || !RELEASE_LOG_DISABLED diff --git a/Source/WebKit2/Platform/Logging.cpp b/Source/WebKit2/Platform/Logging.cpp index a26beadc4..7da0f1f53 100644 --- a/Source/WebKit2/Platform/Logging.cpp +++ b/Source/WebKit2/Platform/Logging.cpp @@ -26,31 +26,25 @@ #include "config.h" #include "Logging.h" +#include "LogInitialization.h" #include <wtf/text/CString.h> -#if !LOG_DISABLED +#if !LOG_DISABLED || !RELEASE_LOG_DISABLED -namespace WebKit { - -#define DEFINE_LOG_CHANNEL(name) \ - WTFLogChannel JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, name) = { WTFLogChannelOff, #name }; -WEBKIT2_LOG_CHANNELS(DEFINE_LOG_CHANNEL) +#define DEFINE_WEBKIT2_LOG_CHANNEL(name) DEFINE_LOG_CHANNEL(name, LOG_CHANNEL_WEBKIT_SUBSYSTEM) +WEBKIT2_LOG_CHANNELS(DEFINE_WEBKIT2_LOG_CHANNEL) -#define LOG_CHANNEL_ADDRESS(name) &JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, name), static WTFLogChannel* logChannels[] = { WEBKIT2_LOG_CHANNELS(LOG_CHANNEL_ADDRESS) }; -const size_t logChannelCount = WTF_ARRAY_LENGTH(logChannels); +namespace WebKit { + +static const size_t logChannelCount = WTF_ARRAY_LENGTH(logChannels); void initializeLogChannelsIfNecessary() { - static bool haveInitializedLogChannels = false; - if (haveInitializedLogChannels) - return; - haveInitializedLogChannels = true; - static bool haveInitializedLoggingChannels = false; if (haveInitializedLoggingChannels) return; @@ -59,21 +53,6 @@ void initializeLogChannelsIfNecessary() WTFInitializeLogChannelStatesFromString(logChannels, logChannelCount, logLevelString().utf8().data()); } -#if PLATFORM(GTK) || PLATFORM(EFL) -WTFLogChannel* logChannelByName(const String& name) -{ - return WTFLogChannelByName(logChannels, logChannelCount, name.utf8().data()); -} -#endif - -#if !PLATFORM(MAC) && !PLATFORM(GTK) && !PLATFORM(EFL) -String logLevelString() -{ - // FIXME: Each platform will need to define their own logLevelString(); - return emptyString(); -} -#endif - } // namespace WebKit -#endif // !LOG_DISABLED +#endif // !LOG_DISABLED || !RELEASE_LOG_DISABLED diff --git a/Source/WebKit2/Platform/Logging.h b/Source/WebKit2/Platform/Logging.h index 1d0b349f1..3d1e172a3 100644 --- a/Source/WebKit2/Platform/Logging.h +++ b/Source/WebKit2/Platform/Logging.h @@ -26,48 +26,60 @@ #ifndef WebKitLogging_h #define WebKitLogging_h +#include <WebCore/LogMacros.h> +#include <functional> #include <wtf/Assertions.h> #include <wtf/text/WTFString.h> -#if !LOG_DISABLED +#if !LOG_DISABLED || !RELEASE_LOG_DISABLED #ifndef LOG_CHANNEL_PREFIX #define LOG_CHANNEL_PREFIX WebKit2Log #endif -namespace WebKit { +#ifdef __cplusplus +extern "C" { +#endif #define WEBKIT2_LOG_CHANNELS(M) \ M(ContextMenu) \ + M(Gamepad) \ M(IconDatabase) \ + M(IDB) \ + M(IndexedDB) \ M(InspectorServer) \ + M(IPC) \ M(KeyHandling) \ + M(Layers) \ M(Network) \ + M(NetworkCache) \ + M(NetworkCacheSpeculativePreloading) \ + M(NetworkCacheStorage) \ M(NetworkScheduling) \ + M(NetworkSession) \ + M(PerformanceLogging) \ M(Plugins) \ + M(Printing) \ + M(ProcessSuspension) \ M(RemoteLayerTree) \ + M(Resize) \ + M(Selection) \ M(SessionState) \ M(StorageAPI) \ M(TextInput) \ - M(View) \ - M(IDB) \ - -#define DECLARE_LOG_CHANNEL(name) \ - extern WTFLogChannel JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, name); + M(ViewGestures) \ + M(ViewState) \ + M(VirtualMemory) \ + M(VisibleRects) \ WEBKIT2_LOG_CHANNELS(DECLARE_LOG_CHANNEL) #undef DECLARE_LOG_CHANNEL -void initializeLogChannelsIfNecessary(void); -String logLevelString(); - -#if PLATFORM(GTK) || PLATFORM(EFL) -WTFLogChannel* logChannelByName(const String&); +#ifdef __cplusplus +} #endif -} // namespace WebKit - -#endif // !LOG_DISABLED +#endif // !LOG_DISABLED || !RELEASE_LOG_DISABLED #endif // Logging_h diff --git a/Source/WebKit2/Platform/Module.cpp b/Source/WebKit2/Platform/Module.cpp index 755fc8714..45c244cda 100644 --- a/Source/WebKit2/Platform/Module.cpp +++ b/Source/WebKit2/Platform/Module.cpp @@ -30,7 +30,7 @@ namespace WebKit { Module::Module(const String& path) : m_path(path) -#if PLATFORM(MAC) && !defined(__LP64__) +#if USE(CF) && !defined(__LP64__) , m_bundleResourceMap(-1) #endif { diff --git a/Source/WebKit2/Platform/Module.h b/Source/WebKit2/Platform/Module.h index e5de8bc45..53bed92f0 100644 --- a/Source/WebKit2/Platform/Module.h +++ b/Source/WebKit2/Platform/Module.h @@ -29,7 +29,7 @@ #include <wtf/Noncopyable.h> #include <wtf/text/WTFString.h> -#if PLATFORM(MAC) +#if USE(CF) #include <wtf/RetainPtr.h> #endif @@ -37,10 +37,6 @@ typedef struct _GModule GModule; #endif -#if PLATFORM(EFL) -#include <Eina.h> -#endif - namespace WebKit { class Module { @@ -54,13 +50,13 @@ public: // live Objective-C objects whose methods come from that bundle. void unload(); -#if PLATFORM(MAC) +#if USE(CF) String bundleIdentifier() const; #endif template<typename FunctionType> FunctionType functionPointer(const char* functionName) const; -#if PLATFORM(MAC) && !defined(__LP64__) +#if USE(CF) && !defined(__LP64__) CFBundleRefNum bundleResourceMap(); #endif @@ -68,15 +64,13 @@ private: void* platformFunctionPointer(const char* functionName) const; String m_path; -#if PLATFORM(MAC) +#if USE(CF) RetainPtr<CFBundleRef> m_bundle; #if !defined(__LP64__) CFBundleRefNum m_bundleResourceMap; #endif #elif PLATFORM(GTK) GModule* m_handle; -#elif PLATFORM(EFL) - OwnPtr<Eina_Module> m_module; #endif }; diff --git a/Source/WebKit2/Platform/SharedMemory.h b/Source/WebKit2/Platform/SharedMemory.h index efa5f0074..08421ae66 100644 --- a/Source/WebKit2/Platform/SharedMemory.h +++ b/Source/WebKit2/Platform/SharedMemory.h @@ -26,25 +26,31 @@ #ifndef SharedMemory_h #define SharedMemory_h +#include <wtf/Forward.h> #include <wtf/Noncopyable.h> -#include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> -#if PLATFORM(GTK) || PLATFORM(EFL) +#if USE(UNIX_DOMAIN_SOCKETS) #include "Attachment.h" -#include <wtf/text/WTFString.h> +#include <wtf/Optional.h> #endif namespace IPC { - class ArgumentDecoder; - class ArgumentEncoder; +class Decoder; +class Encoder; } +#if OS(DARWIN) +namespace WebCore { +class MachSendRight; +} +#endif + namespace WebKit { class SharedMemory : public RefCounted<SharedMemory> { public: - enum Protection { + enum class Protection { ReadOnly, ReadWrite }; @@ -57,55 +63,62 @@ public: bool isNull() const; - void encode(IPC::ArgumentEncoder&) const; - static bool decode(IPC::ArgumentDecoder&, Handle&); + void clear(); + + void encode(IPC::Encoder&) const; + static bool decode(IPC::Decoder&, Handle&); #if USE(UNIX_DOMAIN_SOCKETS) - IPC::Attachment releaseToAttachment() const; - void adoptFromAttachment(int fileDescriptor, size_t); + IPC::Attachment releaseAttachment() const; + void adoptAttachment(IPC::Attachment&&); #endif private: friend class SharedMemory; -#if OS(DARWIN) +#if USE(UNIX_DOMAIN_SOCKETS) + mutable IPC::Attachment m_attachment; +#elif OS(DARWIN) mutable mach_port_t m_port; -#elif USE(UNIX_DOMAIN_SOCKETS) - mutable int m_fileDescriptor; -#endif size_t m_size; +#endif }; - - // 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); - - // Create a shared memory object with the given size by vm_copy'ing the given buffer. - // Will return 0 on failure. - static PassRefPtr<SharedMemory> createFromVMBuffer(void*, size_t); + static RefPtr<SharedMemory> allocate(size_t); + static RefPtr<SharedMemory> create(void*, size_t, Protection); + static RefPtr<SharedMemory> map(const Handle&, Protection); +#if USE(UNIX_DOMAIN_SOCKETS) + static RefPtr<SharedMemory> wrapMap(void*, size_t, int fileDescriptor); +#endif ~SharedMemory(); bool createHandle(Handle&, Protection); size_t size() const { return m_size; } - void* data() const { return m_data; } - - // Creates a copy-on-write copy of the first |size| bytes. - PassRefPtr<SharedMemory> createCopyOnWriteCopy(size_t) const; + void* data() const + { + ASSERT(m_data); + return m_data; + } // Return the system page size in bytes. static unsigned systemPageSize(); private: +#if OS(DARWIN) + WebCore::MachSendRight createSendRight(Protection) const; +#endif + size_t m_size; void* m_data; - bool m_shouldVMDeallocateData; +#if PLATFORM(COCOA) + Protection m_protection; +#endif -#if OS(DARWIN) +#if USE(UNIX_DOMAIN_SOCKETS) + std::optional<int> m_fileDescriptor; + bool m_isWrappingMap { false }; +#elif OS(DARWIN) mach_port_t m_port; -#elif USE(UNIX_DOMAIN_SOCKETS) - int m_fileDescriptor; #endif }; diff --git a/Source/WebKit2/Platform/WorkQueue.h b/Source/WebKit2/Platform/WorkQueue.h deleted file mode 100644 index e322f59f1..000000000 --- a/Source/WebKit2/Platform/WorkQueue.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 OS(DARWIN) -#include <dispatch/dispatch.h> -#endif - -#include <chrono> -#include <functional> -#include <wtf/Forward.h> -#include <wtf/Functional.h> -#include <wtf/HashMap.h> -#include <wtf/PassOwnPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/Threading.h> -#include <wtf/Vector.h> - -#if PLATFORM(GTK) || PLATFORM(EFL) -#include "PlatformProcessIdentifier.h" -#endif - -#if PLATFORM(GTK) -#include <wtf/gobject/GRefPtr.h> -typedef gboolean (*GSourceFunc) (gpointer data); -#elif PLATFORM(EFL) -#include <DispatchQueueEfl.h> -#endif - -class WorkQueue : public ThreadSafeRefCounted<WorkQueue> { -public: - static PassRefPtr<WorkQueue> create(const char* name); - ~WorkQueue(); - - void dispatch(std::function<void ()>); - void dispatchAfter(std::chrono::nanoseconds, std::function<void ()>); - -#if OS(DARWIN) - dispatch_queue_t dispatchQueue() const { return m_dispatchQueue; } -#elif PLATFORM(GTK) - void registerSocketEventHandler(int, std::function<void ()>, std::function<void ()>); - void unregisterSocketEventHandler(int); -#elif PLATFORM(EFL) - void registerSocketEventHandler(int, std::function<void ()>); - void unregisterSocketEventHandler(int); -#endif - -private: - explicit WorkQueue(const char* name); - - void platformInitialize(const char* name); - void platformInvalidate(); - -#if OS(DARWIN) - static void executeFunction(void*); - dispatch_queue_t m_dispatchQueue; -#elif PLATFORM(GTK) - class EventSource; - class SocketEventSource; - - static void startWorkQueueThread(WorkQueue*); - void workQueueThreadBody(); - void dispatchOnSource(GSource*, std::function<void ()>, GSourceFunc); - - ThreadIdentifier m_workQueueThread; - GRefPtr<GMainContext> m_eventContext; - Mutex m_eventLoopLock; - GRefPtr<GMainLoop> m_eventLoop; - Mutex m_eventSourcesLock; - HashMap<int, Vector<SocketEventSource*>> m_eventSources; -#elif PLATFORM(EFL) - RefPtr<DispatchQueue> m_dispatchQueue; -#endif -}; - -#endif // WorkQueue_h diff --git a/Source/WebKit2/Platform/gtk/ModuleGtk.cpp b/Source/WebKit2/Platform/glib/ModuleGlib.cpp index ef1ce112a..ef1ce112a 100644 --- a/Source/WebKit2/Platform/gtk/ModuleGtk.cpp +++ b/Source/WebKit2/Platform/glib/ModuleGlib.cpp diff --git a/Source/WebKit2/Platform/gtk/WorkQueueGtk.cpp b/Source/WebKit2/Platform/gtk/WorkQueueGtk.cpp deleted file mode 100644 index ae03c47dd..000000000 --- a/Source/WebKit2/Platform/gtk/WorkQueueGtk.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2011 Igalia S.L. - * Copyright (C) 2010 Apple Inc. All rights reserved. - * Portions Copyright (c) 2010 Motorola Mobility, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "WorkQueue.h" - -#include <gio/gio.h> -#include <glib.h> -#include <wtf/gobject/GRefPtr.h> - -// WorkQueue::EventSource -class WorkQueue::EventSource { -public: - EventSource(std::function<void()> function, WorkQueue* workQueue) - : m_function(std::move(function)) - , m_workQueue(workQueue) - { - ASSERT(workQueue); - } - - virtual ~EventSource() { } - - void performWork() - { - m_function(); - } - - static gboolean performWorkOnce(EventSource* eventSource) - { - ASSERT(eventSource); - eventSource->performWork(); - return FALSE; - } - - static void deleteEventSource(EventSource* eventSource) - { - ASSERT(eventSource); - delete eventSource; - } - -private: - std::function<void ()> m_function; - RefPtr<WorkQueue> m_workQueue; -}; - -class WorkQueue::SocketEventSource : public WorkQueue::EventSource { -public: - SocketEventSource(std::function<void ()> function, WorkQueue* workQueue, GCancellable* cancellable, std::function<void ()> closeFunction) - : EventSource(std::move(function), workQueue) - , m_cancellable(cancellable) - , m_closeFunction(std::move(closeFunction)) - { - ASSERT(cancellable); - } - - void cancel() - { - g_cancellable_cancel(m_cancellable); - } - - void didClose() - { - m_closeFunction(); - } - - bool isCancelled() const - { - return g_cancellable_is_cancelled(m_cancellable); - } - - static gboolean eventCallback(GSocket*, GIOCondition condition, SocketEventSource* eventSource) - { - ASSERT(eventSource); - - if (eventSource->isCancelled()) { - // EventSource has been cancelled, return FALSE to destroy the source. - return FALSE; - } - - if (condition & G_IO_HUP || condition & G_IO_ERR || condition & G_IO_NVAL) { - eventSource->didClose(); - return FALSE; - } - - if (condition & G_IO_IN) { - eventSource->performWork(); - return TRUE; - } - - ASSERT_NOT_REACHED(); - return FALSE; - } - -private: - GCancellable* m_cancellable; - std::function<void ()> m_closeFunction; -}; - -// WorkQueue -static const size_t kVisualStudioThreadNameLimit = 31; - -void WorkQueue::platformInitialize(const char* name) -{ - m_eventContext = adoptGRef(g_main_context_new()); - ASSERT(m_eventContext); - m_eventLoop = adoptGRef(g_main_loop_new(m_eventContext.get(), FALSE)); - ASSERT(m_eventLoop); - - // This name can be com.apple.WebKit.ProcessLauncher or com.apple.CoreIPC.ReceiveQueue. - // We are using those names for the thread name, but both are longer than 31 characters, - // which is the limit of Visual Studio for thread names. - // When log is enabled createThread() will assert instead of truncate the name, so we need - // to make sure we don't use a name longer than 31 characters. - const char* threadName = g_strrstr(name, "."); - if (threadName) - threadName++; - else - threadName = name; - if (strlen(threadName) > kVisualStudioThreadNameLimit) - threadName += strlen(threadName) - kVisualStudioThreadNameLimit; - - m_workQueueThread = createThread(reinterpret_cast<WTF::ThreadFunction>(&WorkQueue::startWorkQueueThread), this, threadName); -} - -void WorkQueue::platformInvalidate() -{ - MutexLocker locker(m_eventLoopLock); - - if (m_eventLoop) { - if (g_main_loop_is_running(m_eventLoop.get())) - g_main_loop_quit(m_eventLoop.get()); - m_eventLoop.clear(); - } - - m_eventContext.clear(); -} - -void WorkQueue::startWorkQueueThread(WorkQueue* workQueue) -{ - workQueue->workQueueThreadBody(); -} - -void WorkQueue::workQueueThreadBody() -{ - g_main_loop_run(m_eventLoop.get()); -} - -void WorkQueue::registerSocketEventHandler(int fileDescriptor, std::function<void ()> function, std::function<void ()> closeFunction) -{ - GRefPtr<GSocket> socket = adoptGRef(g_socket_new_from_fd(fileDescriptor, 0)); - ASSERT(socket); - GRefPtr<GCancellable> cancellable = adoptGRef(g_cancellable_new()); - GRefPtr<GSource> dispatchSource = adoptGRef(g_socket_create_source(socket.get(), G_IO_IN, cancellable.get())); - ASSERT(dispatchSource); - SocketEventSource* eventSource = new SocketEventSource(std::move(function), this, - cancellable.get(), std::move(closeFunction)); - - g_source_set_callback(dispatchSource.get(), reinterpret_cast<GSourceFunc>(&WorkQueue::SocketEventSource::eventCallback), - 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); - Vector<SocketEventSource*> sources; - auto it = m_eventSources.find(fileDescriptor); - if (it != m_eventSources.end()) - sources = it->value; - - sources.append(eventSource); - m_eventSources.set(fileDescriptor, sources); - } - - g_source_attach(dispatchSource.get(), m_eventContext.get()); -} - -void WorkQueue::unregisterSocketEventHandler(int fileDescriptor) -{ - ASSERT(fileDescriptor); - - MutexLocker locker(m_eventSourcesLock); - - ASSERT(m_eventSources.contains(fileDescriptor)); - auto it = m_eventSources.find(fileDescriptor); - - if (it != m_eventSources.end()) { - Vector<SocketEventSource*> sources = it->value; - for (unsigned i = 0; i < sources.size(); i++) - sources[i]->cancel(); - - m_eventSources.remove(it); - } -} - -void WorkQueue::dispatchOnSource(GSource* dispatchSource, std::function<void ()> function, GSourceFunc sourceCallback) -{ - g_source_set_callback(dispatchSource, sourceCallback, new EventSource(std::move(function), this), - reinterpret_cast<GDestroyNotify>(&WorkQueue::EventSource::deleteEventSource)); - - g_source_attach(dispatchSource, m_eventContext.get()); -} - -void WorkQueue::dispatch(std::function<void ()> function) -{ - GRefPtr<GSource> dispatchSource = adoptGRef(g_idle_source_new()); - g_source_set_priority(dispatchSource.get(), G_PRIORITY_DEFAULT); - dispatchOnSource(dispatchSource.get(), std::move(function), - reinterpret_cast<GSourceFunc>(&WorkQueue::EventSource::performWorkOnce)); -} - -void WorkQueue::dispatchAfter(std::chrono::nanoseconds duration, std::function<void ()> function) -{ - GRefPtr<GSource> dispatchSource = adoptGRef(g_timeout_source_new( - static_cast<guint>(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count()))); - dispatchOnSource(dispatchSource.get(), std::move(function), - reinterpret_cast<GSourceFunc>(&WorkQueue::EventSource::performWorkOnce)); -} diff --git a/Source/WebKit2/Platform/unix/EnvironmentUtilities.cpp b/Source/WebKit2/Platform/unix/EnvironmentUtilities.cpp new file mode 100644 index 000000000..0de876715 --- /dev/null +++ b/Source/WebKit2/Platform/unix/EnvironmentUtilities.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "EnvironmentUtilities.h" + +#include <wtf/text/CString.h> + +namespace WebKit { + +namespace EnvironmentUtilities { + +void stripValuesEndingWithString(const char* environmentVariable, const char* searchValue) +{ + ASSERT(environmentVariable); + ASSERT(searchValue); + + // Grab the current value of the environment variable. + char* environmentValue = getenv(environmentVariable); + + if (!environmentValue || environmentValue[0] == '\0') + return; + + // Set up the strings we'll be searching for. + size_t searchLength = strlen(searchValue); + if (!searchLength) + return; + + Vector<char> searchValueWithColonVector; + searchValueWithColonVector.grow(searchLength + 2); + char* searchValueWithColon = searchValueWithColonVector.data(); + size_t searchLengthWithColon = searchLength + 1; + + memcpy(searchValueWithColon, searchValue, searchLength); + searchValueWithColon[searchLength] = ':'; + searchValueWithColon[searchLengthWithColon] = '\0'; + + // Loop over environmentValueBuffer, removing any components that match the search value ending with a colon. + char* componentStart = environmentValue; + char* match = strstr(componentStart, searchValueWithColon); + bool foundAnyMatches = match != NULL; + while (match != NULL) { + // Update componentStart to point to the colon immediately preceding the match. + char* nextColon = strstr(componentStart, ":"); + while (nextColon && nextColon < match) { + componentStart = nextColon; + nextColon = strstr(componentStart + 1, ":"); + } + + // Copy over everything right of the match to the current component start, and search from there again. + if (componentStart[0] == ':') { + // If componentStart points to a colon, copy the colon over. + strcpy(componentStart, match + searchLength); + } else { + // Otherwise, componentStart still points to the beginning of environmentValueBuffer, so don't copy over the colon. + // The edge case is if the colon is the last character in the string, so "match + searchLengthWithoutColon + 1" is the + // null terminator of the original input, in which case this is still safe. + strcpy(componentStart, match + searchLengthWithColon); + } + + match = strstr(componentStart, searchValueWithColon); + } + + // Search for the value without a trailing colon, seeing if the original input ends with it. + match = strstr(componentStart, searchValue); + while (match != NULL) { + if (match[searchLength] == '\0') + break; + match = strstr(match + 1, searchValue); + } + + // Since the original input ends with the search, strip out the last component. + if (match) { + // Update componentStart to point to the colon immediately preceding the match. + char* nextColon = strstr(componentStart, ":"); + while (nextColon && nextColon < match) { + componentStart = nextColon; + nextColon = strstr(componentStart + 1, ":"); + } + + // Whether componentStart points to the original string or the last colon, putting the null terminator there will get us the desired result. + componentStart[0] = '\0'; + + foundAnyMatches = true; + } + + // If we found no matches, don't change anything. + if (!foundAnyMatches) + return; + + // If we have nothing left, just unset the variable + if (environmentValue[0] == '\0') { + unsetenv(environmentVariable); + return; + } + + setenv(environmentVariable, environmentValue, 1); +} + +} // namespace EnvironmentUtilities + +} // namespace WebKit diff --git a/Source/WebKit2/Platform/PlatformProcessIdentifier.h b/Source/WebKit2/Platform/unix/EnvironmentUtilities.h index 1a630487b..fed77bc3f 100644 --- a/Source/WebKit2/Platform/PlatformProcessIdentifier.h +++ b/Source/WebKit2/Platform/unix/EnvironmentUtilities.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * 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 @@ -23,24 +23,20 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef EnvironmentUtilities_h +#define EnvironmentUtilities_h -#ifndef PlatformProcessIdentifier_h -#define PlatformProcessIdentifier_h - -#if PLATFORM(EFL) -#include <unistd.h> -#endif +#include <wtf/text/WTFString.h> namespace WebKit { -#if PLATFORM(MAC) -typedef pid_t PlatformProcessIdentifier; -#elif PLATFORM(GTK) -typedef int PlatformProcessIdentifier; -#elif PLATFORM(EFL) -typedef pid_t PlatformProcessIdentifier; -#endif +namespace EnvironmentUtilities { + +void stripValuesEndingWithString(const char* environmentVariable, const char* search); + +} // namespace EnvironmentUtilities + +} // namespace WebKit -} // namespace WebKit +#endif // #define EnvironmentUtilities_h -#endif // PlatformProcessIdentifier_h diff --git a/Source/WebKit2/Platform/gtk/LoggingGtk.cpp b/Source/WebKit2/Platform/unix/LoggingUnix.cpp index 44e5b118d..8014a5dcf 100644 --- a/Source/WebKit2/Platform/gtk/LoggingGtk.cpp +++ b/Source/WebKit2/Platform/unix/LoggingUnix.cpp @@ -27,17 +27,15 @@ #include "config.h" #include "Logging.h" -#include <glib.h> - namespace WebKit { -#if !LOG_DISABLED +#if !LOG_DISABLED || !RELEASE_LOG_DISABLED String logLevelString() { - return g_getenv("WEBKIT_DEBUG"); + return getenv("WEBKIT_DEBUG"); } -#endif // !LOG_DISABLED +#endif // !LOG_DISABLED || !RELEASE_LOG_DISABLED } diff --git a/Source/WebKit2/Platform/unix/SharedMemoryUnix.cpp b/Source/WebKit2/Platform/unix/SharedMemoryUnix.cpp index 5beba1370..c246312f9 100644 --- a/Source/WebKit2/Platform/unix/SharedMemoryUnix.cpp +++ b/Source/WebKit2/Platform/unix/SharedMemoryUnix.cpp @@ -29,8 +29,8 @@ #if USE(UNIX_DOMAIN_SOCKETS) #include "SharedMemory.h" -#include "ArgumentDecoder.h" -#include "ArgumentEncoder.h" +#include "Decoder.h" +#include "Encoder.h" #include <errno.h> #include <fcntl.h> #include <stdlib.h> @@ -43,61 +43,71 @@ #include <wtf/RandomNumber.h> #include <wtf/UniStdExtras.h> #include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> namespace WebKit { SharedMemory::Handle::Handle() - : m_fileDescriptor(-1) - , m_size(0) { } SharedMemory::Handle::~Handle() { - if (!isNull()) - closeWithRetry(m_fileDescriptor); +} + +void SharedMemory::Handle::clear() +{ + m_attachment = IPC::Attachment(); } bool SharedMemory::Handle::isNull() const { - return m_fileDescriptor == -1; + return m_attachment.fileDescriptor() == -1; } -void SharedMemory::Handle::encode(IPC::ArgumentEncoder& encoder) const +void SharedMemory::Handle::encode(IPC::Encoder& encoder) const { - encoder << releaseToAttachment(); + encoder << releaseAttachment(); } -bool SharedMemory::Handle::decode(IPC::ArgumentDecoder& decoder, Handle& handle) +bool SharedMemory::Handle::decode(IPC::Decoder& decoder, Handle& handle) { - ASSERT_ARG(handle, !handle.m_size); ASSERT_ARG(handle, handle.isNull()); IPC::Attachment attachment; if (!decoder.decode(attachment)) return false; - handle.adoptFromAttachment(attachment.releaseFileDescriptor(), attachment.size()); + handle.adoptAttachment(WTFMove(attachment)); return true; } -IPC::Attachment SharedMemory::Handle::releaseToAttachment() const +IPC::Attachment SharedMemory::Handle::releaseAttachment() const { - int temp = m_fileDescriptor; - m_fileDescriptor = -1; - return IPC::Attachment(temp, m_size); + return WTFMove(m_attachment); } -void SharedMemory::Handle::adoptFromAttachment(int fileDescriptor, size_t size) +void SharedMemory::Handle::adoptAttachment(IPC::Attachment&& attachment) { - ASSERT(!m_size); ASSERT(isNull()); - m_fileDescriptor = fileDescriptor; - m_size = size; + m_attachment = WTFMove(attachment); } -PassRefPtr<SharedMemory> SharedMemory::create(size_t size) +static inline int accessModeMMap(SharedMemory::Protection protection) +{ + switch (protection) { + case SharedMemory::Protection::ReadOnly: + return PROT_READ; + case SharedMemory::Protection::ReadWrite: + return PROT_READ | PROT_WRITE; + } + + ASSERT_NOT_REACHED(); + return PROT_READ | PROT_WRITE; +} + +RefPtr<SharedMemory> SharedMemory::create(void* address, size_t size, Protection protection) { CString tempName; @@ -111,7 +121,7 @@ PassRefPtr<SharedMemory> SharedMemory::create(size_t size) } while (fileDescriptor == -1 && errno == EINTR); } if (fileDescriptor == -1) { - WTFLogAlways("Failed to create shared memory file %s", tempName.data()); + WTFLogAlways("Failed to create shared memory file %s: %s", tempName.data(), strerror(errno)); return 0; } @@ -123,7 +133,7 @@ PassRefPtr<SharedMemory> SharedMemory::create(size_t size) } } - void* data = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileDescriptor, 0); + void* data = mmap(address, size, accessModeMMap(protection), MAP_SHARED, fileDescriptor, 0); if (data == MAP_FAILED) { closeWithRetry(fileDescriptor); shm_unlink(tempName.data()); @@ -139,66 +149,61 @@ PassRefPtr<SharedMemory> SharedMemory::create(size_t size) return instance.release(); } -static inline int accessModeMMap(SharedMemory::Protection protection) +RefPtr<SharedMemory> SharedMemory::allocate(size_t size) { - switch (protection) { - case SharedMemory::ReadOnly: - return PROT_READ; - case SharedMemory::ReadWrite: - return PROT_READ | PROT_WRITE; - } - - ASSERT_NOT_REACHED(); - return PROT_READ | PROT_WRITE; + return SharedMemory::create(nullptr, size, SharedMemory::Protection::ReadWrite); } -PassRefPtr<SharedMemory> SharedMemory::create(const Handle& handle, Protection protection) +RefPtr<SharedMemory> SharedMemory::map(const Handle& handle, Protection protection) { ASSERT(!handle.isNull()); - void* data = mmap(0, handle.m_size, accessModeMMap(protection), MAP_SHARED, handle.m_fileDescriptor, 0); + int fd = handle.m_attachment.releaseFileDescriptor(); + void* data = mmap(0, handle.m_attachment.size(), accessModeMMap(protection), MAP_SHARED, fd, 0); + closeWithRetry(fd); if (data == MAP_FAILED) - return 0; + return nullptr; + RefPtr<SharedMemory> instance = wrapMap(data, handle.m_attachment.size(), -1); + instance->m_fileDescriptor = std::nullopt; + instance->m_isWrappingMap = false; + return instance; +} + +RefPtr<SharedMemory> SharedMemory::wrapMap(void* data, size_t size, int fileDescriptor) +{ RefPtr<SharedMemory> instance = adoptRef(new SharedMemory()); instance->m_data = data; - instance->m_fileDescriptor = handle.m_fileDescriptor; - instance->m_size = handle.m_size; - handle.m_fileDescriptor = -1; + instance->m_size = size; + instance->m_fileDescriptor = fileDescriptor; + instance->m_isWrappingMap = true; return instance; } SharedMemory::~SharedMemory() { + if (m_isWrappingMap) + return; + munmap(m_data, m_size); - closeWithRetry(m_fileDescriptor); + if (m_fileDescriptor) + closeWithRetry(m_fileDescriptor.value()); } bool SharedMemory::createHandle(Handle& handle, Protection) { - ASSERT_ARG(handle, !handle.m_size); ASSERT_ARG(handle, handle.isNull()); + ASSERT(m_fileDescriptor); // FIXME: Handle the case where the passed Protection is ReadOnly. // See https://bugs.webkit.org/show_bug.cgi?id=131542. - int duplicatedHandle; - while ((duplicatedHandle = dup(m_fileDescriptor)) == -1) { - if (errno != EINTR) { - ASSERT_NOT_REACHED(); - return false; - } - } - - while (fcntl(duplicatedHandle, F_SETFD, FD_CLOEXEC) == -1) { - if (errno != EINTR) { - ASSERT_NOT_REACHED(); - closeWithRetry(duplicatedHandle); - return false; - } + int duplicatedHandle = dupCloseOnExec(m_fileDescriptor.value()); + if (duplicatedHandle == -1) { + ASSERT_NOT_REACHED(); + return false; } - handle.m_fileDescriptor = duplicatedHandle; - handle.m_size = m_size; + handle.m_attachment = IPC::Attachment(duplicatedHandle, m_size); return true; } |