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

Revision 1234, 33.4 kB (checked in by holin, 13 years ago)

fix gcc 4.3 compile errors and some warnings (largely from Adrian Knoth)

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "config.h"
25 #include "IsoHandlerManager.h"
26 #include "ieee1394service.h"
27 #include "libstreaming/generic/StreamProcessor.h"
28
29 #include "libutil/Atomic.h"
30 #include "libutil/PosixThread.h"
31 #include "libutil/SystemTimeSource.h"
32 #include "libutil/Watchdog.h"
33
34 #include <cstring>
35 #include <assert.h>
36
37 IMPL_DEBUG_MODULE( IsoHandlerManager, IsoHandlerManager, DEBUG_LEVEL_NORMAL );
38 IMPL_DEBUG_MODULE( IsoTask, IsoTask, DEBUG_LEVEL_NORMAL );
39
40 using namespace Streaming;
41
42 // --- ISO Thread --- //
43
44 IsoTask::IsoTask(IsoHandlerManager& manager, enum IsoHandler::EHandlerType t)
45     : m_manager( manager )
46     , m_SyncIsoHandler ( NULL )
47     , m_handlerType( t )
48 {
49 }
50
51 IsoTask::~IsoTask()
52 {
53     sem_destroy(&m_activity_semaphore);
54 }
55
56 bool
57 IsoTask::Init()
58 {
59     request_update = 0;
60
61     int i;
62     for (i=0; i < ISOHANDLERMANAGER_MAX_ISO_HANDLERS_PER_PORT; i++) {
63         m_IsoHandler_map_shadow[i] = NULL;
64         m_poll_fds_shadow[i].events = 0;
65     }
66     m_poll_nfds_shadow = 0;
67
68     #ifdef DEBUG
69     m_last_loop_entry = 0;
70     m_successive_short_loops = 0;
71     #endif
72
73     sem_init(&m_activity_semaphore, 0, 0);
74     return true;
75 }
76
77 bool
78 IsoTask::requestShadowMapUpdate()
79 {
80     debugOutput(DEBUG_LEVEL_VERBOSE, "(%p) enter\n", this);
81     INC_ATOMIC(&request_update);
82     return true;
83 }
84
85 // updates the internal stream map
86 // note that this should be executed with the guarantee that
87 // nobody will modify the parent data structures
88 void
89 IsoTask::updateShadowMapHelper()
90 {
91     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) updating shadow vars...\n", this);
92     unsigned int i, cnt, max;
93     max = m_manager.m_IsoHandlers.size();
94     m_SyncIsoHandler = NULL;
95     for (i = 0, cnt = 0; i < max; i++) {
96         IsoHandler *h = m_manager.m_IsoHandlers.at(i);
97         assert(h);
98
99         // skip the handlers not intended for us
100         if(h->getType() != m_handlerType) continue;
101
102         if (h->isEnabled()) {
103             m_IsoHandler_map_shadow[cnt] = h;
104             m_poll_fds_shadow[cnt].fd = h->getFileDescriptor();
105             m_poll_fds_shadow[cnt].revents = 0;
106             m_poll_fds_shadow[cnt].events = POLLIN;
107             cnt++;
108             // FIXME: need a more generic approach here
109             if(   m_SyncIsoHandler == NULL
110                && h->getType() == IsoHandler::eHT_Transmit) {
111                 m_SyncIsoHandler = h;
112             }
113
114             debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) %s handler %p added\n",
115                                               this, h->getTypeString(), h);
116         } else {
117             debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) %s handler %p skipped (disabled)\n",
118                                               this, h->getTypeString(), h);
119         }
120         if(cnt > ISOHANDLERMANAGER_MAX_ISO_HANDLERS_PER_PORT) {
121             debugWarning("Too much ISO Handlers in thread...\n");
122             break;
123         }
124     }
125
126     // FIXME: need a more generic approach here
127     // if there are no active transmit handlers,
128     // use the first receive handler
129     if(   m_SyncIsoHandler == NULL
130        && m_poll_nfds_shadow) {
131         m_SyncIsoHandler = m_IsoHandler_map_shadow[0];
132     }
133     m_poll_nfds_shadow = cnt;
134     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) updated shadow vars...\n", this);
135 }
136
137 bool
138 IsoTask::Execute()
139 {
140     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
141                        "(%p, %s) Execute\n",
142                        this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"));
143     int err;
144     unsigned int i;
145     unsigned int m_poll_timeout = 10;
146
147     #ifdef DEBUG
148     uint64_t now = Util::SystemTimeSource::getCurrentTimeAsUsecs();
149     int diff = now - m_last_loop_entry;
150     if(diff < 100) {
151         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
152                            "(%p, %s) short loop detected (%d usec), cnt: %d\n",
153                            this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"),
154                            diff, m_successive_short_loops);
155         m_successive_short_loops++;
156         if(m_successive_short_loops > 10000) {
157             debugError("Shutting down runaway thread\n");
158             return false;
159         }
160     } else {
161         // reset the counter
162         m_successive_short_loops = 0;
163     }
164     m_last_loop_entry = now;
165     #endif
166
167     // if some other thread requested a shadow map update, do it
168     if(request_update) {
169         updateShadowMapHelper();
170         DEC_ATOMIC(&request_update); // ack the update
171         assert(request_update >= 0);
172     }
173
174     // bypass if no handlers are registered
175     if (m_poll_nfds_shadow == 0) {
176         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
177                            "(%p, %s) bypass iterate since no handlers to poll\n",
178                            this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"));
179         usleep(m_poll_timeout * 1000);
180         return true;
181     }
182
183     // FIXME: what can happen is that poll() returns, but not all clients are
184     // ready. there might be some busy waiting behavior that still has to be solved.
185
186     // setup the poll here
187     // we should prevent a poll() where no events are specified, since that will only time-out
188     bool no_one_to_poll = true;
189     while(no_one_to_poll) {
190         for (i = 0; i < m_poll_nfds_shadow; i++) {
191             short events = 0;
192             IsoHandler *h = m_IsoHandler_map_shadow[i];
193             // we should only poll on a transmit handler
194             // that has a client that is ready to send
195             // something. Otherwise it will end up in
196             // busy wait looping since the packet function
197             // will defer processing (also avoids the
198             // AGAIN problem)
199             if (h->canIterateClient()) {
200                 events = POLLIN | POLLPRI;
201                 no_one_to_poll = false;
202                 // if we are going to poll() it, let's ensure
203                 // it can run until someone wants it to exit
204                 h->allowIterateLoop();
205             }
206             m_poll_fds_shadow[i].events = events;
207         }
208
209         if(no_one_to_poll) {
210             debugOutputExtreme(DEBUG_LEVEL_VERBOSE,
211                                "(%p, %s) No one to poll, waiting for something to happen\n",
212                                this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"));
213             // wait for something to happen
214             switch(waitForActivity()) {
215                 case IsoTask::eAR_Error:
216                     debugError("Error while waiting for activity\n");
217                     return false;
218                 case IsoTask::eAR_Interrupted:
219                     // FIXME: what to do here?
220                     debugWarning("Interrupted while waiting for activity\n");
221                     break;
222                 case IsoTask::eAR_Timeout:
223                     // FIXME: what to do here?
224                     debugWarning("Timeout while waiting for activity\n");
225                     break;
226                 case IsoTask::eAR_Activity:
227                     // do nothing
228                     debugOutputExtreme(DEBUG_LEVEL_VERBOSE,
229                                        "(%p, %s) something happened\n",
230                                        this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"));
231                     break;
232             }
233         }
234     }
235
236     // Use a shadow map of the fd's such that we don't have to update
237     // the fd map everytime we run poll().
238     err = poll (m_poll_fds_shadow, m_poll_nfds_shadow, m_poll_timeout);
239
240     if (err < 0) {
241         if (errno == EINTR) {
242             debugOutput(DEBUG_LEVEL_VERBOSE, "Ignoring poll return due to signal\n");
243             return true;
244         }
245         debugFatal("poll error: %s\n", strerror (errno));
246         return false;
247     }
248
249     for (i = 0; i < m_poll_nfds_shadow; i++) {
250         #ifdef DEBUG
251         if(m_poll_fds_shadow[i].revents) {
252             debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE,
253                         "(%p, %s) received events: %08X for (%d/%d, %p, %s)\n",
254                         this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"),
255                         m_poll_fds_shadow[i].revents,
256                         i, m_poll_nfds_shadow,
257                         m_IsoHandler_map_shadow[i],
258                         m_IsoHandler_map_shadow[i]->getTypeString());
259         }
260         #endif
261
262         // if we get here, it means two things:
263         // 1) the kernel can accept or provide packets (poll returned POLLIN)
264         // 2) the client can provide or accept packets (since we enabled polling)
265         if(m_poll_fds_shadow[i].revents & (POLLIN)) {
266             m_IsoHandler_map_shadow[i]->iterate();
267         } else {
268             // there might be some error condition
269             if (m_poll_fds_shadow[i].revents & POLLERR) {
270                 debugWarning("(%p) error on fd for %d\n", this, i);
271             }
272             if (m_poll_fds_shadow[i].revents & POLLHUP) {
273                 debugWarning("(%p) hangup on fd for %d\n", this, i);
274             }
275         }
276
277 //         #ifdef DEBUG
278 //         // check if the handler is still alive
279 //         if(m_IsoHandler_map_shadow[i]->isDead()) {
280 //             debugError("Iso handler (%p, %s) is dead!\n",
281 //                        m_IsoHandler_map_shadow[i],
282 //                        m_IsoHandler_map_shadow[i]->getTypeString());
283 //             return false; // shutdown the system
284 //         }
285 //         #endif
286
287     }
288     return true;
289 }
290
291 enum IsoTask::eActivityResult
292 IsoTask::waitForActivity()
293 {
294     debugOutputExtreme(DEBUG_LEVEL_VERBOSE,
295                        "(%p, %s) waiting for activity\n",
296                        this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"));
297     struct timespec ts;
298     int result;
299
300     if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
301         debugError("clock_gettime failed\n");
302         return eAR_Error;
303     }
304     long long int timeout_nsec=0;
305     int timeout_sec = 0;
306
307     timeout_nsec = ISOHANDLERMANAGER_ISO_TASK_WAIT_TIMEOUT_USECS * 1000LL;
308     timeout_sec = 0;
309     while(timeout_nsec >= 1000000000LL) {
310         timeout_sec += 1;
311         timeout_nsec -= 1000000000LL;
312     }
313     ts.tv_nsec += timeout_nsec;
314     ts.tv_sec += timeout_sec;
315
316     result = sem_timedwait(&m_activity_semaphore, &ts);
317
318     if(result != 0) {
319         if (errno == ETIMEDOUT) {
320             debugOutput(DEBUG_LEVEL_VERBOSE,
321                         "(%p) sem_timedwait() timed out (result=%d)\n",
322                         this, result);
323             return eAR_Timeout;
324         } else if (errno == EINTR) {
325             debugOutput(DEBUG_LEVEL_VERBOSE,
326                         "(%p) sem_timedwait() interrupted by signal (result=%d)\n",
327                         this, result);
328             return eAR_Interrupted;
329         } else {
330             debugError("(%p) sem_timedwait error (result=%d errno=%d)\n",
331                         this, result, errno);
332             debugError("(%p) timeout_sec=%d timeout_nsec=%lld ts.sec=%d ts.nsec=%lld\n",
333                        this, timeout_sec, timeout_nsec, ts.tv_sec, ts.tv_nsec);
334             return eAR_Error;
335         }
336     }
337
338     debugOutputExtreme(DEBUG_LEVEL_VERBOSE,
339                        "(%p, %s) got activity\n",
340                        this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"));
341     return eAR_Activity;
342 }
343
344 void
345 IsoTask::signalActivity()
346 {
347     // signal the activity cond var
348     sem_post(&m_activity_semaphore);
349     debugOutputExtreme(DEBUG_LEVEL_VERBOSE,
350                        "(%p, %s) activity\n",
351                        this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"));
352 }
353
354 void IsoTask::setVerboseLevel(int i) {
355     setDebugLevel(i);
356 }
357
358 // -- the ISO handler manager -- //
359 IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service)
360    : m_State(E_Created)
361    , m_service( service )
362    , m_realtime(false), m_priority(0)
363    , m_IsoThreadTransmit ( NULL )
364    , m_IsoTaskTransmit ( NULL )
365    , m_IsoThreadReceive ( NULL )
366    , m_IsoTaskReceive ( NULL )
367 {
368 }
369
370 IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service, bool run_rt, int rt_prio)
371    : m_State(E_Created)
372    , m_service( service )
373    , m_realtime(run_rt), m_priority(rt_prio)
374    , m_IsoThreadTransmit ( NULL )
375    , m_IsoTaskTransmit ( NULL )
376    , m_IsoThreadReceive ( NULL )
377    , m_IsoTaskReceive ( NULL )
378 {
379 }
380
381 IsoHandlerManager::~IsoHandlerManager()
382 {
383     stopHandlers();
384     pruneHandlers();
385     if(m_IsoHandlers.size() > 0) {
386         debugError("Still some handlers in use\n");
387     }
388     if (m_IsoThreadTransmit) {
389         m_IsoThreadTransmit->Stop();
390         delete m_IsoThreadTransmit;
391     }
392     if (m_IsoThreadReceive) {
393         m_IsoThreadReceive->Stop();
394         delete m_IsoThreadReceive;
395     }
396     if (m_IsoTaskTransmit) {
397         delete m_IsoTaskTransmit;
398     }
399     if (m_IsoTaskReceive) {
400         delete m_IsoTaskReceive;
401     }
402 }
403
404 void
405 IsoHandlerManager::requestShadowMapUpdate()
406 {
407     if(m_IsoTaskTransmit) m_IsoTaskTransmit->requestShadowMapUpdate();
408     if(m_IsoTaskReceive) m_IsoTaskReceive->requestShadowMapUpdate();
409 }
410
411 bool
412 IsoHandlerManager::setThreadParameters(bool rt, int priority) {
413     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) switch to: (rt=%d, prio=%d)...\n", this, rt, priority);
414     if (priority > THREAD_MAX_RTPRIO) priority = THREAD_MAX_RTPRIO; // cap the priority
415     m_realtime = rt;
416     m_priority = priority;
417
418     if (m_IsoThreadTransmit) {
419         if (m_realtime) {
420             m_IsoThreadTransmit->AcquireRealTime(m_priority
421                                                  + ISOHANDLERMANAGER_ISO_PRIO_INCREASE
422                                                  + ISOHANDLERMANAGER_ISO_PRIO_INCREASE_XMIT);
423         } else {
424             m_IsoThreadTransmit->DropRealTime();
425         }
426     }
427     if (m_IsoThreadReceive) {
428         if (m_realtime) {
429             m_IsoThreadReceive->AcquireRealTime(m_priority
430                                                 + ISOHANDLERMANAGER_ISO_PRIO_INCREASE
431                                                 + ISOHANDLERMANAGER_ISO_PRIO_INCREASE_RECV);
432         } else {
433             m_IsoThreadReceive->DropRealTime();
434         }
435     }
436
437     return true;
438 }
439
440 bool IsoHandlerManager::init()
441 {
442     debugOutput( DEBUG_LEVEL_VERBOSE, "Initializing ISO manager %p...\n", this);
443     // check state
444     if(m_State != E_Created) {
445         debugError("Manager already initialized...\n");
446         return false;
447     }
448
449     // create threads to iterate our ISO handlers
450     debugOutput( DEBUG_LEVEL_VERBOSE, "Create iso thread for %p transmit...\n", this);
451     m_IsoTaskTransmit = new IsoTask( *this, IsoHandler::eHT_Transmit );
452     if(!m_IsoTaskTransmit) {
453         debugFatal("No task\n");
454         return false;
455     }
456     m_IsoTaskTransmit->setVerboseLevel(getDebugLevel());
457     m_IsoThreadTransmit = new Util::PosixThread(m_IsoTaskTransmit, m_realtime,
458                                                 m_priority + ISOHANDLERMANAGER_ISO_PRIO_INCREASE
459                                                 + ISOHANDLERMANAGER_ISO_PRIO_INCREASE_XMIT,
460                                                 PTHREAD_CANCEL_DEFERRED);
461
462     if(!m_IsoThreadTransmit) {
463         debugFatal("No thread\n");
464         return false;
465     }
466     m_IsoThreadTransmit->setVerboseLevel(getDebugLevel());
467
468     debugOutput( DEBUG_LEVEL_VERBOSE, "Create iso thread for %p receive...\n", this);
469     m_IsoTaskReceive = new IsoTask( *this, IsoHandler::eHT_Receive );
470     if(!m_IsoTaskReceive) {
471         debugFatal("No task\n");
472         return false;
473     }
474     m_IsoTaskReceive->setVerboseLevel(getDebugLevel());
475     m_IsoThreadReceive = new Util::PosixThread(m_IsoTaskReceive, m_realtime,
476                                                m_priority + ISOHANDLERMANAGER_ISO_PRIO_INCREASE
477                                                + ISOHANDLERMANAGER_ISO_PRIO_INCREASE_RECV,
478                                                PTHREAD_CANCEL_DEFERRED);
479
480     if(!m_IsoThreadReceive) {
481         debugFatal("No thread\n");
482         return false;
483     }
484     m_IsoThreadReceive->setVerboseLevel(getDebugLevel());
485     // register the thread with the RT watchdog
486     Util::Watchdog *watchdog = m_service.getWatchdog();
487     if(watchdog) {
488         if(!watchdog->registerThread(m_IsoThreadTransmit)) {
489             debugWarning("could not register iso transmit thread with watchdog\n");
490         }
491         if(!watchdog->registerThread(m_IsoThreadReceive)) {
492             debugWarning("could not register iso receive thread with watchdog\n");
493         }
494     } else {
495         debugWarning("could not find valid watchdog\n");
496     }
497
498     if (m_IsoThreadTransmit->Start() != 0) {
499         debugFatal("Could not start ISO Transmit thread\n");
500         return false;
501     }
502     if (m_IsoThreadReceive->Start() != 0) {
503         debugFatal("Could not start ISO Receive thread\n");
504         return false;
505     }
506
507     m_State=E_Running;
508     return true;
509 }
510
511 bool
512 IsoHandlerManager::disable(IsoHandler *h) {
513     bool result;
514     int i=0;
515     debugOutput(DEBUG_LEVEL_VERBOSE, "Disable on IsoHandler %p\n", h);
516     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
517         it != m_IsoHandlers.end();
518         ++it )
519     {
520         if ((*it) == h) {
521             result = h->disable();
522             if(h->getType() == IsoHandler::eHT_Transmit) {
523                 result &= m_IsoTaskTransmit->requestShadowMapUpdate();
524             } else {
525                 result &= m_IsoTaskReceive->requestShadowMapUpdate();
526             }
527             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " disabled\n");
528             return result;
529         }
530         i++;
531     }
532     debugError("Handler not found\n");
533     return false;
534 }
535
536 bool
537 IsoHandlerManager::enable(IsoHandler *h) {
538     bool result;
539     int i=0;
540     debugOutput(DEBUG_LEVEL_VERBOSE, "Enable on IsoHandler %p\n", h);
541     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
542         it != m_IsoHandlers.end();
543         ++it )
544     {
545         if ((*it) == h) {
546             result = h->enable();
547             if(h->getType() == IsoHandler::eHT_Transmit) {
548                 result &= m_IsoTaskTransmit->requestShadowMapUpdate();
549             } else {
550                 result &= m_IsoTaskReceive->requestShadowMapUpdate();
551             }
552             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " enabled\n");
553             return result;
554         }
555         i++;
556     }
557     debugError("Handler not found\n");
558     return false;
559 }
560
561 void
562 IsoHandlerManager::signalActivityTransmit()
563 {
564     assert(m_IsoTaskTransmit);
565     m_IsoTaskTransmit->signalActivity();
566 }
567
568 void
569 IsoHandlerManager::signalActivityReceive()
570 {
571     assert(m_IsoTaskReceive);
572     m_IsoTaskReceive->signalActivity();
573 }
574
575 bool IsoHandlerManager::registerHandler(IsoHandler *handler)
576 {
577     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
578     assert(handler);
579     handler->setVerboseLevel(getDebugLevel());
580     m_IsoHandlers.push_back(handler);
581     requestShadowMapUpdate();
582     return true;
583 }
584
585 bool IsoHandlerManager::unregisterHandler(IsoHandler *handler)
586 {
587     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
588     assert(handler);
589
590     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
591       it != m_IsoHandlers.end();
592       ++it )
593     {
594         if ( *it == handler ) {
595             m_IsoHandlers.erase(it);
596             requestShadowMapUpdate();
597             return true;
598         }
599     }
600     debugFatal("Could not find handler (%p)\n", handler);
601     return false; //not found
602 }
603
604 /**
605  * Registers an StreamProcessor with the IsoHandlerManager.
606  *
607  * If nescessary, an IsoHandler is created to handle this stream.
608  * Once an StreamProcessor is registered to the handler, it will be included
609  * in the ISO streaming cycle (i.e. receive/transmit of it will occur).
610  *
611  * @param stream the stream to register
612  * @return true if registration succeeds
613  *
614  * \todo : currently there is a one-to-one mapping
615  *        between streams and handlers, this is not ok for
616  *        multichannel receive
617  */
618 bool IsoHandlerManager::registerStream(StreamProcessor *stream)
619 {
620     debugOutput( DEBUG_LEVEL_VERBOSE, "Registering stream %p\n",stream);
621     assert(stream);
622
623     IsoHandler* h = NULL;
624
625     // make sure the stream isn't already attached to a handler
626     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
627       it != m_IsoHandlers.end();
628       ++it )
629     {
630         if((*it)->isStreamRegistered(stream)) {
631             debugError( "stream already registered!\n");
632             return false;
633         }
634     }
635
636     // clean up all handlers that aren't used
637     pruneHandlers();
638
639     // allocate a handler for this stream
640     if (stream->getType()==StreamProcessor::ePT_Receive) {
641         // setup the optimal parameters for the raw1394 ISO buffering
642         unsigned int packets_per_period = stream->getPacketsPerPeriod();
643         unsigned int max_packet_size = stream->getMaxPacketSize();
644         unsigned int page_size = getpagesize() - 2; // for one reason or another this is necessary
645
646         // Ensure we don't request a packet size bigger than the
647         // kernel-enforced maximum which is currently 1 page.
648         if (max_packet_size > page_size) {
649             debugError("max packet size (%u) > page size (%u)\n", max_packet_size, page_size);
650             return false;
651         }
652
653         unsigned int irq_interval = packets_per_period / MINIMUM_INTERRUPTS_PER_PERIOD;
654         if(irq_interval <= 0) irq_interval=1;
655        
656         // the receive buffer size doesn't matter for the latency,
657         // but it has a minimal value in order for libraw to operate correctly (300)
658         int buffers=400;
659
660         // create the actual handler
661         h = new IsoHandler(*this, IsoHandler::eHT_Receive,
662                            buffers, max_packet_size, irq_interval);
663
664         debugOutput( DEBUG_LEVEL_VERBOSE, " creating IsoRecvHandler\n");
665
666         if(!h) {
667             debugFatal("Could not create IsoRecvHandler\n");
668             return false;
669         }
670
671     } else if (stream->getType()==StreamProcessor::ePT_Transmit) {
672         // setup the optimal parameters for the raw1394 ISO buffering
673 //        unsigned int packets_per_period = stream->getPacketsPerPeriod();
674         unsigned int max_packet_size = stream->getMaxPacketSize();
675 //         unsigned int page_size = getpagesize();
676
677         // Ensure we don't request a packet size bigger than the
678         // kernel-enforced maximum which is currently 1 page.
679 //         if (max_packet_size > page_size) {
680 //             debugError("max packet size (%u) > page size (%u)\n", max_packet_size, page_size);
681 //             return false;
682 //         }
683         if (max_packet_size > MAX_XMIT_PACKET_SIZE) {
684             debugError("max packet size (%u) > MAX_XMIT_PACKET_SIZE (%u)\n",
685                        max_packet_size, MAX_XMIT_PACKET_SIZE);
686             return false;
687         }
688
689         // the SP specifies how many packets to ISO-buffer
690         int buffers = stream->getNbPacketsIsoXmitBuffer();
691         if (buffers > MAX_XMIT_NB_BUFFERS) {
692             debugOutput(DEBUG_LEVEL_VERBOSE,
693                         "nb buffers (%u) > MAX_XMIT_NB_BUFFERS (%u)\n",
694                         buffers, MAX_XMIT_NB_BUFFERS);
695             buffers = MAX_XMIT_NB_BUFFERS;
696         }
697         unsigned int irq_interval = buffers / MINIMUM_INTERRUPTS_PER_PERIOD;
698         if(irq_interval <= 0) irq_interval=1;
699
700         debugOutput( DEBUG_LEVEL_VERBOSE, " creating IsoXmitHandler\n");
701
702         // create the actual handler
703         h = new IsoHandler(*this, IsoHandler::eHT_Transmit,
704                            buffers, max_packet_size, irq_interval);
705
706         if(!h) {
707             debugFatal("Could not create IsoXmitHandler\n");
708             return false;
709         }
710
711     } else {
712         debugFatal("Bad stream type\n");
713         return false;
714     }
715
716     h->setVerboseLevel(getDebugLevel());
717
718     // init the handler
719     if(!h->init()) {
720         debugFatal("Could not initialize receive handler\n");
721         return false;
722     }
723
724     // register the stream with the handler
725     if(!h->registerStream(stream)) {
726         debugFatal("Could not register receive stream with handler\n");
727         return false;
728     }
729
730     // register the handler with the manager
731     if(!registerHandler(h)) {
732         debugFatal("Could not register receive handler with manager\n");
733         return false;
734     }
735     debugOutput( DEBUG_LEVEL_VERBOSE, " registered stream (%p) with handler (%p)\n", stream, h);
736
737     m_StreamProcessors.push_back(stream);
738     debugOutput( DEBUG_LEVEL_VERBOSE, " %d streams, %d handlers registered\n",
739                                       m_StreamProcessors.size(), m_IsoHandlers.size());
740     return true;
741 }
742
743 bool IsoHandlerManager::unregisterStream(StreamProcessor *stream)
744 {
745     debugOutput( DEBUG_LEVEL_VERBOSE, "Unregistering stream %p\n",stream);
746     assert(stream);
747
748     // make sure the stream isn't attached to a handler anymore
749     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
750       it != m_IsoHandlers.end();
751       ++it )
752     {
753         if((*it)->isStreamRegistered(stream)) {
754             if(!(*it)->unregisterStream(stream)) {
755                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not unregister stream (%p) from handler (%p)...\n",stream,*it);
756                 return false;
757             }
758             debugOutput( DEBUG_LEVEL_VERBOSE, " unregistered stream (%p) from handler (%p)...\n",stream,*it);
759         }
760     }
761
762     // clean up all handlers that aren't used
763     pruneHandlers();
764
765     // remove the stream from the registered streams list
766     for ( StreamProcessorVectorIterator it = m_StreamProcessors.begin();
767       it != m_StreamProcessors.end();
768       ++it )
769     {
770         if ( *it == stream ) {
771             m_StreamProcessors.erase(it);
772             debugOutput( DEBUG_LEVEL_VERBOSE, " deleted stream (%p) from list...\n", *it);
773             return true;
774         }
775     }
776     return false; //not found
777 }
778
779 /**
780  * @brief unregister a handler from the manager
781  * @note called without the lock held.
782  */
783 void IsoHandlerManager::pruneHandlers() {
784     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
785     IsoHandlerVector toUnregister;
786
787     // find all handlers that are not in use
788     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
789           it != m_IsoHandlers.end();
790           ++it )
791     {
792         if(!((*it)->inUse())) {
793             debugOutput( DEBUG_LEVEL_VERBOSE, " handler (%p) not in use\n",*it);
794             toUnregister.push_back(*it);
795         }
796     }
797     // delete them
798     for ( IsoHandlerVectorIterator it = toUnregister.begin();
799           it != toUnregister.end();
800           ++it )
801     {
802         unregisterHandler(*it);
803
804         debugOutput( DEBUG_LEVEL_VERBOSE, " deleting handler (%p)\n",*it);
805
806         // Now the handler's been unregistered it won't be reused
807         // again.  Therefore it really needs to be formally deleted
808         // to free up the raw1394 handle.  Otherwise things fall
809         // apart after several xrun recoveries as the system runs
810         // out of resources to support all the disused but still
811         // allocated raw1394 handles.  At least this is the current
812         // theory as to why we end up with "memory allocation"
813         // failures after several Xrun recoveries.
814         delete *it;
815     }
816 }
817
818 bool
819 IsoHandlerManager::stopHandlerForStream(Streaming::StreamProcessor *stream) {
820     // check state
821     if(m_State != E_Running) {
822         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
823         return false;
824     }
825     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
826       it != m_IsoHandlers.end();
827       ++it )
828     {
829         if((*it)->isStreamRegistered(stream)) {
830             debugOutput( DEBUG_LEVEL_VERBOSE, " stopping handler %p for stream %p\n", *it, stream);
831             if(!(*it)->disable()) {
832                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not disable handler (%p)\n",*it);
833                 return false;
834             }
835             bool result;
836             if((*it)->getType() == IsoHandler::eHT_Transmit) {
837                 result = m_IsoTaskTransmit->requestShadowMapUpdate();
838             } else {
839                 result = m_IsoTaskReceive->requestShadowMapUpdate();
840             }
841             if(!result) {
842                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not update shadow map for handler (%p)\n",*it);
843                 return false;
844             }
845             return true;
846         }
847     }
848     debugError("Stream %p has no attached handler\n", stream);
849     return false;
850 }
851
852 int
853 IsoHandlerManager::getPacketLatencyForStream(Streaming::StreamProcessor *stream) {
854     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
855       it != m_IsoHandlers.end();
856       ++it )
857     {
858         if((*it)->isStreamRegistered(stream)) {
859             return (*it)->getPacketLatency();
860         }
861     }
862     debugError("Stream %p has no attached handler\n", stream);
863     return 0;
864 }
865
866 void
867 IsoHandlerManager::flushHandlerForStream(Streaming::StreamProcessor *stream) {
868     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
869       it != m_IsoHandlers.end();
870       ++it )
871     {
872         if((*it)->isStreamRegistered(stream)) {
873             return (*it)->flush();
874         }
875     }
876     debugError("Stream %p has no attached handler\n", stream);
877     return;
878 }
879
880 bool
881 IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream) {
882     return startHandlerForStream(stream, -1);
883 }
884
885 bool
886 IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream, int cycle) {
887     // check state
888     if(m_State != E_Running) {
889         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
890         return false;
891     }
892     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
893       it != m_IsoHandlers.end();
894       ++it )
895     {
896         if((*it)->isStreamRegistered(stream)) {
897             debugOutput( DEBUG_LEVEL_VERBOSE, " starting handler %p for stream %p\n", *it, stream);
898             if(!(*it)->enable(cycle)) {
899                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not enable handler (%p)\n",*it);
900                 return false;
901             }
902             bool result;
903             if((*it)->getType() == IsoHandler::eHT_Transmit) {
904                 result = m_IsoTaskTransmit->requestShadowMapUpdate();
905             } else {
906                 result = m_IsoTaskReceive->requestShadowMapUpdate();
907             }
908             if(!result) {
909                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not update shadow map for handler (%p)\n",*it);
910                 return false;
911             }
912             return true;
913         }
914     }
915     debugError("Stream %p has no attached handler\n", stream);
916     return false;
917 }
918
919 bool IsoHandlerManager::stopHandlers() {
920     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
921
922     // check state
923     if(m_State != E_Running) {
924         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
925         return false;
926     }
927
928     bool retval=true;
929
930     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
931         it != m_IsoHandlers.end();
932         ++it )
933     {
934         debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping handler (%p)\n",*it);
935         if(!(*it)->disable()){
936             debugOutput( DEBUG_LEVEL_VERBOSE, " could not stop handler (%p)\n",*it);
937             retval=false;
938         }
939         bool result;
940         if((*it)->getType() == IsoHandler::eHT_Transmit) {
941             result = m_IsoTaskTransmit->requestShadowMapUpdate();
942         } else {
943             result = m_IsoTaskReceive->requestShadowMapUpdate();
944         }
945         if(!result) {
946             debugOutput( DEBUG_LEVEL_VERBOSE, " could not update shadow map for handler (%p)\n",*it);
947             return false;
948         }
949     }
950
951     if (retval) {
952         m_State=E_Prepared;
953     } else {
954         m_State=E_Error;
955     }
956     return retval;
957 }
958
959 bool IsoHandlerManager::reset() {
960     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
961     // check state
962     if(m_State == E_Error) {
963         debugFatal("Resetting from error condition not yet supported...\n");
964         return false;
965     }
966     // if not in an error condition, reset means stop the handlers
967     return stopHandlers();
968 }
969
970 void IsoHandlerManager::setVerboseLevel(int i) {
971     setDebugLevel(i);
972     // propagate the debug level
973     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
974           it != m_IsoHandlers.end();
975           ++it )
976     {
977         (*it)->setVerboseLevel(i);
978     }
979     if(m_IsoThreadTransmit) m_IsoThreadTransmit->setVerboseLevel(i);
980     if(m_IsoTaskTransmit)   m_IsoTaskTransmit->setVerboseLevel(i);
981     if(m_IsoThreadReceive)  m_IsoThreadReceive->setVerboseLevel(i);
982     if(m_IsoTaskReceive)    m_IsoTaskReceive->setVerboseLevel(i);
983 }
984
985 void IsoHandlerManager::dumpInfo() {
986     #ifdef DEBUG
987     unsigned int i=0;
988     debugOutputShort( DEBUG_LEVEL_NORMAL, "Dumping IsoHandlerManager Stream handler information...\n");
989     debugOutputShort( DEBUG_LEVEL_NORMAL, " State: %d\n",(int)m_State);
990
991     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
992           it != m_IsoHandlers.end();
993           ++it )
994     {
995         debugOutputShort( DEBUG_LEVEL_NORMAL, " IsoHandler %d (%p)\n",i++,*it);
996         (*it)->dumpInfo();
997     }
998     #endif
999 }
1000
1001 const char *
1002 IsoHandlerManager::eHSToString(enum eHandlerStates s) {
1003     switch (s) {
1004         default: return "Invalid";
1005         case E_Created: return "Created";
1006         case E_Prepared: return "Prepared";
1007         case E_Running: return "Running";
1008         case E_Error: return "Error";
1009     }
1010 }
Note: See TracBrowser for help on using the browser.