00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 #include "CeylanSystem.h"
00028 
00029 
00030 #include "CeylanLogPlug.h"                
00031 #include "CeylanOperators.h"              
00032 #include "CeylanMathsBasic.h"             
00033 #include "CeylanEnvironmentVariables.h"   
00034 #include "CeylanFile.h"                   
00035 
00036 
00037 #ifdef CEYLAN_USES_CONFIG_H
00038 #include "CeylanConfig.h"                 
00039 #endif // CEYLAN_USES_CONFIG_H
00040 
00041 
00042 
00043 #if CEYLAN_ARCH_NINTENDO_DS
00044 
00045 #include "CeylanConfigForNintendoDS.h"    
00046 #include "CeylanFIFO.h"                   
00047 
00048 #endif // CEYLAN_ARCH_NINTENDO_DS
00049 
00050 
00051 
00052 #if CEYLAN_ARCH_WINDOWS
00053 #include "CeylanNetwork.h"                
00054 #endif // CEYLAN_ARCH_WINDOWS
00055 
00056 
00057 
00058 
00059 extern "C"
00060 {
00061 
00062 #if CEYLAN_ARCH_NINTENDO_DS
00063 
00064 #include "fat.h"                          
00065 
00066 #include <fcntl.h> 
00067 #include <unistd.h> 
00068 
00069 #endif // CEYLAN_ARCH_NINTENDO_DS
00070 
00071 
00072 #ifdef CEYLAN_USES_UNISTD_H
00073 #include <unistd.h>                       
00074 #endif // CEYLAN_USES_UNISTD_H
00075 
00076 #ifdef CEYLAN_USES_STRING_H
00077 #include <string.h>
00078 #endif // CEYLAN_USES_STRING_H
00079 
00080 #ifdef CEYLAN_USES_SYS_TIME_H
00081 #include <sys/time.h>                     
00082 #endif // CEYLAN_USES_SYS_TYME_H
00083 
00084 
00085 #ifdef CEYLAN_USES_SYS_SELECT_H
00086 #include <sys/select.h>                   
00087 #endif // CEYLAN_USES_SYS_SELECT_H
00088 
00089 #ifdef CEYLAN_USES_WINDOWS_H
00090 #include <windows.h>                      
00091 #endif // CEYLAN_USES_WINDOWS_H
00092 
00093 #ifdef CEYLAN_USES_SYS_TYPES_H
00094 #include <sys/types.h>                    
00095 #endif // CEYLAN_USES_SYS_TYPES_H
00096 
00097 #ifdef CEYLAN_USES_SYS_TIMEB_H
00098 #include <sys/timeb.h>                    
00099 #endif // CEYLAN_USES_SYS_TIMEB_H
00100 
00101 #ifdef CEYLAN_USES_WINSOCK2_H
00102 #include <winsock2.h>                     
00103 #endif // CEYLAN_USES_WINSOCK2_H
00104 
00105 }
00106 
00107 
00108 #define CEYLAN_CHECK_FOR_FREEZE 0
00109 
00110 #if CEYLAN_CHECK_FOR_FREEZE
00111 #include <iostream>
00112 #endif // CEYLAN_CHECK_FOR_FREEZE
00113 
00114 
00115 #include <cstdlib>
00116 #include <cerrno>                         
00117 #include <iostream>                       
00118 
00119 
00120 
00121 
00122 using std::string ;
00123 using std::map ;
00124 
00125 
00126 using namespace Ceylan::Log ;
00127 using namespace Ceylan::System ;
00128 
00129 
00130 
00131 #if CEYLAN_ARCH_NINTENDO_DS
00132 
00134 extern const Size Ceylan::System::CacheLineSize = 32 ;
00135 
00136 
00138 map<Ceylan::Byte *,Ceylan::Byte *> Ceylan::System::CacheProtectedMap ;
00139 
00140 #endif // CEYLAN_ARCH_NINTENDO_DS
00141 
00142 
00143 
00144 extern const Ceylan::System::InterruptMask 
00145     Ceylan::System::AllInterruptsDisabled = 0 ;
00146 
00147 
00148 
00149 Ceylan::System::SystemException::SystemException( const string & message ) :
00150     Ceylan::Exception( message )
00151 {
00152 
00153 }
00154 
00155 
00156 
00157 
00158 Ceylan::System::SystemException::~SystemException() throw()
00159 {
00160 
00161 }
00162 
00163 
00164 
00165 Ceylan::System::IOException::IOException( const string & message ) :
00166     SystemException( message )
00167 {
00168 
00169 }
00170 
00171 
00172 
00173 
00174 Ceylan::System::IOException::~IOException() throw() 
00175 {
00176 
00177 }
00178 
00179 
00180 
00181 const Second Ceylan::System::MaximumDurationWithMicrosecondAccuracy = 4100 ;
00182 
00183 
00184 const Ceylan::Uint32 OneMillion = 1000000 ;
00185 
00186 
00187 
00188 
00189 ErrorCode Ceylan::System::getError() 
00190 {
00191 
00192     return errno ;
00193     
00194 }
00195 
00196 
00197 
00198 
00199 string Ceylan::System::explainError( ErrorCode errorID ) 
00200 {
00201 
00202     return string( ::strerror( errorID ) ) ;
00203     
00204 }
00205 
00206 
00207 
00208 
00209 string Ceylan::System::explainError() 
00210 {
00211 
00212 #ifdef CEYLAN_USES_STRERROR
00213 
00214     return string( ::strerror( errno ) ) ;
00215 
00216 #else // CEYLAN_USES_STRERROR
00217 
00218     return "Ceylan::System::explainError not available on this platform "
00219         "(no ::strerror function found)" ;
00220 
00221 #endif // CEYLAN_USES_STRERROR
00222 
00223 }
00224 
00225 
00226 
00227 string Ceylan::System::getShellName() 
00228 {
00229 
00230     return Ceylan::System::getEnvironmentVariable( "SHELL" ) ;
00231     
00232 }
00233 
00234 
00235 
00236 
00237 
00238 
00239 
00240 
00241 
00242 
00243 
00244 void Ceylan::System::InitializeInterrupts( bool force ) 
00245 {
00246 
00247 #if CEYLAN_ARCH_NINTENDO_DS
00248         
00249 
00250 #ifdef CEYLAN_RUNS_ON_ARM7
00251 
00252     throw SystemException( 
00253         "Ceylan::System::InitializeInterrupts: only available on the ARM9." ) ;
00254 
00255 #elif defined(CEYLAN_RUNS_ON_ARM9)
00256 
00257     static bool initialized = false ;
00258     
00259     if ( ( ! initialized ) || force )
00260     {
00261     
00262         
00263         irqInit() ;
00264 
00265         
00266 
00267 
00268 
00269 
00270         irqEnable( IRQ_VBLANK ) ;
00271         
00272         
00273         swiWaitForVBlank() ;
00274         
00275         initialized = true ;
00276         
00277         
00278         
00279     }   
00280 
00281 #endif // CEYLAN_RUNS_ON_ARM7
00282 
00283     
00284 #else // CEYLAN_ARCH_NINTENDO_DS
00285 
00286     LogPlug::warning( "Ceylan::System::InitializeInterrupts "
00287         "should not be called on this platform." ) ;
00288     
00289 #endif // CEYLAN_ARCH_NINTENDO_DS
00290 
00291 }
00292 
00293 
00294 
00295 InterruptMask Ceylan::System::SetEnabledInterrupts( InterruptMask newMask )
00296 {
00297 
00298 #if CEYLAN_ARCH_NINTENDO_DS
00299         
00300     
00301 
00302     InterruptMask previousMask = REG_IME ;
00303     
00304     REG_IME = newMask ;
00305     
00306     return previousMask ;
00307 
00308 #else // CEYLAN_ARCH_NINTENDO_DS
00309 
00310     LogPlug::warning( "Ceylan::System::SetEnabledInterrupts "
00311         "should not be called on this platform." ) ;
00312     
00313     
00314     return 0 ;
00315     
00316 #endif // CEYLAN_ARCH_NINTENDO_DS
00317 
00318 }
00319 
00320 
00321 
00322 void Ceylan::System::InitializeIPC() 
00323 {
00324 
00325 #if CEYLAN_ARCH_NINTENDO_DS
00326         
00327 
00328 #ifdef CEYLAN_RUNS_ON_ARM7
00329 
00330     throw SystemException( 
00331         "Ceylan::System::InitializeIPC: only available on the ARM9." ) ;
00332 
00333 #elif defined(CEYLAN_RUNS_ON_ARM9)
00334 
00335     
00336     FIFO * fifo = new FIFO() ;
00337     
00338     fifo->activate() ;
00339     
00340 #endif // CEYLAN_RUNS_ON_ARM7
00341 
00342     
00343 #else // CEYLAN_ARCH_NINTENDO_DS
00344 
00345     LogPlug::warning( "Ceylan::System::InitializeIPC "
00346         "should not be called on this platform." ) ;
00347     
00348 #endif // CEYLAN_ARCH_NINTENDO_DS
00349 
00350 }
00351 
00352 
00353 
00354 Ceylan::Byte * Ceylan::System::CacheProtectedNew( Size numberOfBytes )
00355 {
00356 
00357 #if CEYLAN_ARCH_NINTENDO_DS
00358 
00359 #ifdef CEYLAN_RUNS_ON_ARM9
00360 
00361 
00362     
00363     static bool inUse = false ;
00364     
00365     while ( inUse )
00366         ;
00367     
00368     inUse = true ;
00369     
00370     int savedIME = REG_IME ;
00371 
00372     REG_IME = AllInterruptsDisabled ;
00373     
00374     
00375 
00376 
00377 
00378 
00379 
00380 
00381     Ceylan::Byte * biggerBuffer = new Ceylan::Byte[ 
00382         numberOfBytes + CacheLineSize - 1 ] ;
00383     
00384     if ( biggerBuffer == 0 )
00385     {
00386     
00387         REG_IME = savedIME ;
00388         inUse = false ;
00389         
00390         throw SystemException( "Ceylan::System::CacheProtectedNew failed: "
00391             "null pointer returned, not enough memory?" ) ;
00392     
00393     }
00394     
00395     
00396 
00397 
00398 
00399 
00400     Ceylan::Byte * boundaryAlignedBuffer = biggerBuffer 
00401         + ( CacheLineSize - reinterpret_cast<Ceylan::Uint32>( biggerBuffer ) ) 
00402             % CacheLineSize ;
00403 
00404     
00405 
00406 
00407 
00408 
00409 
00410 
00411 
00412  
00413         
00414     
00415 
00416 
00417 
00418 
00419  
00420     Ceylan::System::CacheProtectedMap[ boundaryAlignedBuffer ] = biggerBuffer ;
00421 
00422 
00423     REG_IME = savedIME ;
00424     
00425     inUse = false ;
00426     
00427     return boundaryAlignedBuffer ;
00428      
00429     
00430 #else // CEYLAN_RUNS_ON_ARM9
00431 
00432     throw SystemException( "Ceylan::System::CacheProtectedNew failed: "
00433         "not available on the ARM7." ) ;
00434     
00435 #endif // CEYLAN_RUNS_ON_ARM9
00436         
00437 #else // CEYLAN_ARCH_NINTENDO_DS
00438 
00439     throw SystemException( "Ceylan::System::CacheProtectedNew failed: "
00440         "not available on this platform." ) ;
00441 
00442 #endif // CEYLAN_ARCH_NINTENDO_DS
00443 
00444 }
00445 
00446 
00447 
00448 void Ceylan::System::CacheProtectedDelete( Ceylan::Byte * cacheProtectedBuffer )
00449 {
00450 
00451 #if CEYLAN_ARCH_NINTENDO_DS
00452 
00453 #ifdef CEYLAN_RUNS_ON_ARM9
00454 
00455     
00456     static bool inUse = false ;
00457     
00458     while ( inUse )
00459         ;
00460     
00461     inUse = true ;
00462     
00463     int savedIME = REG_IME ;
00464 
00465     REG_IME = AllInterruptsDisabled ;
00466 
00467     
00468     
00469     map<Ceylan::Byte *,Ceylan::Byte *>::iterator it =
00470             CacheProtectedMap.find( cacheProtectedBuffer ) ;
00471             
00472     if ( it == CacheProtectedMap.end() )
00473     {
00474     
00475         REG_IME = savedIME ;
00476         inUse = false ;
00477         
00478         throw SystemException( "Ceylan::System::CacheProtectedDelete failed: "
00479             "pointer " + Ceylan::toString( cacheProtectedBuffer ) 
00480             + " not found." ) ;
00481             
00482     }
00483     
00484     
00485 
00486 
00487 
00488 
00489 
00490 
00491         
00492     delete [] (*it).second ;
00493     
00494     REG_IME = savedIME ;
00495     inUse = false ;
00496                     
00497 #else // CEYLAN_RUNS_ON_ARM9
00498 
00499     throw SystemException( "CacheProtectedDelete failed: "
00500         "not available on the ARM7." ) ;
00501     
00502 #endif // CEYLAN_RUNS_ON_ARM9
00503         
00504 #else // CEYLAN_ARCH_NINTENDO_DS
00505 
00506     throw SystemException( "CacheProtectedDelete failed: "
00507         "not available on this platform." ) ;
00508 
00509 #endif // CEYLAN_ARCH_NINTENDO_DS
00510 
00511 }
00512 
00513 
00514 
00515 bool Ceylan::System::HasAvailableData( FileDescriptor fd ) 
00516 {
00517 
00518 #if CEYLAN_ARCH_NINTENDO_DS
00519         
00520     LogPlug::error( "Ceylan::System::HasAvailableData: "
00521         "not supported on the Nintendo DS platform." ) ;
00522 
00523     return false ;
00524     
00525 #else // CEYLAN_ARCH_NINTENDO_DS
00526 
00527 #if CEYLAN_USES_FILE_DESCRIPTORS
00528 
00529     struct timeval tv ;
00530     tv.tv_sec  = 0 ;
00531     tv.tv_usec = 0 ;
00532 
00533     
00534     fd_set set ;
00535     FD_ZERO( & set ) ;
00536     FD_SET( fd, & set ) ;
00537 
00538     Ceylan::Sint32 n = ::select( fd + 1, & set, 0, 0, & tv ) ;
00539 
00540     if ( n > 0 )
00541         return FD_ISSET( fd, & set ) ;
00542 
00543     if ( n == -1 )
00544         LogPlug::error( "Ceylan::System::HasAvailableData failed: "
00545             + System::explainError() ) ;
00546 
00547     return false ;
00548 
00549 #else // CEYLAN_USES_FILE_DESCRIPTORS
00550 
00551     LogPlug::error( "Ceylan::System::HasAvailableData: "
00552         "file descriptor feature not available" ) ;
00553 
00554     return false ;
00555 
00556 #endif // CEYLAN_USES_FILE_DESCRIPTORS
00557 
00558 #endif // CEYLAN_ARCH_NINTENDO_DS
00559 
00560 }
00561 
00562 
00563 
00564 Size Ceylan::System::FDRead( FileDescriptor fd, char * dataBuffer,
00565     Size toReadBytesNumber )
00566 {
00567 
00568 #if CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00569     LogPlug::trace( "Ceylan::System::FDRead: will try to read "
00570         + Ceylan::toString( 
00571             static_cast<Ceylan::Uint32>( toReadBytesNumber ) ) + " byte(s)." ) ;
00572 #endif // CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00573 
00574 
00575     SignedSize totalReadBytesNumber = 0 ;
00576 
00577 #if CEYLAN_ARCH_WINDOWS
00578 
00579     
00580 
00581 #if CEYLAN_USES_NETWORK
00582 
00583     char * pos = dataBuffer ;
00584 
00585     SignedSize readBytesNumber ;
00586     
00587 
00588     while ( toReadBytesNumber &&
00589         ( readBytesNumber = ::recv( fd, pos, 
00590             static_cast<int>( toReadBytesNumber ), 
00591              0 ) ) != 0 )
00592     {
00593 
00594 #if CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00595                 LogPlug::trace( "Ceylan::System::FDRead: recv returned "
00596                     + Ceylan::toString( readBytesNumber ) + "." ) ;
00597 #endif // CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00598 
00599 
00600         if ( readBytesNumber == SOCKET_ERROR )
00601         {
00602 
00603             
00604             if ( Network::getSocketError() == WSAEWOULDBLOCK )
00605             {
00606 
00607 #if CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00608                 LogPlug::trace( "Ceylan::System::FDRead: "
00609                     "operation would block." ) ;
00610 #endif // CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00611 
00612                 readBytesNumber = 0 ;
00613                 break ;
00614             }
00615             else
00616             {
00617 
00618 #if CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00619                 LogPlug::trace( "Ceylan::System::FDRead: operation failed." ) ;
00620 #endif // CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00621 
00622                 throw IOException( "Ceylan::System::FDRead failed: "
00623                     + Network::explainSocketError() ) ;
00624             }
00625 
00626         }
00627 
00628         totalReadBytesNumber += readBytesNumber ;
00629         toReadBytesNumber    -= readBytesNumber ;
00630         pos                  += readBytesNumber ;
00631 
00632     }
00633 
00634     
00635 
00636 
00637 #else // CEYLAN_USES_NETWORK
00638 
00639     throw Features::FeatureNotAvailableException( "Ceylan::System::FDRead: "
00640         "network feature not available" ) ;
00641 
00642 #endif // CEYLAN_USES_NETWORK
00643 
00644 #else // CEYLAN_ARCH_WINDOWS
00645 
00646 #if CEYLAN_USES_FILE_DESCRIPTORS
00647 
00648 
00649     char * pos = dataBuffer ;
00650 
00651     SignedSize readBytesNumber ;
00652     
00653     while ( toReadBytesNumber &&
00654         ( readBytesNumber = ::read( fd, pos, toReadBytesNumber ) ) != 0 )
00655     {
00656 
00657         if ( readBytesNumber < 0 )
00658         {
00659 
00660             
00661             if ( System::getError() == EAGAIN )
00662             {
00663                 readBytesNumber = 0 ;
00664                 break ;
00665             }
00666             else
00667             {
00668                 throw IOException( "Ceylan::System::FDRead failed: "
00669                     + explainError() ) ;
00670             }
00671 
00672         }
00673 
00674         totalReadBytesNumber += readBytesNumber ;
00675         toReadBytesNumber    -= readBytesNumber ;
00676         pos                  += readBytesNumber ;
00677 
00678     }
00679 
00680     
00681 
00682 
00683 #else // CEYLAN_USES_FILE_DESCRIPTORS
00684 
00685     throw Features::FeatureNotAvailableException( "Ceylan::System::FDRead: "
00686         "file descriptor feature not available" ) ;
00687 
00688 #endif // CEYLAN_USES_FILE_DESCRIPTORS
00689 
00690 #endif // CEYLAN_ARCH_WINDOWS
00691 
00692 
00693 #if CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00694     LogPlug::trace( "Ceylan::System::FDRead: read "
00695         + Ceylan::toString( totalReadBytesNumber ) + " byte(s)." ) ;
00696 #endif // CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00697 
00698     return static_cast<Size>( totalReadBytesNumber ) ;
00699 
00700 }
00701 
00702 
00703 
00704 Size Ceylan::System::FDWrite( FileDescriptor fd,
00705     const Ceylan::Byte * dataBuffer, Size toWriteBytesNumber )
00706 {
00707 
00708 #if CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00709     LogPlug::trace( "Ceylan::System::FDWrite: will try to write "
00710         + Ceylan::toString( 
00711             static_cast<Ceylan::Uint32>( toWriteBytesNumber ) ) 
00712         + " byte(s)." ) ;
00713 #endif // CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00714 
00715 
00716     SignedSize totalWroteBytesNumber = 0 ;
00717 
00718 #if CEYLAN_ARCH_WINDOWS
00719 
00720     
00721 
00722 #if CEYLAN_USES_NETWORK
00723 
00724     const char * pos = dataBuffer ;
00725 
00726     SignedSize wroteBytesNumber ;
00727 
00728     while( toWriteBytesNumber
00729         && ( wroteBytesNumber = ::send( fd, pos, 
00730             static_cast<int>( toWriteBytesNumber ), 
00731              0 ) ) != 0 )
00732     {
00733 
00734         if ( wroteBytesNumber < 0 )
00735         {
00736 
00737             
00738 
00739 
00740 
00741 
00742             if ( Network::getSocketError() == WSAEWOULDBLOCK )
00743             {
00744                 wroteBytesNumber = 0 ;
00745                 break ;
00746 
00747             }
00748             else
00749             {
00750 
00751                 throw IOException( "Ceylan::System::FDWrite failed: "
00752                     + Network::explainSocketError() ) ;
00753             }
00754         }
00755 
00756         totalWroteBytesNumber += wroteBytesNumber ;
00757         toWriteBytesNumber    -= wroteBytesNumber ;
00758         pos                   += wroteBytesNumber ;
00759 
00760     }
00761 
00762 #else // CEYLAN_USES_NETWORK
00763 
00764     throw Features::FeatureNotAvailableException( "Ceylan::System::FDWrite: "
00765         "network feature not available" ) ;
00766 
00767 #endif // CEYLAN_USES_NETWORK
00768 
00769 #else // CEYLAN_ARCH_WINDOWS
00770 
00771 #if CEYLAN_USES_FILE_DESCRIPTORS
00772 
00773 
00774     const char * pos = dataBuffer ;
00775 
00776     SignedSize wroteBytesNumber ;
00777 
00778     while( toWriteBytesNumber
00779         && ( wroteBytesNumber = ::write( fd, pos, toWriteBytesNumber ) ) != 0 )
00780     {
00781 
00782         if ( wroteBytesNumber < 0 )
00783         {
00784 
00785             
00786             if ( System::getError() == EAGAIN )
00787             {
00788                 wroteBytesNumber = 0 ;
00789                 break ;
00790 
00791             }
00792             else
00793             {
00794 
00795                 throw IOException( "Ceylan::System::FDWrite failed: "
00796                     + explainError() ) ;
00797             }
00798         }
00799 
00800         totalWroteBytesNumber += wroteBytesNumber ;
00801         toWriteBytesNumber    -= wroteBytesNumber ;
00802         pos                   += wroteBytesNumber ;
00803 
00804     }
00805 
00806 
00807 #else // CEYLAN_USES_FILE_DESCRIPTORS
00808 
00809     throw Features::FeatureNotAvailableException( "Ceylan::System::FDWrite: "
00810         "file descriptor feature not available" ) ;
00811 
00812 #endif // CEYLAN_USES_FILE_DESCRIPTORS
00813 
00814 #endif // CEYLAN_ARCH_WINDOWS
00815 
00816 #if CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00817     LogPlug::trace( "Ceylan::System::FDWrite: wrote "
00818         + Ceylan::toString( totalWroteBytesNumber ) + " byte(s)." ) ;
00819 #endif // CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00820 
00821     return static_cast<Size>( totalWroteBytesNumber ) ;
00822 
00823 }
00824 
00825 
00826 
00827 
00828 
00829 
00830 
00831 
00832 Second Ceylan::System::getTime() 
00833 {
00834 
00835 #ifdef CEYLAN_USES_TIME
00836 
00837     Ceylan::Sint32 currentTime = static_cast<Ceylan::Sint32>(
00838             ::time( 0 ) ) ;
00839 
00840     if ( currentTime == -1 )
00841         throw SystemException( explainError( getError() ) ) ;
00842 
00843     
00844 
00845 
00846 
00847 
00848 
00849     return static_cast<Second>( currentTime ) ;
00850 
00851 #else // CEYLAN_USES_TIME
00852 
00853     throw SystemException( "Ceylan::System::getTime: "
00854         "not available on this platform (no ::time function found)." ) ;
00855 
00856 #endif // CEYLAN_USES_TIME
00857 
00858 }
00859 
00860 
00861 
00862 string Ceylan::System::timeToString( const time_t & t )
00863 {
00864 
00865 #ifdef CEYLAN_USES_CTIME
00866 
00867     char * charTime = ::ctime( &t ) ;
00868 
00869     if ( charTime == 0 )
00870         throw SystemException( "Ceylan::System::timeToString: "
00871             "unable to convert time to string with ctime." ) ;
00872 
00873     string stringTime = charTime ;
00874     string eol = "\n" ;
00875     stringTime.erase( stringTime.size() - eol.size(), eol.size() ) ;
00876     return stringTime ;
00877 
00878 #else // CEYLAN_USES_CTIME
00879 
00880     throw SystemException( "Ceylan::System::timeToString: "
00881         "not available on this platform (no ::ctime function found)." ) ;
00882 
00883 #endif // CEYLAN_USES_CTIME
00884 
00885 }
00886 
00887 
00888 
00889 string Ceylan::System::durationToString(
00890     Second startingSecond, Microsecond startingMicrosecond,
00891     Second stoppingSecond, Microsecond stoppingMicrosecond )
00892 {
00893 
00894     
00895 
00896 
00897     
00898     Second s1 = startingSecond + startingMicrosecond / OneMillion ;
00899     Second s2 = stoppingSecond + stoppingMicrosecond / OneMillion ;
00900 
00901     Microsecond r1 = startingMicrosecond % OneMillion ;
00902     Microsecond r2 = stoppingMicrosecond % OneMillion ;
00903 
00904     
00905 
00906     if ( s1 > s2 )
00907         throw SystemException( "Ceylan::System::durationToString: "
00908             "specified duration is negative." ) ;
00909 
00910     if ( s1 == s2 )
00911     {
00912         if ( r1 > r2 )
00913             throw SystemException( "Ceylan::System::durationToString: "
00914                 "specified duration should not be negative." ) ;
00915     }
00916 
00917 
00918     
00919 
00920     if ( r2 >= r1 )
00921     {
00922         return Ceylan::toString( s2 - s1 ) + " second(s) and "
00923             + Ceylan::toString( r2 - r1 ) + " microsecond(s)" ;
00924     }
00925     else
00926     {
00927         return Ceylan::toString( s2 - s1 - 1 ) + " second(s) and "
00928             + Ceylan::toString( OneMillion + r2 - r1 )
00929             + " microsecond(s)" ;
00930     }
00931 
00932 }
00933 
00934 
00935 
00936 Microsecond Ceylan::System::getDurationBetween(
00937     Second startingSecond, Microsecond startingMicrosecond,
00938     Second stoppingSecond, Microsecond stoppingMicrosecond )
00939 {
00940 
00941 
00942     
00943 
00944 
00945 
00946 
00947          
00948 
00949     
00950     Second s1 = startingSecond + startingMicrosecond / OneMillion ;
00951     Second s2 = stoppingSecond + stoppingMicrosecond / OneMillion ;
00952 
00953     Microsecond r1 = startingMicrosecond % OneMillion ;
00954     Microsecond r2 = stoppingMicrosecond % OneMillion ;
00955 
00956     
00957 
00958     if ( s1 > s2 )
00959         throw SystemException( "Ceylan::System::getDurationBetween: "
00960             "specified duration is negative." ) ;
00961 
00962     if ( s1 == s2 )
00963     {
00964         if ( r1 > r2 )
00965             throw SystemException( "Ceylan::System::getDurationBetween: "
00966                 "specified duration should not be negative." ) ;
00967     }
00968 
00969 
00970     
00971 
00972     if ( ( s2 - s1 ) > MaximumDurationWithMicrosecondAccuracy )
00973         throw SystemException( "Ceylan::System::getDurationBetween: "
00974                 "specified duration should not exceed "
00975                 + Ceylan::toString( MaximumDurationWithMicrosecondAccuracy ) 
00976                 + " seconds." ) ;
00977 
00978     return ( ( s2 - s1 ) * OneMillion + r2 -r1 ) ;
00979 
00980 }
00981 
00982 
00983 
00984 void Ceylan::System::getPreciseTime( Second & seconds, Microsecond & microsec )
00985 {
00986 
00987 #ifdef CEYLAN_USES_GETTIMEOFDAY
00988 
00989     timeval currentTime ;
00990 
00991     if ( ::gettimeofday( & currentTime,
00992              0 ) != 0 )
00993         throw SystemException( "System::getPreciseTime: "
00994             + Ceylan::System::explainError() ) ;
00995 
00996     seconds  = static_cast<Second>( currentTime.tv_sec ) ;
00997     microsec = static_cast<Microsecond>( currentTime.tv_usec ) ;
00998 
00999 #else // CEYLAN_USES_GETTIMEOFDAY
01000 
01001 
01002 #ifdef CEYLAN_USES__FTIME_S
01003 
01004     struct _timeb timeBuffer ;
01005 
01006     if( ::_ftime_s( & timeBuffer ) != 0 )
01007         throw SystemException( "System::getPreciseTime: "
01008             "_ftime_s failed." ) ;
01009 
01010     seconds  = static_cast<Second>( timeBuffer.time ) ;
01011     microsec = static_cast<Microsecond>( timeBuffer.millitm * 1000 ) ;
01012 
01013 
01014 #else // CEYLAN_USES__FTIME_S
01015 
01016     throw SystemException( "System::getPreciseTime: "
01017         "not available on this platform." ) ;
01018 
01019 #endif // CEYLAN_USES__FTIME_S
01020 
01021 #endif // CEYLAN_USES_GETTIMEOFDAY
01022 
01023 }
01024 
01025 
01026 
01027 Microsecond Ceylan::System::getAccuracyOfPreciseTime( Microsecond * minGap,
01028     Microsecond * maxGap ) 
01029 {
01030 
01031     Ceylan::Uint32 numberOfMeasures = 100 ;
01032 
01033     
01034 
01035 
01036 
01037 
01038     Microsecond minDuration = 4000000000U ;
01039     Microsecond maxDuration = 0 ;
01040 
01041     Microsecond currentDuration ;
01042     Microsecond cumulativeDuration = 0 ;
01043 
01044     Microsecond lastSecond ;
01045     Microsecond lastMicrosecond ;
01046 
01047     Microsecond currentSecond ;
01048     Microsecond currentMicrosecond ;
01049 
01050 #if CEYLAN_DEBUG_SYSTEM
01051 
01052     
01053 
01054 
01055 
01056 
01057 
01058 
01059 
01060     Microsecond * durations = new Microsecond[numberOfMeasures] ;
01061 
01062 #endif // CEYLAN_DEBUG_SYSTEM
01063 
01064     getPreciseTime( lastSecond, lastMicrosecond ) ;
01065 
01066     for ( Ceylan::Uint32 i = 0; i < numberOfMeasures; i++ )
01067     {
01068     
01069         getPreciseTime( currentSecond, currentMicrosecond ) ;
01070         
01071         currentDuration = getDurationBetween( lastSecond, lastMicrosecond,
01072             currentSecond, currentMicrosecond ) ;
01073                     
01074         if ( currentDuration < minDuration )
01075             minDuration = currentDuration ;
01076         else if ( currentDuration > maxDuration )
01077             maxDuration = currentDuration ;
01078             
01079         cumulativeDuration += currentDuration ;
01080 
01081 #if CEYLAN_DEBUG_SYSTEM
01082         durations[i] = currentDuration ;
01083 #endif // CEYLAN_DEBUG_SYSTEM
01084 
01085         lastSecond = currentSecond ;
01086         lastMicrosecond = currentMicrosecond ;
01087 
01088     }
01089 
01090     if ( minGap != 0 )
01091         *minGap = minDuration ;
01092 
01093     if ( maxGap != 0 )
01094         *maxGap = maxDuration ;
01095 
01096 #if CEYLAN_DEBUG_SYSTEM
01097 
01098     for ( Ceylan::Uint32 i = 0; i < numberOfMeasures; i++ )
01099         Log::LogPlug::debug( "Duration of getPreciseTime call: "
01100             + Ceylan::toString( durations[i] ) + " microseconds." ) ;
01101             
01102     Log::LogPlug::debug( "Real average duration: "
01103         + Ceylan::toString(
01104             static_cast<Ceylan::Float32>( 
01105                 cumulativeDuration ) / numberOfMeasures ) ) ;
01106 
01107     delete durations ;
01108 
01109 #endif // CEYLAN_DEBUG_SYSTEM
01110 
01111     Microsecond result = static_cast<Microsecond>(
01112         cumulativeDuration /  numberOfMeasures ) ;
01113 
01114     
01115     if ( result == 0 )
01116         return 1 ;
01117     else
01118         return result ;
01119 
01120 }
01121 
01122 
01123 
01124 Microsecond Ceylan::System::getPreciseTimeCallDuration() 
01125 {
01126 
01127     static Microsecond duration = 0 ;
01128 
01129     
01130     if ( duration != 0 )
01131         return duration ;
01132 
01133     
01134     Ceylan::Uint16 calls = 1000 ;
01135 
01136     Second lastSecond ;
01137     Microsecond lastMicrosecond ;
01138 
01139     Second currentSecond ;
01140     Microsecond currentMicrosecond ;
01141 
01142     getPreciseTime( lastSecond, lastMicrosecond ) ;
01143 
01144     
01145     for ( Ceylan::Uint16 i = 0; i < calls ; i++ )
01146         getPreciseTime( currentSecond, currentMicrosecond ) ;
01147 
01148     Microsecond totalTime = getDurationBetween( lastSecond, lastMicrosecond,
01149         currentSecond, currentMicrosecond ) ;
01150 
01151     
01152     duration = totalTime / calls ;
01153 
01154     if ( duration == 0 )
01155         duration = 1 ;
01156         
01157     return duration ;
01158 
01159 }
01160 
01161 
01162 
01163 void Ceylan::System::sleepForSeconds( Second seconds )
01164 {
01165 
01166 #if CEYLAN_ARCH_NINTENDO_DS
01167 
01168     basicSleep( seconds,  0 ) ;
01169 
01170 #else // CEYLAN_ARCH_NINTENDO_DS
01171     
01172 #ifdef CEYLAN_USES_SLEEP
01173 
01174     Second stillToBeSlept = seconds ;
01175 
01176     while ( stillToBeSlept != 0 )
01177     {
01178 
01179         
01180 
01181 
01182 
01183 
01184         stillToBeSlept = ::sleep( stillToBeSlept ) ;
01185 
01186     }
01187 
01188 #else // CEYLAN_USES_SLEEP
01189 
01190 #ifdef CEYLAN_USES_WINDOWS_H
01191 
01192     
01193     ::Sleep( 1000 * seconds  ) ;
01194 
01195 #else // CEYLAN_USES_WINDOWS_H
01196 
01197     throw SystemException( "Ceylan::sleepForSeconds: "
01198         "not available on this platform (no ::sleep function found)" ) ;
01199 
01200 #endif // CEYLAN_USES_WINDOWS_H
01201 
01202 #endif // CEYLAN_USES_SLEEP
01203 
01204 #endif // CEYLAN_ARCH_NINTENDO_DS
01205 
01206 }
01207 
01208 
01209 
01210 bool Ceylan::System::areSubSecondSleepsAvailable() 
01211 {
01212 
01213 #if CEYLAN_ARCH_NINTENDO_DS
01214         
01215     
01216     return true ; 
01217 
01218 #elif CEYLAN_ARCH_WINDOWS == 1
01219 
01220     return true ;
01221     
01222 #else // CEYLAN_ARCH_WINDOWS
01223 
01224 
01225 #if CEYLAN_USES_FILE_DESCRIPTORS
01226     return true ;
01227 #else // CEYLAN_USES_FILE_DESCRIPTORS
01228     return false ;
01229 #endif // CEYLAN_USES_FILE_DESCRIPTORS
01230     
01231     
01232 #endif // CEYLAN_ARCH_NINTENDO_DS
01233         
01234 }
01235 
01236 
01237 
01238 void Ceylan::System::basicSleep( Second seconds, Nanosecond nanos ) 
01239 {
01240 
01241 #if CEYLAN_DEBUG_SYSTEM
01242     LogPlug::debug( "Ceylan::System::basicSleep: requested duration is "
01243         + Ceylan::toString( seconds ) + " second(s) and "
01244         + Ceylan::toString( nanos ) + " nanosecond(s)." ) ;
01245 #endif // CEYLAN_DEBUG_SYSTEM
01246 
01247 
01248 #if CEYLAN_ARCH_NINTENDO_DS
01249 
01250 #ifdef CEYLAN_RUNS_ON_ARM9
01251     InitializeInterrupts(  false ) ;
01252 #endif // CEYLAN_RUNS_ON_ARM9
01253     
01254     
01255     Ceylan::Uint32 vblankCount = seconds * 60 + nanos * (6/100000000) ;
01256     
01257     while ( vblankCount > 0 )
01258     {
01259         swiWaitForVBlank();
01260         vblankCount-- ;
01261     }
01262     
01263 #else // CEYLAN_ARCH_NINTENDO_DS
01264 
01265 
01266 #if CEYLAN_ARCH_WINDOWS
01267 
01268     
01269     ::Sleep( seconds * 1000 + nanos / OneMillion ) ;
01270 
01271 #else // CEYLAN_ARCH_WINDOWS
01272 
01273 
01274 #define CEYLAN_USES_NANOSLEEP 0
01275 
01276 #if CEYLAN_USES_NANOSLEEP
01277 
01278     
01279 
01280 
01281 
01282 
01283 
01284 
01285 
01286 
01287 
01288 
01289 
01290 
01291     timespec waiter ;
01292 
01293     waiter.tv_sec  = static_cast<Second>( seconds ) ;
01294     waiter.tv_nsec = static_cast<long>( nanos ) ;
01295 
01296     if ( ::nanosleep( & waiter,  0 ) != 0 )
01297         throw SystemException( "System::basicSleep with nanosleep failed: "
01298             + Ceylan::System::explainError() ) ;
01299 
01300 #else // CEYLAN_USES_NANOSLEEP
01301 
01302 
01303 #if CEYLAN_USES_FILE_DESCRIPTORS
01304 
01305     
01306 
01307 
01308 
01309 
01310 
01311 
01312 
01313     timeval timeout ;
01314     timeout.tv_sec = seconds ;
01315 
01316     
01317     timeout.tv_usec = static_cast<long>( nanos / 1000 ) ;
01318 
01319 
01320     
01321     if ( ::select( 0, static_cast<fd_set *>( 0 ),
01322             static_cast<fd_set *>( 0 ), static_cast<fd_set *>( 0 ),
01323             & timeout ) < 0 )
01324         throw SystemException( "System::basicSleep with select failed: "
01325             + Ceylan::System::explainError() ) ;
01326 
01327 #else // CEYLAN_USES_FILE_DESCRIPTORS
01328 
01329     throw SystemException( "System::basicSleep: "
01330         "file descriptor feature not available" ) ;
01331 
01332 #endif // CEYLAN_USES_FILE_DESCRIPTORS
01333 
01334 
01335 #endif // CEYLAN_USES_NANOSLEEP
01336 
01337 #endif // CEYLAN_ARCH_WINDOWS
01338 
01339 #endif // CEYLAN_ARCH_NINTENDO_DS
01340 
01341 #if CEYLAN_DEBUG_SYSTEM
01342     LogPlug::debug( "Ceylan::System::basicSleep: awoken now." ) ;
01343 #endif // CEYLAN_DEBUG_SYSTEM
01344 
01345 }
01346 
01347 
01348 
01349 void Ceylan::System::atomicSleep() 
01350 {
01351 
01352 #if CEYLAN_ARCH_NINTENDO_DS
01353     
01354 #ifdef CEYLAN_RUNS_ON_ARM9
01355     InitializeInterrupts(  false ) ;
01356 #endif // CEYLAN_RUNS_ON_ARM9
01357 
01358     
01359 
01360 
01361 
01362 
01363 
01364     swiWaitForVBlank() ;
01365     
01366 #else // CEYLAN_ARCH_NINTENDO_DS
01367 
01368     
01369 
01370 
01371 
01372 
01373 
01374 
01375 
01376 
01377 
01378 
01379     const Ceylan::Float32 marginDecreaseFactor = 0.75f ;
01380 
01381 #if CEYLAN_DEBUG_SYSTEM
01382 
01383         LogPlug::debug( "Ceylan::System::atomicSleep triggered." ) ;
01384 
01385 #endif // CEYLAN_DEBUG_SYSTEM
01386 
01387     static Microsecond durationToRequest = static_cast<Microsecond>(
01388         marginDecreaseFactor * getSchedulingGranularity() ) ;
01389         
01390     basicSleep( durationToRequest ) ;
01391 
01392 #endif // CEYLAN_ARCH_NINTENDO_DS       
01393 
01394 
01395 }
01396 
01397 
01398 
01399 void Ceylan::System::basicSleep( Microsecond micros ) 
01400 {
01401 
01402     
01403     basicSleep(  micros / OneMillion,
01404          ( micros % OneMillion ) * 1000 ) ;
01405 
01406 }
01407 
01408 
01409 
01410 bool Ceylan::System::smartSleep( Second seconds, Microsecond micros )
01411 {
01412 
01413 
01414     
01415 
01416 
01417 
01418 
01419 
01420 
01421 
01422 
01423 
01424 
01425     
01426     Second targetSecond ;
01427     Microsecond targetMicrosecond ;
01428 
01429     getPreciseTime( targetSecond, targetMicrosecond ) ;
01430 
01431     
01432     targetSecond += seconds ;
01433 
01434     
01435 
01436 
01437 
01438 
01439     targetMicrosecond += micros - getPreciseTimeCallDuration() - 1  ;
01440 
01441     
01442 
01443 
01444 
01445 
01446 
01447 
01448     
01449 
01450 
01451 
01452 
01453 
01454     const Ceylan::Float32 marginIncreaseFactor = 1.2f ;
01455 
01456 
01457     
01458 
01459 
01460 
01461 
01462 
01463 
01464 
01465 
01466 
01467     const Microsecond usedGranularity = static_cast<Microsecond>(
01468         getSchedulingGranularity() * marginIncreaseFactor ) ;
01469 
01470     
01471 
01472 
01473 
01474 
01475 
01476 
01477 
01478 
01479     Ceylan::Uint32 fullTimeSliceCount = ( seconds * OneMillion + micros )
01480         / usedGranularity ;
01481 
01482 #if CEYLAN_DEBUG_SYSTEM
01483     LogPlug::debug( "Ceylan::System::smartSleep: will first use "
01484         + Ceylan::toString( fullTimeSliceCount )
01485         + " full time slice(s) for waiting." ) ;
01486 #endif // CEYLAN_DEBUG_SYSTEM
01487 
01488     
01489 
01490 
01491 
01492 
01493 
01494 
01495 
01496     if ( fullTimeSliceCount != 0 )
01497     {
01498 
01499 #if CEYLAN_DEBUG_SYSTEM
01500 
01501         LogPlug::debug( "Ceylan::System::smartSleep: will ask basicSleep "
01502             + Ceylan::toString( fullTimeSliceCount
01503                 * getSchedulingGranularity() )
01504             + " microseconds." ) ;
01505 
01506 #endif // CEYLAN_DEBUG_SYSTEM
01507 
01508         basicSleep( fullTimeSliceCount * getSchedulingGranularity() ) ;
01509 
01510     }
01511 
01512     Second currentSecond ;
01513     Microsecond currentMicrosecond ;
01514 
01515     getPreciseTime( currentSecond, currentMicrosecond ) ;
01516 
01517     
01518 
01519 
01520 
01521 
01522     Ceylan::SignedLongInteger currentError
01523         = ( currentSecond - targetSecond ) * OneMillion
01524             + currentMicrosecond - targetMicrosecond ;
01525 
01526     LogPlug::debug( "Ceylan::System::smartSleep: "
01527         "after having waited the big chunk, we are at "
01528         + Ceylan::toString( -currentError ) 
01529         + " microseconds before deadline." ) ;
01530         
01531 #if CEYLAN_DEBUG_SYSTEM
01532     Ceylan::Uint32 atomicCount = 0 ;
01533 #endif // CEYLAN_DEBUG_SYSTEM
01534             
01535 
01536 
01537     while ( -currentError > static_cast<int>( 2 * usedGranularity ) )
01538     {
01539 
01540 #if CEYLAN_DEBUG_SYSTEM
01541         atomicCount++ ;
01542 #endif // CEYLAN_DEBUG_SYSTEM
01543 
01544         
01545 
01546 
01547 
01548 
01549         atomicSleep() ;
01550 
01551         getPreciseTime( currentSecond, currentMicrosecond ) ;
01552         
01553         
01554         currentError = ( currentSecond - targetSecond ) * OneMillion
01555             + currentMicrosecond - targetMicrosecond ;
01556             
01557     }
01558 
01559 #if CEYLAN_DEBUG_SYSTEM
01560 
01561     LogPlug::debug( "Ceylan::System::smartSleep: used "
01562         + Ceylan::toString( atomicCount )
01563         + " atomic waitings." ) ;
01564 
01565 #endif // CEYLAN_DEBUG_SYSTEM
01566 
01567     
01568     if ( currentError > 0 )
01569     {
01570     
01571         LogPlug::warning( "Ceylan::System::smartSleep: "
01572             "sleeps waited too much, target time missed of "
01573             + Ceylan::toString( currentError )
01574             + " microseconds, because of non-precomputed "
01575             "or underestimated time slices (their evaluated duration was "
01576             + Ceylan::toString( getSchedulingGranularity() )
01577             + " microseconds)." ) ;
01578         return false ;
01579         
01580     }
01581 
01582     
01583 
01584 
01585 #if CEYLAN_DEBUG_SYSTEM
01586 
01587     Microsecond remaining = static_cast<Microsecond>( -currentError ) ;
01588 
01589     LogPlug::debug( "Ceylan::System::smartSleep: remaining time ("
01590         + Ceylan::toString( remaining ) + " microseconds)"
01591             + " will be spent in active waiting." ) ;
01592 
01593 #endif // CEYLAN_DEBUG_SYSTEM
01594 
01595 
01596     bool done = false ;
01597 
01598     
01599 
01600 
01601 
01602 
01603 
01604 
01605 #if CEYLAN_CHECK_FOR_FREEZE
01606     std::cerr << std::endl << "active waiting started -> " ;
01607 #endif // CEYLAN_CHECK_FOR_FREEZE
01608 
01609     Ceylan::Sint32 preciseTimeDuration =
01610         static_cast<Sint32>( getPreciseTimeCallDuration() ) ;
01611 
01612 #if CEYLAN_DEBUG_SYSTEM
01613 
01614     Ceylan::Uint32 logCount = 0 ;
01615 
01616 #endif // CEYLAN_DEBUG_SYSTEM
01617 
01618     
01619     Ceylan::Sint32 remainingTime ;
01620 
01621     while( ! done )
01622     {
01623 
01624         getPreciseTime( currentSecond, currentMicrosecond ) ;
01625         remainingTime =
01626             static_cast<Sint32>( targetSecond - currentSecond ) * OneMillion
01627             + targetMicrosecond - currentMicrosecond ;
01628 
01629 #if CEYLAN_DEBUG_SYSTEM
01630         
01631         logCount++ ;
01632         
01633         if ( ( logCount % 50 ) == 0 )
01634             LogPlug::debug( "Ceylan::System::smartSleep: "
01635                 "remaining time in active waiting is "
01636                 + Ceylan::toString( remainingTime ) + " microseconds." ) ;
01637             
01638         
01639 #endif // CEYLAN_DEBUG_SYSTEM
01640 
01641 
01642 #if CEYLAN_ARCH_WINDOWS
01643 
01644         
01645 
01646 
01647 
01648 
01649 
01650 
01651 
01652 
01653 
01654 
01655 
01656 
01657 
01658 
01659 
01660 
01661 
01662 
01663 
01664 
01665 
01666 
01667 
01668 
01669 
01670 
01671 
01672 
01673 
01674 
01675 
01676 
01677 
01678 
01679         
01680         if ( remaining  < 1.5 * usedGranularity )
01681         {
01682 
01683 #if CEYLAN_DEBUG_SYSTEM
01684             LogPlug::debug( "Ceylan::System::smartSleep: remaining time ("
01685                 + Ceylan::toString( remaining ) + " microseconds)"
01686                 + " smaller than half of a time slice ("
01687                 + Ceylan::toString( usedGranularity ) 
01688                 + " microseconds) and we are on Windows, "
01689                 "we prefer to finish earlier than later." ) ;
01690 #endif // CEYLAN_DEBUG_SYSTEM
01691 
01692             return false ;
01693 
01694         }
01695 
01696 #endif // CEYLAN_ARCH_WINDOWS
01697 
01698         
01699 
01700 
01701 
01702 
01703         if ( remainingTime < preciseTimeDuration )
01704             done = true ;
01705 
01706         
01707 
01708 
01709 
01710 
01711 
01712 
01713     }
01714 
01715 #if CEYLAN_CHECK_FOR_FREEZE
01716     std::cerr << "finished" ;
01717 #endif // CEYLAN_CHECK_FOR_FREEZE
01718 
01719     
01720 
01721     return true ;
01722     
01723 }
01724 
01725 
01726 
01727 bool Ceylan::System::smartSleepUntil( Second second, Microsecond micro )    
01728 {
01729 
01730     Second currentSecond ;
01731     Microsecond currentMicrosecond ;
01732 
01733     getPreciseTime( currentSecond, currentMicrosecond ) ;
01734 
01735     
01736 
01737 
01738 
01739 
01740     currentMicrosecond++ ;
01741 
01742     if ( currentSecond > second || currentMicrosecond > micro )
01743         throw SystemException( "Ceylan::System::smartSleepUntil: "
01744             "specified date (" + Ceylan::toString( second )
01745             + " seconds and " + Ceylan::toString( micro )
01746             + " microseconds) is on the past (current date is "
01747             + Ceylan::toString( currentSecond ) + " seconds, "
01748             + Ceylan::toString( currentMicrosecond ) + " microseconds)." ) ;
01749      
01750     if ( micro < currentMicrosecond )
01751     {
01752         second-- ;
01753         micro += OneMillion ;
01754     }
01755     
01756     return smartSleep( second - currentSecond, micro - currentMicrosecond ) ;
01757 
01758 }
01759 
01760 
01761 
01762 Microsecond Ceylan::System::getActualDurationForSleep(
01763         Microsecond requestedMicroseconds, Second requestedSeconds )
01764 {
01765 
01766 
01767     
01768     
01769 
01770     
01771 
01772     Second lastSecond ;
01773     Microsecond lastMicrosecond ;
01774 
01775     Second currentSecond ;
01776     Microsecond currentMicrosecond ;
01777 
01778     getPreciseTime( lastSecond, lastMicrosecond ) ;
01779     
01780     Ceylan::System::basicSleep( requestedSeconds ,
01781         requestedMicroseconds * 1000  ) ;
01782         
01783     getPreciseTime( currentSecond, currentMicrosecond ) ;
01784 
01785 
01786     
01787 
01788 
01789 
01790 
01791 
01792     return getDurationBetween( lastSecond, lastMicrosecond, 
01793         currentSecond, currentMicrosecond) ;
01794 
01795 }
01796 
01797 
01798 
01799 Microsecond Ceylan::System::getSchedulingGranularity() 
01800 {
01801 
01802     
01803 
01804 
01805 
01806 
01807 
01808 
01809 
01810 
01811 
01812 
01813     static Microsecond granularity = 0 ;
01814     
01815     
01816     if ( granularity != 0 )
01817         return granularity ;
01818     
01819 #if CEYLAN_DEBUG_SYSTEM
01820 
01821     bool logMeasures = true ;
01822     
01823     
01824 
01825 
01826 
01827 
01828      
01829     const string logFilename = "granularity.dat" ;
01830     
01831     File * logFile = 0 ;
01832     
01833     if ( logMeasures )
01834     {
01835     
01836         logFile = & File::Create( logFilename ) ;
01837         logFile->write( 
01838             "# This file records the requested sleep durations (first column)\n"
01839             "# and the corresponding actual sleep durations (second column).\n"
01840             "# The scheduling granularity can be usually guessed from it.\n"
01841             "# One may use gnuplot to analyze the result,\n"
01842             "# see test/system/testCeylanTime.cc.\n\n"   ) ;
01843             
01844         LogPlug::trace( "Ceylan::System::getSchedulingGranularity: "
01845             "computing granularity now, and logging the result in the '"
01846             + logFilename + "' file." ) ;
01847 
01848     }   
01849     else
01850     {
01851     
01852         LogPlug::trace( "Ceylan::System::getSchedulingGranularity: "
01853             "computing granularity now (no file logging requested)." ) ;
01854             
01855     }
01856         
01857 #endif // CEYLAN_DEBUG_SYSTEM
01858 
01859 
01860     
01861 
01862 
01863     
01864 
01865 
01866 
01867 
01868 
01869 
01870     Microsecond lastMeasuredDuration = 0 ;
01871     Microsecond currentMeasuredDuration = 0 ;
01872 
01873     
01874     const Microsecond durationStep = 250 ;
01875 
01882     Microsecond maximumPossibleDuration = 110000 ;
01883 
01884 
01885     
01886 
01887 
01888 
01889 
01890 
01891 
01892 
01893     Microsecond currentRequestedDuration = 0 ;
01894 
01895     while ( currentRequestedDuration < maximumPossibleDuration )
01896     {
01897 
01898         
01899         currentRequestedDuration += durationStep ;
01900         
01901         lastMeasuredDuration = currentMeasuredDuration ;
01902         
01903         currentMeasuredDuration =
01904             getActualDurationForSleep( currentRequestedDuration ) ;
01905 
01906 #if CEYLAN_DEBUG_SYSTEM
01907         logFile->write( Ceylan::toString( currentRequestedDuration ) 
01908             + " \t " + Ceylan::toString( currentMeasuredDuration ) 
01909             + " \n" ) ;
01910 #endif // CEYLAN_DEBUG_SYSTEM
01911 
01912 
01913         
01914         if ( currentMeasuredDuration == lastMeasuredDuration )
01915         {
01916             if ( currentMeasuredDuration == 0 )
01917                 continue ;
01918             else
01919                 break ;
01920         }
01921         
01922         
01923         
01924         if ( Ceylan::Maths::Abs( static_cast<Ceylan::Float32>(
01925                     currentMeasuredDuration - lastMeasuredDuration ) )
01926                 / ( currentMeasuredDuration + lastMeasuredDuration ) < 0.005f )
01927             break ;
01928 
01929 #if CEYLAN_DEBUG_SYSTEM
01930         LogPlug::debug( "Previous (" + Ceylan::toString( lastMeasuredDuration )
01931             + ") and current (" + Ceylan::toString( currentMeasuredDuration )
01932             + ") measured durations are not deemed relatively equal, "
01933             " continuing." ) ;
01934 #endif // CEYLAN_DEBUG_SYSTEM
01935 
01936     }
01937 
01938 
01939     
01940 
01941 
01942 
01943 
01944     Microsecond testDuration = 900 ;
01945 
01946 
01947     
01948     if ( currentRequestedDuration == maximumPossibleDuration )
01949     {
01950     
01951         currentMeasuredDuration = getActualDurationForSleep( testDuration ) ;
01952         LogPlug::warning( "Ceylan::System::getSchedulingGranularity: "
01953             "failed to guess actual time slice duration, starting with "
01954             + Ceylan::toString( currentMeasuredDuration )
01955             + " microseconds as an experimental basis." ) ;
01956             
01957     }
01958     else
01959     {
01960 
01961 #if CEYLAN_DEBUG_SYSTEM
01962         
01963         LogPlug::debug( "Relative equality has been found between previous ("
01964             + Ceylan::toString( lastMeasuredDuration )
01965             + ") and current (" + Ceylan::toString( currentMeasuredDuration )
01966             + ") measured durations, research was stopped." ) ;
01967 #endif // CEYLAN_DEBUG_SYSTEM
01968 
01969     }
01970 
01971 
01972     
01973 
01974 
01975 
01976 
01977     const Ceylan::Uint8 sampleCount = 20 ;
01978 
01979     
01980     granularity = 0 ;
01981 
01982     for ( Ceylan::Uint8 i = 0; i < sampleCount; i++ )
01983     {
01984 
01985         
01986 
01987 
01988 
01989 
01990 
01991 
01992         granularity += getActualDurationForSleep(
01993             static_cast<Microsecond>( 0.4 * currentMeasuredDuration ) ) ;
01994 
01995     }
01996 
01997     granularity = static_cast<Microsecond>( 
01998         ( granularity * 1.0f ) / sampleCount ) ;
01999 
02000     
02001 
02002 
02003 
02004 
02005 
02006 
02007 
02008 
02009 
02010 
02011 
02012 
02013 
02014 
02015 
02016         
02017      
02018 #if CEYLAN_DEBUG_SYSTEM
02019     LogPlug::debug( "Final returned scheduling granularity is "
02020         + Ceylan::toString( granularity ) + " microseconds." ) ;
02021         
02022     if ( logFile != 0 )
02023     {
02024         logFile->close() ;
02025         delete logFile ;
02026         logFile = 0 ;
02027     }   
02028 #endif // CEYLAN_DEBUG_SYSTEM
02029 
02030     return granularity ;
02031 
02032 }
02033 
02034 
02035 
02036 bool Ceylan::System::setLegacyStreamSynchronization( bool synchronized )    
02037 {
02038 
02039     
02040 
02041 
02042 
02043 
02044 
02045 
02046 
02047 
02048     
02049     return std::ios::sync_with_stdio( synchronized ) ;
02050 
02051 }
02052