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

Revision 753, 18.7 kB (checked in by ppalmers, 13 years ago)

have separate threads for every handler

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
31 #include <assert.h>
32
33 #define MINIMUM_INTERRUPTS_PER_PERIOD  8U
34
35 IMPL_DEBUG_MODULE( IsoHandlerManager, IsoHandlerManager, DEBUG_LEVEL_NORMAL );
36
37 using namespace Streaming;
38
39 IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service)
40    : m_State(E_Created)
41    , m_service( service )
42    , m_realtime(false), m_priority(0)
43 {}
44
45 IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service, bool run_rt, int rt_prio)
46    : m_State(E_Created)
47    , m_service( service )
48    , m_realtime(run_rt), m_priority(rt_prio)
49 {}
50
51 IsoHandlerManager::~IsoHandlerManager()
52 {
53     stopHandlers();
54 }
55
56 bool
57 IsoHandlerManager::setThreadParameters(bool rt, int priority) {
58     if (priority > 98) priority = 98; // cap the priority
59     m_realtime = rt;
60     m_priority = priority;
61     bool result = true;
62     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
63         it != m_IsoHandlers.end();
64         ++it )
65     {
66         result &= (*it)->setThreadParameters(m_realtime, m_priority);
67     }
68     return result;
69 }
70
71 bool IsoHandlerManager::init()
72 {
73     debugOutput( DEBUG_LEVEL_VERBOSE, "Initializing ISO manager %p...\n", this);
74     // check state
75     if(m_State != E_Created) {
76         debugError("Manager already initialized...\n");
77         return false;
78     }
79
80     m_State=E_Running;
81     return true;
82 }
83
84 bool
85 IsoHandlerManager::disable(IsoHandler *h) {
86     bool result;
87     int i=0;
88     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Disable on IsoHandler %p\n", h);
89     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
90         it != m_IsoHandlers.end();
91         ++it )
92     {
93         if ((*it) == h) {
94             result = h->disable();
95             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " disabled\n");
96             return result;
97         }
98         i++;
99     }
100     debugError("Handler not found\n");
101     return false;
102 }
103
104 bool
105 IsoHandlerManager::enable(IsoHandler *h) {
106     bool result;
107     int i=0;
108     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Enable on IsoHandler %p\n", h);
109     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
110         it != m_IsoHandlers.end();
111         ++it )
112     {
113         if ((*it) == h) {
114             result = h->enable();
115             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " enabled\n");
116             return result;
117         }
118         i++;
119     }
120     debugError("Handler not found\n");
121     return false;
122 }
123
124 bool IsoHandlerManager::registerHandler(IsoHandler *handler)
125 {
126     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
127     assert(handler);
128     handler->setVerboseLevel(getDebugLevel());
129     m_IsoHandlers.push_back(handler);
130     return true;
131 }
132
133 bool IsoHandlerManager::unregisterHandler(IsoHandler *handler)
134 {
135     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
136     assert(handler);
137
138     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
139       it != m_IsoHandlers.end();
140       ++it )
141     {
142         if ( *it == handler ) {
143             m_IsoHandlers.erase(it);
144             return true;
145         }
146     }
147     debugFatal("Could not find handler (%p)\n", handler);
148     return false; //not found
149 }
150
151 /**
152  * Registers an StreamProcessor with the IsoHandlerManager.
153  *
154  * If nescessary, an IsoHandler is created to handle this stream.
155  * Once an StreamProcessor is registered to the handler, it will be included
156  * in the ISO streaming cycle (i.e. receive/transmit of it will occur).
157  *
158  * @param stream the stream to register
159  * @return true if registration succeeds
160  *
161  * \todo : currently there is a one-to-one mapping
162  *        between streams and handlers, this is not ok for
163  *        multichannel receive
164  */
165 bool IsoHandlerManager::registerStream(StreamProcessor *stream)
166 {
167     debugOutput( DEBUG_LEVEL_VERBOSE, "Registering stream %p\n",stream);
168     assert(stream);
169
170     IsoHandler* h = NULL;
171
172     // make sure the stream isn't already attached to a handler
173     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
174       it != m_IsoHandlers.end();
175       ++it )
176     {
177         if((*it)->isStreamRegistered(stream)) {
178             debugError( "stream already registered!\n");
179             return false;
180         }
181     }
182
183     // clean up all handlers that aren't used
184     pruneHandlers();
185
186     // allocate a handler for this stream
187     if (stream->getType()==StreamProcessor::ePT_Receive) {
188         // setup the optimal parameters for the raw1394 ISO buffering
189         unsigned int packets_per_period = stream->getPacketsPerPeriod();
190
191 #if 1
192         // hardware interrupts occur when one DMA block is full, and the size of one DMA
193         // block = PAGE_SIZE. Setting the max_packet_size makes sure that the HW irq
194         // occurs at a period boundary (optimal CPU use)
195
196         // NOTE: try and use MINIMUM_INTERRUPTS_PER_PERIOD hardware interrupts
197         //       per period for better latency.
198         unsigned int max_packet_size=(MINIMUM_INTERRUPTS_PER_PERIOD * getpagesize()) / packets_per_period;
199
200         if (max_packet_size < stream->getMaxPacketSize()) {
201             debugWarning("calculated max packet size (%u) < stream max packet size (%u)\n",
202                          max_packet_size ,(unsigned int)stream->getMaxPacketSize());
203             max_packet_size = stream->getMaxPacketSize();
204         }
205
206         // Ensure we don't request a packet size bigger than the
207         // kernel-enforced maximum which is currently 1 page.
208         if (max_packet_size > (unsigned int)getpagesize()) {
209             debugWarning("max packet size (%u) > page size (%u)\n", max_packet_size ,(unsigned int)getpagesize());
210             max_packet_size = getpagesize();
211         }
212
213         unsigned int irq_interval = packets_per_period / MINIMUM_INTERRUPTS_PER_PERIOD;
214         if(irq_interval <= 0) irq_interval=1;
215         // FIXME: test
216         //irq_interval=1;
217
218 #else
219         // hardware interrupts occur when one DMA block is full, and the size of one DMA
220         // block = PAGE_SIZE. Setting the max_packet_size enables control over the IRQ
221         // frequency, as the controller uses max_packet_size, and not the effective size
222         // when writing to the DMA buffer.
223
224         // configure it such that we have an irq for every PACKETS_PER_INTERRUPT packets
225         unsigned int irq_interval=PACKETS_PER_INTERRUPT;
226
227         // unless the period size doesn't allow this
228         if ((packets_per_period/MINIMUM_INTERRUPTS_PER_PERIOD) < irq_interval) {
229             irq_interval=1;
230         }
231
232         // FIXME: test
233         irq_interval=1;
234 #warning Using fixed irq_interval
235
236         unsigned int max_packet_size=getpagesize() / irq_interval;
237
238         if (max_packet_size < stream->getMaxPacketSize()) {
239             max_packet_size=stream->getMaxPacketSize();
240         }
241
242         // Ensure we don't request a packet size bigger than the
243         // kernel-enforced maximum which is currently 1 page.
244         if (max_packet_size > (unsigned int)getpagesize())
245                     max_packet_size = getpagesize();
246
247 #endif
248         /* the receive buffer size doesn't matter for the latency,
249            but it has a minimal value in order for libraw to operate correctly (300) */
250         int buffers=400;
251         //max_packet_size = getpagesize(); // HACK
252         //irq_interval=2; // HACK
253         // create the actual handler
254         h = new IsoRecvHandler(*this, buffers,
255                                                max_packet_size, irq_interval);
256         if(!h) {
257             debugFatal("Could not create IsoRecvHandler\n");
258             return false;
259         }
260         debugOutput( DEBUG_LEVEL_VERBOSE, " registering IsoRecvHandler\n");
261
262     } else if (stream->getType()==StreamProcessor::ePT_Transmit) {
263         // setup the optimal parameters for the raw1394 ISO buffering
264         unsigned int packets_per_period = stream->getPacketsPerPeriod();
265
266         // hardware interrupts occur when one DMA block is full, and the size of one DMA
267         // block = PAGE_SIZE. Setting the max_packet_size makes sure that the HW irq
268         // occurs at a period boundary (optimal CPU use)
269         // NOTE: try and use MINIMUM_INTERRUPTS_PER_PERIOD interrupts per period
270         //       for better latency.
271         unsigned int max_packet_size=MINIMUM_INTERRUPTS_PER_PERIOD * getpagesize() / packets_per_period;
272         if (max_packet_size < stream->getMaxPacketSize()) {
273             max_packet_size = stream->getMaxPacketSize();
274         }
275
276         // Ensure we don't request a packet size bigger than the
277         // kernel-enforced maximum which is currently 1 page.
278         if (max_packet_size > (unsigned int)getpagesize())
279                     max_packet_size = getpagesize();
280
281          unsigned int irq_interval = packets_per_period / MINIMUM_INTERRUPTS_PER_PERIOD;
282          if(irq_interval <= 0) irq_interval = 1;
283
284         // the transmit buffer size should be as low as possible for latency.
285         // note however that the raw1394 subsystem tries to keep this buffer
286         // full, so we have to make sure that we have enough events in our
287         // event buffers
288
289         // FIXME: latency spoiler
290         // every irq_interval packets an interrupt will occur. that is when
291         // buffers get transfered, meaning that we should have at least some
292         // margin here
293         //irq_interval=2;
294         //int buffers=30;
295         //max_packet_size = getpagesize(); // HACK
296
297         // the SP specifies how many packets to buffer
298         int buffers = stream->getNbPacketsIsoXmitBuffer();
299
300         // create the actual handler
301         h = new IsoXmitHandler(*this, buffers,
302                                                max_packet_size, irq_interval);
303
304         debugOutput( DEBUG_LEVEL_VERBOSE, " registering IsoXmitHandler\n");
305
306         if(!h) {
307             debugFatal("Could not create IsoXmitHandler\n");
308             return false;
309         }
310     } else {
311         debugFatal("Bad stream type\n");
312         return false;
313     }
314
315     h->setVerboseLevel(getDebugLevel());
316
317     // init the handler
318     if(!h->init()) {
319         debugFatal("Could not initialize receive handler\n");
320         return false;
321     }
322
323     // set the handler's thread parameters
324     if(!h->setThreadParameters(m_realtime, m_priority)) {
325         debugFatal("Could not set handler thread parameters\n");
326         return false;
327     }
328
329     // register the stream with the handler
330     if(!h->registerStream(stream)) {
331         debugFatal("Could not register receive stream with handler\n");
332         return false;
333     }
334
335     // register the handler with the manager
336     if(!registerHandler(h)) {
337         debugFatal("Could not register receive handler with manager\n");
338         return false;
339     }
340     debugOutput( DEBUG_LEVEL_VERBOSE, " registered stream (%p) with handler (%p)\n", stream, h);
341
342     m_StreamProcessors.push_back(stream);
343     debugOutput( DEBUG_LEVEL_VERBOSE, " %d streams, %d handlers registered\n",
344                                       m_StreamProcessors.size(), m_IsoHandlers.size());
345     return true;
346 }
347
348 bool IsoHandlerManager::unregisterStream(StreamProcessor *stream)
349 {
350     debugOutput( DEBUG_LEVEL_VERBOSE, "Unregistering stream %p\n",stream);
351     assert(stream);
352
353     // make sure the stream isn't attached to a handler anymore
354     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
355       it != m_IsoHandlers.end();
356       ++it )
357     {
358         if((*it)->isStreamRegistered(stream)) {
359             if(!(*it)->unregisterStream(stream)) {
360                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not unregister stream (%p) from handler (%p)...\n",stream,*it);
361                 return false;
362             }
363             debugOutput( DEBUG_LEVEL_VERBOSE, " unregistered stream (%p) from handler (%p)...\n",stream,*it);
364         }
365     }
366
367     // clean up all handlers that aren't used
368     pruneHandlers();
369
370     // remove the stream from the registered streams list
371     for ( StreamProcessorVectorIterator it = m_StreamProcessors.begin();
372       it != m_StreamProcessors.end();
373       ++it )
374     {
375         if ( *it == stream ) {
376             m_StreamProcessors.erase(it);
377             debugOutput( DEBUG_LEVEL_VERBOSE, " deleted stream (%p) from list...\n", *it);
378             return true;
379         }
380     }
381     return false; //not found
382 }
383
384 /**
385  * @brief unregister a handler from the manager
386  * @note called without the lock held.
387  */
388 void IsoHandlerManager::pruneHandlers() {
389     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
390     IsoHandlerVector toUnregister;
391
392     // find all handlers that are not in use
393     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
394           it != m_IsoHandlers.end();
395           ++it )
396     {
397         if(!((*it)->inUse())) {
398             debugOutput( DEBUG_LEVEL_VERBOSE, " handler (%p) not in use\n",*it);
399             toUnregister.push_back(*it);
400         }
401     }
402     // delete them
403     for ( IsoHandlerVectorIterator it = toUnregister.begin();
404           it != toUnregister.end();
405           ++it )
406     {
407         unregisterHandler(*it);
408
409         debugOutput( DEBUG_LEVEL_VERBOSE, " deleting handler (%p)\n",*it);
410
411         // Now the handler's been unregistered it won't be reused
412         // again.  Therefore it really needs to be formally deleted
413         // to free up the raw1394 handle.  Otherwise things fall
414         // apart after several xrun recoveries as the system runs
415         // out of resources to support all the disused but still
416         // allocated raw1394 handles.  At least this is the current
417         // theory as to why we end up with "memory allocation"
418         // failures after several Xrun recoveries.
419         delete *it;
420     }
421 }
422
423 bool
424 IsoHandlerManager::stopHandlerForStream(Streaming::StreamProcessor *stream) {
425     // check state
426     if(m_State != E_Running) {
427         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
428         return false;
429     }
430     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
431       it != m_IsoHandlers.end();
432       ++it )
433     {
434         if((*it)->isStreamRegistered(stream)) {
435             bool result;
436             debugOutput( DEBUG_LEVEL_VERBOSE, " stopping handler %p for stream %p\n", *it, stream);
437             result = (*it)->disable();
438             if(!result) {
439                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not disable handler (%p)\n",*it);
440                 return false;
441             }
442             return true;
443         }
444     }
445     debugError("Stream %p has no attached handler\n", stream);
446     return false;
447 }
448
449 int
450 IsoHandlerManager::getPacketLatencyForStream(Streaming::StreamProcessor *stream) {
451     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
452       it != m_IsoHandlers.end();
453       ++it )
454     {
455         if((*it)->isStreamRegistered(stream)) {
456             return (*it)->getPacketLatency();
457         }
458     }
459     debugError("Stream %p has no attached handler\n", stream);
460     return 0;
461 }
462
463 void
464 IsoHandlerManager::flushHandlerForStream(Streaming::StreamProcessor *stream) {
465     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
466       it != m_IsoHandlers.end();
467       ++it )
468     {
469         if((*it)->isStreamRegistered(stream)) {
470             return (*it)->flush();
471         }
472     }
473     debugError("Stream %p has no attached handler\n", stream);
474     return;
475 }
476
477 bool
478 IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream) {
479     return startHandlerForStream(stream, -1);
480 }
481
482 bool
483 IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream, int cycle) {
484     // check state
485     if(m_State != E_Running) {
486         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
487         return false;
488     }
489     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
490       it != m_IsoHandlers.end();
491       ++it )
492     {
493         if((*it)->isStreamRegistered(stream)) {
494             bool result;
495             debugOutput( DEBUG_LEVEL_VERBOSE, " starting handler %p for stream %p\n", *it, stream);
496             result = (*it)->enable(cycle);
497             if(!result) {
498                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not enable handler (%p)\n",*it);
499                 return false;
500             }
501             return true;
502         }
503     }
504     debugError("Stream %p has no attached handler\n", stream);
505     return false;
506 }
507
508 bool IsoHandlerManager::stopHandlers() {
509     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
510
511     // check state
512     if(m_State != E_Running) {
513         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
514         return false;
515     }
516
517     bool retval=true;
518
519     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
520         it != m_IsoHandlers.end();
521         ++it )
522     {
523         debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping handler (%p)\n",*it);
524         if(!(*it)->disable()){
525             debugOutput( DEBUG_LEVEL_VERBOSE, " could not stop handler (%p)\n",*it);
526             retval=false;
527         }
528     }
529
530     if (retval) {
531         m_State=E_Prepared;
532     } else {
533         m_State=E_Error;
534     }
535     return retval;
536 }
537
538 bool IsoHandlerManager::reset() {
539     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
540     // check state
541     if(m_State == E_Error) {
542         debugFatal("Resetting from error condition not yet supported...\n");
543         return false;
544     }
545     // if not in an error condition, reset means stop the handlers
546     return stopHandlers();
547 }
548
549 void IsoHandlerManager::setVerboseLevel(int i) {
550     setDebugLevel(i);
551     // propagate the debug level
552     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
553           it != m_IsoHandlers.end();
554           ++it )
555     {
556         (*it)->setVerboseLevel(i);
557     }
558 }
559
560 void IsoHandlerManager::dumpInfo() {
561     int i=0;
562     debugOutputShort( DEBUG_LEVEL_NORMAL, "Dumping IsoHandlerManager Stream handler information...\n");
563     debugOutputShort( DEBUG_LEVEL_NORMAL, " State: %d\n",(int)m_State);
564
565     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
566           it != m_IsoHandlers.end();
567           ++it )
568     {
569         debugOutputShort( DEBUG_LEVEL_NORMAL, " IsoHandler %d (%p)\n",i++,*it);
570         (*it)->dumpInfo();
571     }
572 }
573
574 const char *
575 IsoHandlerManager::eHSToString(enum eHandlerStates s) {
576     switch (s) {
577         default: return "Invalid";
578         case E_Created: return "Created";
579         case E_Prepared: return "Prepared";
580         case E_Running: return "Running";
581         case E_Error: return "Error";
582     }
583 }
Note: See TracBrowser for help on using the browser.