root/branches/libffado-2.0/src/libcontrol/Element.cpp

Revision 1295, 7.2 kB (checked in by ppalmers, 13 years ago)

add range checks for libcontrol indexes. add support for signals w/o arguments

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "Element.h"
25
26 #include "libutil/PosixMutex.h"
27
28 namespace Control {
29
30 IMPL_DEBUG_MODULE( Element, Element, DEBUG_LEVEL_NORMAL );
31
32 // This serves as an ID
33 // incremented on every Element creation
34 // ID's are unique as long as we don't create
35 // more than 2^64 elements.
36 // if we would create 1000 Elements per second
37 // we'd still need >500000 years to wrap.
38 // I guess we're safe.
39 static uint64_t GlobalElementCounter=0;
40
41 Element::Element(Element *parent)
42 : m_element_lock ( NULL )
43 , m_parent( parent )
44 , m_Name ( "NoName" )
45 , m_Label ( "No Label" )
46 , m_Description ( "No Description" )
47 , m_id(GlobalElementCounter++)
48 {
49     // no parent, we are the root of an independent control tree
50     // this means we have to create a lock
51     if(parent == NULL) {
52         m_element_lock = new Util::PosixMutex("CTLEL");
53     }
54 }
55
56 Element::Element(Element *parent, std::string n)
57 : m_element_lock ( NULL )
58 , m_parent( parent )
59 , m_Name( n )
60 , m_Label ( "No Label" )
61 , m_Description ( "No Description" )
62 , m_id(GlobalElementCounter++)
63 {
64     // no parent, we are the root of an independent control tree
65     // this means we have to create a lock
66     if(parent == NULL) {
67         m_element_lock = new Util::PosixMutex("CTLEL");
68     }
69 }
70
71 Element::~Element()
72 {
73     if(m_element_lock) delete m_element_lock;
74 }
75
76 void
77 Element::lockControl()
78 {
79     if(!m_parent) {
80         debugOutput( DEBUG_LEVEL_VERBOSE, "Locking tree...\n");
81     }
82     getLock().Lock();
83 }
84
85 void
86 Element::unlockControl()
87 {
88     if(!m_parent) {
89         debugOutput( DEBUG_LEVEL_VERBOSE, "Unlocking tree...\n");
90     }
91     getLock().Unlock();
92 }
93
94 Util::Mutex&
95 Element::getLock()
96 {
97     assert(m_parent != NULL || m_element_lock != NULL);
98     if(m_parent) {
99         return m_parent->getLock();
100     } else {
101         return *m_element_lock;
102     }
103 }
104
105 void
106 Element::show()
107 {
108     debugOutput( DEBUG_LEVEL_NORMAL, "Element %s\n",
109         getName().c_str());
110 }
111
112 void
113 Element::setVerboseLevel(int l)
114 {
115     setDebugLevel(l);
116     if(m_element_lock) m_element_lock->setVerboseLevel(l);
117     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
118 }
119
120 bool
121 Element::addSignalHandler( SignalFunctor* functor )
122 {
123     debugOutput(DEBUG_LEVEL_VERBOSE, "Adding signal handler (%p)\n", functor);
124     m_signalHandlers.push_back( functor );
125     return true;
126 }
127
128 bool
129 Element::remSignalHandler( SignalFunctor* functor )
130 {
131     debugOutput(DEBUG_LEVEL_VERBOSE, "Removing signal handler (%p)\n", functor);
132
133     for ( std::vector< SignalFunctor* >::iterator it = m_signalHandlers.begin();
134           it != m_signalHandlers.end();
135           ++it )
136     {
137         if ( *it == functor ) {
138             debugOutput(DEBUG_LEVEL_VERBOSE, " found\n");
139             m_signalHandlers.erase( it );
140             return true;
141         }
142     }
143     debugOutput(DEBUG_LEVEL_VERBOSE, " not found\n");
144     return false;
145 }
146
147 bool
148 Element::emitSignal(int id, int value)
149 {
150     for ( std::vector< SignalFunctor* >::iterator it = m_signalHandlers.begin();
151           it != m_signalHandlers.end();
152           ++it )
153     {
154         SignalFunctor *f = *it;
155         if(f && f->m_id == id) (*f)(value);
156     }
157     return true;
158 }
159
160 bool
161 Element::emitSignal(int id)
162 {
163     for ( std::vector< SignalFunctor* >::iterator it = m_signalHandlers.begin();
164           it != m_signalHandlers.end();
165           ++it )
166     {
167         SignalFunctor *f = *it;
168         if(f && f->m_id == id) (*f)();
169     }
170     return true;
171 }
172
173 //// --- Container --- ////
174 Container::Container(Element *p)
175 : Element(p)
176 {
177 }
178
179 Container::Container(Element *p, std::string n)
180 : Element(p, n)
181 {
182 }
183
184 Container::~Container()
185 {
186 }
187
188 unsigned int
189 Container::countElements()
190 {
191     lockControl();
192     unsigned int s = m_Children.size();
193     unlockControl();
194     return s;
195 }
196
197 const ElementVector &
198 Container::getElementVector()
199 {
200     if(!getLock().isLocked()) {
201         debugWarning("called on unlocked tree!\n");
202     }
203     return m_Children;
204 }
205
206 bool
207 Container::addElement(Element *e)
208 {
209     Util::MutexLockHelper lock(getLock());
210     if (e==NULL) {
211         debugWarning("Cannot add NULL element\n");
212         return false;
213     }
214
215     debugOutput( DEBUG_LEVEL_VERBOSE, "Adding Element %s to %s\n",
216         e->getName().c_str(), getName().c_str());
217
218     // don't allow duplicates, only makes life hard
219     for ( ElementVectorIterator it = m_Children.begin();
220       it != m_Children.end();
221       ++it )
222     {
223         if(*it == e) {
224             debugOutput( DEBUG_LEVEL_VERBOSE, "Not adding Element %s, already present\n",
225                 e->getName().c_str());
226             return false;
227         }
228     }
229
230     m_Children.push_back(e);
231     // unlock before emitting the signal
232     lock.earlyUnlock();
233     emitSignal(eS_Updated, m_Children.size());
234     return true;
235 }
236
237 bool
238 Container::deleteElementNoLock(Element *e)
239 {
240     if(e == NULL) return false;
241     debugOutput( DEBUG_LEVEL_VERBOSE, "Deleting Element %s from %s\n",
242         e->getName().c_str(), getName().c_str());
243
244     for ( ElementVectorIterator it = m_Children.begin();
245       it != m_Children.end();
246       ++it )
247     {
248         if(*it == e) {
249             m_Children.erase(it);
250             return true;
251         }
252     }
253
254     debugOutput( DEBUG_LEVEL_VERBOSE, "Element %s not found \n",e->getName().c_str());
255     return false; //not found
256 }
257
258 bool
259 Container::deleteElement(Element *e)
260 {
261     bool retval;
262     Util::MutexLockHelper lock(getLock());
263     retval = deleteElementNoLock(e);
264     if(retval) {
265         // unlock before emitting the signal
266         lock.earlyUnlock();
267         emitSignal(eS_Updated, m_Children.size());
268     }
269     return retval;
270 }
271
272 bool
273 Container::clearElements(bool delete_pointers)
274 {
275     Util::MutexLockHelper lock(getLock());
276     while(m_Children.size()) {
277         Element *e=m_Children[0];
278         deleteElementNoLock(e);
279         if (delete_pointers) delete e;
280     }
281
282     // unlock before emitting the signal
283     lock.earlyUnlock();
284     emitSignal(eS_Updated, m_Children.size());
285     return true;
286 }
287
288 void
289 Container::show()
290 {
291     Util::MutexLockHelper lock(getLock());
292     debugOutput( DEBUG_LEVEL_NORMAL, "Container %s (%d Elements)\n",
293         getName().c_str(), m_Children.size());
294
295     for ( ElementVectorIterator it = m_Children.begin();
296       it != m_Children.end();
297       ++it )
298     {
299         (*it)->show();
300     }
301 }
302
303 void
304 Container::setVerboseLevel(int l)
305 {
306     setDebugLevel(l);
307     for ( ElementVectorIterator it = m_Children.begin();
308       it != m_Children.end();
309       ++it )
310     {
311         (*it)->setVerboseLevel(l);
312     }
313     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
314 }
315
316 } // namespace Control
Note: See TracBrowser for help on using the browser.