root/trunk/libffado/src/libcontrol/Element.cpp

Revision 1763, 8.1 kB (checked in by ppalmers, 14 years ago)

Merged revisions 1536,1541,1544-1546,1549,1554-1562,1571,1579-1581,1618,1632,1634-1635,1661,1677-1679,1703-1704,1715,1720-1723,1743-1745,1755 via svnmerge from
svn+ssh://ffadosvn@ffado.org/ffado/branches/libffado-2.0

Also fix remaining format string warnings.

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 bool
95 Element::isControlLocked()
96 {
97     return getLock().isLocked();
98 }
99
100 Util::Mutex&
101 Element::getLock()
102 {
103     assert(m_parent != NULL || m_element_lock != NULL);
104     if(m_parent) {
105         return m_parent->getLock();
106     } else {
107         return *m_element_lock;
108     }
109 }
110
111 bool
112 Element::canChangeValue()
113 {
114     return true;
115 }
116
117 void
118 Element::show()
119 {
120     debugOutput( DEBUG_LEVEL_NORMAL, "Element %s\n",
121         getName().c_str());
122 }
123
124 void
125 Element::setVerboseLevel(int l)
126 {
127     setDebugLevel(l);
128     if(m_element_lock) m_element_lock->setVerboseLevel(l);
129     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
130 }
131
132 bool
133 Element::addSignalHandler( SignalFunctor* functor )
134 {
135     debugOutput(DEBUG_LEVEL_VERBOSE, "Adding signal handler (%p)\n", functor);
136     m_signalHandlers.push_back( functor );
137     return true;
138 }
139
140 bool
141 Element::remSignalHandler( SignalFunctor* functor )
142 {
143     debugOutput(DEBUG_LEVEL_VERBOSE, "Removing signal handler (%p)\n", functor);
144
145     for ( std::vector< SignalFunctor* >::iterator it = m_signalHandlers.begin();
146           it != m_signalHandlers.end();
147           ++it )
148     {
149         if ( *it == functor ) {
150             debugOutput(DEBUG_LEVEL_VERBOSE, " found\n");
151             m_signalHandlers.erase( it );
152             return true;
153         }
154     }
155     debugOutput(DEBUG_LEVEL_VERBOSE, " not found\n");
156     return false;
157 }
158
159 bool
160 Element::emitSignal(int id, int value)
161 {
162     for ( std::vector< SignalFunctor* >::iterator it = m_signalHandlers.begin();
163           it != m_signalHandlers.end();
164           ++it )
165     {
166         SignalFunctor *f = *it;
167         if(f && f->m_id == id) (*f)(value);
168     }
169     return true;
170 }
171
172 bool
173 Element::emitSignal(int id)
174 {
175     for ( std::vector< SignalFunctor* >::iterator it = m_signalHandlers.begin();
176           it != m_signalHandlers.end();
177           ++it )
178     {
179         SignalFunctor *f = *it;
180         if(f && f->m_id == id) (*f)();
181     }
182     return true;
183 }
184
185 //// --- Container --- ////
186 Container::Container(Element *p)
187 : Element(p)
188 {
189 }
190
191 Container::Container(Element *p, std::string n)
192 : Element(p, n)
193 {
194 }
195
196 Container::~Container()
197 {
198 }
199
200 unsigned int
201 Container::countElements()
202 {
203     lockControl();
204     unsigned int s = m_Children.size();
205     unlockControl();
206     return s;
207 }
208
209 const ElementVector &
210 Container::getElementVector()
211 {
212     if(!getLock().isLocked()) {
213         debugWarning("called on unlocked tree!\n");
214     }
215     return m_Children;
216 }
217
218 /**
219  * Finds an element by name
220  * Note that you have to run this with the lock held,
221  * otherwise there is no guarantee that the element will
222  * not be deleted from the tree by an async event (e.g. busreset)
223  *
224  * @param name element name
225  * @return element or null if not found
226  */
227 Element *
228 Container::getElementByName(std::string name) {
229     if(!getLock().isLocked()) debugWarning("Getting a Config::Element without locking the control tree, dangerous!\n");
230     for ( ElementVectorIterator it = m_Children.begin();
231       it != m_Children.end();
232       ++it )
233     {
234         if((*it)->getName() == name) {
235             debugOutput( DEBUG_LEVEL_VERBOSE, "Found Element %s (%s) \n",
236                 (*it)->getName().c_str(), (*it)->getDescription().c_str());
237             return *it;
238         }
239     }
240     return NULL;
241 }
242
243 bool
244 Container::addElement(Element *e)
245 {
246     Util::MutexLockHelper lock(getLock());
247     if (e==NULL) {
248         debugWarning("Cannot add NULL element\n");
249         return false;
250     }
251
252     debugOutput( DEBUG_LEVEL_VERBOSE, "Adding Element %s to %s\n",
253         e->getName().c_str(), getName().c_str());
254
255     // don't allow duplicates, only makes life hard
256     for ( ElementVectorIterator it = m_Children.begin();
257       it != m_Children.end();
258       ++it )
259     {
260         if(*it == e) {
261             debugOutput( DEBUG_LEVEL_VERBOSE, "Not adding Element %s, already present\n",
262                 e->getName().c_str());
263             return false;
264         }
265     }
266
267     m_Children.push_back(e);
268     // unlock before emitting the signal
269     lock.earlyUnlock();
270     emitSignal(eS_Updated, m_Children.size());
271     return true;
272 }
273
274 bool
275 Container::deleteElementNoLock(Element *e)
276 {
277     if(e == NULL) return false;
278     debugOutput( DEBUG_LEVEL_VERBOSE, "Deleting Element %s from %s\n",
279         e->getName().c_str(), getName().c_str());
280
281     for ( ElementVectorIterator it = m_Children.begin();
282       it != m_Children.end();
283       ++it )
284     {
285         if(*it == e) {
286             m_Children.erase(it);
287             return true;
288         }
289     }
290
291     debugOutput( DEBUG_LEVEL_VERBOSE, "Element %s not found \n",e->getName().c_str());
292     return false; //not found
293 }
294
295 bool
296 Container::deleteElement(Element *e)
297 {
298     bool retval;
299     Util::MutexLockHelper lock(getLock());
300     retval = deleteElementNoLock(e);
301     if(retval) {
302         // unlock before emitting the signal
303         lock.earlyUnlock();
304         emitSignal(eS_Updated, m_Children.size());
305     }
306     return retval;
307 }
308
309 bool
310 Container::clearElements(bool delete_pointers)
311 {
312     Util::MutexLockHelper lock(getLock());
313     while(m_Children.size()) {
314         Element *e=m_Children[0];
315         deleteElementNoLock(e);
316         if (delete_pointers) delete e;
317     }
318
319     // unlock before emitting the signal
320     lock.earlyUnlock();
321     emitSignal(eS_Updated, m_Children.size());
322     return true;
323 }
324
325 void
326 Container::show()
327 {
328     Util::MutexLockHelper lock(getLock());
329     debugOutput( DEBUG_LEVEL_NORMAL, "Container %s (%zd Elements)\n",
330         getName().c_str(), m_Children.size());
331
332     for ( ElementVectorIterator it = m_Children.begin();
333       it != m_Children.end();
334       ++it )
335     {
336         (*it)->show();
337     }
338 }
339
340 void
341 Container::setVerboseLevel(int l)
342 {
343     setDebugLevel(l);
344     for ( ElementVectorIterator it = m_Children.begin();
345       it != m_Children.end();
346       ++it )
347     {
348         (*it)->setVerboseLevel(l);
349     }
350     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
351 }
352
353 } // namespace Control
Note: See TracBrowser for help on using the browser.