root/branches/libfreebob-2.0/src/libstreaming/IsoHandlerManager.cpp

Revision 309, 14.6 kB (checked in by jwoithe, 16 years ago)

MOTU: Fixed false "missed rx cycle" report following xrun recovery.
Ensure iso rx/tx contexts are deallocated during shutdown/xrun recovery by explicitly deleting IsoHandlers? in IsoHandlerManager::pruneHandlers(). If they aren't deleted here they never get deleted because the reference is lost.
IsoHandler? destructor should only call stop() if the handle is valid.
IsoXmitHandler?'s destructor sets the handle NULL to prevent double-free by the inherited IsoHandler? destructor.
Don't call raw1394_iso_shutdown() from our code. libraw1394 1.2.1 has a bug whereby raw1394_new_handle() fails to initialise the iso_packet_infos field. The bug hits us particularly in IsoRecvHandler::prepare(). It's also not really necessary to call raw1394_iso_shutdown() since raw1394_destroy_handle() will do any cleanups we happen to need.
MOTU: the receive stream no longer falsely complains of buffer problems during device shutdown.
MOTU: fixed a false "missed cycle" detection immediately after the stream was enabled.

Line 
1 /* $Id$ */
2
3 /*
4  *   FreeBob Streaming API
5  *   FreeBob = Firewire (pro-)audio for linux
6  *
7  *   http://freebob.sf.net
8  *
9  *   Copyright (C) 2006 Pieter Palmers <pieterpalmers@users.sourceforge.net>
10  *
11  *   This program is free software {} you can redistribute it and/or modify
12  *   it under the terms of the GNU General Public License as published by
13  *   the Free Software Foundation {} either version 2 of the License, or
14  *   (at your option) any later version.
15  *
16  *   This program is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY {} without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with this program {} if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  *
26  *
27  */
28
29 #include "IsoHandlerManager.h"
30 #include "IsoHandler.h"
31 #include "IsoStream.h"
32 #include <assert.h>
33
34
35 namespace FreebobStreaming
36 {
37
38 IMPL_DEBUG_MODULE( IsoHandlerManager, IsoHandlerManager, DEBUG_LEVEL_NORMAL );
39
40 IsoHandlerManager::IsoHandlerManager() :
41    m_poll_timeout(100), m_poll_fds(0), m_poll_nfds(0)
42 {
43
44 }
45
46
47 IsoHandlerManager::~IsoHandlerManager()
48 {
49
50 }
51
52 bool IsoHandlerManager::Init()
53 {
54         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
55
56         return true;
57 }
58
59 // Intel recommends that a serializing instruction
60 // should be called before and after rdtsc.
61 // CPUID is a serializing instruction.
62 #define read_rdtsc(time) \
63         __asm__ __volatile__( \
64         "pushl %%ebx\n\t" \
65         "cpuid\n\t" \
66         "rdtsc\n\t" \
67         "mov %%eax,(%0)\n\t" \
68         "cpuid\n\t" \
69         "popl %%ebx\n\t" \
70         : /* no output */ \
71         : "S"(&time) \
72         : "eax", "ecx", "edx", "memory")
73
74 static inline unsigned long debugGetCurrentUTime() {
75     unsigned retval;
76     read_rdtsc(retval);
77     return retval;
78 }
79
80 bool IsoHandlerManager::Execute()
81 {
82         int err;
83         int i=0;
84         debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "enter...\n");
85        
86         unsigned long tstamp=debugGetCurrentUTime();
87
88         err = poll (m_poll_fds, m_poll_nfds, m_poll_timeout);
89        
90 //      debugOutput(DEBUG_LEVEL_VERBOSE, "Poll took: %6d\n", debugGetCurrentUTime()-tstamp);
91        
92         if (err == -1) {
93                 if (errno == EINTR) {
94                         return true;
95                 }
96                 debugFatal("poll error: %s\n", strerror (errno));
97                 return false;
98         }
99
100         for (i = 0; i < m_poll_nfds; i++) {
101                 if (m_poll_fds[i].revents & POLLERR) {
102                         debugWarning("error on fd for %d\n",i);
103                 }
104
105                 if (m_poll_fds[i].revents & POLLHUP) {
106                         debugWarning("hangup on fd for %d\n",i);
107                 }
108                
109                 if(m_poll_fds[i].revents & (POLLIN)) {
110                         IsoHandler *s=m_IsoHandlers.at(i);
111                         assert(s);
112                        
113                         unsigned int packetcount_prev=s->getPacketCount();
114                        
115                         tstamp=debugGetCurrentUTime();
116                        
117                         s->iterate();
118 /*                      debugOutput(DEBUG_LEVEL_VERBOSE, "Iterate %p: time: %6d | packets: %3d\n",
119                              s, debugGetCurrentUTime()-tstamp, s->getPacketCount()-packetcount_prev
120                              );*/
121                 }
122         }
123         return true;
124
125 }
126
127 bool IsoHandlerManager::prepare()
128 {
129         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
130     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
131           it != m_IsoHandlers.end();
132           ++it )
133     {
134         if(!(*it)->prepare()) {
135                         debugFatal("Could not prepare handlers\n");
136                         return false;
137         }
138     }
139
140         return true;
141 }
142
143
144
145 bool IsoHandlerManager::registerHandler(IsoHandler *handler)
146 {
147         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
148         assert(handler);
149        
150         m_IsoHandlers.push_back(handler);
151        
152         handler->setVerboseLevel(getDebugLevel());
153
154         // rebuild the fd map for poll()'ing.
155         return rebuildFdMap(); 
156
157 }
158
159 bool IsoHandlerManager::unregisterHandler(IsoHandler *handler)
160 {
161         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
162         assert(handler);
163
164         for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
165           it != m_IsoHandlers.end();
166           ++it )
167         {
168                 if ( *it == handler ) {
169                         // erase the iso handler from the list
170                         m_IsoHandlers.erase(it);
171                         // rebuild the fd map for poll()'ing.
172                         return rebuildFdMap();
173                 }
174         }
175         debugFatal("Could not find handler (%p)\n", handler);
176        
177         return false; //not found
178
179 }
180
181 bool IsoHandlerManager::rebuildFdMap() {
182         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
183         int i=0;
184
185         m_poll_nfds=0;
186         if(m_poll_fds) free(m_poll_fds);
187
188         // count the number of handlers
189         m_poll_nfds=m_IsoHandlers.size();
190
191         // allocate the fd array
192         m_poll_fds   = (struct pollfd *) calloc (m_poll_nfds, sizeof (struct pollfd));
193         if(!m_poll_fds) {
194                 debugFatal("Could not allocate memory for poll FD array\n");
195                 return false;
196         }
197
198         // fill the fd map
199         for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
200           it != m_IsoHandlers.end();
201           ++it )
202         {
203                 m_poll_fds[i].fd=(*it)->getFileDescriptor();
204                 m_poll_fds[i].events = POLLIN;
205                 i++;
206         }
207
208         return true;
209 }
210
211 void IsoHandlerManager::disablePolling(IsoStream *stream) {
212     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Disable polling on stream %p\n",stream);
213         int i=0;
214         for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
215           it != m_IsoHandlers.end();
216           ++it )
217         {
218            if ((*it)->isStreamRegistered(stream)) {
219                m_poll_fds[i].events = 0;
220                m_poll_fds[i].revents = 0;
221             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "polling disabled\n");
222            }
223            i++;
224         }
225
226 }
227
228 void IsoHandlerManager::enablePolling(IsoStream *stream) {
229     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Enable polling on stream %p\n",stream);
230         int i=0;
231         for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
232           it != m_IsoHandlers.end();
233           ++it )
234         {
235            if ((*it)->isStreamRegistered(stream)) {
236                m_poll_fds[i].events = POLLIN;
237                m_poll_fds[i].revents = 0;
238             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "polling enabled\n");
239            }
240            i++;
241         }
242 }
243
244
245 /**
246  * Registers an IsoStream with the IsoHandlerManager.
247  *
248  * If nescessary, an IsoHandler is created to handle this stream.
249  * Once an IsoStream is registered to the handler, it will be included
250  * in the ISO streaming cycle (i.e. receive/transmit of it will occur).
251  *
252  * @param stream the stream to register
253  * @return true if registration succeeds
254  *
255  * \todo : currently there is a one-to-one mapping
256  *        between streams and handlers, this is not ok for
257  *        multichannel receive
258  */
259 bool IsoHandlerManager::registerStream(IsoStream *stream)
260 {
261         debugOutput( DEBUG_LEVEL_VERBOSE, "Registering stream %p\n",stream);
262         assert(stream);
263
264         // make sure the stream isn't already attached to a handler
265         for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
266           it != m_IsoHandlers.end();
267           ++it )
268         {
269                 if((*it)->isStreamRegistered(stream)) {
270                         debugWarning( "stream already registered!\n");
271                         (*it)->unregisterStream(stream);
272                        
273                 }
274         }
275        
276         // clean up all handlers that aren't used
277         pruneHandlers();
278
279         // allocate a handler for this stream
280         if (stream->getType()==IsoStream::EST_Receive) {
281                 // setup the optimal parameters for the raw1394 ISO buffering
282                 unsigned int packets_per_period=stream->getPacketsPerPeriod();
283                
284                 // hardware interrupts occur when one DMA block is full, and the size of one DMA
285                 // block = PAGE_SIZE. Setting the max_packet_size makes sure that the HW irq is
286                 // occurs at a period boundary (optimal CPU use)
287                
288                 // NOTE: try and use 4 hardware interrupts per period for better latency.
289                 unsigned int max_packet_size=4 * getpagesize() / packets_per_period;
290                 if (max_packet_size < stream->getMaxPacketSize()) {
291                         max_packet_size=stream->getMaxPacketSize();
292                 }
293
294                 // Ensure we don't request a packet size bigger than the
295                 // kernel-enforced maximum which is currently 1 page.
296                 if (max_packet_size > (unsigned int)getpagesize())
297                         max_packet_size = getpagesize();
298
299                 int irq_interval=packets_per_period / 4;
300         if(irq_interval <= 0) irq_interval=1;
301
302                 /* the receive buffer size doesn't matter for the latency,
303                    but it has a minimal value in order for libraw to operate correctly (300) */
304                 int buffers=400;
305                
306                 // create the actual handler
307                 IsoRecvHandler *h = new IsoRecvHandler(stream->getPort(), buffers,
308                                                        max_packet_size, irq_interval);
309
310                 debugOutput( DEBUG_LEVEL_VERBOSE, " registering IsoRecvHandler\n");
311
312                 if(!h) {
313                         debugFatal("Could not create IsoRecvHandler\n");
314                         return false;
315                 }
316
317                 h->setVerboseLevel(getDebugLevel());
318
319                 // init the handler
320                 if(!h->init()) {
321                         debugFatal("Could not initialize receive handler\n");
322                         return false;
323                 }
324
325                 // register the stream with the handler
326                 if(!h->registerStream(stream)) {
327                         debugFatal("Could not register receive stream with handler\n");
328                         return false;
329                 }
330
331                 // register the handler with the manager
332                 if(!registerHandler(h)) {
333                         debugFatal("Could not register receive handler with manager\n");
334                         return false;
335                 }
336                 debugOutput( DEBUG_LEVEL_VERBOSE, " registered stream (%p) with handler (%p)\n",stream,h);
337         }
338        
339         if (stream->getType()==IsoStream::EST_Transmit) {
340        
341                 // setup the optimal parameters for the raw1394 ISO buffering
342                 unsigned int packets_per_period=stream->getPacketsPerPeriod();
343                 // hardware interrupts occur when one DMA block is full, and the size of one DMA
344                 // block = PAGE_SIZE. Setting the max_packet_size makes sure that the HW irq 
345                 // occurs at a period boundary (optimal CPU use)
346                 // NOTE: try and use 4 interrupts per period for better latency.
347                 unsigned int max_packet_size=4 * getpagesize() / packets_per_period;
348                 if (max_packet_size < stream->getMaxPacketSize()) {
349                         max_packet_size=stream->getMaxPacketSize();
350                 }
351
352                 // Ensure we don't request a packet size bigger than the
353                 // kernel-enforced maximum which is currently 1 page.
354                 if (max_packet_size > (unsigned int)getpagesize())
355                         max_packet_size = getpagesize();
356
357                 int irq_interval=packets_per_period / 4;
358                 if(irq_interval <= 0) irq_interval=1;
359        
360                 // the transmit buffer size should be as low as possible for latency.
361                 // note however that the raw1394 subsystem tries to keep this buffer
362                 // full, so we have to make sure that we have enough events in our
363                 // event buffers
364                 int buffers=packets_per_period;
365                
366                 // NOTE: this is dangerous: what if there is not enough prefill?
367 //              if (buffers<10) buffers=10;     
368                
369                 // create the actual handler
370                 IsoXmitHandler *h = new IsoXmitHandler(stream->getPort(), buffers,
371                                                        max_packet_size, irq_interval);
372
373                 debugOutput( DEBUG_LEVEL_VERBOSE, " registering IsoXmitHandler\n");
374
375                 if(!h) {
376                         debugFatal("Could not create IsoXmitHandler\n");
377                         return false;
378                 }
379
380                 h->setVerboseLevel(getDebugLevel());
381
382                 // init the handler
383                 if(!h->init()) {
384                         debugFatal("Could not initialize transmit handler\n");
385                         return false;
386                 }
387
388                 // register the stream with the handler
389                 if(!h->registerStream(stream)) {
390                         debugFatal("Could not register transmit stream with handler\n");
391                         return false;
392                 }
393
394                 // register the handler with the manager
395                 if(!registerHandler(h)) {
396                         debugFatal("Could not register transmit handler with manager\n");
397                         return false;
398                 }
399                 debugOutput( DEBUG_LEVEL_VERBOSE, " registered stream (%p) with handler (%p)\n",stream,h);
400
401         }
402
403         m_IsoStreams.push_back(stream);
404         debugOutput( DEBUG_LEVEL_VERBOSE, " %d streams, %d handlers registered\n",
405                                           m_IsoStreams.size(), m_IsoHandlers.size());
406
407         return true;
408 }
409
410 bool IsoHandlerManager::unregisterStream(IsoStream *stream)
411 {
412         debugOutput( DEBUG_LEVEL_VERBOSE, "Unregistering stream %p\n",stream);
413         assert(stream);
414
415         // make sure the stream isn't attached to a handler anymore
416         for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
417           it != m_IsoHandlers.end();
418           ++it )
419         {
420                 if((*it)->isStreamRegistered(stream)) {
421                         if(!(*it)->unregisterStream(stream)) {
422                                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not unregister stream (%p) from handler (%p)...\n",stream,*it);
423                                 return false;
424                         }
425                        
426                         debugOutput( DEBUG_LEVEL_VERBOSE, " unregistered stream (%p) from handler (%p)...\n",stream,*it);
427                 }
428         }
429
430         // clean up all handlers that aren't used
431         pruneHandlers();
432
433         // remove the stream from the registered streams list
434         for ( IsoStreamVectorIterator it = m_IsoStreams.begin();
435           it != m_IsoStreams.end();
436           ++it )
437         {
438                 if ( *it == stream ) {
439                         m_IsoStreams.erase(it);
440                        
441                         debugOutput( DEBUG_LEVEL_VERBOSE, " deleted stream (%p) from list...\n", *it);
442                         return true;
443                 }
444         }
445
446         return false; //not found
447
448 }
449
450 void IsoHandlerManager::pruneHandlers() {
451         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
452         IsoHandlerVector toUnregister;
453
454         // find all handlers that are not in use
455     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
456           it != m_IsoHandlers.end();
457           ++it )
458     {
459                 if(!((*it)->inUse())) {
460                         debugOutput( DEBUG_LEVEL_VERBOSE, " handler (%p) not in use\n",*it);
461                         toUnregister.push_back(*it);
462                 }
463     }
464         // delete them
465     for ( IsoHandlerVectorIterator it = toUnregister.begin();
466           it != toUnregister.end();
467           ++it )
468     {
469                 unregisterHandler(*it);
470                 debugOutput( DEBUG_LEVEL_VERBOSE, " deleting handler (%p)\n",*it);
471
472                 // Now the handler's been unregistered it won't be reused
473                 // again.  Therefore it really needs to be formally deleted
474                 // to free up the raw1394 handle.  Otherwise things fall
475                 // apart after several xrun recoveries as the system runs
476                 // out of resources to support all the disused but still
477                 // allocated raw1394 handles.  At least this is the current
478                 // theory as to why we end up with "memory allocation"
479                 // failures after several Xrun recoveries.
480                 delete *it;
481     }
482
483 }
484
485 bool IsoHandlerManager::startHandlers() {
486         return startHandlers(-1);
487 }
488
489 bool IsoHandlerManager::startHandlers(int cycle) {
490         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
491
492         for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
493           it != m_IsoHandlers.end();
494           ++it )
495         {
496                 debugOutput( DEBUG_LEVEL_VERBOSE, " starting handler (%p)\n",*it);
497                 if(!(*it)->start(cycle)) {
498                         debugOutput( DEBUG_LEVEL_VERBOSE, " could not start handler (%p)\n",*it);
499                         return false;
500                 }
501         }
502        
503         return true;
504 }
505
506 bool IsoHandlerManager::stopHandlers() {
507         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
508
509         for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
510           it != m_IsoHandlers.end();
511           ++it )
512         {
513                 debugOutput( DEBUG_LEVEL_VERBOSE, " stopping handler (%p)\n",*it);
514                 if(!(*it)->stop()){
515                         debugOutput( DEBUG_LEVEL_VERBOSE, " could not stop handler (%p)\n",*it);
516                         return false;
517                 }
518         }
519         return true;
520 }
521
522 void IsoHandlerManager::setVerboseLevel(int i) {
523         setDebugLevel(i);
524
525     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
526           it != m_IsoHandlers.end();
527           ++it )
528     {
529                 (*it)->setVerboseLevel(i);
530     }
531 }
532
533 void IsoHandlerManager::dumpInfo() {
534         debugOutputShort( DEBUG_LEVEL_NORMAL, "Dumping IsoHandlerManager Stream handler information...\n");
535         int i=0;
536
537     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
538           it != m_IsoHandlers.end();
539           ++it )
540     {
541                 debugOutputShort( DEBUG_LEVEL_NORMAL, " Stream %d (%p)\n",i++,*it);
542
543                 (*it)->dumpInfo();
544     }
545
546 }
547
548 } // end of namespace FreebobStreaming
549
Note: See TracBrowser for help on using the browser.