00001 
00032 #include "linden_common.h"
00033 
00034 #include "lltimer.h"
00035 
00036 #include "u64.h"
00037 
00038 #if LL_WINDOWS
00039 #       define WIN32_LEAN_AND_MEAN
00040 #       include <winsock2.h>
00041 #       include <windows.h>
00042 #elif LL_LINUX || LL_SOLARIS
00043 #       include <sys/time.h>
00044 #       include <sched.h>
00045 #elif LL_DARWIN
00046 #       include <sys/time.h>
00047 #else 
00048 #       error "architecture not supported"
00049 #endif
00050 
00051 
00052 
00053 
00054 
00055 const U32 SEC_PER_DAY = 86400;
00056 const F64 SEC_TO_MICROSEC = 1000000.f;
00057 const U64 SEC_TO_MICROSEC_U64 = 1000000;
00058 const F64 USEC_TO_SEC_F64 = 0.000001;
00059 
00060 
00061 
00062 
00063 
00064 
00065 S32 gUTCOffset = 0; 
00066 LLTimer* LLTimer::sTimer = NULL;
00067 
00068 F64 gClockFrequency = 0.0;
00069 F64 gClockFrequencyInv = 0.0;
00070 F64 gClocksToMicroseconds = 0.0;
00071 U64 gTotalTimeClockCount = 0;
00072 U64 gLastTotalTimeClockCount = 0;
00073 
00074 
00075 
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 #if LL_WINDOWS
00084 void ms_sleep(long ms)
00085 {
00086         Sleep((U32)ms);
00087 }
00088 
00089 void llyield()
00090 {
00091         SleepEx(0, TRUE); 
00092 }
00093 #elif LL_LINUX || LL_SOLARIS
00094 void ms_sleep(long ms)
00095 {
00096         struct timespec t;
00097         t.tv_sec = ms / 1000;
00098         t.tv_nsec = (ms % 1000) * 1000000l;
00099         nanosleep(&t, NULL);
00100 }
00101 
00102 void llyield()
00103 {
00104         sched_yield();
00105 }
00106 #elif LL_DARWIN
00107 void ms_sleep(long ms)
00108 {
00109         struct timespec t;
00110         t.tv_sec = ms / 1000;
00111         t.tv_nsec = (ms % 1000) * 1000000l;
00112         nanosleep(&t, NULL);
00113 }
00114 
00115 void llyield()
00116 {
00117 
00118 }
00119 #else 
00120 # error "architecture not supported"
00121 #endif
00122 
00123 
00124 
00125 
00126 
00127 #if LL_WINDOWS
00128 U64 get_clock_count()
00129 {
00130         static bool firstTime = true;
00131         static U64 offset;
00132                 
00133 
00134         
00135         LARGE_INTEGER clock_count;
00136         QueryPerformanceCounter(&clock_count);
00137         if (firstTime) {
00138                 offset = clock_count.QuadPart;
00139                 firstTime = false;
00140         }
00141         return clock_count.QuadPart - offset;
00142 }
00143 
00144 F64 calc_clock_frequency(U32 uiMeasureMSecs)
00145 {
00146         __int64 freq;
00147         QueryPerformanceFrequency((LARGE_INTEGER *) &freq);
00148         return (F64)freq;
00149 }
00150 #endif // LL_WINDOWS
00151 
00152 
00153 #if LL_LINUX || LL_DARWIN || LL_SOLARIS
00154 
00155 F64 calc_clock_frequency(unsigned int uiMeasureMSecs)
00156 {
00157         return 1000000.0; 
00158 }
00159 
00160 U64 get_clock_count()
00161 {
00162         
00163         struct timeval tv;
00164         gettimeofday(&tv, NULL);
00165         return tv.tv_sec*SEC_TO_MICROSEC_U64 + tv.tv_usec;
00166 }
00167 #endif
00168 
00169 
00170 void update_clock_frequencies()
00171 {
00172         gClockFrequency = calc_clock_frequency(50U);
00173         gClockFrequencyInv = 1.0/gClockFrequency;
00174         gClocksToMicroseconds = gClockFrequencyInv * SEC_TO_MICROSEC;
00175 }
00176 
00177 
00179 
00180 
00181 
00182 U64 totalTime()
00183 {
00184         U64 current_clock_count = get_clock_count();
00185         if (!gTotalTimeClockCount)
00186         {
00187                 update_clock_frequencies();
00188                 gTotalTimeClockCount = current_clock_count;
00189 
00190 #if LL_WINDOWS
00191                 
00192                 
00193                 
00194 
00195                 gTotalTimeClockCount = (U64)(time(NULL) * gClockFrequency);
00196 #endif
00197 
00198                 
00199                 gLastTotalTimeClockCount = current_clock_count;
00200         }
00201         else
00202         {
00203                 if (current_clock_count >= gLastTotalTimeClockCount)
00204                 {
00205                         
00206                         gTotalTimeClockCount += current_clock_count - gLastTotalTimeClockCount;
00207                 }
00208                 else
00209                 {
00210                         
00211                         gTotalTimeClockCount += (0xFFFFFFFFFFFFFFFFULL - gLastTotalTimeClockCount) + current_clock_count;
00212                 }
00213 
00214                 
00215                 gLastTotalTimeClockCount = current_clock_count;
00216         }
00217 
00218         
00219         return (U64)(gTotalTimeClockCount*gClocksToMicroseconds);
00220 }
00221 
00222 
00224 
00225 LLTimer::LLTimer()
00226 {
00227         if (!gClockFrequency)
00228         {
00229                 update_clock_frequencies();
00230         }
00231 
00232         mStarted = TRUE;
00233         reset();
00234 }
00235 
00236 LLTimer::~LLTimer()
00237 {
00238 }
00239 
00240 
00241 U64 LLTimer::getTotalTime()
00242 {
00243         
00244         return totalTime();
00245 }       
00246 
00247 
00248 F64 LLTimer::getTotalSeconds()
00249 {
00250         return U64_to_F64(getTotalTime()) * USEC_TO_SEC_F64;
00251 }
00252 
00253 void LLTimer::reset()
00254 {
00255         mLastClockCount = get_clock_count();
00256         mExpirationTicks = 0;
00257 }
00258 
00260 
00261 U64 LLTimer::getCurrentClockCount()
00262 {
00263         return get_clock_count();
00264 }
00265 
00267 
00268 void LLTimer::setLastClockCount(U64 current_count)
00269 {
00270         mLastClockCount = current_count;
00271 }
00272 
00274 
00275 static
00276 U64 getElapsedTimeAndUpdate(U64& lastClockCount)
00277 {
00278         U64 current_clock_count = get_clock_count();
00279         U64 result;
00280 
00281         if (current_clock_count >= lastClockCount)
00282         {
00283                 result = current_clock_count - lastClockCount;
00284         }
00285         else
00286         {
00287                 
00288                 result = 0;
00289         }
00290 
00291         lastClockCount = current_clock_count;
00292 
00293         return result;
00294 }
00295 
00296 
00297 F64 LLTimer::getElapsedTimeF64() const
00298 {
00299         U64 last = mLastClockCount;
00300         return (F64)getElapsedTimeAndUpdate(last) * gClockFrequencyInv;
00301 }
00302 
00303 F32 LLTimer::getElapsedTimeF32() const
00304 {
00305         return (F32)getElapsedTimeF64();
00306 }
00307 
00308 F64 LLTimer::getElapsedTimeAndResetF64()
00309 {
00310         return (F64)getElapsedTimeAndUpdate(mLastClockCount) * gClockFrequencyInv;
00311 }
00312 
00313 F32 LLTimer::getElapsedTimeAndResetF32()
00314 {
00315         return (F32)getElapsedTimeAndResetF64();
00316 }
00317 
00319 
00320 void  LLTimer::setTimerExpirySec(F32 expiration)
00321 {
00322         mExpirationTicks = get_clock_count()
00323                 + (U64)((F32)(expiration * gClockFrequency));
00324 }
00325 
00326 F32 LLTimer::getRemainingTimeF32()
00327 {
00328         U64 cur_ticks = get_clock_count();
00329         if (cur_ticks > mExpirationTicks)
00330         {
00331                 return 0.0f;
00332         }
00333         return F32((mExpirationTicks - cur_ticks) * gClockFrequencyInv);
00334 }
00335 
00336 
00337 BOOL  LLTimer::checkExpirationAndReset(F32 expiration)
00338 {
00339         U64 cur_ticks = get_clock_count();
00340         if (cur_ticks < mExpirationTicks)
00341         {
00342                 return FALSE;
00343         }
00344 
00345         mExpirationTicks = cur_ticks
00346                 + (U64)((F32)(expiration * gClockFrequency));
00347         return TRUE;
00348 }
00349 
00350 
00351 BOOL  LLTimer::hasExpired()
00352 {
00353         return (get_clock_count() >= mExpirationTicks)
00354                 ? TRUE : FALSE;
00355 }
00356 
00358 
00359 BOOL LLTimer::knownBadTimer()
00360 {
00361         BOOL failed = FALSE;
00362 
00363 #if LL_WINDOWS
00364         WCHAR bad_pci_list[][10] = {L"1039:0530",
00365                                                         L"1039:0620",
00366                                                             L"10B9:0533",
00367                                                             L"10B9:1533",
00368                                                             L"1106:0596",
00369                                                             L"1106:0686",
00370                                                             L"1166:004F",
00371                                                             L"1166:0050",
00372                                                             L"8086:7110",
00373                                                             L"\0"
00374         };
00375 
00376         HKEY hKey = NULL;
00377         LONG nResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"SYSTEM\\CurrentControlSet\\Enum\\PCI", 0,
00378                                                                   KEY_EXECUTE | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey);
00379         
00380         WCHAR name[1024];
00381         DWORD name_len = 1024;
00382         FILETIME scrap;
00383 
00384         S32 key_num = 0;
00385         WCHAR pci_id[10];
00386 
00387         wcscpy(pci_id, L"0000:0000");    
00388 
00389         while (nResult == ERROR_SUCCESS)
00390         {
00391                 nResult = ::RegEnumKeyEx(hKey, key_num++, name, &name_len, NULL, NULL, NULL, &scrap);
00392 
00393                 if (nResult == ERROR_SUCCESS)
00394                 {
00395                         memcpy(&pci_id[0],&name[4],4);          
00396                         memcpy(&pci_id[5],&name[13],4);         
00397 
00398                         for (S32 check = 0; bad_pci_list[check][0]; check++)
00399                         {
00400                                 if (!wcscmp(pci_id, bad_pci_list[check]))
00401                                 {
00402 
00403                                         failed = TRUE;
00404                                         break;
00405                                 }
00406                         }
00407 
00408                         name_len = 1024;
00409                 }
00410         }
00411 #endif
00412         return(failed);
00413 }
00414 
00416 
00417 
00418 
00420 
00421 U32 time_corrected()
00422 {
00423         U32 corrected_time = (U32)time(NULL) + gUTCOffset;
00424         return corrected_time;
00425 }
00426 
00427 
00428 
00429 
00430 BOOL is_daylight_savings()
00431 {
00432         time_t now = time(NULL);
00433 
00434         
00435         struct tm* internal_time = localtime(&now);
00436 
00437         
00438         
00439         
00440         return (internal_time->tm_isdst > 0);
00441 }
00442 
00443 
00444 struct tm* utc_to_pacific_time(S32 utc_time, BOOL pacific_daylight_time)
00445 {
00446         time_t unix_time = (time_t)utc_time;
00447 
00448         S32 pacific_offset_hours;
00449         if (pacific_daylight_time)
00450         {
00451                 pacific_offset_hours = -7;
00452         }
00453         else
00454         {
00455                 pacific_offset_hours = -8;
00456         }
00457 
00458         
00459         
00460         
00461         unix_time += pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN;
00462  
00463         
00464         struct tm* internal_time = gmtime(&unix_time);
00465 
00466         
00467 
00468 
00469 
00470 
00471 
00472 
00473 
00474         return internal_time;
00475 }
00476 
00477 
00478 void microsecondsToTimecodeString(U64 current_time, char *tcstring)
00479 {
00480         U64 hours;
00481         U64 minutes;
00482         U64 seconds;
00483         U64 frames;
00484         U64 subframes;
00485 
00486         hours = current_time / (U64)3600000000ul;
00487         minutes = current_time / (U64)60000000;
00488         minutes %= 60;
00489         seconds = current_time / (U64)1000000;
00490         seconds %= 60;
00491         frames = current_time / (U64)41667;
00492         frames %= 24;
00493         subframes = current_time / (U64)42;
00494         subframes %= 100;
00495 
00496         sprintf(tcstring,"%3.3d:%2.2d:%2.2d:%2.2d.%2.2d",(int)hours,(int)minutes,(int)seconds,(int)frames,(int)subframes);              
00497 }
00498 
00499 
00500 void secondsToTimecodeString(F32 current_time, char *tcstring)
00501 {
00502         microsecondsToTimecodeString((U64)((F64)(SEC_TO_MICROSEC*current_time)), tcstring);
00503 }
00504 
00505 
00507 
00508 
00509 
00511 
00512 std::list<LLEventTimer*> LLEventTimer::sActiveList;
00513 
00514 LLEventTimer::LLEventTimer(F32 period)
00515 : mEventTimer()
00516 {
00517         mPeriod = period;
00518         sActiveList.push_back(this);
00519 }
00520 
00521 LLEventTimer::~LLEventTimer() 
00522 {
00523         sActiveList.remove(this);
00524 }
00525 
00526 void LLEventTimer::updateClass() 
00527 {
00528         std::list<LLEventTimer*> completed_timers;
00529         for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); ) 
00530         {
00531                 LLEventTimer* timer = *iter++;
00532                 F32 et = timer->mEventTimer.getElapsedTimeF32();
00533                 if (et > timer->mPeriod) {
00534                         timer->mEventTimer.reset();
00535                         if ( timer->tick() )
00536                         {
00537                                 completed_timers.push_back( timer );
00538                         }
00539                 }
00540         }
00541 
00542         if ( completed_timers.size() > 0 )
00543         {
00544                 for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin(); 
00545                          completed_iter != completed_timers.end(); 
00546                          completed_iter++ ) 
00547                 {
00548                         delete *completed_iter;
00549                 }
00550         }
00551 }
00552