зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1711090 - Part 2: Allow creating a nsITimer with a std::function callback, r=KrisWright
Differential Revision: https://phabricator.services.mozilla.com/D115089
This commit is contained in:
Родитель
4b3f75001a
Коммит
4c32cf1fe5
|
@ -632,3 +632,34 @@ TEST(Timers, FuzzTestTimers)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Timers, ClosureCallback)
|
||||
{
|
||||
AutoCreateAndDestroyReentrantMonitor newMon;
|
||||
ASSERT_TRUE(newMon);
|
||||
|
||||
AutoTestThread testThread;
|
||||
ASSERT_TRUE(testThread);
|
||||
|
||||
nsIThread* notifiedThread = nullptr;
|
||||
|
||||
nsCOMPtr<nsITimer> timer;
|
||||
nsresult rv = NS_NewTimerWithCallback(
|
||||
getter_AddRefs(timer),
|
||||
[&](nsITimer*) {
|
||||
nsCOMPtr<nsIThread> current(do_GetCurrentThread());
|
||||
|
||||
ReentrantMonitorAutoEnter mon(*newMon);
|
||||
ASSERT_FALSE(notifiedThread);
|
||||
notifiedThread = current;
|
||||
mon.Notify();
|
||||
},
|
||||
50, nsITimer::TYPE_ONE_SHOT, "(test) Timers.ClosureCallback", testThread);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
ReentrantMonitorAutoEnter mon(*newMon);
|
||||
while (!notifiedThread) {
|
||||
mon.Wait();
|
||||
}
|
||||
ASSERT_EQ(notifiedThread, testThread);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ interface nsIEventTarget;
|
|||
%{C++
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include <functional>
|
||||
|
||||
/**
|
||||
* The signature of the timer callback function passed to initWithFuncCallback.
|
||||
|
@ -304,6 +305,34 @@ NS_NewTimerWithCallback(nsITimerCallback* aCallback,
|
|||
uint32_t aType,
|
||||
nsIEventTarget* aTarget = nullptr);
|
||||
|
||||
nsresult
|
||||
NS_NewTimerWithCallback(nsITimer** aTimer,
|
||||
std::function<void(nsITimer*)>&& aCallback,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType,
|
||||
const char* aNameString,
|
||||
nsIEventTarget* aTarget = nullptr);
|
||||
mozilla::Result<nsCOMPtr<nsITimer>, nsresult>
|
||||
NS_NewTimerWithCallback(std::function<void(nsITimer*)>&& aCallback,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType,
|
||||
const char* aNameString,
|
||||
nsIEventTarget* aTarget = nullptr);
|
||||
|
||||
nsresult
|
||||
NS_NewTimerWithCallback(nsITimer** aTimer,
|
||||
std::function<void(nsITimer*)>&& aCallback,
|
||||
const mozilla::TimeDuration& aDelay,
|
||||
uint32_t aType,
|
||||
const char* aNameString,
|
||||
nsIEventTarget* aTarget = nullptr);
|
||||
mozilla::Result<nsCOMPtr<nsITimer>, nsresult>
|
||||
NS_NewTimerWithCallback(std::function<void(nsITimer*)>&& aCallback,
|
||||
const mozilla::TimeDuration& aDelay,
|
||||
uint32_t aType,
|
||||
const char* aNameString,
|
||||
nsIEventTarget* aTarget = nullptr);
|
||||
|
||||
nsresult
|
||||
NS_NewTimerWithFuncCallback(nsITimer** aTimer,
|
||||
nsTimerCallbackFunc aCallback,
|
||||
|
|
|
@ -114,6 +114,45 @@ nsresult NS_NewTimerWithCallback(nsITimer** aTimer, nsITimerCallback* aCallback,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
mozilla::Result<nsCOMPtr<nsITimer>, nsresult> NS_NewTimerWithCallback(
|
||||
std::function<void(nsITimer*)>&& aCallback, uint32_t aDelay, uint32_t aType,
|
||||
const char* aNameString, nsIEventTarget* aTarget) {
|
||||
nsCOMPtr<nsITimer> timer;
|
||||
MOZ_TRY(NS_NewTimerWithCallback(getter_AddRefs(timer), std::move(aCallback),
|
||||
aDelay, aType, aNameString, aTarget));
|
||||
return timer;
|
||||
}
|
||||
nsresult NS_NewTimerWithCallback(nsITimer** aTimer,
|
||||
std::function<void(nsITimer*)>&& aCallback,
|
||||
uint32_t aDelay, uint32_t aType,
|
||||
const char* aNameString,
|
||||
nsIEventTarget* aTarget) {
|
||||
return NS_NewTimerWithCallback(aTimer, std::move(aCallback),
|
||||
TimeDuration::FromMilliseconds(aDelay), aType,
|
||||
aNameString, aTarget);
|
||||
}
|
||||
|
||||
mozilla::Result<nsCOMPtr<nsITimer>, nsresult> NS_NewTimerWithCallback(
|
||||
std::function<void(nsITimer*)>&& aCallback, const TimeDuration& aDelay,
|
||||
uint32_t aType, const char* aNameString, nsIEventTarget* aTarget) {
|
||||
nsCOMPtr<nsITimer> timer;
|
||||
MOZ_TRY(NS_NewTimerWithCallback(getter_AddRefs(timer), std::move(aCallback),
|
||||
aDelay, aType, aNameString, aTarget));
|
||||
return timer;
|
||||
}
|
||||
nsresult NS_NewTimerWithCallback(nsITimer** aTimer,
|
||||
std::function<void(nsITimer*)>&& aCallback,
|
||||
const TimeDuration& aDelay, uint32_t aType,
|
||||
const char* aNameString,
|
||||
nsIEventTarget* aTarget) {
|
||||
RefPtr<nsTimer> timer = nsTimer::WithEventTarget(aTarget);
|
||||
|
||||
MOZ_TRY(timer->InitWithClosureCallback(std::move(aCallback), aDelay, aType,
|
||||
aNameString));
|
||||
timer.forget(aTimer);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mozilla::Result<nsCOMPtr<nsITimer>, nsresult> NS_NewTimerWithFuncCallback(
|
||||
nsTimerCallbackFunc aCallback, void* aClosure, uint32_t aDelay,
|
||||
uint32_t aType, const char* aNameString, nsIEventTarget* aTarget) {
|
||||
|
@ -380,6 +419,19 @@ nsresult nsTimerImpl::Init(nsIObserver* aObserver, uint32_t aDelayInMs,
|
|||
return InitCommon(aDelayInMs, aType, std::move(cb));
|
||||
}
|
||||
|
||||
nsresult nsTimerImpl::InitWithClosureCallback(
|
||||
std::function<void(nsITimer*)>&& aCallback, const TimeDuration& aDelay,
|
||||
uint32_t aType, const char* aNameString) {
|
||||
if (NS_WARN_IF(!aCallback)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
Callback cb(ClosureCallback{std::move(aCallback), aNameString});
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
return InitCommon(aDelay, aType, std::move(cb));
|
||||
}
|
||||
|
||||
nsresult nsTimerImpl::Cancel() {
|
||||
CancelImpl(false);
|
||||
return NS_OK;
|
||||
|
@ -560,7 +612,8 @@ void nsTimerImpl::Fire(int32_t aGeneration) {
|
|||
[&](const ObserverCallback& o) {
|
||||
o->Observe(mITimer, NS_TIMER_CALLBACK_TOPIC, nullptr);
|
||||
},
|
||||
[&](const FuncCallback& f) { f.mFunc(mITimer, f.mClosure); });
|
||||
[&](const FuncCallback& f) { f.mFunc(mITimer, f.mClosure); },
|
||||
[&](const ClosureCallback& c) { c.mFunc(mITimer); });
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (aGeneration == mGeneration) {
|
||||
|
@ -625,17 +678,18 @@ void nsTimerImpl::LogFiring(const Callback& aCallback, uint8_t aType,
|
|||
|
||||
aCallback.match(
|
||||
[&](const UnknownCallback&) {
|
||||
MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
|
||||
("[%d] ??? timer (%s, %5d ms)\n", getpid(), typeStr, aDelay));
|
||||
MOZ_LOG(
|
||||
GetTimerFiringsLog(), LogLevel::Debug,
|
||||
("[%d] ??? timer (%s, %5d ms)\n", getpid(), typeStr, aDelay));
|
||||
},
|
||||
[&](const InterfaceCallback& i) {
|
||||
MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
|
||||
("[%d] iface timer (%s %5d ms): %p\n", getpid(), typeStr,
|
||||
("[%d] iface timer (%s %5d ms): %p\n", getpid(), typeStr,
|
||||
aDelay, i.get()));
|
||||
},
|
||||
[&](const ObserverCallback& o) {
|
||||
MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
|
||||
("[%d] obs timer (%s %5d ms): %p\n", getpid(), typeStr,
|
||||
("[%d] obs timer (%s %5d ms): %p\n", getpid(), typeStr,
|
||||
aDelay, o.get()));
|
||||
},
|
||||
[&](const FuncCallback& f) {
|
||||
|
@ -699,12 +753,17 @@ void nsTimerImpl::LogFiring(const Callback& aCallback, uint8_t aType,
|
|||
}
|
||||
|
||||
MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
|
||||
("[%d] fn timer (%s %5d ms): %s%s\n", getpid(), typeStr,
|
||||
("[%d] fn timer (%s %5d ms): %s%s\n", getpid(), typeStr,
|
||||
aDelay, annotation, name));
|
||||
|
||||
if (needToFreeName) {
|
||||
free(const_cast<char*>(name));
|
||||
}
|
||||
},
|
||||
[&](const ClosureCallback& c) {
|
||||
MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
|
||||
("[%d] closure timer (%s %5d ms): %s\n", getpid(), typeStr,
|
||||
aDelay, c.mName));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -739,7 +798,8 @@ void nsTimerImpl::GetName(nsACString& aName) {
|
|||
MOZ_ASSERT(f.mName.is<FuncCallback::NameNothing>());
|
||||
aName.AssignLiteral("Anonymous_callback_timer");
|
||||
}
|
||||
});
|
||||
},
|
||||
[&](const ClosureCallback& c) { aName.Assign(c.mName); });
|
||||
}
|
||||
|
||||
void nsTimerImpl::SetHolder(nsTimerImplHolder* aHolder) { mHolder = aHolder; }
|
||||
|
|
|
@ -88,8 +88,15 @@ class nsTimerImpl {
|
|||
Name mName;
|
||||
};
|
||||
|
||||
using Callback = mozilla::Variant<UnknownCallback, InterfaceCallback,
|
||||
ObserverCallback, FuncCallback>;
|
||||
/// A callback defined by an owned closure and its name for logging purposes.
|
||||
struct ClosureCallback {
|
||||
std::function<void(nsITimer*)> mFunc;
|
||||
const char* mName;
|
||||
};
|
||||
|
||||
using Callback =
|
||||
mozilla::Variant<UnknownCallback, InterfaceCallback, ObserverCallback,
|
||||
FuncCallback, ClosureCallback>;
|
||||
|
||||
nsresult InitCommon(uint32_t aDelayMS, uint32_t aType,
|
||||
Callback&& newCallback);
|
||||
|
@ -137,6 +144,10 @@ class nsTimerImpl {
|
|||
uint32_t aDelay, uint32_t aType,
|
||||
const FuncCallback::Name& aName);
|
||||
|
||||
nsresult InitWithClosureCallback(std::function<void(nsITimer*)>&& aCallback,
|
||||
const mozilla::TimeDuration& aDelay,
|
||||
uint32_t aType, const char* aNameString);
|
||||
|
||||
// This weak reference must be cleared by the nsTimerImplHolder by calling
|
||||
// SetHolder(nullptr) before the holder is destroyed.
|
||||
nsTimerImplHolder* mHolder;
|
||||
|
@ -182,6 +193,16 @@ class nsTimer final : public nsITimer {
|
|||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_FORWARD_SAFE_NSITIMER(mImpl);
|
||||
|
||||
// NOTE: This constructor is not exposed on `nsITimer` as NS_FORWARD_SAFE_
|
||||
// does not support forwarding rvalue references.
|
||||
nsresult InitWithClosureCallback(std::function<void(nsITimer*)>&& aCallback,
|
||||
const mozilla::TimeDuration& aDelay,
|
||||
uint32_t aType, const char* aNameString) {
|
||||
return mImpl ? mImpl->InitWithClosureCallback(std::move(aCallback), aDelay,
|
||||
aType, aNameString)
|
||||
: NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
virtual size_t SizeOfIncludingThis(
|
||||
mozilla::MallocSizeOf aMallocSizeOf) const override;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче