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:
Nika Layzell 2021-05-18 16:24:48 +00:00
Родитель 4b3f75001a
Коммит 4c32cf1fe5
4 изменённых файлов: 150 добавлений и 9 удалений

Просмотреть файл

@ -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;