> From: Charles Lepple [mailto:[email protected]] > On Oct 3, 2012, at 8:41 AM, <[email protected]> wrote: > > > I see, however I think that it's actually better to do the encapsulation. > > Justification: > > > > 1/ We need to alter widespread code, anyway (I mean if we used > > clock_gettime already and just needed to implement it for platforms > > that don't have it, using the autoconf macro would be nice and fast > > way to do it, but since we don't, well, see point 2 and 3) > > It would be nice if we could use the autoconf macro, but the problem is that > we > are not guaranteed to have the monotonic clock type just because we have > clock_gettime().
Exactly. My idea is to provide an interface that is capable of falling-back to RTC if monotonic isn't available --- without the need of checking the clock_gettime return value every time it's used. Moreover, I agree with Arnaud that the clock_difftime function should be able to accept NULL argument (either 1st or 2nd) to simplify the typical usage (i.e. comparison with current time it'll get on its own). To be able to do that, I need my own type (so that I can store the clock type) and therefore I need a new interface (ideally opaque). That's about it, it's not too complicated :-) > > But of course, I can just implement clock_gettime; however, I already > > have the new module written, so I'd rather continue in this direction, > > if you don't insist on it... > > Note that I'm still on my branch so no harm done. ;-) > > Your original timer abstraction sounded like it might need a lot of test code > to > go along with it. Please keep it simple, only implementing the interfaces > that are > necessary for now. I don't recall the state of unit test code in the NUT tree > (there was a branch at one point), but this might be hard to debug if we don't > have some simple test harnesses. After all, rolling the clock back (which is > my > understanding of what the monotonic clock interface guards against) is > usually a > privileged operation. The interface (currently implemented) is attached; it's all wrapped around portable implementation of nut_clock_gettime and matching nut_clock_difftime, the rest are really straightforward wrappers/ macra. Please let me know if you find it unfeasible. > Since you're working for Eaton, Arnaud has the final word here, but speaking > as > someone who plans to review the code, this sounds to me like it is getting > overly > complicated. The source code (implementation) has 168 lines, now, of which cca 60 are the wrappers. Of course, only POSIX CLOCK_REALTIME, CLOCK_MONOTONIC, Linux-specific CLOCK_MONOTONIC_RAW and time_t fallback are supported, now. The idea is to add also mach_time.h implementation for Mac OSX, perhaps use of gethrtime on Solaris for the monotonic clock etc... vaclav ----------------------------- Eaton Elektrotechnika s.r.o. ~ S�dlo spolecnosti, jak je zaps�no v rejstr�ku: Kom�rovsk� 2406, Praha 9 - Horn� Pocernice, 193 00, Cesk� Republika ~ Jm�no, m�sto, kde byla spolecnost zaregistrov�na: Praha ~ Identifikacn� c�slo (ICO): 498 11 894 -----------------------------
#ifndef nut_common_clock_h #define nut_common_clock_h /** * \brief Portable clock * * The module provides portable clock implementation. * * The main reason of creation of this module is to provide * possibility of usage of monotonic clock (if available * on the platform). * Since different platforms use different implementations, * the unification and encapsulation is provided by this * module. * * \author Vaclav Krpec <[email protected]> * \date 2012/10/02 */ #include <unistd.h> #include <time.h> /* POSIX clock (clock_*time functions) available */ #if (defined_POSIX_TIMERS && 0 < _POSIX_TIMERS) #define USE_POSIX_CLOCK /* RTC must be always available for POSIX clock implementation */ #define USE_POSIX_REALTIME_CLOCK /* Use raw monotonic clock if available (recent Linux) */ #if (defined CLOCK_MONOTONIC_RAW) #define USE_LINUX_RAW_MONOTONIC_CLOCK /* Use POSIX monotonic clock */ #elif (defined _POSIX_MONOTONIC_CLOCK) #define USE_POSIX_MONOTONIC_CLOCK #endif /* end of #ifdef CLOCK_MONOTONIC_RAW */ /* ADD OTHER IMPLEMENTATION-SPECIFIC CHECKS & DEFINITIONS, HERE */ /* #elif () ... */ /* Good old C89 time_t fallback */ #else #define USE_TIME_T_CLOCK #define USE_TIME_T_REALTIME_CLOCK #define USE_TIME_T_MONOTONIC_CLOCK #endif /* end of impl-specific checks & definitions */ /** Clock mode */ typedef enum { RTC, /** Real-time clock (best implementation available) */ MONOTONIC_PREF, /** Monotonic clock (preferred, RTC fallback accepted) */ MONOTONIC, /** Monotonic clock (enforced) */ } nut_clock_mode_t; /* end of typedef enum */ typedef struct nut_time nut_time_t; /** Time specification */ /** Implementation of time specification */ struct nut_time { nut_clock_mode_t mode; /** Clock mode */ #if defined USE_POSIX_CLOCK struct timespec impl; /** POSIX implementation */ #elif defined USE_TIME_T_CLOCK time_t impl; /** Fallback implementation */ #endif }; /* end of struct time */ /** * \brief Get time stamp * * The macro expands to \ref nut_clock_gettimex call * using the \c MONOTONIC_PREF clock mode to request * current time stamp (ideally from monotonic clock). * Typical usage is for measuring time that passed since * a certain moment (see \ref nut_clock_sec_since). * * \brief tm Time stamp */ #define nut_clock_timestamp(tm) nut_clock_gettimex(MONOTONIC_PREF, (tm)) /** * \brief Get time passed since a time stamp * * The macro expands to difference of current time * and a provided time stamp. * See \ref nut_clock_difftime for more info. * * Typical usage: * \code * * nut_time_t time_stamp; * nut_clock_timestamp(time_stamp); * * // Time flies... (but thou shalt not use // since we're plain old C ;-) * * if (nut_clock_sec_since(time_stamp) >= time_offset) { * // Execute scheduled action * } * * \endcode * * \param tm Time stamp * * \return Seconds passed since \c tm (generally with floating point) */ #define nut_clock_sec_since(tm) nut_clock_difftime(NULL, (tm)) /** * \brief Get current time stamp * * Note that the provided time stamp resolution depends on the actually * used implementation of the clock. * * \param mode Clock mode * \param tm Provided time * * \retval 0 in case of success * \retval EINVAL if clock mode isn't supported * \retval EFAULT in case of internal error */ int nut_clock_gettime(nut_clock_mode_t mode, nut_time_t *tm); /** * \brief Get current time stamp or die * * The function wraps around \ref nut_clock_gettime so that if * the time stamp can't be obtained, a fatal message is logged * and the process aborts. * Note that this should never happen for \c mode of \c RTC * or \c MONOTONIC_PREF, since the RTC should always be supported * and \c MONOTONIC_PREF may fall-back to RTC if monotonic clock * isn't available. * * \param mode Clock mode * \param tm Provided time */ void nut_clock_gettimex(nut_clock_mode_t mode, nut_time_t *tm); /** * \brief Compute time difference * * The function returns difference (in seconds) between * two time points as if they were subtracted (2nd from the 1st): * result = \c tm1 - \c tm2 * * Note that either argument may be omitted (i.e. == \c NULL in C). * In that case, the function shall behave as if the argument * was containing current time obtained using the same clock mode * as the other. * This should always be possible (since it was done before). * If the arguments are of different modes, the function shall abort * the process since such usage is logically erroneous. * * Typical usage would therefore be: * \code * * nut_time_t time_stamp; * * nut_clock_gettimex(MONOTONIC_PREF, &time_stamp); * * // Time flies... * * // Get positive time that passed since time_stamp was taken (in seconds) * double sec_spent = nut_clock_difftime(NULL, time_stamp); * * \endcode * * \param tm1 Time stamp * \param tm2 Time stamp * * \return Difference between the time stamps in seconds */ double nut_clock_difftime(const nut_time_t *tm1, const nut_time_t *tm2); /** * \brief Compare time stamps (loosely) * * The function simply calls \ref nut_clock_difftime * and returns -1, 0 or 1 depending on whether the * returned time stamp difference is less then \c -sigma, * within the 0-centered \c sigma interval * or greater than \c sigma, respectively. * * Note that for the arguments, everything applying to * \ref nut_clock_difftime applies as well. * * Also note that for \c sigma = 0.0, this function becomes * a standard comparison function (the restriction wrapper * is already provided: \ref nut_clock_cmptime. * * \param tm1 Time stamp * \param tm2 Time stamp * \param sigma Sigma parameter (defines the comparison precision) * * \retval -1 if \c tm1 < \c tm2 (except for difference less than \c sigma) * \retval 0 if \c tm1 == \c tm2 (except for difference less than \c sigma) * \retval 1 if \c tm1 > \c tm2 (except for difference less than \c sigma) */ int nut_clock_cmptime_sigma(const nut_time_t *tm1, const nut_time_t *tm2, double sigma); /** * \brief Compare time stamps (strictly) * * The function wraps around \ref nut_clock_cmptime_sigma, * fixing the \c sigma parameter to 0.0. * (i.e. works as a standard semantics comparison * function). * * Also note that for time stamps with high resolution, * comparison such as this might be too strict; * you might want to consider \ref nut_clock_cmptime_sigma * function, instead. * * \param tm1 Time stamp * \param tm2 Time stamp * * \retval -1 if \c tm1 < \c tm2 * \retval 0 if \c tm1 == \c tm2 * \retval 1 if \c tm1 > \c tm2 */ int nut_clock_cmptime(const nut_time_t *tm1, const nut_time_t *tm2); #endif /* end of #ifndef nut_common_clock_h */
_______________________________________________ Nut-upsdev mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/nut-upsdev
