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

Revision 797, 20.2 kB (checked in by ppalmers, 16 years ago)

parameters for better latency performance

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 "config.h"
25 #include "IsoHandlerManager.h"
26 #include "ieee1394service.h"
27 #include "IsoHandler.h"
28 #include "libstreaming/generic/StreamProcessor.h"
29
30 #include "libutil/Atomic.h"
31
32 #include "libutil/PosixThread.h"
33
34 #include <assert.h>
35
36 IMPL_DEBUG_MODULE( IsoHandlerManager, IsoHandlerManager, DEBUG_LEVEL_NORMAL );
37
38 using namespace Streaming;
39
40 IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service)
41    : m_State(E_Created)
42    , m_service( service )
43    , m_realtime(false), m_priority(0)
44    , m_Thread ( NULL )
45 {}
46
47 IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service, bool run_rt, int rt_prio)
48    : m_State(E_Created)
49    , m_service( service )
50    , m_realtime(run_rt), m_priority(rt_prio)
51    , m_Thread ( NULL )
52 {}
53
54 IsoHandlerManager::~IsoHandlerManager()
55 {
56     stopHandlers();
57     pruneHandlers();
58     if(m_IsoHandlers.size() > 0) {
59         debugError("Still some handlers in use\n");
60     }
61     if (m_Thread) {
62         m_Thread->Stop();
63         delete m_Thread;
64     }
65 }
66
67 bool
68 IsoHandlerManager::setThreadParameters(bool rt, int priority) {
69     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) switch to: (rt=%d, prio=%d)...\n", this, rt, priority);
70     if (priority > 98) priority = 98; // cap the priority
71     m_realtime = rt;
72     m_priority = priority;
73     bool result = true;
74     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
75         it != m_IsoHandlers.end();
76         ++it )
77     {
78         result &= (*it)->setThreadParameters(m_realtime, m_priority);
79     }
80
81     if (m_Thread) {
82         if (m_realtime) {
83             m_Thread->AcquireRealTime(m_priority);
84         } else {
85             m_Thread->DropRealTime();
86         }
87     }
88
89     return result;
90 }
91
92 /**
93  * Update the shadow variables. Should only be called from
94  * the iso handler iteration thread
95  */
96 void
97 IsoHandlerManager::updateShadowVars()
98 {
99     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "updating shadow vars...\n");
100     unsigned int i;
101     m_poll_nfds_shadow = m_IsoHandlers.size();
102     if(m_poll_nfds_shadow > ISOHANDLERMANAGER_MAX_ISO_HANDLERS_PER_PORT) {
103         debugWarning("Too much ISO Handlers in manager...\n");
104         m_poll_nfds_shadow = ISOHANDLERMANAGER_MAX_ISO_HANDLERS_PER_PORT;
105     }
106     for (i = 0; i < m_poll_nfds_shadow; i++) {
107         IsoHandler *h = m_IsoHandlers.at(i);
108         assert(h);
109         m_IsoHandler_map_shadow[i] = h;
110
111         m_poll_fds_shadow[i].fd = h->getFileDescriptor();
112         m_poll_fds_shadow[i].revents = 0;
113         if (h->isEnabled()) {
114             m_poll_fds_shadow[i].events = POLLIN;
115         } else {
116             m_poll_fds_shadow[i].events = 0;
117         }
118     }
119     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, " updated shadow vars...\n");
120 }
121
122 bool
123 IsoHandlerManager::Init() {
124     debugOutput( DEBUG_LEVEL_VERBOSE, "%p: Init thread...\n", this);
125     bool result = true;
126     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
127         it != m_IsoHandlers.end();
128         ++it )
129     {
130         result &= (*it)->Init();
131     }
132     return result;
133 }
134
135 bool
136 IsoHandlerManager::Execute() {
137     int err;
138     unsigned int i;
139
140     unsigned int m_poll_timeout = 100;
141
142     // update the shadow variables if requested
143    // if(m_request_fdmap_update) {
144         updateShadowVars();
145     //    ZERO_ATOMIC((SInt32*)&m_request_fdmap_update);
146     //}
147
148     // bypass if no handlers are registered
149     if (m_poll_nfds_shadow == 0) {
150         usleep(m_poll_timeout * 1000);
151         return true;
152     }
153
154     // Use a shadow map of the fd's such that the poll call is not in a critical section
155     uint64_t poll_enter = m_service.getCurrentTimeAsUsecs();
156     err = poll (m_poll_fds_shadow, m_poll_nfds_shadow, m_poll_timeout);
157     uint64_t poll_exit = m_service.getCurrentTimeAsUsecs();
158
159     if (err == -1) {
160         if (errno == EINTR) {
161             return true;
162         }
163         debugFatal("poll error: %s\n", strerror (errno));
164         return false;
165     }
166
167     int nb_rcv = 0;
168     int nb_xmit = 0;
169     uint64_t iter_enter = m_service.getCurrentTimeAsUsecs();
170     for (i = 0; i < m_poll_nfds_shadow; i++) {
171         if(m_poll_fds_shadow[i].revents) {
172             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "received events: %08X for (%p)\n",
173                 m_poll_fds_shadow[i].revents, m_IsoHandler_map_shadow[i]);
174         }
175         if (m_poll_fds_shadow[i].revents & POLLERR) {
176             debugWarning("error on fd for %d\n",i);
177         }
178
179         if (m_poll_fds_shadow[i].revents & POLLHUP) {
180             debugWarning("hangup on fd for %d\n",i);
181         }
182
183         if(m_poll_fds_shadow[i].revents & (POLLIN)) {
184             m_IsoHandler_map_shadow[i]->iterate();
185             if (m_IsoHandler_map_shadow[i]->getType() == IsoHandler::eHT_Receive) {
186                 nb_rcv++;
187             } else {
188                 nb_xmit++;
189             }
190         }
191     }
192     uint64_t iter_exit = m_service.getCurrentTimeAsUsecs();
193    
194     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " poll took %6lldus, iterate took %6lldus, iterated (R: %2d, X: %2d) handlers\n",
195                 poll_exit-poll_enter, iter_exit-iter_enter,
196                 nb_rcv, nb_xmit);
197
198     return true;
199 }
200
201 bool IsoHandlerManager::init()
202 {
203     debugOutput( DEBUG_LEVEL_VERBOSE, "Initializing ISO manager %p...\n", this);
204     // check state
205     if(m_State != E_Created) {
206         debugError("Manager already initialized...\n");
207         return false;
208     }
209
210 #if ISOHANDLER_PER_HANDLER_THREAD
211 #else
212     // create a thread to iterate our handlers
213     debugOutput( DEBUG_LEVEL_VERBOSE, "Start thread for %p...\n", this);
214     m_Thread = new Util::PosixThread(this, m_realtime, m_priority,
215                                      PTHREAD_CANCEL_DEFERRED);
216     if(!m_Thread) {
217         debugFatal("No thread\n");
218         return false;
219     }
220     if (m_Thread->Start() != 0) {
221         debugFatal("Could not start update thread\n");
222         return false;
223     }
224 #endif
225
226     m_State=E_Running;
227     return true;
228 }
229
230 bool
231 IsoHandlerManager::disable(IsoHandler *h) {
232     bool result;
233     int i=0;
234     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Disable on IsoHandler %p\n", h);
235     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
236         it != m_IsoHandlers.end();
237         ++it )
238     {
239         if ((*it) == h) {
240             result = h->disable();
241             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " disabled\n");
242             return result;
243         }
244         i++;
245     }
246     debugError("Handler not found\n");
247     return false;
248 }
249
250 bool
251 IsoHandlerManager::enable(IsoHandler *h) {
252     bool result;
253     int i=0;
254     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Enable on IsoHandler %p\n", h);
255     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
256         it != m_IsoHandlers.end();
257         ++it )
258     {
259         if ((*it) == h) {
260             result = h->enable();
261             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " enabled\n");
262             return result;
263         }
264         i++;
265     }
266     debugError("Handler not found\n");
267     return false;
268 }
269
270 bool IsoHandlerManager::registerHandler(IsoHandler *handler)
271 {
272     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
273     assert(handler);
274     handler->setVerboseLevel(getDebugLevel());
275     m_IsoHandlers.push_back(handler);
276     return true;
277 }
278
279 bool IsoHandlerManager::unregisterHandler(IsoHandler *handler)
280 {
281     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
282     assert(handler);
283
284     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
285       it != m_IsoHandlers.end();
286       ++it )
287     {
288         if ( *it == handler ) {
289             m_IsoHandlers.erase(it);
290             return true;
291         }
292     }
293     debugFatal("Could not find handler (%p)\n", handler);
294     return false; //not found
295 }
296
297 /**
298  * Registers an StreamProcessor with the IsoHandlerManager.
299  *
300  * If nescessary, an IsoHandler is created to handle this stream.
301  * Once an StreamProcessor is registered to the handler, it will be included
302  * in the ISO streaming cycle (i.e. receive/transmit of it will occur).
303  *
304  * @param stream the stream to register
305  * @return true if registration succeeds
306  *
307  * \todo : currently there is a one-to-one mapping
308  *        between streams and handlers, this is not ok for
309  *        multichannel receive
310  */
311 bool IsoHandlerManager::registerStream(StreamProcessor *stream)
312 {
313     debugOutput( DEBUG_LEVEL_VERBOSE, "Registering stream %p\n",stream);
314     assert(stream);
315
316     IsoHandler* h = NULL;
317
318     // make sure the stream isn't already attached to a handler
319     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
320       it != m_IsoHandlers.end();
321       ++it )
322     {
323         if((*it)->isStreamRegistered(stream)) {
324             debugError( "stream already registered!\n");
325             return false;
326         }
327     }
328
329     // clean up all handlers that aren't used
330     pruneHandlers();
331
332     // allocate a handler for this stream
333     if (stream->getType()==StreamProcessor::ePT_Receive) {
334         // setup the optimal parameters for the raw1394 ISO buffering
335         unsigned int packets_per_period = stream->getPacketsPerPeriod();
336         unsigned int max_packet_size = stream->getMaxPacketSize();
337         unsigned int page_size = getpagesize() - 2; // for one reason or another this is necessary
338
339         // Ensure we don't request a packet size bigger than the
340         // kernel-enforced maximum which is currently 1 page.
341         if (max_packet_size > page_size) {
342             debugError("max packet size (%u) > page size (%u)\n", max_packet_size, page_size);
343             return false;
344         }
345
346         unsigned int irq_interval = packets_per_period / MINIMUM_INTERRUPTS_PER_PERIOD;
347         if(irq_interval <= 0) irq_interval=1;
348        
349         // the receive buffer size doesn't matter for the latency,
350         // but it has a minimal value in order for libraw to operate correctly (300)
351         int buffers=400;
352
353         // create the actual handler
354         h = new IsoHandler(*this, IsoHandler::eHT_Receive,
355                            buffers, max_packet_size, irq_interval);
356
357         debugOutput( DEBUG_LEVEL_VERBOSE, " creating IsoRecvHandler\n");
358
359         if(!h) {
360             debugFatal("Could not create IsoRecvHandler\n");
361             return false;
362         }
363
364     } else if (stream->getType()==StreamProcessor::ePT_Transmit) {
365         // setup the optimal parameters for the raw1394 ISO buffering
366         unsigned int packets_per_period = stream->getPacketsPerPeriod();
367         unsigned int max_packet_size = stream->getMaxPacketSize();
368         unsigned int page_size = getpagesize();
369
370         // Ensure we don't request a packet size bigger than the
371         // kernel-enforced maximum which is currently 1 page.
372         if (max_packet_size > page_size) {
373             debugError("max packet size (%u) > page size (%u)\n", max_packet_size, page_size);
374             return false;
375         }
376
377         max_packet_size = page_size;
378         unsigned int irq_interval = packets_per_period / MINIMUM_INTERRUPTS_PER_PERIOD;
379         if(irq_interval <= 0) irq_interval=1;
380
381         // the SP specifies how many packets to ISO-buffer
382         int buffers = stream->getNbPacketsIsoXmitBuffer();
383
384         debugOutput( DEBUG_LEVEL_VERBOSE, " creating IsoXmitHandler\n");
385
386         // create the actual handler
387         h = new IsoHandler(*this, IsoHandler::eHT_Transmit,
388                            buffers, max_packet_size, irq_interval);
389
390         if(!h) {
391             debugFatal("Could not create IsoXmitHandler\n");
392             return false;
393         }
394     } else {
395         debugFatal("Bad stream type\n");
396         return false;
397     }
398
399     h->setVerboseLevel(getDebugLevel());
400
401     // init the handler
402     if(!h->init()) {
403         debugFatal("Could not initialize receive handler\n");
404         return false;
405     }
406
407     // set the handler's thread parameters
408     if(!h->setThreadParameters(m_realtime, m_priority)) {
409         debugFatal("Could not set handler thread parameters\n");
410         return false;
411     }
412
413     // register the stream with the handler
414     if(!h->registerStream(stream)) {
415         debugFatal("Could not register receive stream with handler\n");
416         return false;
417     }
418
419     // register the handler with the manager
420     if(!registerHandler(h)) {
421         debugFatal("Could not register receive handler with manager\n");
422         return false;
423     }
424     debugOutput( DEBUG_LEVEL_VERBOSE, " registered stream (%p) with handler (%p)\n", stream, h);
425
426     m_StreamProcessors.push_back(stream);
427     debugOutput( DEBUG_LEVEL_VERBOSE, " %d streams, %d handlers registered\n",
428                                       m_StreamProcessors.size(), m_IsoHandlers.size());
429     return true;
430 }
431
432 bool IsoHandlerManager::unregisterStream(StreamProcessor *stream)
433 {
434     debugOutput( DEBUG_LEVEL_VERBOSE, "Unregistering stream %p\n",stream);
435     assert(stream);
436
437     // make sure the stream isn't attached to a handler anymore
438     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
439       it != m_IsoHandlers.end();
440       ++it )
441     {
442         if((*it)->isStreamRegistered(stream)) {
443             if(!(*it)->unregisterStream(stream)) {
444                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not unregister stream (%p) from handler (%p)...\n",stream,*it);
445                 return false;
446             }
447             debugOutput( DEBUG_LEVEL_VERBOSE, " unregistered stream (%p) from handler (%p)...\n",stream,*it);
448         }
449     }
450
451     // clean up all handlers that aren't used
452     pruneHandlers();
453
454     // remove the stream from the registered streams list
455     for ( StreamProcessorVectorIterator it = m_StreamProcessors.begin();
456       it != m_StreamProcessors.end();
457       ++it )
458     {
459         if ( *it == stream ) {
460             m_StreamProcessors.erase(it);
461             debugOutput( DEBUG_LEVEL_VERBOSE, " deleted stream (%p) from list...\n", *it);
462             return true;
463         }
464     }
465     return false; //not found
466 }
467
468 /**
469  * @brief unregister a handler from the manager
470  * @note called without the lock held.
471  */
472 void IsoHandlerManager::pruneHandlers() {
473     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
474     IsoHandlerVector toUnregister;
475
476     // find all handlers that are not in use
477     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
478           it != m_IsoHandlers.end();
479           ++it )
480     {
481         if(!((*it)->inUse())) {
482             debugOutput( DEBUG_LEVEL_VERBOSE, " handler (%p) not in use\n",*it);
483             toUnregister.push_back(*it);
484         }
485     }
486     // delete them
487     for ( IsoHandlerVectorIterator it = toUnregister.begin();
488           it != toUnregister.end();
489           ++it )
490     {
491         unregisterHandler(*it);
492
493         debugOutput( DEBUG_LEVEL_VERBOSE, " deleting handler (%p)\n",*it);
494
495         // Now the handler's been unregistered it won't be reused
496         // again.  Therefore it really needs to be formally deleted
497         // to free up the raw1394 handle.  Otherwise things fall
498         // apart after several xrun recoveries as the system runs
499         // out of resources to support all the disused but still
500         // allocated raw1394 handles.  At least this is the current
501         // theory as to why we end up with "memory allocation"
502         // failures after several Xrun recoveries.
503         delete *it;
504     }
505 }
506
507 bool
508 IsoHandlerManager::stopHandlerForStream(Streaming::StreamProcessor *stream) {
509     // check state
510     if(m_State != E_Running) {
511         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
512         return false;
513     }
514     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
515       it != m_IsoHandlers.end();
516       ++it )
517     {
518         if((*it)->isStreamRegistered(stream)) {
519             bool result;
520             debugOutput( DEBUG_LEVEL_VERBOSE, " stopping handler %p for stream %p\n", *it, stream);
521             result = (*it)->disable();
522             if(!result) {
523                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not disable handler (%p)\n",*it);
524                 return false;
525             }
526             return true;
527         }
528     }
529     debugError("Stream %p has no attached handler\n", stream);
530     return false;
531 }
532
533 int
534 IsoHandlerManager::getPacketLatencyForStream(Streaming::StreamProcessor *stream) {
535     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
536       it != m_IsoHandlers.end();
537       ++it )
538     {
539         if((*it)->isStreamRegistered(stream)) {
540             return (*it)->getPacketLatency();
541         }
542     }
543     debugError("Stream %p has no attached handler\n", stream);
544     return 0;
545 }
546
547 void
548 IsoHandlerManager::flushHandlerForStream(Streaming::StreamProcessor *stream) {
549     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
550       it != m_IsoHandlers.end();
551       ++it )
552     {
553         if((*it)->isStreamRegistered(stream)) {
554             return (*it)->flush();
555         }
556     }
557     debugError("Stream %p has no attached handler\n", stream);
558     return;
559 }
560
561 bool
562 IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream) {
563     return startHandlerForStream(stream, -1);
564 }
565
566 bool
567 IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream, int cycle) {
568     // check state
569     if(m_State != E_Running) {
570         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
571         return false;
572     }
573     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
574       it != m_IsoHandlers.end();
575       ++it )
576     {
577         if((*it)->isStreamRegistered(stream)) {
578             bool result;
579             debugOutput( DEBUG_LEVEL_VERBOSE, " starting handler %p for stream %p\n", *it, stream);
580             result = (*it)->enable(cycle);
581             if(!result) {
582                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not enable handler (%p)\n",*it);
583                 return false;
584             }
585             return true;
586         }
587     }
588     debugError("Stream %p has no attached handler\n", stream);
589     return false;
590 }
591
592 bool IsoHandlerManager::stopHandlers() {
593     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
594
595     // check state
596     if(m_State != E_Running) {
597         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
598         return false;
599     }
600
601     bool retval=true;
602
603     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
604         it != m_IsoHandlers.end();
605         ++it )
606     {
607         debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping handler (%p)\n",*it);
608         if(!(*it)->disable()){
609             debugOutput( DEBUG_LEVEL_VERBOSE, " could not stop handler (%p)\n",*it);
610             retval=false;
611         }
612     }
613
614     if (retval) {
615         m_State=E_Prepared;
616     } else {
617         m_State=E_Error;
618     }
619     return retval;
620 }
621
622 bool IsoHandlerManager::reset() {
623     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
624     // check state
625     if(m_State == E_Error) {
626         debugFatal("Resetting from error condition not yet supported...\n");
627         return false;
628     }
629     // if not in an error condition, reset means stop the handlers
630     return stopHandlers();
631 }
632
633 void IsoHandlerManager::setVerboseLevel(int i) {
634     setDebugLevel(i);
635     // propagate the debug level
636     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
637           it != m_IsoHandlers.end();
638           ++it )
639     {
640         (*it)->setVerboseLevel(i);
641     }
642 }
643
644 void IsoHandlerManager::dumpInfo() {
645     int i=0;
646     debugOutputShort( DEBUG_LEVEL_NORMAL, "Dumping IsoHandlerManager Stream handler information...\n");
647     debugOutputShort( DEBUG_LEVEL_NORMAL, " State: %d\n",(int)m_State);
648
649     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
650           it != m_IsoHandlers.end();
651           ++it )
652     {
653         debugOutputShort( DEBUG_LEVEL_NORMAL, " IsoHandler %d (%p)\n",i++,*it);
654         (*it)->dumpInfo();
655     }
656 }
657
658 const char *
659 IsoHandlerManager::eHSToString(enum eHandlerStates s) {
660     switch (s) {
661         default: return "Invalid";
662         case E_Created: return "Created";
663         case E_Prepared: return "Prepared";
664         case E_Running: return "Running";
665         case E_Error: return "Error";
666     }
667 }
Note: See TracBrowser for help on using the browser.