40 | | IsoHandlerManager::IsoHandlerManager() : |
---|
41 | | m_State(E_Created), |
---|
42 | | m_poll_timeout(100), m_poll_fds(0), m_poll_nfds(0), |
---|
43 | | m_realtime(false), m_priority(0), m_xmit_nb_frames( 20 ) |
---|
| 41 | using namespace Streaming; |
---|
| 42 | |
---|
| 43 | IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service) |
---|
| 44 | : m_State(E_Created) |
---|
| 45 | , m_service( service ) |
---|
| 46 | , m_poll_timeout(100), m_poll_nfds_shadow(0) |
---|
| 47 | , m_realtime(false), m_priority(0), m_xmit_nb_frames( 20 ) |
---|
46 | | IsoHandlerManager::IsoHandlerManager(bool run_rt, unsigned int rt_prio) : |
---|
47 | | m_State(E_Created), |
---|
48 | | m_poll_timeout(100), m_poll_fds(0), m_poll_nfds(0), |
---|
49 | | m_realtime(run_rt), m_priority(rt_prio), m_xmit_nb_frames( 20 ) |
---|
| 50 | IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service, bool run_rt, unsigned int rt_prio) |
---|
| 51 | : m_State(E_Created) |
---|
| 52 | , m_service( service ) |
---|
| 53 | , m_poll_timeout(100), m_poll_nfds_shadow(0) |
---|
| 54 | , m_realtime(run_rt), m_priority(rt_prio), m_xmit_nb_frames( 20 ) |
---|
| 144 | } |
---|
| 145 | |
---|
| 146 | /** |
---|
| 147 | * Update the shadow variables. Should only be called from |
---|
| 148 | * the iso handler iteration thread |
---|
| 149 | */ |
---|
| 150 | void |
---|
| 151 | IsoHandlerManager::updateShadowVars() |
---|
| 152 | { |
---|
| 153 | debugOutput( DEBUG_LEVEL_VERBOSE, "updating shadow vars...\n"); |
---|
| 154 | unsigned int i; |
---|
| 155 | m_poll_nfds_shadow = m_IsoHandlers.size(); |
---|
| 156 | if(m_poll_nfds_shadow > FFADO_MAX_ISO_HANDLERS_PER_PORT) { |
---|
| 157 | debugWarning("Too much ISO Handlers in manager...\n"); |
---|
| 158 | m_poll_nfds_shadow = FFADO_MAX_ISO_HANDLERS_PER_PORT; |
---|
| 159 | } |
---|
| 160 | for (i = 0; i < m_poll_nfds_shadow; i++) { |
---|
| 161 | IsoHandler *h = m_IsoHandlers.at(i); |
---|
| 162 | assert(h); |
---|
| 163 | m_IsoHandler_map_shadow[i] = h; |
---|
| 164 | |
---|
| 165 | m_poll_fds_shadow[i].fd = h->getFileDescriptor(); |
---|
| 166 | m_poll_fds_shadow[i].revents = 0; |
---|
| 167 | if (h->isEnabled()) { |
---|
| 168 | m_poll_fds_shadow[i].events = POLLIN; |
---|
| 169 | } else { |
---|
| 170 | m_poll_fds_shadow[i].events = 0; |
---|
| 171 | } |
---|
| 172 | } |
---|
| 173 | debugOutput( DEBUG_LEVEL_VERBOSE, " updated shadow vars...\n"); |
---|
123 | | int i=0; |
---|
124 | | debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "poll %d fd's, timeout = %dms...\n", m_poll_nfds, m_poll_timeout); |
---|
125 | | |
---|
126 | | err = poll (m_poll_fds, m_poll_nfds, m_poll_timeout); |
---|
| 185 | int i; |
---|
| 186 | |
---|
| 187 | // update the shadow variables if requested |
---|
| 188 | if(m_request_fdmap_update) { |
---|
| 189 | updateShadowVars(); |
---|
| 190 | ZERO_ATOMIC((SInt32*)&m_request_fdmap_update); |
---|
| 191 | } |
---|
| 192 | |
---|
| 193 | // bypass if no handlers are registered |
---|
| 194 | if (m_poll_nfds_shadow == 0) { |
---|
| 195 | usleep(m_poll_timeout * 1000); |
---|
| 196 | return true; |
---|
| 197 | } |
---|
| 198 | |
---|
| 199 | // Use a shadow map of the fd's such that the poll call is not in a critical section |
---|
| 200 | |
---|
| 201 | err = poll (m_poll_fds_shadow, m_poll_nfds_shadow, m_poll_timeout); |
---|
140 | | // debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "(%d) handler %p: iterate? %d, revents: %08X\n", |
---|
141 | | // i, s, (m_poll_fds[i].revents & (POLLIN) == 1), m_poll_fds[i].revents); |
---|
| 215 | // debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "post poll: (%d) handler %p: enabled? %d, events: %08X, revents: %08X\n", |
---|
| 216 | // i, s, s->isEnabled(), m_poll_fds_shadow[i].events, m_poll_fds_shadow[i].revents); |
---|
| 271 | int i; |
---|
| 272 | |
---|
| 273 | if (m_isoManagerThread == NULL) { |
---|
| 274 | debugOutput( DEBUG_LEVEL_VERBOSE, "No thread running, so no shadow variables needed.\n"); |
---|
| 275 | return; |
---|
| 276 | } |
---|
| 277 | |
---|
| 278 | // the m_request_fdmap_update variable is zeroed by the |
---|
| 279 | // handler thread when it has accepted the new FD map |
---|
| 280 | // and copied it over to it's shadow variables. |
---|
| 281 | while(m_request_fdmap_update && m_isoManagerThread) { |
---|
| 282 | usleep(1000); |
---|
| 283 | } |
---|
| 284 | |
---|
| 285 | debugOutput(DEBUG_LEVEL_VERBOSE, " requesting update of shadow variables...\n"); |
---|
| 286 | // request that the handler thread updates it's FD shadow |
---|
| 287 | INC_ATOMIC((SInt32*)&m_request_fdmap_update); |
---|
| 288 | |
---|
| 289 | debugOutput(DEBUG_LEVEL_VERBOSE, " waiting for update of shadow variables to complete...\n"); |
---|
| 290 | // the m_request_fdmap_update variable is zeroed by the |
---|
| 291 | // handler thread when it has accepted the new FD map |
---|
| 292 | // and copied it over to it's shadow variables. |
---|
| 293 | while(m_request_fdmap_update && m_isoManagerThread) { |
---|
| 294 | usleep(1000); |
---|
| 295 | } |
---|
| 296 | debugOutput(DEBUG_LEVEL_VERBOSE, " shadow variables updated...\n"); |
---|
| 297 | } |
---|
| 298 | |
---|
| 299 | bool |
---|
| 300 | IsoHandlerManager::disable(IsoHandler *h) { |
---|
| 301 | bool result; |
---|
204 | | |
---|
205 | | m_poll_nfds=0; |
---|
206 | | if(m_poll_fds) free(m_poll_fds); |
---|
207 | | |
---|
208 | | // count the number of handlers |
---|
209 | | m_poll_nfds=m_IsoHandlers.size(); |
---|
210 | | |
---|
211 | | // allocate the fd array |
---|
212 | | m_poll_fds = (struct pollfd *) calloc (m_poll_nfds, sizeof (struct pollfd)); |
---|
213 | | if(!m_poll_fds) { |
---|
214 | | debugFatal("Could not allocate memory for poll FD array\n"); |
---|
215 | | return false; |
---|
216 | | } |
---|
217 | | |
---|
218 | | // fill the fd map |
---|
219 | | for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); |
---|
220 | | it != m_IsoHandlers.end(); |
---|
221 | | ++it ) |
---|
222 | | { |
---|
223 | | m_poll_fds[i].fd=(*it)->getFileDescriptor(); |
---|
224 | | m_poll_fds[i].events = POLLIN; |
---|
225 | | i++; |
---|
226 | | } |
---|
227 | | |
---|
228 | | return true; |
---|
229 | | } |
---|
230 | | |
---|
231 | | void IsoHandlerManager::disablePolling(StreamProcessor *stream) { |
---|
232 | | int i=0; |
---|
233 | | |
---|
234 | | debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Disable polling on stream %p\n",stream); |
---|
235 | | |
---|
| 303 | debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Disable on IsoHandler %p\n", h); |
---|
424 | | if(irq_interval <= 0) irq_interval=1; |
---|
425 | | #else |
---|
426 | | // hardware interrupts occur when one DMA block is full, and the size of one DMA |
---|
427 | | // block = PAGE_SIZE. Setting the max_packet_size enables control over the IRQ |
---|
428 | | // frequency, as the controller uses max_packet_size, and not the effective size |
---|
429 | | // when writing to the DMA buffer. |
---|
430 | | |
---|
431 | | // configure it such that we have an irq for every PACKETS_PER_INTERRUPT packets |
---|
432 | | unsigned int irq_interval = PACKETS_PER_INTERRUPT; |
---|
433 | | |
---|
434 | | // unless the period size doesn't allow this |
---|
435 | | if ((packets_per_period/MINIMUM_INTERRUPTS_PER_PERIOD) < irq_interval) { |
---|
436 | | irq_interval = 1; |
---|
437 | | } |
---|
438 | | |
---|
439 | | // FIXME: test |
---|
440 | | irq_interval = 1; |
---|
441 | | #warning Using fixed irq_interval |
---|
442 | | |
---|
443 | | unsigned int max_packet_size = getpagesize() / irq_interval; |
---|
444 | | |
---|
445 | | if (max_packet_size < stream->getMaxPacketSize()) { |
---|
446 | | max_packet_size = stream->getMaxPacketSize(); |
---|
447 | | } |
---|
448 | | |
---|
449 | | // Ensure we don't request a packet size bigger than the |
---|
450 | | // kernel-enforced maximum which is currently 1 page. |
---|
451 | | if (max_packet_size > (unsigned int)getpagesize()) |
---|
452 | | max_packet_size = getpagesize(); |
---|
453 | | #endif |
---|
| 494 | if(irq_interval <= 0) irq_interval = 1; |
---|
| 495 | |
---|
580 | | |
---|
581 | | } |
---|
582 | | |
---|
583 | | |
---|
584 | | bool IsoHandlerManager::prepare() |
---|
585 | | { |
---|
| 623 | } |
---|
| 624 | |
---|
| 625 | bool |
---|
| 626 | IsoHandlerManager::stopHandlerForStream(Streaming::StreamProcessor *stream) { |
---|
| 627 | // check state |
---|
| 628 | if(m_State != E_Running) { |
---|
| 629 | debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State)); |
---|
| 630 | return false; |
---|
| 631 | } |
---|
| 632 | for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); |
---|
| 633 | it != m_IsoHandlers.end(); |
---|
| 634 | ++it ) |
---|
| 635 | { |
---|
| 636 | if((*it)->isStreamRegistered(stream)) { |
---|
| 637 | bool result; |
---|
| 638 | debugOutput( DEBUG_LEVEL_VERBOSE, " stopping handler %p for stream %p\n", *it, stream); |
---|
| 639 | result = (*it)->disable(); |
---|
| 640 | //requestShadowUpdate(); |
---|
| 641 | if(!result) { |
---|
| 642 | debugOutput( DEBUG_LEVEL_VERBOSE, " could not disable handler (%p)\n",*it); |
---|
| 643 | return false; |
---|
| 644 | } |
---|
| 645 | return true; |
---|
| 646 | } |
---|
| 647 | } |
---|
| 648 | debugError("Stream %p has no attached handler\n", stream); |
---|
| 649 | return false; |
---|
| 650 | } |
---|
| 651 | |
---|
| 652 | int |
---|
| 653 | IsoHandlerManager::getPacketLatencyForStream(Streaming::StreamProcessor *stream) { |
---|
| 654 | for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); |
---|
| 655 | it != m_IsoHandlers.end(); |
---|
| 656 | ++it ) |
---|
| 657 | { |
---|
| 658 | if((*it)->isStreamRegistered(stream)) { |
---|
| 659 | return (*it)->getPacketLatency(); |
---|
| 660 | } |
---|
| 661 | } |
---|
| 662 | debugError("Stream %p has no attached handler\n", stream); |
---|
| 663 | return 0; |
---|
| 664 | } |
---|
| 665 | |
---|
| 666 | void |
---|
| 667 | IsoHandlerManager::flushHandlerForStream(Streaming::StreamProcessor *stream) { |
---|
| 668 | for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); |
---|
| 669 | it != m_IsoHandlers.end(); |
---|
| 670 | ++it ) |
---|
| 671 | { |
---|
| 672 | if((*it)->isStreamRegistered(stream)) { |
---|
| 673 | return (*it)->flush(); |
---|
| 674 | } |
---|
| 675 | } |
---|
| 676 | debugError("Stream %p has no attached handler\n", stream); |
---|
| 677 | return; |
---|
| 678 | } |
---|
| 679 | |
---|
| 680 | bool |
---|
| 681 | IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream) { |
---|
| 682 | return startHandlerForStream(stream, -1); |
---|
| 683 | } |
---|
| 684 | |
---|
| 685 | bool |
---|
| 686 | IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream, int cycle) { |
---|
| 687 | // check state |
---|
| 688 | if(m_State != E_Running) { |
---|
| 689 | debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State)); |
---|
| 690 | return false; |
---|
| 691 | } |
---|
| 692 | for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); |
---|
| 693 | it != m_IsoHandlers.end(); |
---|
| 694 | ++it ) |
---|
| 695 | { |
---|
| 696 | if((*it)->isStreamRegistered(stream)) { |
---|
| 697 | bool result; |
---|
| 698 | debugOutput( DEBUG_LEVEL_VERBOSE, " starting handler %p for stream %p\n", *it, stream); |
---|
| 699 | result = (*it)->enable(cycle); |
---|
| 700 | requestShadowUpdate(); |
---|
| 701 | if(!result) { |
---|
| 702 | debugOutput( DEBUG_LEVEL_VERBOSE, " could not enable handler (%p)\n",*it); |
---|
| 703 | return false; |
---|
| 704 | } |
---|
| 705 | return true; |
---|
| 706 | } |
---|
| 707 | } |
---|
| 708 | debugError("Stream %p has no attached handler\n", stream); |
---|
| 709 | return false; |
---|
| 710 | } |
---|
| 711 | |
---|
| 712 | bool IsoHandlerManager::stopHandlers() { |
---|
| 713 | debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
| 714 | |
---|
| 715 | // check state |
---|
| 716 | if(m_State != E_Running) { |
---|
| 717 | debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State)); |
---|
| 718 | return false; |
---|
| 719 | } |
---|
| 720 | |
---|
587 | | |
---|
588 | | debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
589 | | |
---|
590 | | // check state |
---|
591 | | if(m_State != E_Created) { |
---|
592 | | debugError("Incorrect state, expected E_Created, got %d\n",(int)m_State); |
---|
593 | | return false; |
---|
594 | | } |
---|
595 | | |
---|
596 | | for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); |
---|
597 | | it != m_IsoHandlers.end(); |
---|
598 | | ++it ) |
---|
599 | | { |
---|
600 | | if(!(*it)->prepare()) { |
---|
601 | | debugFatal("Could not prepare handlers\n"); |
---|
| 722 | debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping ISO iterator thread...\n"); |
---|
| 723 | |
---|
| 724 | m_isoManagerThread->Stop(); |
---|
| 725 | m_isoManagerThread = NULL; |
---|
| 726 | ZERO_ATOMIC((SInt32*)&m_request_fdmap_update); |
---|
| 727 | |
---|
| 728 | for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); |
---|
| 729 | it != m_IsoHandlers.end(); |
---|
| 730 | ++it ) |
---|
| 731 | { |
---|
| 732 | debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping handler (%p)\n",*it); |
---|
| 733 | if(!(*it)->disable()){ |
---|
| 734 | debugOutput( DEBUG_LEVEL_VERBOSE, " could not stop handler (%p)\n",*it); |
---|
611 | | |
---|
612 | | return retval; |
---|
613 | | } |
---|
614 | | |
---|
615 | | bool IsoHandlerManager::startHandlers() { |
---|
616 | | return startHandlers(-1); |
---|
617 | | } |
---|
618 | | |
---|
619 | | bool IsoHandlerManager::startHandlers(int cycle) { |
---|
620 | | bool retval=true; |
---|
621 | | |
---|
622 | | debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
623 | | |
---|
624 | | // check state |
---|
625 | | if(m_State != E_Prepared) { |
---|
626 | | debugError("Incorrect state, expected E_Prepared, got %d\n",(int)m_State); |
---|
627 | | return false; |
---|
628 | | } |
---|
629 | | |
---|
630 | | for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); |
---|
631 | | it != m_IsoHandlers.end(); |
---|
632 | | ++it ) |
---|
633 | | { |
---|
634 | | debugOutput( DEBUG_LEVEL_VERBOSE, " starting handler (%p)\n",*it); |
---|
635 | | if(!(*it)->start(cycle)) { |
---|
636 | | debugOutput( DEBUG_LEVEL_VERBOSE, " could not start handler (%p)\n",*it); |
---|
637 | | retval=false; |
---|
638 | | } |
---|
639 | | } |
---|
640 | | |
---|
641 | | debugOutput( DEBUG_LEVEL_VERBOSE, "Starting ISO iterator thread...\n"); |
---|
642 | | |
---|
643 | | // note: libraw1394 doesn't like it if you poll() and/or iterate() before |
---|
644 | | // starting the streams. |
---|
645 | | // start the iso runner thread |
---|
646 | | m_isoManagerThread->Start(); |
---|
647 | | |
---|
648 | | if (retval) { |
---|
649 | | m_State=E_Running; |
---|
650 | | } else { |
---|
651 | | m_State=E_Error; |
---|
652 | | } |
---|
653 | | |
---|
654 | | return retval; |
---|
655 | | } |
---|
656 | | |
---|
657 | | bool IsoHandlerManager::stopHandlers() { |
---|
658 | | debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
659 | | |
---|
660 | | // check state |
---|
661 | | if(m_State != E_Running) { |
---|
662 | | debugError("Incorrect state, expected E_Running, got %d\n",(int)m_State); |
---|
663 | | return false; |
---|
664 | | } |
---|
665 | | |
---|
666 | | bool retval=true; |
---|
667 | | |
---|
668 | | debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping ISO iterator thread...\n"); |
---|
669 | | m_isoManagerThread->Stop(); |
---|
670 | | |
---|
671 | | for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); |
---|
672 | | it != m_IsoHandlers.end(); |
---|
673 | | ++it ) |
---|
674 | | { |
---|
675 | | debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping handler (%p)\n",*it); |
---|
676 | | if(!(*it)->stop()){ |
---|
677 | | debugOutput( DEBUG_LEVEL_VERBOSE, " could not stop handler (%p)\n",*it); |
---|
678 | | retval=false; |
---|
679 | | } |
---|
680 | | } |
---|
681 | | |
---|
682 | | if (retval) { |
---|
683 | | m_State=E_Prepared; |
---|
684 | | } else { |
---|
685 | | m_State=E_Error; |
---|
686 | | } |
---|
687 | | |
---|