root/branches/libffado-2.0/src/libieee1394/IsoHandlerManager.cpp

Revision 1262, 34.8 kB (checked in by ppalmers, 16 years ago)

fix small bug in calculation of semaphore timeout: ensuring that nsec < 1 sec should be done on the resulting timespec. Made SPM activity timeout dependent on the period size, since we can expect that there is activity at least once every period.

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