2020-01-09 01:19:14 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#ifndef WEBGLCOMMANDQUEUE_H_
|
|
|
|
#define WEBGLCOMMANDQUEUE_H_
|
|
|
|
|
2020-01-09 01:19:26 +03:00
|
|
|
#include "mozilla/FunctionTypeTraits.h"
|
2020-01-09 01:19:14 +03:00
|
|
|
#include "mozilla/dom/ProducerConsumerQueue.h"
|
|
|
|
#include "mozilla/ipc/IPDLParamTraits.h"
|
2020-01-09 01:19:26 +03:00
|
|
|
#include <type_traits>
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
// Get around a bug in Clang related to __thiscall method pointers
|
|
|
|
#if defined(_M_IX86)
|
|
|
|
# define SINK_FCN_CC __thiscall
|
|
|
|
#else
|
|
|
|
# define SINK_FCN_CC
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
using mozilla::ipc::IPDLParamTraits;
|
2020-04-30 06:06:33 +03:00
|
|
|
using mozilla::webgl::Consumer;
|
|
|
|
using mozilla::webgl::Producer;
|
|
|
|
using mozilla::webgl::ProducerConsumerQueue;
|
2020-05-01 01:21:45 +03:00
|
|
|
using mozilla::webgl::QueueStatus;
|
2020-01-09 01:19:14 +03:00
|
|
|
|
2020-04-30 06:06:33 +03:00
|
|
|
template <typename Derived, typename SinkType>
|
|
|
|
struct MethodDispatcher;
|
|
|
|
|
2020-05-01 01:21:45 +03:00
|
|
|
enum CommandResult { kSuccess, kTimeExpired, kQueueEmpty, kError };
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
enum CommandSyncType { ASYNC, SYNC };
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A CommandSource is obtained from a CommandQueue. Use it by inserting a
|
|
|
|
* command (represented by type Command) using InsertCommand, which also
|
|
|
|
* needs all parameters to the command. They are then serialized and sent
|
|
|
|
* to the CommandSink, which must understand the Command+Args combination
|
|
|
|
* to execute it.
|
|
|
|
*/
|
2020-04-30 06:06:33 +03:00
|
|
|
template <typename Command>
|
2020-05-01 01:21:45 +03:00
|
|
|
class CommandSource {
|
2020-01-09 01:19:14 +03:00
|
|
|
public:
|
2020-05-01 01:21:45 +03:00
|
|
|
explicit CommandSource(UniquePtr<Producer>&& aSource)
|
|
|
|
: mSource(std::move(aSource)) {
|
|
|
|
MOZ_ASSERT(mSource);
|
|
|
|
}
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
template <typename... Args>
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus InsertCommand(Command aCommand, Args&&... aArgs) {
|
|
|
|
return this->mSource->TryWaitInsert(Nothing() /* wait forever */, aCommand,
|
|
|
|
aArgs...);
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus InsertCommand(Command aCommand) {
|
|
|
|
return this->mSource->TryWaitInsert(Nothing() /* wait forever */, aCommand);
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename... Args>
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus RunCommand(Command aCommand, Args&&... aArgs) {
|
2020-01-09 01:19:14 +03:00
|
|
|
return InsertCommand(aCommand, std::forward<Args>(aArgs)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
// For IPDL:
|
2020-02-19 00:08:00 +03:00
|
|
|
CommandSource() = default;
|
2020-05-01 01:21:45 +03:00
|
|
|
|
|
|
|
protected:
|
|
|
|
friend struct IPDLParamTraits<mozilla::CommandSource<Command>>;
|
|
|
|
|
|
|
|
UniquePtr<Producer> mSource;
|
2020-01-09 01:19:14 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A CommandSink is obtained from a CommandQueue. It executes commands that
|
|
|
|
* originated in its CommandSource. Use this class by calling one of the
|
|
|
|
* Process methods, which will autonomously deserialize, dispatch and
|
|
|
|
* post-process the execution. This class handles deserialization -- dispatch
|
|
|
|
* and processing are to be provided by a subclass in its implementation of the
|
|
|
|
* pure-virtual DispatchCommand method. DispatchCommand implementations can
|
|
|
|
* easily run functions and methods using arguments taken from the command
|
|
|
|
* queue by calling the Dispatch methods in this class.
|
|
|
|
*/
|
2020-04-30 06:06:33 +03:00
|
|
|
template <typename Command>
|
2020-05-01 01:21:45 +03:00
|
|
|
class CommandSink {
|
2020-01-09 01:19:14 +03:00
|
|
|
public:
|
2020-05-01 01:21:45 +03:00
|
|
|
explicit CommandSink(UniquePtr<Consumer>&& aSink) : mSink(std::move(aSink)) {
|
|
|
|
MOZ_ASSERT(mSink);
|
|
|
|
}
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Attempts to process the next command in the queue, if one is available.
|
|
|
|
*/
|
2020-01-09 01:19:16 +03:00
|
|
|
CommandResult ProcessOne(const Maybe<TimeDuration>& aTimeout) {
|
2020-01-09 01:19:14 +03:00
|
|
|
Command command;
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus status = (aTimeout.isNothing() || aTimeout.value())
|
|
|
|
? this->mSink->TryWaitRemove(aTimeout, command)
|
|
|
|
: this->mSink->TryRemove(command);
|
2020-01-09 01:19:14 +03:00
|
|
|
|
2020-05-01 01:21:45 +03:00
|
|
|
if (status == QueueStatus::kSuccess) {
|
2020-01-09 01:19:14 +03:00
|
|
|
if (DispatchCommand(command)) {
|
2020-05-01 01:21:45 +03:00
|
|
|
return CommandResult::kSuccess;
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
2020-05-01 01:21:45 +03:00
|
|
|
return CommandResult::kError;
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
|
2020-05-01 01:21:45 +03:00
|
|
|
if (status == QueueStatus::kNotReady) {
|
|
|
|
return CommandResult::kQueueEmpty;
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
|
2020-05-01 01:21:45 +03:00
|
|
|
if (status == QueueStatus::kOOMError) {
|
2020-01-09 01:19:14 +03:00
|
|
|
ReportOOM();
|
|
|
|
}
|
2020-05-01 01:21:45 +03:00
|
|
|
return CommandResult::kError;
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
CommandResult ProcessOneNow() { return ProcessOne(Some(TimeDuration(0))); }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Drains the queue until the queue is empty or an error occurs, whichever
|
|
|
|
* comes first.
|
|
|
|
* Returns the result of the last attempt to process a command, which will
|
|
|
|
* be either QueueEmpty or Error.
|
|
|
|
*/
|
|
|
|
CommandResult ProcessAll() {
|
|
|
|
CommandResult result;
|
|
|
|
do {
|
|
|
|
result = ProcessOneNow();
|
2020-05-01 01:21:45 +03:00
|
|
|
} while (result == CommandResult::kSuccess);
|
2020-01-09 01:19:14 +03:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Drains the queue until aDuration expires, the queue is empty, or an error
|
|
|
|
* occurs, whichever comes first.
|
|
|
|
* Returns the result of the last attempt to process a command.
|
|
|
|
*/
|
|
|
|
CommandResult ProcessUpToDuration(TimeDuration aDuration) {
|
|
|
|
TimeStamp start = TimeStamp::Now();
|
|
|
|
TimeStamp now = start;
|
|
|
|
CommandResult result;
|
|
|
|
|
|
|
|
do {
|
|
|
|
result = ProcessOne(Some(aDuration - (now - start)));
|
|
|
|
now = TimeStamp::Now();
|
2020-05-01 01:21:45 +03:00
|
|
|
} while ((result == CommandResult::kSuccess) &&
|
|
|
|
((now - start) < aDuration));
|
2020-01-09 01:19:14 +03:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For IPDL:
|
2020-02-19 00:08:00 +03:00
|
|
|
CommandSink() = default;
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
// non-void return value, non-const method variant
|
|
|
|
template <typename T, typename ReturnType, typename... Args>
|
|
|
|
bool DispatchAsyncMethod(T& aObj, ReturnType (T::*aMethod)(Args...)) {
|
2020-03-28 16:57:18 +03:00
|
|
|
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
2020-01-09 01:19:14 +03:00
|
|
|
if (!ReadArgs(args)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
CallMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// non-void return value, const method variant
|
|
|
|
template <typename T, typename ReturnType, typename... Args>
|
|
|
|
bool DispatchAsyncMethod(const T& aObj,
|
|
|
|
ReturnType (T::*aMethod)(Args...) const) {
|
2020-03-28 16:57:18 +03:00
|
|
|
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
2020-01-09 01:19:14 +03:00
|
|
|
if (!ReadArgs(args)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
CallMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// void return value, non-const method variant
|
|
|
|
template <typename T, typename... Args>
|
|
|
|
bool DispatchAsyncMethod(T* aObj, void (T::*aMethod)(Args...)) {
|
2020-03-28 16:57:18 +03:00
|
|
|
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
2020-01-09 01:19:14 +03:00
|
|
|
if (!ReadArgs(args)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
CallVoidMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// void return value, const method variant
|
|
|
|
template <typename T, typename... Args>
|
|
|
|
bool DispatchAsyncMethod(const T* aObj, void (T::*aMethod)(Args...) const) {
|
2020-03-28 16:57:18 +03:00
|
|
|
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
2020-01-09 01:19:14 +03:00
|
|
|
if (!ReadArgs(args)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
CallVoidMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2020-05-01 01:21:45 +03:00
|
|
|
friend struct IPDLParamTraits<mozilla::CommandSink<Command>>;
|
|
|
|
|
2020-01-09 01:19:14 +03:00
|
|
|
/**
|
|
|
|
* Implementations will usually be something like a big switch statement
|
|
|
|
* that calls one of the Dispatch methods in this class.
|
|
|
|
*/
|
|
|
|
virtual bool DispatchCommand(Command command) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Implementations can override this to detect out-of-memory during
|
|
|
|
* deserialization.
|
|
|
|
*/
|
|
|
|
virtual void ReportOOM() {}
|
|
|
|
|
|
|
|
template <typename... Args, size_t... Indices>
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus CallTryRemove(std::tuple<Args...>& aArgs,
|
|
|
|
std::index_sequence<Indices...>) {
|
|
|
|
QueueStatus status = mSink->TryRemove(std::get<Indices>(aArgs)...);
|
2020-01-09 01:19:14 +03:00
|
|
|
// The CommandQueue inserts the command and the args together as an atomic
|
|
|
|
// operation. We already read the command so the args must also be
|
|
|
|
// available.
|
2020-05-01 01:21:45 +03:00
|
|
|
MOZ_ASSERT(status != QueueStatus::kNotReady);
|
2020-01-09 01:19:14 +03:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus CallTryRemove(std::tuple<>& aArgs,
|
|
|
|
std::make_integer_sequence<size_t, 0>) {
|
|
|
|
return QueueStatus::kSuccess;
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename MethodType, typename... Args,
|
2020-04-30 06:06:33 +03:00
|
|
|
size_t... Indices, typename ReturnType>
|
|
|
|
std::result_of<MethodType> CallMethod(T& aObj, MethodType aMethod,
|
|
|
|
std::tuple<Args...>& aArgs,
|
|
|
|
std::index_sequence<Indices...>) {
|
2020-01-09 01:19:14 +03:00
|
|
|
return (aObj.*aMethod)(std::forward<Args>(std::get<Indices>(aArgs))...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename MethodType, typename... Args,
|
|
|
|
size_t... Indices>
|
|
|
|
void CallVoidMethod(T& aObj, MethodType aMethod, std::tuple<Args...>& aArgs,
|
|
|
|
std::index_sequence<Indices...>) {
|
|
|
|
(aObj.*aMethod)(std::forward<Args>(std::get<Indices>(aArgs))...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename... Args>
|
|
|
|
bool ReadArgs(std::tuple<Args...>& aArgs) {
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus status =
|
|
|
|
CallTryRemove(aArgs, std::index_sequence_for<Args...>{});
|
2020-01-09 01:19:14 +03:00
|
|
|
return IsSuccess(status);
|
|
|
|
}
|
2020-05-01 01:21:45 +03:00
|
|
|
|
|
|
|
UniquePtr<Consumer> mSink;
|
2020-01-09 01:19:14 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
enum SyncResponse : uint8_t { RESPONSE_NAK, RESPONSE_ACK };
|
|
|
|
|
|
|
|
/**
|
2020-04-30 06:06:33 +03:00
|
|
|
* This is the Source for a SyncCommandSink. It takes an extra PCQ,
|
|
|
|
* the ResponsePcq, and uses it to receive synchronous responses from
|
|
|
|
* the sink. The ResponsePcq is a regular ProducerConsumerQueue,
|
|
|
|
* not a CommandQueue.
|
2020-01-09 01:19:14 +03:00
|
|
|
*/
|
2020-04-30 06:06:33 +03:00
|
|
|
template <typename Command>
|
|
|
|
class SyncCommandSource : public CommandSource<Command> {
|
2020-01-09 01:19:14 +03:00
|
|
|
public:
|
2020-04-30 06:06:33 +03:00
|
|
|
using BaseType = CommandSource<Command>;
|
|
|
|
SyncCommandSource(UniquePtr<Producer>&& aProducer,
|
|
|
|
UniquePtr<Consumer>&& aResponseConsumer)
|
|
|
|
: CommandSource<Command>(std::move(aProducer)),
|
2020-05-01 01:21:45 +03:00
|
|
|
mResponseSink(std::move(aResponseConsumer)) {}
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
template <typename... Args>
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus RunAsyncCommand(Command aCommand, Args&&... aArgs) {
|
2020-01-09 01:19:14 +03:00
|
|
|
return this->RunCommand(aCommand, std::forward<Args>(aArgs)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename... Args>
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus RunVoidSyncCommand(Command aCommand, Args&&... aArgs) {
|
|
|
|
QueueStatus status =
|
|
|
|
RunAsyncCommand(aCommand, std::forward<Args>(aArgs)...);
|
2020-01-09 01:19:14 +03:00
|
|
|
return IsSuccess(status) ? this->ReadSyncResponse() : status;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename ResultType, typename... Args>
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus RunSyncCommand(Command aCommand, ResultType& aReturn,
|
|
|
|
Args&&... aArgs) {
|
|
|
|
QueueStatus status =
|
2020-01-09 01:19:14 +03:00
|
|
|
RunVoidSyncCommand(aCommand, std::forward<Args>(aArgs)...);
|
|
|
|
return IsSuccess(status) ? this->ReadResult(aReturn) : status;
|
|
|
|
}
|
|
|
|
|
|
|
|
// for IPDL:
|
2020-02-19 00:08:00 +03:00
|
|
|
SyncCommandSource() = default;
|
2020-04-30 06:06:33 +03:00
|
|
|
friend struct mozilla::ipc::IPDLParamTraits<SyncCommandSource<Command>>;
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
protected:
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus ReadSyncResponse() {
|
2020-01-09 01:19:14 +03:00
|
|
|
SyncResponse response;
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus status =
|
|
|
|
mResponseSink->TryWaitRemove(Nothing() /* wait forever */, response);
|
|
|
|
MOZ_ASSERT(status != QueueStatus::kNotReady);
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
if (IsSuccess(status) && response != RESPONSE_ACK) {
|
2020-05-01 01:21:45 +03:00
|
|
|
return QueueStatus::kFatalError;
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2020-05-01 01:21:45 +03:00
|
|
|
QueueStatus ReadResult(T& aResult) {
|
|
|
|
QueueStatus status = mResponseSink->TryRemove(aResult);
|
2020-01-09 01:19:14 +03:00
|
|
|
// The Sink posts the response code and result as an atomic transaction. We
|
|
|
|
// already read the response code so the result must be available.
|
2020-05-01 01:21:45 +03:00
|
|
|
MOZ_ASSERT(status != QueueStatus::kNotReady);
|
2020-01-09 01:19:14 +03:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2020-05-01 01:21:45 +03:00
|
|
|
UniquePtr<Consumer> mResponseSink;
|
2020-01-09 01:19:14 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2020-04-30 06:06:33 +03:00
|
|
|
* This is the Sink for a SyncCommandSource. It takes an extra PCQ, the
|
|
|
|
* ResponsePcq, and uses it to issue synchronous responses to the client.
|
2020-01-09 01:19:14 +03:00
|
|
|
* Subclasses can use the DispatchSync methods in this class in their
|
|
|
|
* DispatchCommand implementations.
|
2020-04-30 06:06:33 +03:00
|
|
|
* The ResponsePcq is not a CommandQueue.
|
2020-01-09 01:19:14 +03:00
|
|
|
*/
|
2020-04-30 06:06:33 +03:00
|
|
|
template <typename Command>
|
|
|
|
class SyncCommandSink : public CommandSink<Command> {
|
|
|
|
using BaseType = CommandSink<Command>;
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
public:
|
2020-04-30 06:06:33 +03:00
|
|
|
SyncCommandSink(UniquePtr<Consumer>&& aConsumer,
|
2020-05-01 01:21:45 +03:00
|
|
|
UniquePtr<Producer>&& aResponseSource)
|
2020-04-30 06:06:33 +03:00
|
|
|
: CommandSink<Command>(std::move(aConsumer)),
|
2020-05-01 01:21:45 +03:00
|
|
|
mResponseSource(std::move(aResponseSource)) {}
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
// for IPDL:
|
2020-02-19 00:08:00 +03:00
|
|
|
SyncCommandSink() = default;
|
2020-04-30 06:06:33 +03:00
|
|
|
friend struct mozilla::ipc::IPDLParamTraits<SyncCommandSink<Command>>;
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
// Places RESPONSE_ACK and the typed return value, or RESPONSE_NAK, in
|
|
|
|
// the response queue,
|
|
|
|
// __cdecl/__thiscall non-const method variant.
|
|
|
|
template <typename T, typename ReturnType, typename... Args>
|
|
|
|
bool DispatchSyncMethod(T& aObj,
|
|
|
|
ReturnType SINK_FCN_CC (T::*aMethod)(Args...)) {
|
2020-03-28 16:57:18 +03:00
|
|
|
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
2020-01-09 01:19:14 +03:00
|
|
|
if (!BaseType::ReadArgs(args)) {
|
|
|
|
WriteNAK();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnType response = BaseType::CallMethod(
|
|
|
|
aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
|
|
|
|
|
|
|
return WriteACK(response);
|
|
|
|
}
|
|
|
|
|
|
|
|
// __cdecl/__thiscall const method variant.
|
|
|
|
template <typename T, typename ReturnType, typename... Args>
|
|
|
|
bool DispatchSyncMethod(const T& aObj,
|
|
|
|
ReturnType SINK_FCN_CC (T::*aMethod)(Args...) const) {
|
2020-03-28 16:57:18 +03:00
|
|
|
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
2020-01-09 01:19:14 +03:00
|
|
|
if (!BaseType::ReadArgs(args)) {
|
|
|
|
WriteNAK();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnType response = BaseType::CallMethod(
|
|
|
|
aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
|
|
|
|
|
|
|
return WriteACK(response);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(_M_IX86)
|
|
|
|
// __stdcall non-const method variant.
|
|
|
|
template <typename T, typename ReturnType, typename... Args>
|
|
|
|
bool DispatchSyncMethod(T& aObj,
|
|
|
|
ReturnType __stdcall (T::*aMethod)(Args...)) {
|
2020-03-28 16:57:18 +03:00
|
|
|
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
2020-01-09 01:19:14 +03:00
|
|
|
if (!BaseType::ReadArgs(args)) {
|
|
|
|
WriteNAK();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnType response = BaseType::CallMethod(
|
|
|
|
aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
|
|
|
|
|
|
|
return WriteACK(response);
|
|
|
|
}
|
|
|
|
|
|
|
|
// __stdcall const method variant.
|
|
|
|
template <typename T, typename ReturnType, typename... Args>
|
|
|
|
bool DispatchSyncMethod(const T& aObj,
|
|
|
|
ReturnType __stdcall (T::*aMethod)(Args...) const) {
|
2020-03-28 16:57:18 +03:00
|
|
|
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
2020-01-09 01:19:14 +03:00
|
|
|
if (!BaseType::ReadArgs(args)) {
|
|
|
|
WriteNAK();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnType response = BaseType::CallMethod(
|
|
|
|
aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
|
|
|
|
|
|
|
return WriteACK(response);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// __cdecl/__thiscall non-const void method variant
|
|
|
|
template <typename T, typename... Args>
|
|
|
|
bool DispatchSyncMethod(T& aObj, void SINK_FCN_CC (T::*aMethod)(Args...)) {
|
2020-03-28 16:57:18 +03:00
|
|
|
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
2020-01-09 01:19:14 +03:00
|
|
|
if (!BaseType::ReadArgs(args)) {
|
|
|
|
WriteNAK();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
BaseType::CallVoidMethod(aObj, aMethod, args,
|
|
|
|
std::index_sequence_for<Args...>{});
|
|
|
|
return WriteACK();
|
|
|
|
}
|
|
|
|
|
|
|
|
// __cdecl/__thiscall const void method variant
|
|
|
|
template <typename T, typename... Args>
|
|
|
|
bool DispatchSyncMethod(const T& aObj,
|
|
|
|
void SINK_FCN_CC (T::*aMethod)(Args...) const) {
|
2020-03-28 16:57:18 +03:00
|
|
|
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
2020-01-09 01:19:14 +03:00
|
|
|
if (!BaseType::ReadArgs(args)) {
|
|
|
|
WriteNAK();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
BaseType::CallVoidMethod(aObj, aMethod, args,
|
|
|
|
std::index_sequence_for<Args...>{});
|
|
|
|
return WriteACK();
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(_M_IX86)
|
|
|
|
// __stdcall non-const void method variant
|
|
|
|
template <typename T, typename... Args>
|
|
|
|
bool DispatchSyncMethod(T& aObj, void __stdcall (T::*aMethod)(Args...)) {
|
2020-03-28 16:57:18 +03:00
|
|
|
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
2020-01-09 01:19:14 +03:00
|
|
|
if (!BaseType::ReadArgs(args)) {
|
|
|
|
WriteNAK();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
BaseType::CallVoidMethod(aObj, aMethod, args,
|
|
|
|
std::index_sequence_for<Args...>{});
|
|
|
|
return WriteACK();
|
|
|
|
}
|
|
|
|
|
|
|
|
// __stdcall const void method variant
|
|
|
|
template <typename T, typename... Args>
|
|
|
|
bool DispatchSyncMethod(const T& aObj,
|
|
|
|
void __stdcall (T::*aMethod)(Args...) const) {
|
2020-03-28 16:57:18 +03:00
|
|
|
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
2020-01-09 01:19:14 +03:00
|
|
|
if (!BaseType::ReadArgs(args)) {
|
|
|
|
WriteNAK();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
BaseType::CallVoidMethod(aObj, aMethod, args,
|
|
|
|
std::index_sequence_for<Args...>{});
|
|
|
|
return WriteACK();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
protected:
|
|
|
|
template <typename... Args>
|
|
|
|
bool WriteArgs(const Args&... aArgs) {
|
2020-05-01 01:21:45 +03:00
|
|
|
return IsSuccess(mResponseSource->TryInsert(aArgs...));
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename... Args>
|
|
|
|
bool WriteACK(const Args&... aArgs) {
|
|
|
|
SyncResponse ack = RESPONSE_ACK;
|
|
|
|
return WriteArgs(ack, aArgs...);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WriteNAK() {
|
|
|
|
SyncResponse nak = RESPONSE_NAK;
|
|
|
|
return WriteArgs(nak);
|
|
|
|
}
|
|
|
|
|
2020-05-01 01:21:45 +03:00
|
|
|
UniquePtr<Producer> mResponseSource;
|
2020-04-30 06:06:33 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Can be used by a sink to find and execute the handler for a given commandId.
|
|
|
|
*/
|
|
|
|
template <typename Derived>
|
|
|
|
struct CommandDispatchDriver {
|
|
|
|
/**
|
|
|
|
* Find and run the command.
|
|
|
|
*/
|
|
|
|
template <size_t commandId, typename... Args>
|
|
|
|
static MOZ_ALWAYS_INLINE bool DispatchCommandHelper(size_t aId,
|
|
|
|
Args&... aArgs) {
|
|
|
|
if (commandId == aId) {
|
|
|
|
return Derived::template Dispatch<commandId>(aArgs...);
|
|
|
|
}
|
|
|
|
return Derived::template DispatchCommand<commandId + 1>(aId, aArgs...);
|
|
|
|
}
|
2020-01-09 01:19:14 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This CommandDispatcher provides helper methods that subclasses can
|
|
|
|
* use to dispatch sync/async commands to a method via a CommandSink.
|
|
|
|
* See DECLARE_METHOD_DISPATCHER and DEFINE_METHOD_DISPATCHER.
|
|
|
|
*/
|
2020-04-30 06:06:33 +03:00
|
|
|
template <typename Derived, typename _SinkType>
|
2020-01-09 01:19:14 +03:00
|
|
|
struct MethodDispatcher {
|
2020-04-30 06:06:33 +03:00
|
|
|
using SinkType = _SinkType;
|
2020-01-09 01:19:14 +03:00
|
|
|
template <CommandSyncType syncType>
|
|
|
|
struct DispatchMethod;
|
2020-05-01 01:21:45 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
// Specialization for dispatching asynchronous methods
|
|
|
|
template <typename Derived, typename _SinkType>
|
|
|
|
template <>
|
|
|
|
struct MethodDispatcher<Derived,
|
|
|
|
_SinkType>::DispatchMethod<CommandSyncType::ASYNC> {
|
|
|
|
template <typename MethodType, typename ObjectType>
|
|
|
|
static MOZ_ALWAYS_INLINE bool Run(SinkType& aSink, MethodType mMethod,
|
|
|
|
ObjectType& aObj) {
|
|
|
|
return aSink.DispatchAsyncMethod(aObj, mMethod);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Specialization for dispatching synchronous methods
|
|
|
|
template <typename Derived, typename _SinkType>
|
|
|
|
template <>
|
|
|
|
struct MethodDispatcher<Derived,
|
|
|
|
_SinkType>::DispatchMethod<CommandSyncType::SYNC> {
|
|
|
|
template <typename MethodType, typename ObjectType>
|
|
|
|
static MOZ_ALWAYS_INLINE bool Run(SinkType& aSink, MethodType aMethod,
|
|
|
|
ObjectType& aObj) {
|
|
|
|
return aSink.DispatchSyncMethod(aObj, aMethod);
|
|
|
|
}
|
2020-01-09 01:19:14 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
// Declares a MethodDispatcher with the given name and CommandSink type.
|
|
|
|
// The ObjectType is the type of the object this class will dispatch methods to.
|
2020-04-30 06:06:33 +03:00
|
|
|
#define DECLARE_METHOD_DISPATCHER(_DISPATCHER, _SINKTYPE, _OBJECTTYPE) \
|
|
|
|
struct _DISPATCHER : public MethodDispatcher<_DISPATCHER, _SINKTYPE> { \
|
2020-01-09 01:19:14 +03:00
|
|
|
using ObjectType = _OBJECTTYPE; \
|
2020-04-30 06:06:33 +03:00
|
|
|
template <size_t commandId = 0> \
|
2020-01-09 01:19:14 +03:00
|
|
|
static MOZ_ALWAYS_INLINE bool DispatchCommand(size_t aId, SinkType& aSink, \
|
|
|
|
ObjectType& aObj) { \
|
2020-04-30 06:06:33 +03:00
|
|
|
MOZ_ASSERT_UNREACHABLE("Unhandled command ID"); \
|
|
|
|
return false; \
|
2020-04-30 04:56:55 +03:00
|
|
|
} \
|
2020-01-09 01:19:14 +03:00
|
|
|
template <size_t commandId> \
|
2020-04-30 06:06:33 +03:00
|
|
|
static MOZ_ALWAYS_INLINE bool Dispatch(SinkType& aSink, ObjectType& aObj); \
|
|
|
|
template <size_t commandId> \
|
2020-01-09 01:19:14 +03:00
|
|
|
struct MethodInfo; \
|
|
|
|
template <size_t commandId> \
|
|
|
|
static constexpr CommandSyncType SyncType(); \
|
|
|
|
template <typename MethodType, MethodType method> \
|
|
|
|
static constexpr size_t Id(); \
|
|
|
|
};
|
|
|
|
|
|
|
|
// Defines a handler in the given dispatcher for the command with the given
|
|
|
|
// id. The handler uses a CommandSink to read parameters, call the
|
|
|
|
// given method using the given synchronization protocol, and provide
|
|
|
|
// compile-time lookup of the ID by class method.
|
2020-04-30 06:06:33 +03:00
|
|
|
#define DEFINE_METHOD_DISPATCHER(_DISPATCHER, _ID, _METHOD, _SYNC) \
|
|
|
|
/* template <> \
|
|
|
|
bool _DISPATCHER::DispatchCommand<_ID>(size_t aId, SinkType & aSink, \
|
|
|
|
ObjectType & aObj) { \
|
|
|
|
return CommandDispatchDriver<_DISPATCHER>::DispatchCommandHelper<_ID>( \
|
|
|
|
aId, aSink, aObj); \
|
|
|
|
} \
|
|
|
|
template <> \
|
|
|
|
bool _DISPATCHER::Dispatch<_ID>(SinkType & aSink, ObjectType & aObj) { \
|
|
|
|
return DispatchMethod<_SYNC>::Run(aSink, &_METHOD, aObj); \
|
|
|
|
} */ \
|
|
|
|
template <> \
|
|
|
|
struct _DISPATCHER::MethodInfo<_ID> { \
|
|
|
|
using MethodType = decltype(&_METHOD); \
|
|
|
|
}; \
|
|
|
|
template <> \
|
|
|
|
constexpr CommandSyncType _DISPATCHER::SyncType<_ID>() { \
|
|
|
|
return _SYNC; \
|
|
|
|
} \
|
|
|
|
template <> \
|
|
|
|
constexpr size_t _DISPATCHER::Id<decltype(&_METHOD), &_METHOD>() { \
|
|
|
|
return _ID; \
|
|
|
|
}
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
namespace ipc {
|
|
|
|
template <typename T>
|
|
|
|
struct IPDLParamTraits;
|
|
|
|
|
2020-05-01 01:21:45 +03:00
|
|
|
template <typename Command>
|
|
|
|
struct IPDLParamTraits<mozilla::CommandSource<Command>> {
|
2020-01-09 01:19:14 +03:00
|
|
|
public:
|
2020-05-01 01:21:45 +03:00
|
|
|
typedef mozilla::CommandSource<Command> paramType;
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
|
|
|
const paramType& aParam) {
|
2020-05-01 01:21:45 +03:00
|
|
|
MOZ_ASSERT(aParam.mSource);
|
|
|
|
WriteIPDLParam(aMsg, aActor, *aParam.mSource.get());
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
|
|
|
IProtocol* aActor, paramType* aResult) {
|
2020-04-30 06:06:33 +03:00
|
|
|
Producer* producer = new Producer;
|
|
|
|
bool ret = ReadIPDLParam(aMsg, aIter, aActor, producer);
|
2020-05-01 01:21:45 +03:00
|
|
|
aResult->mSource.reset(producer);
|
2020-04-30 06:06:33 +03:00
|
|
|
return ret;
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-05-01 01:21:45 +03:00
|
|
|
template <typename Command>
|
|
|
|
struct IPDLParamTraits<mozilla::CommandSink<Command>> {
|
2020-01-09 01:19:14 +03:00
|
|
|
public:
|
2020-05-01 01:21:45 +03:00
|
|
|
typedef mozilla::CommandSink<Command> paramType;
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
|
|
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
|
|
|
const paramType& aParam) {
|
2020-05-01 01:21:45 +03:00
|
|
|
MOZ_ASSERT(aParam.mSink);
|
|
|
|
WriteIPDLParam(aMsg, aActor, *aParam.mSink.get());
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
|
|
|
IProtocol* aActor, paramType* aResult) {
|
2020-04-30 06:06:33 +03:00
|
|
|
Consumer* consumer = new Consumer;
|
|
|
|
bool ret = ReadIPDLParam(aMsg, aIter, aActor, consumer);
|
2020-05-01 01:21:45 +03:00
|
|
|
aResult->mSink.reset(consumer);
|
2020-04-30 06:06:33 +03:00
|
|
|
return ret;
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-04-30 06:06:33 +03:00
|
|
|
template <typename Command>
|
|
|
|
struct IPDLParamTraits<mozilla::SyncCommandSource<Command>>
|
|
|
|
: public IPDLParamTraits<mozilla::CommandSource<Command>> {
|
2020-01-09 01:19:14 +03:00
|
|
|
public:
|
2020-04-30 06:06:33 +03:00
|
|
|
typedef mozilla::SyncCommandSource<Command> paramType;
|
2020-01-09 01:19:14 +03:00
|
|
|
typedef typename paramType::BaseType paramBaseType;
|
|
|
|
|
|
|
|
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
|
|
|
const paramType& aParam) {
|
|
|
|
WriteIPDLParam(aMsg, aActor, static_cast<const paramBaseType&>(aParam));
|
2020-05-01 01:21:45 +03:00
|
|
|
WriteIPDLParam(aMsg, aActor, aParam.mResponseSink);
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
|
|
|
IProtocol* aActor, paramType* aParam) {
|
|
|
|
bool result =
|
|
|
|
ReadIPDLParam(aMsg, aIter, aActor, static_cast<paramBaseType*>(aParam));
|
2020-05-01 01:21:45 +03:00
|
|
|
return result && ReadIPDLParam(aMsg, aIter, aActor, &aParam->mResponseSink);
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-04-30 06:06:33 +03:00
|
|
|
template <typename Command>
|
|
|
|
struct IPDLParamTraits<mozilla::SyncCommandSink<Command>>
|
|
|
|
: public IPDLParamTraits<mozilla::CommandSink<Command>> {
|
2020-01-09 01:19:14 +03:00
|
|
|
public:
|
2020-04-30 06:06:33 +03:00
|
|
|
typedef mozilla::SyncCommandSink<Command> paramType;
|
2020-01-09 01:19:14 +03:00
|
|
|
typedef typename paramType::BaseType paramBaseType;
|
|
|
|
|
|
|
|
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
|
|
|
const paramType& aParam) {
|
|
|
|
WriteIPDLParam(aMsg, aActor, static_cast<const paramBaseType&>(aParam));
|
2020-05-01 01:21:45 +03:00
|
|
|
WriteIPDLParam(aMsg, aActor, aParam.mResponseSource);
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
|
|
|
IProtocol* aActor, paramType* aParam) {
|
|
|
|
bool result =
|
|
|
|
ReadIPDLParam(aMsg, aIter, aActor, static_cast<paramBaseType*>(aParam));
|
2020-05-01 01:21:45 +03:00
|
|
|
return result &&
|
|
|
|
ReadIPDLParam(aMsg, aIter, aActor, &aParam->mResponseSource);
|
2020-01-09 01:19:14 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace ipc
|
|
|
|
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif // WEBGLCOMMANDQUEUE_H_
|