Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

MultiThreadedConnector.cpp

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------------
00002 
00003    Copyright (c) 2000 Tyrell Corporation. All rights reserved.
00004 
00005    Tyrell DarkIce
00006 
00007    File     : MultiThreadedConnector.cpp
00008    Version  : $Revision: 1.6 $
00009    Author   : $Author: jbebel $
00010    Location : $Source: /cvsroot/darkice/darkice/src/MultiThreadedConnector.cpp,v $
00011    
00012    Copyright notice:
00013 
00014     This program is free software; you can redistribute it and/or
00015     modify it under the terms of the GNU General Public License  
00016     as published by the Free Software Foundation; either version 2
00017     of the License, or (at your option) any later version.
00018    
00019     This program is distributed in the hope that it will be useful,
00020     but WITHOUT ANY WARRANTY; without even the implied warranty of 
00021     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
00022     GNU General Public License for more details.
00023    
00024     You should have received a copy of the GNU General Public License
00025     along with this program; if not, write to the Free Software
00026     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00027 
00028 ------------------------------------------------------------------------------*/
00029 
00030 /* ============================================================ include files */
00031 
00032 #ifdef HAVE_CONFIG_H
00033 #include "config.h"
00034 #endif
00035 
00036 #ifdef HAVE_SYS_TYPES_H
00037 #include <sys/types.h>
00038 #else
00039 #error need sys/types.h
00040 #endif
00041 
00042 
00043 #include "Exception.h"
00044 #include "MultiThreadedConnector.h"
00045 
00046 
00047 /* ===================================================  local data structures */
00048 
00049 
00050 /* ================================================  local constants & macros */
00051 
00052 /*------------------------------------------------------------------------------
00053  *  File identity
00054  *----------------------------------------------------------------------------*/
00055 static const char fileid[] = "$Id: MultiThreadedConnector.cpp,v 1.6 2005/04/13 22:03:32 jbebel Exp $";
00056 
00057 
00058 /* ===============================================  local function prototypes */
00059 
00060 
00061 /* =============================================================  module code */
00062 
00063 /*------------------------------------------------------------------------------
00064  *  Initialize the object
00065  *----------------------------------------------------------------------------*/
00066 void
00067 MultiThreadedConnector :: init ( bool    reconnect )    throw ( Exception )
00068 {
00069     this->reconnect = reconnect;
00070 
00071     pthread_mutex_init( &mutexProduce, 0);
00072     pthread_cond_init( &condProduce, 0);
00073     threads = 0;
00074 }
00075 
00076 
00077 /*------------------------------------------------------------------------------
00078  *  De-initialize the object
00079  *----------------------------------------------------------------------------*/
00080 void
00081 MultiThreadedConnector :: strip ( void )                throw ( Exception )
00082 {
00083     if ( threads ) {
00084         delete[] threads;
00085         threads = 0;
00086     }
00087 
00088     pthread_cond_destroy( &condProduce);
00089     pthread_mutex_destroy( &mutexProduce);
00090 }
00091 
00092 
00093 /*------------------------------------------------------------------------------
00094  *  Constructor
00095  *----------------------------------------------------------------------------*/
00096 MultiThreadedConnector :: MultiThreadedConnector (
00097                                 const MultiThreadedConnector &   connector )
00098                                                             throw ( Exception )
00099             : Connector( connector)
00100 {
00101     reconnect       = connector.reconnect;
00102     mutexProduce    = connector.mutexProduce;
00103     condProduce     = connector.condProduce;
00104 
00105     if ( threads ) {
00106         delete[] threads;
00107     }
00108     threads = new ThreadData[numSinks];
00109     for ( unsigned int  i = 0; i < numSinks; ++i ) {
00110         threads[i] = connector.threads[i];
00111     }
00112 }
00113 
00114 
00115 /*------------------------------------------------------------------------------
00116  *  Assignment operator
00117  *----------------------------------------------------------------------------*/
00118 MultiThreadedConnector &
00119 MultiThreadedConnector :: operator= ( const MultiThreadedConnector & connector )
00120                                                             throw ( Exception )
00121 {
00122     if ( this != &connector ) {
00123         Connector::operator=( connector);
00124 
00125         reconnect       = connector.reconnect;
00126         mutexProduce    = connector.mutexProduce;
00127         condProduce     = connector.condProduce;
00128 
00129         if ( threads ) {
00130             delete[] threads;
00131         }
00132         threads = new ThreadData[numSinks];
00133         for ( unsigned int  i = 0; i < numSinks; ++i ) {
00134             threads[i] = connector.threads[i];
00135         }
00136     }
00137 
00138     return *this;
00139 }
00140 
00141 
00142 /*------------------------------------------------------------------------------
00143  *  Open the source and all the sinks if needed
00144  *  Create the sink threads
00145  *----------------------------------------------------------------------------*/
00146 bool
00147 MultiThreadedConnector :: open ( void )                     throw ( Exception )
00148 {
00149     unsigned int        i;
00150     size_t              st;
00151 
00152     if ( !Connector::open() ) {
00153         return false;
00154     }
00155 
00156     running = true;
00157 
00158     pthread_attr_init( &threadAttr);
00159     pthread_attr_getstacksize(&threadAttr, &st);
00160     if (st < 128 * 1024) {
00161         reportEvent( 5, "MultiThreadedConnector :: open, stack size ",
00162                         (long)st);
00163         st = 128 * 1024;
00164         pthread_attr_setstacksize(&threadAttr, st);
00165     }
00166     pthread_attr_setdetachstate( &threadAttr, PTHREAD_CREATE_JOINABLE);
00167 
00168     threads = new ThreadData[numSinks];
00169     for ( i = 0; i < numSinks; ++i ) {
00170         ThreadData    * threadData = threads + i;
00171 
00172         threadData->connector = this;
00173         threadData->ixSink    = i;
00174         threadData->accepting = true;
00175         threadData->isDone    = true;
00176         if ( pthread_create( &(threadData->thread),
00177                              &threadAttr,
00178                              ThreadData::threadFunction,
00179                              threadData ) ) {
00180             break;
00181         }
00182     }
00183 
00184     // if could not create all, delete the ones created
00185     if ( i < numSinks ) {
00186         unsigned int    j;
00187 
00188         // signal to stop for all running threads
00189         pthread_mutex_lock( &mutexProduce);
00190         running = false;
00191         pthread_cond_broadcast( &condProduce);
00192         pthread_mutex_unlock( &mutexProduce);
00193 
00194         for ( j = 0; j < i; ++j ) {
00195             pthread_join( threads[j].thread, 0);
00196         }
00197 
00198         delete[] threads;
00199         threads = 0;
00200 
00201         return false;
00202     }
00203 
00204     return true;
00205 }
00206 
00207 
00208 /*------------------------------------------------------------------------------
00209  *  Transfer some data from the source to the sink
00210  *----------------------------------------------------------------------------*/
00211 unsigned int
00212 MultiThreadedConnector :: transfer ( unsigned long       bytes,
00213                                      unsigned int        bufSize,
00214                                      unsigned int        sec,
00215                                      unsigned int        usec )
00216                                                             throw ( Exception )
00217 {   
00218     unsigned int        b;
00219 
00220     if ( numSinks == 0 ) {
00221         return 0;
00222     }
00223 
00224     if ( bufSize == 0 ) {
00225         return 0;
00226     }
00227 
00228     dataBuffer   = new unsigned char[bufSize];
00229     dataSize     = 0;
00230 
00231     reportEvent( 6, "MultiThreadedConnector :: tranfer, bytes", bytes);
00232 
00233     for ( b = 0; !bytes || b < bytes; ) {
00234         if ( source->canRead( sec, usec) ) {
00235             unsigned int        i;
00236 
00237             pthread_mutex_lock( &mutexProduce);
00238             dataSize = source->read( dataBuffer, bufSize);
00239             b       += dataSize;
00240 
00241             // check for EOF
00242             if ( dataSize == 0 ) {
00243                 reportEvent( 3, "MultiThreadedConnector :: transfer, EOF");
00244                 pthread_mutex_unlock( &mutexProduce);
00245                 break;
00246             }
00247 
00248             for ( i = 0; i < numSinks; ++i ) {
00249                 threads[i].isDone = false;
00250             }
00251 
00252             // tell sink threads that there is some data available
00253             pthread_cond_broadcast( &condProduce);
00254 
00255             // wait for all sink threads to get done with this data
00256             while ( true ) {
00257                 for ( i = 0; i < numSinks && threads[i].isDone; ++i );
00258                 if ( i == numSinks ) {
00259                     break;
00260                 }
00261                 pthread_cond_wait( &condProduce, &mutexProduce);
00262             }
00263             pthread_mutex_unlock( &mutexProduce);
00264         } else {
00265             reportEvent( 3, "MultiThreadedConnector :: transfer, can't read");
00266             break;
00267         }
00268     }
00269 
00270     delete[] dataBuffer;
00271     return b;
00272 }
00273 
00274 
00275 /*------------------------------------------------------------------------------
00276  *  The function for each thread.
00277  *  Read the presented data
00278  *----------------------------------------------------------------------------*/
00279 void
00280 MultiThreadedConnector :: sinkThread( int       ixSink )
00281 {
00282     ThreadData    * threadData = &threads[ixSink];
00283     Sink          * sink       = sinks[ixSink].get();
00284 
00285     while ( running ) {
00286         // wait for some data to become available
00287         pthread_mutex_lock( &mutexProduce);
00288         while ( running && threadData->isDone ) {
00289             pthread_cond_wait( &condProduce, &mutexProduce);
00290         }
00291         if ( !running ) {
00292             pthread_mutex_unlock( &mutexProduce);
00293             break;
00294         }
00295 
00296         if ( threadData->accepting ) {
00297             if ( sink->canWrite( 0, 0) ) {
00298                 try {
00299                     sink->write( dataBuffer, dataSize);
00300                 } catch ( Exception     & e ) {
00301                     // something wrong. don't accept more data, try to
00302                     // reopen the sink next time around
00303                     threadData->accepting = false;
00304                 }
00305             } else {
00306                 reportEvent( 4,
00307                             "MultiThreadedConnector :: sinkThread can't write ",
00308                              ixSink);
00309                 // don't care if we can't write
00310             }
00311         }
00312         threadData->isDone = true;
00313         pthread_cond_broadcast( &condProduce);
00314         pthread_mutex_unlock( &mutexProduce);
00315 
00316         if ( !threadData->accepting ) {
00317             if ( reconnect ) {
00318                 // if we're not accepting, try to reopen the sink
00319                 try {
00320                     sink->close();
00321                     sink->open();
00322                     threadData->accepting = sink->isOpen();
00323                 } catch ( Exception   & e ) {
00324                     // don't care, just try and try again
00325                 }
00326             } else {
00327                 // if !reconnect, just stop the connector
00328                 running = false;
00329             }
00330         }
00331     }
00332 }
00333 
00334 
00335 /*------------------------------------------------------------------------------
00336  *  Stop the treads
00337  *  Close the source and all the sinks if needed
00338  *----------------------------------------------------------------------------*/
00339 void
00340 MultiThreadedConnector :: close ( void )                    throw ( Exception )
00341 {
00342     unsigned int    i;
00343 
00344     // signal to stop for all threads
00345     pthread_mutex_lock( &mutexProduce);
00346     running = false;
00347     pthread_cond_broadcast( &condProduce);
00348     pthread_mutex_unlock( &mutexProduce);
00349 
00350     // wait for all the threads to finish
00351     for ( i = 0; i < numSinks; ++i ) {
00352         pthread_join( threads[i].thread, 0);
00353     }
00354     pthread_attr_destroy( &threadAttr);
00355 
00356     Connector::close();
00357 }
00358 
00359 
00360 /*------------------------------------------------------------------------------
00361  *  The thread function
00362  *----------------------------------------------------------------------------*/
00363 void *
00364 MultiThreadedConnector :: ThreadData :: threadFunction( void  * param )
00365 {
00366     struct sched_param  sched;
00367     int sched_type;
00368     ThreadData     * threadData = (ThreadData*) param;
00369     
00370     pthread_getschedparam( threadData->thread, &sched_type, &sched );
00371 
00372     reportEvent( 5, "MultiThreadedConnector :: ThreadData :: threadFunction, was (thread, priority, type): ",
00373         param,
00374     sched.sched_priority,
00375         sched_type == SCHED_FIFO ? "SCHED_FIFO" :
00376             sched_type == SCHED_RR ? "SCHED_RR" :
00377             sched_type == SCHED_OTHER ? "SCHED_OTHER" :
00378             "INVALID"
00379     );
00380 
00381     sched.sched_priority = 1;
00382     pthread_setschedparam( threadData->thread, SCHED_FIFO, &sched);
00383 
00384     pthread_getschedparam( threadData->thread, &sched_type, &sched );
00385     reportEvent( 5, "MultiThreadedConnector :: ThreadData :: threadFunction, now is (thread, priority, type): ",
00386         param,
00387     sched.sched_priority,
00388         sched_type == SCHED_FIFO ? "SCHED_FIFO" :
00389             sched_type == SCHED_RR ? "SCHED_RR" :
00390             sched_type == SCHED_OTHER ? "SCHED_OTHER" :
00391             "INVALID"
00392     );
00393 
00394     threadData->connector->sinkThread( threadData->ixSink);
00395 
00396     return 0;
00397 }
00398 
00399 
00400 /*------------------------------------------------------------------------------
00401  
00402   $Source: /cvsroot/darkice/darkice/src/MultiThreadedConnector.cpp,v $
00403 
00404   $Log: MultiThreadedConnector.cpp,v $
00405   Revision 1.6  2005/04/13 22:03:32  jbebel
00406   Set priority explicitly for encoding threads.  This needs more testing.
00407 
00408   Revision 1.5  2005/04/11 19:27:43  darkeye
00409   added option to turn off automatic reconnect feature
00410 
00411   Revision 1.4  2004/01/07 13:18:17  darkeye
00412   commited patch sent by John Hay, fixing FreeBSD problems
00413 
00414   Revision 1.3  2002/10/20 20:43:17  darkeye
00415   more graceful reconnect
00416 
00417   Revision 1.2  2002/10/19 13:35:21  darkeye
00418   when a connection is dropped, DarkIce tries to reconnect, indefinitely
00419   removed extreme event reporting for thread-related events
00420 
00421   Revision 1.1  2002/10/19 12:25:47  darkeye
00422   changed internals so that now each encoding/server connection is
00423   a separate thread
00424 
00425 
00426   
00427 ------------------------------------------------------------------------------*/
00428 

Generated on Thu Apr 14 13:59:12 2005 for DarkIce by  doxygen 1.4.1