1 /*
2 * Copyright (C) 2007 Marc Boris Duerner
3 * Copyright (C) 2007 Laurentiu-Gheorghe Crisan
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * As a special exception, you may use this file as part of a free
11 * software library without restriction. Specifically, if other files
12 * instantiate templates or use macros or inline functions from this
13 * file, or you compile this file and link it with other files to
14 * produce an executable, this file does not by itself cause the
15 * resulting executable to be covered by the GNU General Public
16 * License. This exception does not however invalidate any other
17 * reasons why the executable file might be covered by the GNU Library
18 * General Public License.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29 #include "selectorimpl.h"
30 #include "cxxtools/eventloop.h"
31
32 namespace cxxtools {
33
EventLoop()34 EventLoop::EventLoop()
35 : _exitLoop(false)
36 , _allocator(/*255, 64*/)
37 {
38 _selector = new SelectorImpl();
39 }
40
41
~EventLoop()42 EventLoop::~EventLoop()
43 {
44 try
45 {
46 while ( ! _eventQueue.empty() )
47 {
48 Event* ev = _eventQueue.front();
49 _eventQueue.pop_front();
50 ev->destroy(_allocator);
51 }
52 }
53 catch(...)
54 {}
55
56 delete _selector;
57 }
58
59
onAdd(Selectable & s)60 void EventLoop::onAdd( Selectable& s )
61 {
62 return _selector->add( s );
63 }
64
65
onRemove(Selectable & s)66 void EventLoop::onRemove( Selectable& s )
67 {
68 _selector->remove( s );
69 }
70
71
onReinit(Selectable & s)72 void EventLoop::onReinit(Selectable& s)
73 {
74 }
75
76
onChanged(Selectable & s)77 void EventLoop::onChanged(Selectable& s)
78 {
79 _selector->changed(s);
80 }
81
82
onRun()83 void EventLoop::onRun()
84 {
85 while( true )
86 {
87 RecursiveLock lock(_queueMutex);
88
89 if(_exitLoop)
90 {
91 _exitLoop = false;
92 break;
93 }
94
95 if( !_eventQueue.empty() )
96 {
97 lock.unlock();
98 this->processEvents();
99 }
100
101 lock.unlock();
102
103 bool active = this->wait( this->idleTimeout() );
104 if( ! active )
105 timeout.send();
106 }
107
108 exited();
109 }
110
111
onWait(std::size_t msecs)112 bool EventLoop::onWait(std::size_t msecs)
113 {
114 if( _selector->wait(msecs) )
115 {
116 RecursiveLock lock(_queueMutex);
117
118 if( !_eventQueue.empty() )
119 {
120 lock.unlock();
121 this->processEvents();
122 }
123
124 return true;
125 }
126
127 return false;
128 }
129
130
onWake()131 void EventLoop::onWake()
132 {
133 _selector->wake();
134 }
135
136
onExit()137 void EventLoop::onExit()
138 {
139 RecursiveLock lock(_queueMutex);
140 _exitLoop = true;
141 lock.unlock();
142
143 this->wake();
144 }
145
146
onCommitEvent(const Event & ev)147 void EventLoop::onCommitEvent(const Event& ev)
148 {
149 {
150 RecursiveLock lock( _queueMutex );
151
152 // TODO: use a continuous block of memory to store events
153 // this avoids new/delete
154 Event& clonedEvent = ev.clone(_allocator);
155
156 try
157 {
158 _eventQueue.push_back(&clonedEvent);
159 }
160 catch(...)
161 {
162 clonedEvent.destroy(_allocator);
163 throw;
164 }
165 }
166
167 this->wake();
168 }
169
170
onProcessEvents()171 void EventLoop::onProcessEvents()
172 {
173 while( false == _exitLoop )
174 {
175 RecursiveLock lock(_queueMutex);
176
177 if ( _eventQueue.empty() || _exitLoop )
178 break;
179
180 Event* ev = _eventQueue.front();
181 _eventQueue.pop_front();
182
183 try
184 {
185 lock.unlock();
186 event.send(*ev);
187 }
188 catch(...)
189 {
190 ev->destroy(_allocator);
191 throw;
192 }
193
194 ev->destroy(_allocator);
195 }
196 }
197
198 } // namespace cxxtools
199