root/trunk/libffado/src/libieee1394/IsoHandlerManager.cpp

Revision 752, 25.2 kB (checked in by ppalmers, 13 years ago)

- Implement a DLL based mechanism to read the cycle timer. This can potentially be more lightweight for the reader threads since it avoids a the CTR read kernel call. It also has the
side effect that FFADO now works on older kernels that don't implement the cycle timer read call.

Line 
1 /*
2  * Copyright (C) 2005-2007 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 3 of the License, or
12  * (at your option) any later version.
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 "IsoHandlerManager.h"
25 #include "ieee1394service.h"
26 #include "IsoHandler.h"
27 #include "libstreaming/generic/StreamProcessor.h"
28
29 #include "libutil/Atomic.h"
30 #include "libutil/PosixThread.h"
31
32 #include <assert.h>
33
34 #define MINIMUM_INTERRUPTS_PER_PERIOD  4U
35 #define PACKETS_PER_INTERRUPT          4U
36
37 IMPL_DEBUG_MODULE( IsoHandlerManager, IsoHandlerManager, DEBUG_LEVEL_NORMAL );
38
39 using namespace Streaming;
40
41 IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service)
42    : m_State(E_Created)
43    , m_service( service )
44    , m_poll_timeout(100), m_poll_nfds_shadow(0)
45    , m_realtime(false), m_priority(0), m_isoManagerThread ( NULL )
46 {}
47
48 IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service, bool run_rt, int rt_prio)
49    : m_State(E_Created)
50    , m_service( service )
51    , m_poll_timeout(100), m_poll_nfds_shadow(0)
52    , m_realtime(run_rt), m_priority(rt_prio), m_isoManagerThread ( NULL )
53 {}
54
55 IsoHandlerManager::~IsoHandlerManager()
56 {
57     stopHandlers();
58 }
59
60 bool
61 IsoHandlerManager::setThreadParameters(bool rt, int priority) {
62     if (priority > 98) priority = 98; // cap the priority
63     m_realtime = rt;
64     m_priority = priority;
65
66     if (m_isoManagerThread) {
67         if (rt) {
68             m_isoManagerThread->AcquireRealTime(m_priority);
69         } else {
70             m_isoManagerThread->DropRealTime();
71         }
72     }
73     return true;
74 }
75
76 bool IsoHandlerManager::init()
77 {
78     debugOutput( DEBUG_LEVEL_VERBOSE, "Initializing ISO manager %p...\n", this);
79     // check state
80     if(m_State != E_Created) {
81         debugError("Manager already initialized...\n");
82         return false;
83     }
84
85     // the tread that performs the actual packet transfer
86     // needs high priority
87     if (m_priority > 98) m_priority = 98;
88     m_isoManagerThread = new Util::PosixThread(
89         this,
90         m_realtime, m_priority,
91         PTHREAD_CANCEL_DEFERRED);
92
93     if(!m_isoManagerThread) {
94         debugFatal("Could not create iso manager thread\n");
95         return false;
96     }
97     // propagate the debug level
98     m_isoManagerThread->setVerboseLevel(getDebugLevel());
99
100     debugOutput( DEBUG_LEVEL_VERBOSE, "Starting ISO iterator thread...\n");
101     // note: libraw1394 doesn't like it if you poll() and/or iterate() before
102     //       starting the streams. this is prevented by the isEnabled() on a handler
103     // start the iso runner thread
104     if (m_isoManagerThread->Start() == 0) {
105         m_State=E_Running;
106         requestShadowUpdate();
107     } else {
108         m_State=E_Error;
109     }
110     return true;
111 }
112
113 bool IsoHandlerManager::Init()
114 {
115     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
116     return true;
117 }
118
119 /**
120  * the IsoHandlerManager thread execute function iterates the handlers.
121  *
122  * This means that once the thread is running, streams are
123  * transmitted and received (if present on the bus). Make sure
124  * that the clients are registered & ready before starting the
125  * thread!
126  *
127  * The register and unregister functions are thread unsafe, so
128  * should not be used when the thread is running.
129  *
130  * @return false if the handlers could not be iterated.
131  */
132 bool IsoHandlerManager::Execute()
133 {
134     if(!iterate()) {
135         debugFatal("Could not iterate the isoManager\n");
136         return false;
137     }
138     return true;
139 }
140
141 /**
142  * Update the shadow variables. Should only be called from
143  * the iso handler iteration thread
144  */
145 void
146 IsoHandlerManager::updateShadowVars()
147 {
148     debugOutput( DEBUG_LEVEL_VERBOSE, "updating shadow vars...\n");
149     unsigned int i;
150     m_poll_nfds_shadow = m_IsoHandlers.size();
151     if(m_poll_nfds_shadow > FFADO_MAX_ISO_HANDLERS_PER_PORT) {
152         debugWarning("Too much ISO Handlers in manager...\n");
153         m_poll_nfds_shadow = FFADO_MAX_ISO_HANDLERS_PER_PORT;
154     }
155     for (i = 0; i < m_poll_nfds_shadow; i++) {
156         IsoHandler *h = m_IsoHandlers.at(i);
157         assert(h);
158         m_IsoHandler_map_shadow[i] = h;
159
160         m_poll_fds_shadow[i].fd = h->getFileDescriptor();
161         m_poll_fds_shadow[i].revents = 0;
162         if (h->isEnabled()) {
163             m_poll_fds_shadow[i].events = POLLIN;
164         } else {
165             m_poll_fds_shadow[i].events = 0;
166         }
167     }
168     debugOutput( DEBUG_LEVEL_VERBOSE, " updated shadow vars...\n");
169 }
170
171 /**
172  * Poll the handlers managed by this manager, and iterate them
173  * when ready
174  *
175  * @return true when successful
176  */
177 bool IsoHandlerManager::iterate()
178 {
179     int err;
180     unsigned int i;
181
182     // update the shadow variables if requested
183     if(m_request_fdmap_update) {
184         updateShadowVars();
185         ZERO_ATOMIC((SInt32*)&m_request_fdmap_update);
186     }
187
188     // bypass if no handlers are registered
189     if (m_poll_nfds_shadow == 0) {
190         usleep(m_poll_timeout * 1000);
191         return true;
192     }
193
194     // Use a shadow map of the fd's such that the poll call is not in a critical section
195
196     err = poll (m_poll_fds_shadow, m_poll_nfds_shadow, m_poll_timeout);
197
198     if (err == -1) {
199         if (errno == EINTR) {
200             return true;
201         }
202         debugFatal("poll error: %s\n", strerror (errno));
203         return false;
204     }
205
206 //     #ifdef DEBUG
207 //     for (i = 0; i < m_poll_nfds_shadow; i++) {
208 //         IsoHandler *s = m_IsoHandler_map_shadow[i];
209 //         assert(s);
210 //         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "post poll: (%d) handler %p: enabled? %d, events: %08X, revents: %08X\n",
211 //             i, s, s->isEnabled(), m_poll_fds_shadow[i].events, m_poll_fds_shadow[i].revents);
212 //     }
213 //     #endif
214
215     for (i = 0; i < m_poll_nfds_shadow; i++) {
216         if (m_poll_fds_shadow[i].revents & POLLERR) {
217             debugWarning("error on fd for %d\n",i);
218         }
219
220         if (m_poll_fds_shadow[i].revents & POLLHUP) {
221             debugWarning("hangup on fd for %d\n",i);
222         }
223
224         if(m_poll_fds_shadow[i].revents & (POLLIN)) {
225             m_IsoHandler_map_shadow[i]->iterate();
226         }
227     }
228     return true;
229 }
230
231 bool IsoHandlerManager::registerHandler(IsoHandler *handler)
232 {
233     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
234     assert(handler);
235     handler->setVerboseLevel(getDebugLevel());
236
237     m_IsoHandlers.push_back(handler);
238     requestShadowUpdate();
239
240     // rebuild the fd map for poll()'ing.
241     return true;
242 }
243
244 bool IsoHandlerManager::unregisterHandler(IsoHandler *handler)
245 {
246     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
247     assert(handler);
248
249     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
250       it != m_IsoHandlers.end();
251       ++it )
252     {
253         if ( *it == handler ) {
254             m_IsoHandlers.erase(it);
255             requestShadowUpdate();
256             return true;
257         }
258     }
259     debugFatal("Could not find handler (%p)\n", handler);
260     return false; //not found
261 }
262
263 void
264 IsoHandlerManager::requestShadowUpdate() {
265     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
266
267     if (m_isoManagerThread == NULL) {
268         debugOutput( DEBUG_LEVEL_VERBOSE, "No thread running, so no shadow variables needed.\n");
269         return;
270     }
271
272     // the m_request_fdmap_update variable is zeroed by the
273     // handler thread when it has accepted the new FD map
274     // and copied it over to it's shadow variables.
275     while(m_request_fdmap_update && m_isoManagerThread) {
276         usleep(1000);
277     }
278
279     debugOutput(DEBUG_LEVEL_VERBOSE, " requesting update of shadow variables...\n");
280     // request that the handler thread updates it's FD shadow
281     INC_ATOMIC((SInt32*)&m_request_fdmap_update);
282
283     debugOutput(DEBUG_LEVEL_VERBOSE, " waiting for update of shadow variables to complete...\n");
284     // the m_request_fdmap_update variable is zeroed by the
285     // handler thread when it has accepted the new FD map
286     // and copied it over to it's shadow variables.
287     while(m_request_fdmap_update && m_isoManagerThread) {
288         usleep(1000);
289     }
290     debugOutput(DEBUG_LEVEL_VERBOSE, " shadow variables updated...\n");
291 }
292
293 bool
294 IsoHandlerManager::disable(IsoHandler *h) {
295     bool result;
296     int i=0;
297     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Disable on IsoHandler %p\n", h);
298     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
299         it != m_IsoHandlers.end();
300         ++it )
301     {
302         if ((*it) == h) {
303             result = h->disable();
304             requestShadowUpdate();
305             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " disabled\n");
306             return result;
307         }
308         i++;
309     }
310     debugError("Handler not found\n");
311     return false;
312 }
313
314 bool
315 IsoHandlerManager::enable(IsoHandler *h) {
316     bool result;
317     int i=0;
318     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Enable on IsoHandler %p\n", h);
319     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
320         it != m_IsoHandlers.end();
321         ++it )
322     {
323         if ((*it) == h) {
324             result = h->enable();
325             requestShadowUpdate();
326             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " enabled\n");
327             return result;
328         }
329         i++;
330     }
331     debugError("Handler not found\n");
332     return false;
333 }
334
335 /**
336  * Registers an StreamProcessor with the IsoHandlerManager.
337  *
338  * If nescessary, an IsoHandler is created to handle this stream.
339  * Once an StreamProcessor is registered to the handler, it will be included
340  * in the ISO streaming cycle (i.e. receive/transmit of it will occur).
341  *
342  * @param stream the stream to register
343  * @return true if registration succeeds
344  *
345  * \todo : currently there is a one-to-one mapping
346  *        between streams and handlers, this is not ok for
347  *        multichannel receive
348  */
349 bool IsoHandlerManager::registerStream(StreamProcessor *stream)
350 {
351     debugOutput( DEBUG_LEVEL_VERBOSE, "Registering stream %p\n",stream);
352     assert(stream);
353
354     // make sure the stream isn't already attached to a handler
355     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
356       it != m_IsoHandlers.end();
357       ++it )
358     {
359         if((*it)->isStreamRegistered(stream)) {
360             debugError( "stream already registered!\n");
361             return false;
362         }
363     }
364
365     // clean up all handlers that aren't used
366     pruneHandlers();
367
368     // allocate a handler for this stream
369     if (stream->getType()==StreamProcessor::ePT_Receive) {
370         // setup the optimal parameters for the raw1394 ISO buffering
371         unsigned int packets_per_period = stream->getPacketsPerPeriod();
372
373 #if 1
374         // hardware interrupts occur when one DMA block is full, and the size of one DMA
375         // block = PAGE_SIZE. Setting the max_packet_size makes sure that the HW irq
376         // occurs at a period boundary (optimal CPU use)
377
378         // NOTE: try and use MINIMUM_INTERRUPTS_PER_PERIOD hardware interrupts
379         //       per period for better latency.
380         unsigned int max_packet_size=(MINIMUM_INTERRUPTS_PER_PERIOD * getpagesize()) / packets_per_period;
381
382         if (max_packet_size < stream->getMaxPacketSize()) {
383             debugWarning("calculated max packet size (%u) < stream max packet size (%u)\n",
384                          max_packet_size ,(unsigned int)stream->getMaxPacketSize());
385             max_packet_size = stream->getMaxPacketSize();
386         }
387
388         // Ensure we don't request a packet size bigger than the
389         // kernel-enforced maximum which is currently 1 page.
390         if (max_packet_size > (unsigned int)getpagesize()) {
391             debugWarning("max packet size (%u) > page size (%u)\n", max_packet_size ,(unsigned int)getpagesize());
392             max_packet_size = getpagesize();
393         }
394
395         unsigned int irq_interval = packets_per_period / MINIMUM_INTERRUPTS_PER_PERIOD;
396         if(irq_interval <= 0) irq_interval=1;
397         // FIXME: test
398         //irq_interval=1;
399
400 #else
401         // hardware interrupts occur when one DMA block is full, and the size of one DMA
402         // block = PAGE_SIZE. Setting the max_packet_size enables control over the IRQ
403         // frequency, as the controller uses max_packet_size, and not the effective size
404         // when writing to the DMA buffer.
405
406         // configure it such that we have an irq for every PACKETS_PER_INTERRUPT packets
407         unsigned int irq_interval=PACKETS_PER_INTERRUPT;
408
409         // unless the period size doesn't allow this
410         if ((packets_per_period/MINIMUM_INTERRUPTS_PER_PERIOD) < irq_interval) {
411             irq_interval=1;
412         }
413
414         // FIXME: test
415         irq_interval=1;
416 #warning Using fixed irq_interval
417
418         unsigned int max_packet_size=getpagesize() / irq_interval;
419
420         if (max_packet_size < stream->getMaxPacketSize()) {
421             max_packet_size=stream->getMaxPacketSize();
422         }
423
424         // Ensure we don't request a packet size bigger than the
425         // kernel-enforced maximum which is currently 1 page.
426         if (max_packet_size > (unsigned int)getpagesize())
427                     max_packet_size = getpagesize();
428
429 #endif
430         /* the receive buffer size doesn't matter for the latency,
431            but it has a minimal value in order for libraw to operate correctly (300) */
432         int buffers=400;
433         //max_packet_size = getpagesize(); // HACK
434         //irq_interval=2; // HACK
435         // create the actual handler
436         IsoRecvHandler *h = new IsoRecvHandler(*this, buffers,
437                                                max_packet_size, irq_interval);
438
439         debugOutput( DEBUG_LEVEL_VERBOSE, " registering IsoRecvHandler\n");
440
441         if(!h) {
442             debugFatal("Could not create IsoRecvHandler\n");
443             return false;
444         }
445
446         h->setVerboseLevel(getDebugLevel());
447
448         // init the handler
449         if(!h->init()) {
450             debugFatal("Could not initialize receive handler\n");
451             return false;
452         }
453
454         // register the stream with the handler
455         if(!h->registerStream(stream)) {
456             debugFatal("Could not register receive stream with handler\n");
457             return false;
458         }
459
460         // register the handler with the manager
461         if(!registerHandler(h)) {
462             debugFatal("Could not register receive handler with manager\n");
463             return false;
464         }
465         debugOutput( DEBUG_LEVEL_VERBOSE, " registered stream (%p) with handler (%p)\n",stream,h);
466     }
467
468     if (stream->getType()==StreamProcessor::ePT_Transmit) {
469         // setup the optimal parameters for the raw1394 ISO buffering
470         unsigned int packets_per_period = stream->getPacketsPerPeriod();
471
472         // hardware interrupts occur when one DMA block is full, and the size of one DMA
473         // block = PAGE_SIZE. Setting the max_packet_size makes sure that the HW irq
474         // occurs at a period boundary (optimal CPU use)
475         // NOTE: try and use MINIMUM_INTERRUPTS_PER_PERIOD interrupts per period
476         //       for better latency.
477         unsigned int max_packet_size=MINIMUM_INTERRUPTS_PER_PERIOD * getpagesize() / packets_per_period;
478         if (max_packet_size < stream->getMaxPacketSize()) {
479             max_packet_size = stream->getMaxPacketSize();
480         }
481
482         // Ensure we don't request a packet size bigger than the
483         // kernel-enforced maximum which is currently 1 page.
484         if (max_packet_size > (unsigned int)getpagesize())
485                     max_packet_size = getpagesize();
486
487          unsigned int irq_interval = packets_per_period / MINIMUM_INTERRUPTS_PER_PERIOD;
488          if(irq_interval <= 0) irq_interval = 1;
489
490         // the transmit buffer size should be as low as possible for latency.
491         // note however that the raw1394 subsystem tries to keep this buffer
492         // full, so we have to make sure that we have enough events in our
493         // event buffers
494
495         // FIXME: latency spoiler
496         // every irq_interval packets an interrupt will occur. that is when
497         // buffers get transfered, meaning that we should have at least some
498         // margin here
499         //irq_interval=2;
500         //int buffers=30;
501         //max_packet_size = getpagesize(); // HACK
502
503         // the SP specifies how many packets to buffer
504         int buffers = stream->getNbPacketsIsoXmitBuffer();
505
506         // create the actual handler
507         IsoXmitHandler *h = new IsoXmitHandler(*this, buffers,
508                                                max_packet_size, irq_interval);
509
510         debugOutput( DEBUG_LEVEL_VERBOSE, " registering IsoXmitHandler\n");
511
512         if(!h) {
513             debugFatal("Could not create IsoXmitHandler\n");
514             return false;
515         }
516
517         h->setVerboseLevel(getDebugLevel());
518
519         // init the handler
520         if(!h->init()) {
521             debugFatal("Could not initialize transmit handler\n");
522             return false;
523         }
524
525         // register the stream with the handler
526         if(!h->registerStream(stream)) {
527             debugFatal("Could not register transmit stream with handler\n");
528             return false;
529         }
530
531         // register the handler with the manager
532         if(!registerHandler(h)) {
533             debugFatal("Could not register transmit handler with manager\n");
534             return false;
535         }
536         debugOutput( DEBUG_LEVEL_VERBOSE, " registered stream (%p) with handler (%p)\n",stream,h);
537     }
538     m_StreamProcessors.push_back(stream);
539     debugOutput( DEBUG_LEVEL_VERBOSE, " %d streams, %d handlers registered\n",
540                                       m_StreamProcessors.size(), m_IsoHandlers.size());
541     return true;
542 }
543
544 bool IsoHandlerManager::unregisterStream(StreamProcessor *stream)
545 {
546     debugOutput( DEBUG_LEVEL_VERBOSE, "Unregistering stream %p\n",stream);
547     assert(stream);
548
549     // make sure the stream isn't attached to a handler anymore
550     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
551       it != m_IsoHandlers.end();
552       ++it )
553     {
554         if((*it)->isStreamRegistered(stream)) {
555             if(!(*it)->unregisterStream(stream)) {
556                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not unregister stream (%p) from handler (%p)...\n",stream,*it);
557                 return false;
558             }
559             debugOutput( DEBUG_LEVEL_VERBOSE, " unregistered stream (%p) from handler (%p)...\n",stream,*it);
560         }
561     }
562
563     // clean up all handlers that aren't used
564     pruneHandlers();
565
566     // remove the stream from the registered streams list
567     for ( StreamProcessorVectorIterator it = m_StreamProcessors.begin();
568       it != m_StreamProcessors.end();
569       ++it )
570     {
571         if ( *it == stream ) {
572             m_StreamProcessors.erase(it);
573             debugOutput( DEBUG_LEVEL_VERBOSE, " deleted stream (%p) from list...\n", *it);
574             return true;
575         }
576     }
577     return false; //not found
578 }
579
580 /**
581  * @brief unregister a handler from the manager
582  * @note called without the lock held.
583  */
584 void IsoHandlerManager::pruneHandlers() {
585     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
586     IsoHandlerVector toUnregister;
587
588     // find all handlers that are not in use
589     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
590           it != m_IsoHandlers.end();
591           ++it )
592     {
593         if(!((*it)->inUse())) {
594             debugOutput( DEBUG_LEVEL_VERBOSE, " handler (%p) not in use\n",*it);
595             toUnregister.push_back(*it);
596         }
597     }
598     // delete them
599     for ( IsoHandlerVectorIterator it = toUnregister.begin();
600           it != toUnregister.end();
601           ++it )
602     {
603         unregisterHandler(*it);
604
605         debugOutput( DEBUG_LEVEL_VERBOSE, " deleting handler (%p)\n",*it);
606
607         // Now the handler's been unregistered it won't be reused
608         // again.  Therefore it really needs to be formally deleted
609         // to free up the raw1394 handle.  Otherwise things fall
610         // apart after several xrun recoveries as the system runs
611         // out of resources to support all the disused but still
612         // allocated raw1394 handles.  At least this is the current
613         // theory as to why we end up with "memory allocation"
614         // failures after several Xrun recoveries.
615         delete *it;
616     }
617 }
618
619 bool
620 IsoHandlerManager::stopHandlerForStream(Streaming::StreamProcessor *stream) {
621     // check state
622     if(m_State != E_Running) {
623         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
624         return false;
625     }
626     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
627       it != m_IsoHandlers.end();
628       ++it )
629     {
630         if((*it)->isStreamRegistered(stream)) {
631             bool result;
632             debugOutput( DEBUG_LEVEL_VERBOSE, " stopping handler %p for stream %p\n", *it, stream);
633             result = (*it)->disable();
634             //requestShadowUpdate();
635             if(!result) {
636                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not disable handler (%p)\n",*it);
637                 return false;
638             }
639             return true;
640         }
641     }
642     debugError("Stream %p has no attached handler\n", stream);
643     return false;
644 }
645
646 int
647 IsoHandlerManager::getPacketLatencyForStream(Streaming::StreamProcessor *stream) {
648     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
649       it != m_IsoHandlers.end();
650       ++it )
651     {
652         if((*it)->isStreamRegistered(stream)) {
653             return (*it)->getPacketLatency();
654         }
655     }
656     debugError("Stream %p has no attached handler\n", stream);
657     return 0;
658 }
659
660 void
661 IsoHandlerManager::flushHandlerForStream(Streaming::StreamProcessor *stream) {
662     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
663       it != m_IsoHandlers.end();
664       ++it )
665     {
666         if((*it)->isStreamRegistered(stream)) {
667             return (*it)->flush();
668         }
669     }
670     debugError("Stream %p has no attached handler\n", stream);
671     return;
672 }
673
674 bool
675 IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream) {
676     return startHandlerForStream(stream, -1);
677 }
678
679 bool
680 IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream, int cycle) {
681     // check state
682     if(m_State != E_Running) {
683         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
684         return false;
685     }
686     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
687       it != m_IsoHandlers.end();
688       ++it )
689     {
690         if((*it)->isStreamRegistered(stream)) {
691             bool result;
692             debugOutput( DEBUG_LEVEL_VERBOSE, " starting handler %p for stream %p\n", *it, stream);
693             result = (*it)->enable(cycle);
694             requestShadowUpdate();
695             if(!result) {
696                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not enable handler (%p)\n",*it);
697                 return false;
698             }
699             return true;
700         }
701     }
702     debugError("Stream %p has no attached handler\n", stream);
703     return false;
704 }
705
706 bool IsoHandlerManager::stopHandlers() {
707     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
708
709     // check state
710     if(m_State != E_Running) {
711         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
712         return false;
713     }
714
715     bool retval=true;
716     debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping ISO iterator thread...\n");
717
718     m_isoManagerThread->Stop();
719     m_isoManagerThread = NULL;
720     ZERO_ATOMIC((SInt32*)&m_request_fdmap_update);
721
722     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
723         it != m_IsoHandlers.end();
724         ++it )
725     {
726         debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping handler (%p)\n",*it);
727         if(!(*it)->disable()){
728             debugOutput( DEBUG_LEVEL_VERBOSE, " could not stop handler (%p)\n",*it);
729             retval=false;
730         }
731     }
732     requestShadowUpdate();
733
734     if (retval) {
735         m_State=E_Prepared;
736     } else {
737         m_State=E_Error;
738     }
739     return retval;
740 }
741
742 bool IsoHandlerManager::reset() {
743     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
744     // check state
745     if(m_State == E_Error) {
746         debugFatal("Resetting from error condition not yet supported...\n");
747         return false;
748     }
749     // if not in an error condition, reset means stop the handlers
750     return stopHandlers();
751 }
752
753 void IsoHandlerManager::setVerboseLevel(int i) {
754     setDebugLevel(i);
755     // propagate the debug level
756     if(m_isoManagerThread) {
757         m_isoManagerThread->setVerboseLevel(getDebugLevel());
758     }
759     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
760           it != m_IsoHandlers.end();
761           ++it )
762     {
763         (*it)->setVerboseLevel(i);
764     }
765 }
766
767 void IsoHandlerManager::dumpInfo() {
768     int i=0;
769     debugOutputShort( DEBUG_LEVEL_NORMAL, "Dumping IsoHandlerManager Stream handler information...\n");
770     debugOutputShort( DEBUG_LEVEL_NORMAL, " State: %d\n",(int)m_State);
771
772     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
773           it != m_IsoHandlers.end();
774           ++it )
775     {
776         debugOutputShort( DEBUG_LEVEL_NORMAL, " IsoHandler %d (%p)\n",i++,*it);
777         (*it)->dumpInfo();
778     }
779 }
780
781 const char *
782 IsoHandlerManager::eHSToString(enum eHandlerStates s) {
783     switch (s) {
784         default: return "Invalid";
785         case E_Created: return "Created";
786         case E_Prepared: return "Prepared";
787         case E_Running: return "Running";
788         case E_Error: return "Error";
789     }
790 }
Note: See TracBrowser for help on using the browser.