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