1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/modules/interface/module.h"
12#include "webrtc/modules/utility/source/process_thread_impl.h"
13
14
15namespace webrtc {
16ProcessThread::~ProcessThread()
17{
18}
19
20ProcessThread* ProcessThread::CreateProcessThread()
21{
22    return new ProcessThreadImpl();
23}
24
25void ProcessThread::DestroyProcessThread(ProcessThread* module)
26{
27    delete module;
28}
29
30ProcessThreadImpl::ProcessThreadImpl()
31    : _timeEvent(*EventWrapper::Create()),
32      _critSectModules(CriticalSectionWrapper::CreateCriticalSection()),
33      _thread(NULL)
34{
35}
36
37ProcessThreadImpl::~ProcessThreadImpl()
38{
39    delete _critSectModules;
40    delete &_timeEvent;
41}
42
43int32_t ProcessThreadImpl::Start()
44{
45    CriticalSectionScoped lock(_critSectModules);
46    if(_thread)
47    {
48        return -1;
49    }
50    _thread = ThreadWrapper::CreateThread(Run, this, kNormalPriority,
51                                          "ProcessThread");
52    unsigned int id;
53    int32_t retVal = _thread->Start(id);
54    if(retVal >= 0)
55    {
56        return 0;
57    }
58    delete _thread;
59    _thread = NULL;
60    return -1;
61}
62
63int32_t ProcessThreadImpl::Stop()
64{
65    _critSectModules->Enter();
66    if(_thread)
67    {
68        _thread->SetNotAlive();
69
70        ThreadWrapper* thread = _thread;
71        _thread = NULL;
72
73        _timeEvent.Set();
74        _critSectModules->Leave();
75
76        if(thread->Stop())
77        {
78            delete thread;
79        } else {
80            return -1;
81        }
82    } else {
83        _critSectModules->Leave();
84    }
85    return 0;
86}
87
88int32_t ProcessThreadImpl::RegisterModule(Module* module)
89{
90    CriticalSectionScoped lock(_critSectModules);
91
92    // Only allow module to be registered once.
93    for (ModuleList::iterator iter = _modules.begin();
94         iter != _modules.end(); ++iter) {
95        if(module == *iter)
96        {
97            return -1;
98        }
99    }
100
101    _modules.push_front(module);
102
103    // Wake the thread calling ProcessThreadImpl::Process() to update the
104    // waiting time. The waiting time for the just registered module may be
105    // shorter than all other registered modules.
106    _timeEvent.Set();
107    return 0;
108}
109
110int32_t ProcessThreadImpl::DeRegisterModule(const Module* module)
111{
112    CriticalSectionScoped lock(_critSectModules);
113    for (ModuleList::iterator iter = _modules.begin();
114         iter != _modules.end(); ++iter) {
115        if(module == *iter)
116        {
117            _modules.erase(iter);
118            return 0;
119        }
120    }
121    return -1;
122}
123
124bool ProcessThreadImpl::Run(void* obj)
125{
126    return static_cast<ProcessThreadImpl*>(obj)->Process();
127}
128
129bool ProcessThreadImpl::Process()
130{
131    // Wait for the module that should be called next, but don't block thread
132    // longer than 100 ms.
133    int32_t minTimeToNext = 100;
134    {
135        CriticalSectionScoped lock(_critSectModules);
136        for (ModuleList::iterator iter = _modules.begin();
137             iter != _modules.end(); ++iter) {
138          int32_t timeToNext = (*iter)->TimeUntilNextProcess();
139            if(minTimeToNext > timeToNext)
140            {
141                minTimeToNext = timeToNext;
142            }
143        }
144    }
145
146    if(minTimeToNext > 0)
147    {
148        if(kEventError == _timeEvent.Wait(minTimeToNext))
149        {
150            return true;
151        }
152        CriticalSectionScoped lock(_critSectModules);
153        if(!_thread)
154        {
155            return false;
156        }
157    }
158    {
159        CriticalSectionScoped lock(_critSectModules);
160        for (ModuleList::iterator iter = _modules.begin();
161             iter != _modules.end(); ++iter) {
162          int32_t timeToNext = (*iter)->TimeUntilNextProcess();
163            if(timeToNext < 1)
164            {
165                (*iter)->Process();
166            }
167        }
168    }
169    return true;
170}
171}  // namespace webrtc
172