stime.cpp

00001 /*<std-header orig-src='shore'>
00002 
00003  $Id: stime.cpp,v 1.40 2010/12/08 17:37:37 nhall Exp $
00004 
00005 SHORE -- Scalable Heterogeneous Object REpository
00006 
00007 Copyright (c) 1994-99 Computer Sciences Department, University of
00008                       Wisconsin -- Madison
00009 All Rights Reserved.
00010 
00011 Permission to use, copy, modify and distribute this software and its
00012 documentation is hereby granted, provided that both the copyright
00013 notice and this permission notice appear in all copies of the
00014 software, derivative works or modified versions, and any portions
00015 thereof, and that both notices appear in supporting documentation.
00016 
00017 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00018 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00019 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00020 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00021 
00022 This software was developed with support by the Advanced Research
00023 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00024 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00025 Further funding for this work was provided by DARPA through
00026 Rome Research Laboratory Contract No. F30602-97-2-0247.
00027 
00028 */
00029 
00030 #include "w_defines.h"
00031 
00032 /*  -- do not edit anything above this line --   </std-header>*/
00033 
00034 /**\cond skip */
00035 #include <ctime>
00036 #include <cstring>
00037 #include <w_base.h>
00038 #include <stime.h>
00039 #include <w_stream.h>
00040 #include <climits>
00041 
00042 /*
00043    All this magic is to allow either timevals or timespecs
00044    to be used without code change.  It's disgusting, but it
00045    avoid templates.  Templates are evil.
00046 
00047    st_tod    == time of day part of the time
00048    st_hires    == "higher resolution" part of the time
00049    HR_SECOND    == high-resolution units in a second
00050  */  
00051 
00052 #define    NS_SECOND    1000000000    /* nanoseconds in a second */
00053 #define    US_SECOND    1000000    /* microseconds in a second */
00054 #define    MS_SECOND    1000    /* millisecs in a second */
00055 
00056 #ifdef USE_POSIX_TIME
00057 typedef    struct timespec _stime_t;
00058 #define    st_tod        tv_sec
00059 #define    st_hires    tv_nsec
00060 #define    HR_SECOND    NS_SECOND
00061 #else
00062 typedef struct timeval    _stime_t;
00063 #define    st_tod        tv_sec
00064 #define    st_hires    tv_usec
00065 #define    HR_SECOND    US_SECOND
00066 #endif
00067 
00068 #define    HR_MAX        (HR_SECOND-1)
00069 
00070 
00071 
00072 
00073 /*
00074    XXX problems
00075 
00076    Rounding policy is currently ill-defined.  I need to choose one,
00077    and make sure the various input and output (to/from other type)
00078    operators implement it uniformly.  XXX This really needs to be
00079    fixed.
00080  */
00081 
00082 /* Internal constructor, exposes implementation */
00083 stime_t::stime_t(time_t tod, long hires)
00084 {
00085     _time.st_tod = tod;
00086     _time.st_hires = hires;
00087 
00088     normalize();
00089 }
00090 
00091 
00092 stime_t::stime_t(int secs)
00093 {
00094     _time.st_tod = secs;
00095     _time.st_hires = 0;
00096 
00097     /* the conversion automagically normalizes */
00098 }
00099 
00100 stime_t::stime_t(long secs)
00101 {
00102     _time.st_tod = secs;
00103     _time.st_hires = 0;
00104 
00105     /* the conversion automagically normalizes */
00106 }
00107 
00108 
00109 stime_t::stime_t(double secs)
00110 {
00111     _time.st_tod = (long) secs;
00112     _time.st_hires = (long) ((secs - _time.st_tod) * HR_SECOND);
00113 
00114     /* the conversion automagically normalizes */
00115 }
00116 
00117 
00118 #ifdef USE_POSIX_TIME
00119 stime_t::stime_t(const struct timespec &tv)
00120 {
00121     _time.st_tod = tv.tv_sec;
00122     _time.st_hires = tv.tv_nsec * (HR_SECOND / NS_SECOND);
00123 
00124     normalize();
00125 }
00126 #endif
00127 
00128 stime_t::stime_t(const struct timeval &tv)
00129 {
00130     _time.st_tod = tv.tv_sec;
00131     _time.st_hires = tv.tv_usec * (HR_SECOND / US_SECOND);
00132 
00133     normalize();
00134 }
00135 
00136 
00137 bool    stime_t::operator==(const stime_t &r) const
00138 {
00139     return _time.st_tod == r._time.st_tod &&
00140         _time.st_hires == r._time.st_hires;
00141 }
00142 
00143 
00144 bool    stime_t::operator<(const stime_t &r) const
00145 {
00146     if (_time.st_tod == r._time.st_tod)
00147         return _time.st_hires < r._time.st_hires;
00148     return _time.st_tod < r._time.st_tod;
00149 }
00150 
00151 
00152 bool    stime_t::operator<=(const stime_t &r) const
00153 {
00154     return *this == r  ||  *this < r;
00155 }
00156 
00157 
00158 static inline int sign(const int i)
00159 {
00160     return i > 0 ? 1 : i < 0 ? -1 : 0;
00161     
00162 }
00163 
00164 /* Put a stime into normal form, where the HIRES part
00165    will contain less than a TODs worth of HIRES time.
00166    Also, the signs of the TOD and HIRES parts should
00167    agree (unless TOD==0) */
00168 
00169 void stime_t::signs()
00170 {
00171     if (_time.st_tod  &&  _time.st_hires
00172         && sign(_time.st_tod) != sign(_time.st_hires)) {
00173 
00174         if (sign(_time.st_tod) == 1) {
00175             _time.st_tod--;
00176             _time.st_hires += HR_SECOND;
00177         }
00178         else {
00179             _time.st_tod++;
00180             _time.st_hires -= HR_SECOND;
00181         }
00182     }
00183 }
00184 
00185 /* off-by one */
00186 void stime_t::_normalize()
00187 {
00188     if (abs(_time.st_hires) >= HR_SECOND) {
00189         _time.st_tod += sign(_time.st_hires);
00190         _time.st_hires -= sign(_time.st_hires) * HR_SECOND;
00191     }
00192     signs();
00193 }
00194    
00195 
00196 /* something that could be completely wacked out */
00197 void stime_t::normalize()
00198 {
00199     int    factor;
00200 
00201     factor = _time.st_hires / HR_SECOND;
00202     if (factor) {
00203         _time.st_tod += factor;
00204         _time.st_hires -= HR_SECOND * factor;
00205     }
00206 
00207     signs();
00208 }
00209 
00210 
00211 stime_t    stime_t::operator-() const
00212 {
00213     stime_t    result;
00214 
00215     result._time.st_tod = -_time.st_tod;
00216     result._time.st_hires = -_time.st_hires;
00217 
00218     return result;
00219 }
00220 
00221 
00222 stime_t    stime_t::operator+(const stime_t &r) const
00223 {
00224     stime_t    result;
00225 
00226     result._time.st_tod  = _time.st_tod  + r._time.st_tod;
00227     result._time.st_hires = _time.st_hires + r._time.st_hires;
00228 
00229     result._normalize();
00230 
00231     return result;
00232 }
00233 
00234 
00235 stime_t    stime_t::operator-(const stime_t &r) const
00236 {
00237     return *this + -r;
00238 }
00239 
00240 
00241 stime_t stime_t::operator*(const int factor) const
00242 {
00243     stime_t    result;
00244 
00245     result._time.st_tod = _time.st_tod * factor;
00246     result._time.st_hires = _time.st_hires * factor;
00247     result.normalize();
00248 
00249     return result;
00250 }
00251 
00252 /* XXX
00253    Float scaling is stupid for the moment.  It doesn't need
00254    to use double arithmetic, instead it should use an
00255    intermediate normalization step which moves
00256    lost TOD units into the HIRES range.
00257 
00258    The double stuff at least makes it seem to work right.
00259  */  
00260 
00261 
00262 stime_t stime_t::operator/(const int factor) const
00263 {
00264     return *this / (double)factor;
00265 }
00266 
00267 
00268 stime_t    stime_t::operator*(const double factor) const
00269 {
00270     double d = *this;
00271     d *= factor;
00272     stime_t result(d); 
00273     result.normalize();
00274 
00275     return result;
00276 }
00277 
00278 
00279 stime_t    stime_t::operator/(const double factor) const
00280 {
00281     return *this * (1.0 / factor);
00282 }
00283 
00284 
00285 /* The operator X and operator X= can be written in terms of each other */
00286 stime_t &stime_t::operator+=(const stime_t &r)
00287 {
00288     _time.st_tod  += r._time.st_tod;
00289     _time.st_hires += r._time.st_hires;
00290 
00291     _normalize();
00292     
00293     return *this;
00294 }
00295 
00296 
00297 stime_t &stime_t::operator-=(const stime_t &r)
00298 {
00299     _time.st_tod  -= r._time.st_tod;
00300     _time.st_hires -= r._time.st_hires;
00301 
00302     _normalize();
00303     
00304     return *this;
00305 }
00306 
00307 
00308 stime_t::operator double() const
00309 {
00310     return _time.st_tod + _time.st_hires / (double) HR_SECOND;
00311 }
00312 
00313 
00314 stime_t::operator float() const
00315 {
00316     double res = (double) *this;
00317     return (float)res;
00318 //    return _time.st_tod + _time.st_hires / (float) HR_SECOND;
00319 }
00320 
00321 
00322 
00323 
00324 /* XXX do we want this conversion even if we are using timeval
00325    implementation on systems that have timespec? */
00326 #ifdef USE_POSIX_TIME
00327 stime_t::operator struct timespec() const
00328 {
00329     struct    timespec tv;
00330     tv.tv_sec = _time.st_tod;
00331     tv.tv_nsec = _time.st_hires;
00332     return tv;
00333 }
00334 #endif
00335 
00336 // for type conversion
00337 stime_t::operator struct timeval() const
00338 {
00339     struct    timeval tv;
00340     tv.tv_sec = _time.st_tod;
00341     /* This conversion may prevent overflow which may
00342        occurs with some values on some systems. */
00343     tv.tv_usec = _time.st_hires / (HR_SECOND / US_SECOND);
00344     return tv;
00345 }
00346 
00347 
00348 void    stime_t::gettime()
00349 {
00350     int    kr;
00351 #ifdef USE_POSIX_TIME
00352     kr = clock_gettime(CLOCK_REALTIME, &_time);
00353 #else
00354     kr = gettimeofday(&_time, 0);
00355 #endif
00356     if (kr == -1)
00357         W_FATAL(fcOS);
00358 }
00359 
00360 
00361 ostream    &stime_t::print(ostream &s) const
00362 {
00363     ctime(s);
00364 
00365     if (_time.st_hires) {
00366         stime_t    tod(_time.st_tod, 0);
00367 
00368         s << " and " << sinterval_t(*this - tod);
00369     }
00370 
00371     return s;
00372 }
00373 
00374 
00375 ostream &stime_t::ctime(ostream &s) const
00376 {
00377     /* the second field of the time structs should be a time_t */
00378     time_t    kludge = _time.st_tod;
00379     const   int buflen(26); 
00380     char    buf[buflen];    /* XXX well known magic number */
00381 
00382     /// See Makefile.generic for note about this
00383 #ifdef _POSIX_PTHREAD_SEMANTICS 
00384     char    *when = ctime_r(&kludge, buf);
00385 #elif defined(SOLARIS2)
00386     char    *when = ctime_r(&kludge, buf, buflen);
00387 #else
00388     char    *when = ctime_r(&kludge, buf);
00389 #endif
00390 
00391     /* chop the newline */
00392     char *nl = strchr(when, '\n');
00393     if (nl)
00394         *nl = '\0';
00395 
00396     return s << when;
00397 }
00398 
00399 
00400 static void factor_print(ostream &s, long what)
00401 {
00402     struct {
00403         const char    *label;
00404         int        factor;
00405     } factors[] = {
00406         {"%02d:", 60*60},
00407         {"%02d:", 60},
00408         {0, 0}
00409     }, *f = factors;
00410     long    mine;
00411     bool    printed = false;
00412     bool    negative = what < 0;
00413 
00414     if (negative) {
00415         s << '-';
00416         what = -what;
00417     }
00418 
00419     for (f = factors; f->label; f++) {
00420         mine = what / f->factor;
00421         what = what % f->factor;
00422         if (mine || printed) {
00423             W_FORM(s)(f->label, mine);
00424             printed = true;
00425         }
00426     }
00427 
00428     /* always print a seconds field */
00429     W_FORM(s)(printed ? "%02d" : "%d", what);
00430 }
00431 
00432 
00433 ostream    &sinterval_t::print(ostream &s) const
00434 {
00435     factor_print(s, _time.st_tod);
00436 
00437     if (_time.st_hires) {
00438 #ifdef USE_POSIX_TIME
00439         W_FORM(s)(".%09ld", _time.st_hires);
00440 #else
00441         W_FORM(s)(".%06ld", _time.st_hires);
00442 #endif
00443     }
00444 
00445     return s;
00446 }
00447 
00448 
00449 ostream &operator<<(ostream &s, const stime_t &t)
00450 {
00451     return t.print(s);
00452 }
00453 
00454 
00455 ostream &operator<<(ostream &s, const sinterval_t &t)
00456 {
00457     return t.print(s);
00458 }
00459 
00460 
00461 /* Input Conversion operators */
00462 
00463 static inline void from_linear(int sec, int xsec,
00464                 int linear_secs, _stime_t &_time)
00465 {
00466     _time.st_tod = sec + xsec / linear_secs;
00467     xsec = xsec % linear_secs;
00468     if (linear_secs > HR_SECOND)
00469         _time.st_hires = xsec / (linear_secs / HR_SECOND);
00470     else
00471         _time.st_hires = xsec * (HR_SECOND / linear_secs);
00472 }
00473 
00474 
00475 stime_t stime_t::sec(int sec)
00476 {
00477     stime_t    r;
00478 
00479     r._time.st_tod = sec;
00480     r._time.st_hires = 0;
00481 
00482     return r;
00483 }
00484 
00485 
00486 stime_t    stime_t::msec(int ms, int sec)
00487 {
00488     stime_t    r;
00489 
00490     from_linear(sec, ms, MS_SECOND, r._time);
00491     /* conversion normalizes */
00492 
00493     return r;
00494 }
00495 
00496     
00497 stime_t    stime_t::usec(int us, int sec)
00498 {
00499     stime_t    r;
00500 
00501     from_linear(sec, us, US_SECOND, r._time);
00502     /* conversion normalizes */
00503 
00504     return r;
00505 }
00506 
00507 
00508 stime_t    stime_t::nsec(int ns, int sec)
00509 {
00510     stime_t    r;
00511 
00512     from_linear(sec, ns, NS_SECOND, r._time);
00513     /* conversion normalizes */
00514 
00515     return r;
00516 }
00517 
00518 
00519 stime_t    stime_t::now()
00520 {
00521     stime_t    now;
00522     now.gettime();
00523 
00524     return now;
00525 }
00526 
00527 
00528 /* More conversion operators */
00529 /* For now, only the seconds conversion does rounding */ 
00530 
00531 /* roundup #seconds if hr_seconds >= this value */
00532 #define    HR_ROUNDUP    (HR_SECOND / 2)
00533 
00534 static    inline long to_linear(const _stime_t &_time, const int linear_secs)
00535 {
00536     long    result;
00537     int    factor;
00538 
00539     result = _time.st_tod * linear_secs;
00540 
00541     if (linear_secs > HR_SECOND) {
00542         factor = linear_secs / HR_SECOND;
00543         result += _time.st_hires * factor;
00544     }
00545     else {
00546         factor = HR_SECOND / linear_secs;
00547         result += _time.st_hires / factor;
00548     }
00549 
00550     return result;
00551 }
00552 
00553 
00554 long    stime_t::secs() const
00555 {
00556     long    result;
00557 
00558     result = _time.st_tod;
00559     if (_time.st_hires >= HR_ROUNDUP)
00560         result++;
00561 
00562     return result;
00563 }
00564 
00565 long    stime_t::msecs() const
00566 {
00567     return to_linear(_time, MS_SECOND);
00568 }
00569 
00570 long    stime_t::usecs() const
00571 {
00572     return to_linear(_time, US_SECOND);
00573 }
00574 
00575 long    stime_t::nsecs() const
00576 {
00577     return to_linear(_time, NS_SECOND);
00578 }
00579 
00580 /**\endcond skip */

Generated on Thu Dec 9 08:42:27 2010 for Shore Storage Manager by  doxygen 1.4.7