本文整理汇总了C++中NS_NewRunnableMethod函数的典型用法代码示例。如果您正苦于以下问题:C++ NS_NewRunnableMethod函数的具体用法?C++ NS_NewRunnableMethod怎么用?C++ NS_NewRunnableMethod使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了NS_NewRunnableMethod函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的C++代码示例。
示例1: NS_NewRunnableMethod
void
DecoderCallbackFuzzingWrapper::InputExhausted()
{
if (!mTaskQueue->IsCurrentThreadIn()) {
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::InputExhausted);
mTaskQueue->Dispatch(task.forget());
return;
}
if (!mDontDelayInputExhausted && !mDelayedOutput.empty()) {
MediaDataAndInputExhausted& last = mDelayedOutput.back();
CFW_LOGD("InputExhausted delayed until after output of [email protected]%lld",
last.first()->mTime);
last.second() = true;
return;
}
CFW_LOGV("");
MOZ_ASSERT(mCallback);
mCallback->InputExhausted();
}
开发者ID:70599,项目名称:Waterfox,代码行数:20,代码来源:FuzzingWrapper.cpp
示例2: NS_NewRunnableMethod
void
DecoderCallbackFuzzingWrapper::DrainComplete()
{
if (!mTaskQueue->IsCurrentThreadIn()) {
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::DrainComplete);
mTaskQueue->Dispatch(task.forget());
return;
}
MOZ_ASSERT(mCallback);
if (mDelayedOutput.empty()) {
// No queued output -> Draining is complete now.
CFW_LOGV("No delayed output -> DrainComplete now");
mCallback->DrainComplete();
} else {
// Queued output waiting -> Make sure we call DrainComplete when it's empty.
CFW_LOGD("Delayed output -> DrainComplete later");
mDraining = true;
}
}
开发者ID:LaiPhil,项目名称:gecko-dev,代码行数:20,代码来源:FuzzingWrapper.cpp
示例3: ASSERT_OWNING_THREAD
nsresult
LazyIdleThread::EnsureThread()
{
ASSERT_OWNING_THREAD();
if (mShutdown) {
return NS_ERROR_UNEXPECTED;
}
if (mThread) {
return NS_OK;
}
MOZ_ASSERT(!mPendingEventCount, "Shouldn't have events yet!");
MOZ_ASSERT(!mIdleNotificationCount, "Shouldn't have idle events yet!");
MOZ_ASSERT(!mIdleTimer, "Should have killed this long ago!");
MOZ_ASSERT(!mThreadIsShuttingDown, "Should have cleared that!");
nsresult rv;
if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) {
nsCOMPtr<nsIObserverService> obs =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = obs->AddObserver(this, "xpcom-shutdown-threads", false);
NS_ENSURE_SUCCESS(rv, rv);
}
mIdleTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
NS_ENSURE_TRUE(mIdleTimer, NS_ERROR_FAILURE);
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &LazyIdleThread::InitThread);
NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE);
rv = NS_NewThread(getter_AddRefs(mThread), runnable);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
开发者ID:Tripleman,项目名称:mozilla-central,代码行数:41,代码来源:LazyIdleThread.cpp
示例4: NS_IMETHODIMP_
NS_IMETHODIMP_(MozExternalRefCountType) SharedThreadPool::Release(void)
{
MOZ_ASSERT(sMonitor);
bool dispatchShutdownEvent;
{
ReentrantMonitorAutoEnter mon(*sMonitor);
nsrefcnt count = --mRefCnt;
NS_LOG_RELEASE(this, count, "SharedThreadPool");
if (count) {
return count;
}
// Zero refcount. Must shutdown and then delete the thread pool.
// First, dispatch an event to the main thread to call Shutdown() on
// the nsIThreadPool. The Runnable here will add a refcount to the pool,
// and when the Runnable releases the nsIThreadPool it will be deleted.
RefPtr<nsIRunnable> r = NS_NewRunnableMethod(mPool, &nsIThreadPool::Shutdown);
NS_DispatchToMainThread(r);
// Remove SharedThreadPool from table of pools.
sPools->Remove(mName);
MOZ_ASSERT(!sPools->Get(mName));
// Stabilize refcount, so that if something in the dtor QIs,
// it won't explode.
mRefCnt = 1;
delete this;
dispatchShutdownEvent = sPools->Count() == 0;
}
if (dispatchShutdownEvent) {
// No more SharedThreadPools alive. Destroy the hash table.
// Ensure that we only run on the main thread.
// Do this in an event so that if something holds the monitor we won't
// be deleting the monitor while it's held.
NS_DispatchToMainThread(new ShutdownPoolsEvent());
}
return 0;
}
开发者ID:AOSC-Dev,项目名称:Pale-Moon,代码行数:41,代码来源:SharedThreadPool.cpp
示例5: NS_NewNamedThread
nsresult
AudioSink::Init()
{
nsresult rv = NS_NewNamedThread("Media Audio",
getter_AddRefs(mThread),
nullptr,
MEDIA_THREAD_STACK_SIZE);
if (NS_FAILED(rv)) {
mStateMachine->OnAudioSinkError();
return rv;
}
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &AudioSink::AudioLoop);
rv = mThread->Dispatch(event, NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
mStateMachine->OnAudioSinkError();
return rv;
}
return NS_OK;
}
开发者ID:nixiValor,项目名称:Waterfox,代码行数:21,代码来源:AudioSink.cpp
示例6: CreateDecoder
nsresult
MediaCodecDataDecoder::InitDecoder(Surface::Param aSurface)
{
mDecoder = CreateDecoder(mMimeType);
if (!mDecoder) {
INVOKE_CALLBACK(Error);
return NS_ERROR_FAILURE;
}
nsresult rv;
NS_ENSURE_SUCCESS(rv = mDecoder->Configure(mFormat, aSurface, nullptr, 0), rv);
NS_ENSURE_SUCCESS(rv = mDecoder->Start(), rv);
NS_ENSURE_SUCCESS(rv = ResetInputBuffers(), rv);
NS_ENSURE_SUCCESS(rv = ResetOutputBuffers(), rv);
NS_NewNamedThread("MC Decoder", getter_AddRefs(mThread),
NS_NewRunnableMethod(this, &MediaCodecDataDecoder::DecoderLoop));
return NS_OK;
}
开发者ID:pkdevboxy,项目名称:gecko-dev,代码行数:21,代码来源:AndroidDecoderModule.cpp
示例7: lock
// Called on the control thread.
nsresult
BackgroundFileSaver::GetWorkerThreadAttention(bool aShouldInterruptCopy)
{
nsresult rv;
MutexAutoLock lock(mLock);
// We only require attention one time. If this function is called two times
// before the worker thread wakes up, and the first has aShouldInterruptCopy
// false and the second true, we won't forcibly interrupt the copy from the
// control thread. However, that never happens, because calling Finish with a
// success code is the only case that may result in aShouldInterruptCopy being
// false. In that case, we won't call this function again, because consumers
// should not invoke other methods on the control thread after calling Finish.
// And in any case, Finish already closes one end of the pipe, causing the
// copy to finish properly on its own.
if (mWorkerThreadAttentionRequested) {
return NS_OK;
}
if (!mAsyncCopyContext) {
// Copy is not in progress, post an event to handle the change manually.
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &BackgroundFileSaver::ProcessAttention);
NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
rv = mWorkerThread->Dispatch(event, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
} else if (aShouldInterruptCopy) {
// Interrupt the copy. The copy will be resumed, if needed, by the
// ProcessAttention function, invoked by the AsyncCopyCallback function.
NS_CancelAsyncCopy(mAsyncCopyContext, NS_ERROR_ABORT);
}
// Indicate that attention has been requested successfully, there is no need
// to post another event until the worker thread processes the current one.
mWorkerThreadAttentionRequested = true;
return NS_OK;
}
开发者ID:logicoftekk,项目名称:cyberfox,代码行数:41,代码来源:BackgroundFileSaver.cpp
示例8: LOG
void
CacheStorageService::OnMemoryConsumptionChange(CacheMemoryConsumer* aConsumer,
uint32_t aCurrentMemoryConsumption)
{
LOG(("CacheStorageService::OnMemoryConsumptionChange [consumer=%p, size=%u]",
aConsumer, aCurrentMemoryConsumption));
uint32_t savedMemorySize = aConsumer->mReportedMemoryConsumption;
if (savedMemorySize == aCurrentMemoryConsumption)
return;
// Exchange saved size with current one.
aConsumer->mReportedMemoryConsumption = aCurrentMemoryConsumption;
mMemorySize -= savedMemorySize;
mMemorySize += aCurrentMemoryConsumption;
LOG((" mMemorySize=%u (+%u,-%u)", uint32_t(mMemorySize), aCurrentMemoryConsumption, savedMemorySize));
// Bypass purging when memory has not grew up significantly
if (aCurrentMemoryConsumption <= savedMemorySize)
return;
if (mPurging) {
LOG((" already purging"));
return;
}
if (mMemorySize <= CacheObserver::MemoryLimit())
return;
// Throw the oldest data or whole entries away when over certain limits
mPurging = true;
// Must always dipatch, since this can be called under e.g. a CacheFile's lock.
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &CacheStorageService::PurgeOverMemoryLimit);
Dispatch(event);
}
开发者ID:at13,项目名称:mozilla-central,代码行数:40,代码来源:CacheStorageService.cpp
示例9: NS_NewNamedThread
nsRefPtr<GenericPromise>
AudioSink::Init()
{
nsRefPtr<GenericPromise> p = mEndPromise.Ensure(__func__);
nsresult rv = NS_NewNamedThread("Media Audio",
getter_AddRefs(mThread),
nullptr,
MEDIA_THREAD_STACK_SIZE);
if (NS_FAILED(rv)) {
mEndPromise.Reject(rv, __func__);
return p;
}
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &AudioSink::AudioLoop);
rv = mThread->Dispatch(event, NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
mEndPromise.Reject(rv, __func__);
return p;
}
return p;
}
开发者ID:darchons,项目名称:gecko-dev,代码行数:22,代码来源:AudioSink.cpp
示例10: NS_ENSURE_SUCCESS
nsresult
MediaSourceDecoder::SetCDMProxy(CDMProxy* aProxy)
{
nsresult rv = MediaDecoder::SetCDMProxy(aProxy);
NS_ENSURE_SUCCESS(rv, rv);
rv = mReader->SetCDMProxy(aProxy);
NS_ENSURE_SUCCESS(rv, rv);
if (aProxy) {
// The sub readers can't decrypt EME content until they have a CDMProxy,
// and the CDMProxy knows the capabilities of the CDM. The MediaSourceReader
// remains in "waiting for resources" state until then. We need to kick the
// reader out of waiting if the CDM gets added with known capabilities.
CDMCaps::AutoLock caps(aProxy->Capabilites());
if (!caps.AreCapsKnown()) {
nsCOMPtr<nsIRunnable> task(
NS_NewRunnableMethod(this, &MediaDecoder::NotifyWaitingForResourcesStatusChanged));
caps.CallOnMainThreadWhenCapsAvailable(task);
}
}
return NS_OK;
}
开发者ID:nixiValor,项目名称:Waterfox,代码行数:22,代码来源:MediaSourceDecoder.cpp
示例11: LOG
void
CacheStorageService::OnMemoryConsumptionChange(CacheMemoryConsumer* aConsumer,
uint32_t aCurrentMemoryConsumption)
{
LOG(("CacheStorageService::OnMemoryConsumptionChange [consumer=%p, size=%u]",
aConsumer, aCurrentMemoryConsumption));
uint32_t savedMemorySize = aConsumer->mReportedMemoryConsumption;
if (savedMemorySize == aCurrentMemoryConsumption)
return;
// Exchange saved size with current one.
aConsumer->mReportedMemoryConsumption = aCurrentMemoryConsumption;
bool usingDisk = !(aConsumer->mFlags & CacheMemoryConsumer::MEMORY_ONLY);
bool overLimit = Pool(usingDisk).OnMemoryConsumptionChange(
savedMemorySize, aCurrentMemoryConsumption);
if (!overLimit)
return;
// It's likely the timer has already been set when we get here,
// check outside the lock to save resources.
if (mPurgeTimer)
return;
// We don't know if this is called under the service lock or not,
// hence rather dispatch.
nsRefPtr<nsIEventTarget> cacheIOTarget = Thread();
if (!cacheIOTarget)
return;
// Dispatch as a priority task, we want to set the purge timer
// ASAP to prevent vain redispatch of this event.
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &CacheStorageService::SchedulePurgeOverMemoryLimit);
cacheIOTarget->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
}
开发者ID:JuannyWang,项目名称:gecko-dev,代码行数:38,代码来源:CacheStorageService.cpp
示例12: NS_NewRunnableMethod
void
MediaSourceDecoder::ScheduleDurationChange(double aOldDuration,
double aNewDuration,
MSRangeRemovalAction aAction)
{
if (aAction == MSRangeRemovalAction::SKIP) {
if (NS_IsMainThread()) {
MediaDecoder::DurationChanged();
} else {
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &MediaDecoder::DurationChanged);
NS_DispatchToMainThread(task);
}
} else {
if (NS_IsMainThread()) {
DurationChanged(aOldDuration, aNewDuration);
} else {
nsCOMPtr<nsIRunnable> task =
new DurationChangedRunnable(this, aOldDuration, aNewDuration);
NS_DispatchToMainThread(task);
}
}
}
开发者ID:nixiValor,项目名称:Waterfox,代码行数:23,代码来源:MediaSourceDecoder.cpp
示例13: NS_ENSURE_SUCCESS
nsresult
HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers)
{
Link::ResetLinkState(false, Link::ElementHasHref());
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
if (aDocument) {
aDocument->RegisterPendingLinkUpdate(this);
}
void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal;
nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update));
CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMLinkAdded"));
return rv;
}
开发者ID:RickEyre,项目名称:mozilla-central,代码行数:23,代码来源:HTMLLinkElement.cpp
示例14: Run
NS_IMETHOD Run()
{
MOZ_ASSERT(!NS_IsMainThread());
bool continueThread;
do {
continueThread = mDBusWatcher->Poll();
} while (continueThread);
mDBusWatcher->CleanUp();
nsIThread* thread;
nsresult rv = NS_GetCurrentThread(&thread);
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(thread, &nsIThread::Shutdown);
rv = NS_DispatchToMainThread(runnable);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
开发者ID:gw280,项目名称:gecko-dev,代码行数:23,代码来源:DBusThread.cpp
示例15: mAudioCompactor
MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder,
MediaTaskQueue* aBorrowedTaskQueue)
: mAudioCompactor(mAudioQueue)
, mDecoder(aDecoder)
, mTaskQueue(aBorrowedTaskQueue ? aBorrowedTaskQueue
: new MediaTaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
/* aSupportsTailDispatch = */ true))
, mDuration(mTaskQueue, NullableTimeUnit(), "MediaDecoderReader::mDuration (Mirror)")
, mIgnoreAudioOutputFormat(false)
, mStartTime(-1)
, mHitAudioDecodeError(false)
, mShutdown(false)
, mTaskQueueIsBorrowed(!!aBorrowedTaskQueue)
, mAudioDiscontinuity(false)
, mVideoDiscontinuity(false)
{
MOZ_COUNT_CTOR(MediaDecoderReader);
MOZ_ASSERT(NS_IsMainThread());
// Dispatch initialization that needs to happen on that task queue.
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderReader::InitializationTask);
mTaskQueue->Dispatch(r.forget());
}
开发者ID:nafis-sadik,项目名称:gecko-dev,代码行数:23,代码来源:MediaDecoderReader.cpp
示例16: mAudioCompactor
MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
: mAudioCompactor(mAudioQueue)
, mDecoder(aDecoder)
, mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
/* aSupportsTailDispatch = */ true))
, mWatchManager(this, mTaskQueue)
, mTimer(new MediaTimer())
, mBuffered(mTaskQueue, TimeIntervals(), "MediaDecoderReader::mBuffered (Canonical)")
, mDuration(mTaskQueue, NullableTimeUnit(), "MediaDecoderReader::mDuration (Mirror)")
, mThrottleDuration(TimeDuration::FromMilliseconds(500))
, mLastThrottledNotify(TimeStamp::Now() - mThrottleDuration)
, mIgnoreAudioOutputFormat(false)
, mHitAudioDecodeError(false)
, mShutdown(false)
, mAudioDiscontinuity(false)
, mVideoDiscontinuity(false)
{
MOZ_COUNT_CTOR(MediaDecoderReader);
MOZ_ASSERT(NS_IsMainThread());
// Dispatch initialization that needs to happen on that task queue.
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderReader::InitializationTask);
mTaskQueue->Dispatch(r.forget());
}
开发者ID:npark-mozilla,项目名称:gecko-dev,代码行数:24,代码来源:MediaDecoderReader.cpp
示例17: NS_ENSURE_SUCCESS
nsresult
HTMLTrackElement::BindToTree(nsIDocument* aDocument,
nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers)
{
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument,
aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
if (!aDocument) {
return NS_OK;
}
LOG(PR_LOG_DEBUG, ("Track Element bound to tree."));
if (!aParent || !aParent->IsNodeOfType(nsINode::eMEDIA)) {
return NS_OK;
}
// Store our parent so we can look up its frame for display.
if (!mMediaParent) {
mMediaParent = static_cast<HTMLMediaElement*>(aParent);
HTMLMediaElement* media = static_cast<HTMLMediaElement*>(aParent);
// TODO: separate notification for 'alternate' tracks?
media->NotifyAddedSource();
LOG(PR_LOG_DEBUG, ("Track element sent notification to parent."));
mMediaParent->RunInStableState(
NS_NewRunnableMethod(this, &HTMLTrackElement::LoadResource));
}
return NS_OK;
}
开发者ID:Incognito,项目名称:mozilla-central,代码行数:36,代码来源:HTMLTrackElement.cpp
示例18: NS_ENSURE_STATE
nsresult
nsPACMan::LoadPACFromURI(nsIURI *pacURI)
{
NS_ENSURE_STATE(!mShutdown);
NS_ENSURE_ARG(pacURI || mPACURI);
nsCOMPtr<nsIStreamLoader> loader =
do_CreateInstance(NS_STREAMLOADER_CONTRACTID);
NS_ENSURE_STATE(loader);
// Since we might get called from nsProtocolProxyService::Init, we need to
// post an event back to the main thread before we try to use the IO service.
//
// But, we need to flag ourselves as loading, so that we queue up any PAC
// queries the enter between now and when we actually load the PAC file.
if (!mLoadPending) {
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &nsPACMan::StartLoading);
nsresult rv;
if (NS_FAILED(rv = NS_DispatchToCurrentThread(event)))
return rv;
mLoadPending = true;
}
CancelExistingLoad();
mLoader = loader;
if (pacURI) {
mPACURI = pacURI;
mLoadFailureCount = 0; // reset
}
mScheduledReload = LL_MAXINT;
mPAC = nsnull;
return NS_OK;
}
开发者ID:Anachid,项目名称:mozilla-central,代码行数:36,代码来源:nsPACMan.cpp
示例19: DispatchFailConnection
NS_IMETHODIMP
EventSource::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatusCode)
{
mWaitingForOnStopRequest = false;
if (mReadyState == CLOSED) {
return NS_ERROR_ABORT;
}
if (NS_FAILED(aStatusCode)) {
DispatchFailConnection();
return aStatusCode;
}
nsresult rv;
nsresult healthOfRequestResult = CheckHealthOfRequestCallback(aRequest);
if (NS_SUCCEEDED(healthOfRequestResult) &&
mLastConvertionResult == NS_PARTIAL_MORE_INPUT) {
// we had an incomplete UTF8 char at the end of the stream
rv = ParseCharacter(REPLACEMENT_CHAR);
NS_ENSURE_SUCCESS(rv, rv);
}
ClearFields();
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &EventSource::ReestablishConnection);
NS_ENSURE_STATE(event);
rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
return healthOfRequestResult;
}
开发者ID:Georepublic,项目名称:mozilla-central,代码行数:36,代码来源:EventSource.cpp
示例20: MOZ_ASSERT
nsresult
EMEAudioDecoder::Flush()
{
MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
{
MonitorAutoLock mon(mMonitor);
mFlushComplete = false;
}
nsRefPtr<nsIRunnable> task;
task = NS_NewRunnableMethod(this, &EMEAudioDecoder::GmpFlush);
nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
{
MonitorAutoLock mon(mMonitor);
while (!mFlushComplete) {
mon.Wait();
}
}
return NS_OK;
}
开发者ID:dirkschulze,项目名称:gecko-dev,代码行数:24,代码来源:EMEAudioDecoder.cpp
注:本文中的NS_NewRunnableMethod函数示例由纯净天空整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论