BasicUsageEnvironment/BasicTaskScheduler.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // Copyright (c) 1996-2008 Live Networks, Inc.  All rights reserved.
00017 // Basic Usage Environment: for a simple, non-scripted, console application
00018 // Implementation
00019 
00020 
00021 #ifndef IMN_PIM
00022 #include "BasicUsageEnvironment.hh"
00023 #include "HandlerSet.hh"
00024 #include <stdio.h>
00025 #if defined(_QNX4)
00026 #include <sys/select.h>
00027 #include <unix.h>
00028 #endif
00029 
00031 
00032 BasicTaskScheduler* BasicTaskScheduler::createNew() {
00033         return new BasicTaskScheduler();
00034 }
00035 
00036 BasicTaskScheduler::BasicTaskScheduler()
00037   : fMaxNumSockets(0) {
00038   FD_ZERO(&fReadSet);
00039 }
00040 
00041 BasicTaskScheduler::~BasicTaskScheduler() {
00042 }
00043 
00044 #ifndef MILLION
00045 #define MILLION 1000000
00046 #endif
00047 
00048 void BasicTaskScheduler::SingleStep(unsigned maxDelayTime) {
00049   fd_set readSet = fReadSet; // make a copy for this select() call
00050 
00051   DelayInterval const& timeToDelay = fDelayQueue.timeToNextAlarm();
00052   struct timeval tv_timeToDelay;
00053   tv_timeToDelay.tv_sec = timeToDelay.seconds();
00054   tv_timeToDelay.tv_usec = timeToDelay.useconds();
00055   // Very large "tv_sec" values cause select() to fail.
00056   // Don't make it any larger than 1 million seconds (11.5 days)
00057   const long MAX_TV_SEC = MILLION;
00058   if (tv_timeToDelay.tv_sec > MAX_TV_SEC) {
00059     tv_timeToDelay.tv_sec = MAX_TV_SEC;
00060   }
00061   // Also check our "maxDelayTime" parameter (if it's > 0):
00062   if (maxDelayTime > 0 &&
00063       (tv_timeToDelay.tv_sec > (long)maxDelayTime/MILLION ||
00064        (tv_timeToDelay.tv_sec == (long)maxDelayTime/MILLION &&
00065         tv_timeToDelay.tv_usec > (long)maxDelayTime%MILLION))) {
00066     tv_timeToDelay.tv_sec = maxDelayTime/MILLION;
00067     tv_timeToDelay.tv_usec = maxDelayTime%MILLION;
00068   }
00069 
00070   int selectResult = select(fMaxNumSockets, &readSet, NULL, NULL,
00071                             &tv_timeToDelay);
00072   if (selectResult < 0) {
00073 #if defined(__WIN32__) || defined(_WIN32)
00074     int err = WSAGetLastError();
00075     // For some unknown reason, select() in Windoze sometimes fails with WSAEINVAL if
00076     // it was called with no entries set in "readSet".  If this happens, ignore it:
00077     if (err == WSAEINVAL && readSet.fd_count == 0) {
00078       err = 0;
00079       // To stop this from happening again, create a dummy readable socket:
00080       int dummySocketNum = socket(AF_INET, SOCK_DGRAM, 0);
00081       FD_SET((unsigned)dummySocketNum, &fReadSet);
00082     }
00083     if (err != 0) {
00084 #else
00085     if (errno != EINTR && errno != EAGAIN) {
00086 #endif
00087         // Unexpected error - treat this as fatal:
00088 #if !defined(_WIN32_WCE)
00089         perror("BasicTaskScheduler::SingleStep(): select() fails");
00090 #endif
00091         exit(0);
00092       }
00093   }
00094 
00095   // Handle any delayed event that may have come due:
00096   fDelayQueue.handleAlarm();
00097 
00098   // Call the handler function for one readable socket:
00099   HandlerIterator iter(*fReadHandlers);
00100   HandlerDescriptor* handler;
00101   // To ensure forward progress through the handlers, begin past the last
00102   // socket number that we handled:
00103   if (fLastHandledSocketNum >= 0) {
00104     while ((handler = iter.next()) != NULL) {
00105       if (handler->socketNum == fLastHandledSocketNum) break;
00106     }
00107     if (handler == NULL) {
00108       fLastHandledSocketNum = -1;
00109       iter.reset(); // start from the beginning instead
00110     }
00111   }
00112   while ((handler = iter.next()) != NULL) {
00113     if (FD_ISSET(handler->socketNum, &readSet) &&
00114         FD_ISSET(handler->socketNum, &fReadSet) /* sanity check */ &&
00115         handler->handlerProc != NULL) {
00116       fLastHandledSocketNum = handler->socketNum;
00117           // Note: we set "fLastHandledSocketNum" before calling the handler,
00118           // in case the handler calls "doEventLoop()" reentrantly.
00119       (*handler->handlerProc)(handler->clientData, SOCKET_READABLE);
00120       break;
00121     }
00122   }
00123   if (handler == NULL && fLastHandledSocketNum >= 0) {
00124     // We didn't call a handler, but we didn't get to check all of them,
00125     // so try again from the beginning:
00126     iter.reset();
00127     while ((handler = iter.next()) != NULL) {
00128       if (FD_ISSET(handler->socketNum, &readSet) &&
00129           FD_ISSET(handler->socketNum, &fReadSet) /* sanity check */ &&
00130           handler->handlerProc != NULL) {
00131         fLastHandledSocketNum = handler->socketNum;
00132             // Note: we set "fLastHandledSocketNum" before calling the handler,
00133             // in case the handler calls "doEventLoop()" reentrantly.
00134         (*handler->handlerProc)(handler->clientData, SOCKET_READABLE);
00135         break;
00136       }
00137     }
00138     if (handler == NULL) fLastHandledSocketNum = -1;//because we didn't call a handler
00139   }
00140 }
00141 
00142 void BasicTaskScheduler::turnOnBackgroundReadHandling(int socketNum,
00143                                 BackgroundHandlerProc* handlerProc,
00144                                 void* clientData) {
00145   if (socketNum < 0) return;
00146   FD_SET((unsigned)socketNum, &fReadSet);
00147   fReadHandlers->assignHandler(socketNum, handlerProc, clientData);
00148 
00149   if (socketNum+1 > fMaxNumSockets) {
00150     fMaxNumSockets = socketNum+1;
00151   }
00152 }
00153 
00154 void BasicTaskScheduler::turnOffBackgroundReadHandling(int socketNum) {
00155   if (socketNum < 0) return;
00156   FD_CLR((unsigned)socketNum, &fReadSet);
00157   fReadHandlers->removeHandler(socketNum);
00158 
00159   if (socketNum+1 == fMaxNumSockets) {
00160     --fMaxNumSockets;
00161   }
00162 }
00163 #endif
00164 

Generated on Tue Oct 7 15:38:08 2008 for live by  doxygen 1.5.2