blob: 9028c445a5ca7481b638b29a50b6ca4b1e46378a [file] [log] [blame]
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "process_thread_impl.h"
#include "module.h"
#include "trace.h"
namespace webrtc {
ProcessThread::~ProcessThread()
{
}
ProcessThread* ProcessThread::CreateProcessThread()
{
return new ProcessThreadImpl();
}
void ProcessThread::DestroyProcessThread(ProcessThread* module)
{
delete module;
}
ProcessThreadImpl::ProcessThreadImpl()
: _timeEvent(*EventWrapper::Create()),
_critSectModules(CriticalSectionWrapper::CreateCriticalSection()),
_thread(NULL)
{
WEBRTC_TRACE(kTraceMemory, kTraceUtility, -1, "%s created", __FUNCTION__);
}
ProcessThreadImpl::~ProcessThreadImpl()
{
delete _critSectModules;
delete &_timeEvent;
WEBRTC_TRACE(kTraceMemory, kTraceUtility, -1, "%s deleted", __FUNCTION__);
}
WebRtc_Word32 ProcessThreadImpl::Start()
{
CriticalSectionScoped lock(_critSectModules);
if(_thread)
{
return -1;
}
_thread = ThreadWrapper::CreateThread(Run, this, kNormalPriority,
"ProcessThread");
unsigned int id;
WebRtc_Word32 retVal = _thread->Start(id);
if(retVal >= 0)
{
return 0;
}
delete _thread;
_thread = NULL;
return -1;
}
WebRtc_Word32 ProcessThreadImpl::Stop()
{
_critSectModules->Enter();
if(_thread)
{
_thread->SetNotAlive();
ThreadWrapper* thread = _thread;
_thread = NULL;
_timeEvent.Set();
_critSectModules->Leave();
if(thread->Stop())
{
delete thread;
} else {
return -1;
}
} else {
_critSectModules->Leave();
}
return 0;
}
WebRtc_Word32 ProcessThreadImpl::RegisterModule(const Module* module)
{
CriticalSectionScoped lock(_critSectModules);
// Only allow module to be registered once.
ListItem* item = _modules.First();
for(WebRtc_UWord32 i = 0; i < _modules.GetSize() && item; i++)
{
if(module == item->GetItem())
{
return -1;
}
item = _modules.Next(item);
}
_modules.PushFront(module);
WEBRTC_TRACE(kTraceInfo, kTraceUtility, -1,
"number of registered modules has increased to %d",
_modules.GetSize());
// Wake the thread calling ProcessThreadImpl::Process() to update the
// waiting time. The waiting time for the just registered module may be
// shorter than all other registered modules.
_timeEvent.Set();
return 0;
}
WebRtc_Word32 ProcessThreadImpl::DeRegisterModule(const Module* module)
{
CriticalSectionScoped lock(_critSectModules);
ListItem* item = _modules.First();
for(WebRtc_UWord32 i = 0; i < _modules.GetSize() && item; i++)
{
if(module == item->GetItem())
{
int res = _modules.Erase(item);
WEBRTC_TRACE(kTraceInfo, kTraceUtility, -1,
"number of registered modules has decreased to %d",
_modules.GetSize());
return res;
}
item = _modules.Next(item);
}
return -1;
}
bool ProcessThreadImpl::Run(void* obj)
{
return static_cast<ProcessThreadImpl*>(obj)->Process();
}
bool ProcessThreadImpl::Process()
{
// Wait for the module that should be called next, but don't block thread
// longer than 100 ms.
WebRtc_Word32 minTimeToNext = 100;
{
CriticalSectionScoped lock(_critSectModules);
ListItem* item = _modules.First();
for(WebRtc_UWord32 i = 0; i < _modules.GetSize() && item; i++)
{
WebRtc_Word32 timeToNext =
static_cast<Module*>(item->GetItem())->TimeUntilNextProcess();
if(minTimeToNext > timeToNext)
{
minTimeToNext = timeToNext;
}
item = _modules.Next(item);
}
}
if(minTimeToNext > 0)
{
if(kEventError == _timeEvent.Wait(minTimeToNext))
{
return true;
}
if(!_thread)
{
return false;
}
}
{
CriticalSectionScoped lock(_critSectModules);
ListItem* item = _modules.First();
for(WebRtc_UWord32 i = 0; i < _modules.GetSize() && item; i++)
{
WebRtc_Word32 timeToNext =
static_cast<Module*>(item->GetItem())->TimeUntilNextProcess();
if(timeToNext < 1)
{
static_cast<Module*>(item->GetItem())->Process();
}
item = _modules.Next(item);
}
}
return true;
}
} // namespace webrtc