Hi! Thanks for the comments. Se my replies inline below.
regards, Anders Widell 2013-10-30 10:00, Ramesh Betham skrev: > Hi Anders, > > I am not sure on the motivation behind adding more utilities to > core/leap area. > > Also to what extent all these utility functions are used by OpenSAF > services?. Because on behalf of ticket# 537, I am cleaning up the > unused code from leap area and adding more utilities with out actually > using them doesn't make sense. They are not used yet, but they will be used by the patch for ticket [#452]. I am posting the new APIs as a separate ticket since they are generic and can be used even if ticket [#452] is not implemented. Will post the patches for ticket [#452] later today. > > Some of the minor comments on osaf_time are inline with [Ramesh]. > > Coming to the osaf_poll, I have not reviewed yet. But my general > comment is.. Already we have poll utility in os_defs.c > (ncs_sel_obj_poll_single_obj()). Any additional poll specific utility > functions (if they are subjected to use by OpenSAF svc's) can be added > in os_defs.c itself. I could put everything in os_defs.c and os_defs.h, but I kind of agree with the comment at the top of os_defs.h: /***************************************************************************** DESCRIPTION: This module contains old legacy interfaces TODO: clean up and eventually (re)moved ****************************************************************************** */ The idea behind osaf_poll.h and osaf_time.h is that they are closely related to the POSIX header files <poll.h> and <time.h>. So utility functions that enhance POSIX functions found in poll.h are put in the header file osaf_poll.h. Also, I have tried to used APIs that are either identical to, or very similar to, the POSIX APIs. This means that it is very easy to understand how the functions work if you are already faimilar with the corresponding POSIX functions. The API documentation only describes the differences between the POSIX function and the OpenSAF utility function. I also like the idea of separating the code into smaller units with a specific purpose (e.g. osaf_time.h for time-related functions) rather than putting everything into one big file. In an earlier ticket I introduced the file osaf_utility.h as a file for utility functions, but now I consider this to be a mistake. Everything should not go into one single file, but rather the pthreads APIs should be separated out into something called e.g. osaf_thread.h. > > Thanks and Regards, > Ramesh. > > On 10/8/2013 3:51 PM, Anders Widell wrote: >> osaf/libs/core/common/Makefile.am | 2 + >> osaf/libs/core/common/include/osaf_poll.h | 97 +++++++ >> osaf/libs/core/common/include/osaf_time.h | 371 >> ++++++++++++++++++++++++++++++ >> osaf/libs/core/common/osaf_poll.c | 130 ++++++++++ >> osaf/libs/core/common/osaf_time.c | 52 ++++ >> 5 files changed, 652 insertions(+), 0 deletions(-) >> >> >> Add new utility and convenience APIs, declared in osaf_poll.h and >> osaf_time.h, >> respectively. >> >> osaf_poll.h contains utility functions that work in a similar way as the >> Linux >> function poll() and ppoll(), except that they handle errors themselves >> instead >> of returning -1. The errno value EINTR is handled with a loop, and the >> functions >> keep track of time so that the time-out will happen at the same time no >> matter >> if the functions were interrupted by a signal or not. Other errno values will >> cause the process to be aborted, since they indicate the presence of a >> software >> bug and the program cannot continue in a safe way. >> >> osaf_time.h contains utility functions for reading the time and sleeping, >> that >> work in a similar way as the Linux functions clock_gettime() and nanosleep(), >> except that they abort the process instead of returning -1. There are also >> utilty functions for manipulating "struct timespec" times. struct timespec is >> used for representing a time in many POSIX functions, and the reason for >> having >> a structure is that a 64-bit integer is not sufficient for representing the >> full >> time. >> >> diff --git a/osaf/libs/core/common/Makefile.am >> b/osaf/libs/core/common/Makefile.am >> --- a/osaf/libs/core/common/Makefile.am >> +++ b/osaf/libs/core/common/Makefile.am >> @@ -32,6 +32,8 @@ libopensaf_common_la_SOURCES = \ >> ncs_sprr.c \ >> logtrace.c \ >> osaf_utility.c \ >> + osaf_poll.c \ >> + osaf_time.c \ >> nid_start_util.c \ >> saf_edu.c \ >> daemon.c \ >> diff --git a/osaf/libs/core/common/include/osaf_poll.h >> b/osaf/libs/core/common/include/osaf_poll.h >> new file mode 100644 >> --- /dev/null >> +++ b/osaf/libs/core/common/include/osaf_poll.h >> @@ -0,0 +1,97 @@ >> +/* -*- OpenSAF -*- >> + * >> + * (C) Copyright 2013 The OpenSAF Foundation >> + * >> + * This program is distributed in the hope that it will be useful, but >> + * WITHOUT ANY WARRANTY; without even the implied warranty of >> MERCHANTABILITY >> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed >> + * under the GNU Lesser General Public License Version 2.1, February 1999. >> + * The complete license can be accessed from the following location: >> + *http://opensource.org/licenses/lgpl-license.php >> + * See the Copying file included with the OpenSAF distribution for full >> + * licensing terms. >> + * >> + * Author(s): Ericsson AB >> + * >> + */ >> + >> +/** @file >> + * >> + * This file contains an OpenSAF replacement of the POSIX function poll(). >> The >> + * definitions in this file are for internal use within OpenSAF only. >> + */ >> + >> +#ifndef OPENSAF_BASE_OSAF_POLL_H_ >> +#define OPENSAF_BASE_OSAF_POLL_H_ >> + >> +#include <poll.h> >> +#include <time.h> >> +#include <signal.h> >> + >> +#ifdef __cplusplus >> +extern "C" { >> +#endif >> + >> +/** >> + * @brief Wait for events on file descriptors >> + * >> + * This is a convenience function that behaves exactly like the POSIX >> function >> + * poll(3P), except that it will abort the process instead of returning an >> error >> + * code in case of a failure. It handles the EINTR case internally with a >> loop, >> + * and ensures that the function will time out at the same time no matter >> if the >> + * system call was interrupted by a signal or not. >> + * >> + * The return value will always be in the range [0, i_nfds]. >> + */ >> +extern unsigned osaf_poll(struct pollfd* io_fds, nfds_t i_nfds, int >> i_timeout); >> + >> +/** >> + * @brief Wait for events on file descriptors >> + * >> + * This is a convenience function that behaves exactly like the Linux >> function >> + * ppoll(3), except that it will abort the process instead of returning an >> error >> + * code in case of a failure. It handles the EINTR case internally with a >> loop, >> + * and ensures that the function will time out at the same time no matter >> if the >> + * system call was interrupted by a signal or not. Note that since the >> ppoll() >> + * function is currently not included in LSB, this function is implemented >> + * internally using poll(). Therefore, the @a i_sigmask parameter is not >> + * supported and must be set to NULL. >> + * >> + * The return value will always be in the range [0, i_nfds]. >> + */ >> +extern unsigned osaf_ppoll(struct pollfd* io_fds, nfds_t i_nfds, >> + const struct timespec* i_timeout_ts, const sigset_t* i_sigmask); >> + >> +/** >> + * @brief Wait for events on a file descriptor >> + * >> + * This is a convenience function that behaves exactly like the POSIX >> function >> + * poll(3P), except that it only supports waiting for read events on one >> single >> + * file descriptor passed as the parameter @a i_fd. Also, it will abort the >> + * process instead of returning an error code in case the poll() function >> + * fails. It handles the EINTR case internally with a loop, and ensures >> that the >> + * function will time out at the same time no matter if the system call was >> + * interrupted by a signal or not. >> + * >> + * Since there is no struct pollfd* parameter, this convenience function >> has a >> + * different way of reporting what events were received on the file >> descriptor >> + * @a i_fd. It will return 1 if there was a POLLIN event on the file >> descriptor >> + * (just like poll() does). But if poll() returned an error event for the >> file >> + * descriptor @a i_fd, this function will handle the there different cases >> as >> + * follows: >> + * >> + * POLLNVAL - in this case the process will be aborted. >> + * >> + * POLLERR - errno will be set to EIO and -1 will be returned. >> + * >> + * POLLHUP - errno will be set to EPIPE and -1 will be returned. >> + * >> + * The return value from this function will always be in the range [-1, 1]. >> + */ >> +extern int osaf_poll_one_fd(int i_fd, int i_timeout); >> + >> +#ifdef __cplusplus >> +} >> +#endif >> + >> +#endif /* OPENSAF_BASE_OSAF_POLL_H_ */ >> diff --git a/osaf/libs/core/common/include/osaf_time.h >> b/osaf/libs/core/common/include/osaf_time.h >> new file mode 100644 >> --- /dev/null >> +++ b/osaf/libs/core/common/include/osaf_time.h >> @@ -0,0 +1,371 @@ >> +/* -*- OpenSAF -*- >> + * >> + * (C) Copyright 2013 The OpenSAF Foundation >> + * >> + * This program is distributed in the hope that it will be useful, but >> + * WITHOUT ANY WARRANTY; without even the implied warranty of >> MERCHANTABILITY >> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed >> + * under the GNU Lesser General Public License Version 2.1, February 1999. >> + * The complete license can be accessed from the following location: >> + *http://opensource.org/licenses/lgpl-license.php >> + * See the Copying file included with the OpenSAF distribution for full >> + * licensing terms. >> + * >> + * Author(s): Ericsson AB >> + * >> + */ >> + >> +/** @file >> + * >> + * This file contains utility functions related to time and time conversion. >> + * Many functions operate on timespec structures, and require that the >> structure >> + * is normalized. By this is meant that the tv_nsec member of the structure >> has >> + * a value in the range [0, 999999999]. The osaf_normalize_timespec() >> function >> + * can be used to convert a timespec strucure to normalized form, when >> + * necessary. Negative times are not supported. >> + * >> + * The definitions in this file are for internal use within OpenSAF only. >> For >> + * performace reasons, which may be important e.g. when doing time >> measurements, >> + * all functions are declared as inline. >> + */ >> + >> +#ifndef OPENSAF_BASE_OSAF_TIME_H_ >> +#define OPENSAF_BASE_OSAF_TIME_H_ >> + >> +#include <stdint.h> >> +#include <time.h> >> +#include <sys/time.h> >> +#include "osaf_utility.h" >> + >> +#ifdef __cplusplus >> +extern "C" { >> +#endif >> + >> +enum { >> + /** >> + * Number of nanoseconds per second. >> + */ >> + kNanosPerSec = 1000000000, >> + /** >> + * Number of milliseconds per second. >> + */ > [Ramesh]: Comment correction: should be microseconds, below should be > milliseconds [AndersW]: Agreed. >> + kMicrosPerSec = 1000000, >> + /** >> + * Number of microseconds per second. >> + */ >> + kMillisPerSec = 1000 >> +}; >> + >> +/** >> + * @brief Sleep for the specified time >> + * >> + * This is a convenience function that behaves exactly like the POSIX >> function >> + * nanosleep(3P), except that it will abort the process instead of >> returning an >> + * error code in case of a failure. In case the thread was interrupted by a >> + * signal, nanosleep() will be called again to sleep the remaining time. >> + */ >> +extern void osaf_nanosleep(const struct timespec* i_req); >> + >> +/** >> + * @brief Get the time >> + * >> + * This is a convenience function that behaves exactly like the POSIX >> function >> + * clock_gettime(3P), except that it will abort the process instead of >> returning >> + * an error code in case of a failure. >> + */ >> +static inline void osaf_clock_gettime(clockid_t i_clk_id, >> + struct timespec* o_ts); >> + >> +/** >> + * @brief Normalize a timespec structure. >> + * >> + * This function normalizes the timespec structure @a i_ts and stores the >> result >> + * in the output parameter @a o_nrm. The tv_nsec member of the normalized >> + * structure is guaranteed to be in the range [0, 999999999]. The >> parameters are >> + * allowed to point to the same memory address. >> + */ >> +static inline void osaf_normalize_timespec(const struct timespec* i_ts, >> + struct timespec* o_nrm); >> + >> +/** >> + * @brief Calculate the sum of two timespec structures. >> + * >> + * This function adds the two timespec structures @a i_time1 and @a >> i_time2, and >> + * stores the result in the output parameter @a o_sum. The input parameters >> @a >> + * i_time1 and @a i_time2 must be normalized, and the output parameter @a >> o_sum >> + * is guaranteed to also be normalized. The parameters are allowed to point >> to >> + * the same memory address. Negative times are not supported. >> + */ >> +static inline void osaf_timespec_add(const struct timespec* i_time1, >> + const struct timespec* i_time2, >> + struct timespec* o_sum); >> + >> +/** >> + * @brief Calculate the difference between two timespec structures. >> + * >> + * This function subtracts the timespec structure @a i_start from the >> timespec >> + * structure @a i_end, and stores the result in the output parameter @a >> + * o_difference. The input parameters @a i_end and @a i_start must be >> + * normalized, and the output parameter @a o_difference is guaranteed to >> also be >> + * normalized. The parameters are allowed to point to the same memory >> + * address. Negative times are not supported. >> + */ >> +static inline void osaf_timespec_subtract(const struct timespec* i_end, >> + const struct timespec* i_start, >> + struct timespec* o_difference); >> + >> +/** >> + * @brief Compare two timespec structures. >> + * >> + * This function compares the two timespec structures @a i_end and @a >> i_start. >> + * The return value will be -1, 0 or 1, if @a i_end is less than, equal to, >> or >> + * greater than @a i_start, respectively. The input parameters @a i_end and >> @a >> + * i_start must be normalized. >> + */ >> +static inline int osaf_timespec_compare(const struct timespec* i_end, >> + const struct timespec* i_start); >> + >> +/** >> + * @brief Convert a timespec structure to a timeval structure. >> + * >> + * This function converts the timespec structure @a i_ts to a timeval >> structure, >> + * and stores the result in the output parameter @a o_tv. The input >> parameter @a >> + * i_ts does not have to be normalized. The output parameter @a o_tv will be >> + * normalized if the input parameter @a i_ts was normalized. The parameters >> are >> + * allowed to point to the same memory address. >> + */ >> +static inline void osaf_timespec_to_timeval(const struct timespec* i_ts, >> + struct timeval* o_tv); >> + >> +/** >> + * @brief Convert a timeval structure to a timespec structure. >> + * >> + * This function converts the timeval structure @a i_tv to a timespec >> structure, >> + * and stores the result in the output parameter @a o_ts. The input >> parameter @a >> + * i_tv does not have to be normalized. The output parameter @a o_ts will be >> + * normalized if the input parameter @a i_tv was normalized. The parameters >> are >> + * allowed to point to the same memory address. >> + */ >> +static inline void osaf_timeval_to_timespec(const struct timeval* i_tv, >> + struct timespec* o_ts); >> + >> +/** >> + * @brief Convert an integer representing time in milliseconds to a timespec >> + * structure. >> + * >> + * This function converts the integer @a i_millis to a timespec structure, >> and >> + * stores the result in the output parameter @a o_ts. The unit of @a >> i_millis is >> + * milliseconds. The output parameter @a o_ts is guaranteed to be >> normalized. >> + */ >> +static inline void osaf_millis_to_timespec(uint64_t i_millis, >> + struct timespec* o_ts); >> + >> +/** >> + * @brief Convert an integer representing time in microseconds to a timespec >> + * structure. >> + * >> + * This function converts the integer @a i_micros to a timespec structure, >> and >> + * stores the result in the output parameter @a o_ts. The unit of @a >> i_micros is >> + * microseconds. The output parameter @a o_ts is guaranteed to be >> normalized. >> + */ >> +static inline void osaf_micros_to_timespec(uint64_t i_micros, >> + struct timespec* o_ts); >> + >> +/** >> + * @brief Convert a double representing time in seconds to a timespec >> structure. >> + * >> + * This function converts the double precision floating point number @a >> + * i_seconds to a timespec structure, and stores the result in the output >> + * parameter @a o_ts. The unit of @a i_seconds is microseconds. The output >> + * parameter @a o_ts is guaranteed to be normalized. >> + */ >> +static inline void osaf_double_to_timespec(double i_seconds, >> + struct timespec* o_ts); >> + >> +/** >> + * @brief Convert an integer representing time in nanoseconds to a timespec >> + * structure. >> + * >> + * This function converts the integer @a i_nanos to a timespec structure, >> and >> + * stores the result in the output parameter @a o_ts. The unit of @a >> i_nanos is >> + * nanoseconds. The output parameter @a o_ts is guaranteed to be normalized. >> + */ >> +static inline void osaf_nanos_to_timespec(uint64_t i_nanos, >> + struct timespec* o_ts); >> + >> +/** >> + * @brief Convert a timespec structure to an integer representing time >> + * in milliseconds. >> + * >> + * This function converts the timespec structure @a i_ts to an integer >> + * representing time in milliseconds. The result will be rounded down. Note >> that >> + * the returned unsigned 64-bit integer has a smaller range than the range >> than >> + * what is possible to represent in a timespec structure. >> + */ >> +static inline uint64_t osaf_timespec_to_millis(const struct timespec* i_ts); >> + >> +/** >> + * @brief Convert a timespec structure to an integer representing time >> + * in microseconds. >> + * >> + * This function converts the timespec structure @a i_ts to an integer >> + * representing time in microseconds. The result will be rounded down. Note >> that >> + * the returned unsigned 64-bit integer has a smaller range than the range >> than >> + * what is possible to represent in a timespec structure. >> + */ >> +static inline uint64_t osaf_timespec_to_micros(const struct timespec* i_ts); >> + >> +/** >> + * @brief Convert a timespec structure to an integer representing time >> + * in nanoseconds. >> + * >> + * This function converts the timespec structure @a i_ts to an integer >> + * representing time in nanoseconds. Note that the returned unsigned 64-bit >> + * integer has a smaller range than the range than what is possible to >> represent >> + * in a timespec structure. >> + */ >> +static inline uint64_t osaf_timespec_to_nanos(const struct timespec* i_ts); >> + >> +/** >> + * @brief Convert a timespec structure to a double representing time in >> + * seconds. >> + * >> + * This function converts the timespec structure @a i_ts to a double >> precision >> + * floating point number. The input parameter @a i_ts does not have to be >> + * normalized. The unit of the returned value is seconds. Note you will lose >> + * precision when converting to a double. >> + */ >> +static inline double osaf_timespec_to_double(const struct timespec* i_ts); >> + >> +static inline void osaf_clock_gettime(clockid_t i_clk_id, struct timespec* >> o_ts) >> +{ >> + if (clock_gettime(i_clk_id, o_ts) != 0) osaf_abort(i_clk_id); >> +} >> + >> +static inline void osaf_normalize_timespec(const struct timespec* i_ts, >> + struct timespec* o_nrm) >> +{ >> + time_t sec = i_ts->tv_sec + i_ts->tv_nsec / kNanosPerSec; >> + long nsec = i_ts->tv_nsec % kNanosPerSec; >> + if (nsec < 0) { >> + sec -= 1; >> + nsec += kNanosPerSec; >> + } >> + o_nrm->tv_sec = sec; >> + o_nrm->tv_nsec = nsec; >> +} >> + >> +static inline void osaf_timespec_add(const struct timespec* i_time1, >> + const struct timespec* i_time2, >> + struct timespec* o_sum) >> +{ >> + time_t sec = i_time1->tv_sec + i_time2->tv_sec; >> + long nsec = i_time1->tv_nsec + i_time2->tv_nsec; >> + if (nsec >= kNanosPerSec) { >> + sec += 1; >> + nsec -= kNanosPerSec; >> + } >> + o_sum->tv_sec = sec; >> + o_sum->tv_nsec = nsec; >> +} >> + >> +static inline void osaf_timespec_subtract(const struct timespec* i_end, >> + const struct timespec* i_start, >> + struct timespec* o_difference) >> +{ >> + time_t sec = i_end->tv_sec - i_start->tv_sec; >> + long nsec = i_end->tv_nsec - i_start->tv_nsec; >> + if (nsec < 0) { >> + sec -= 1; >> + nsec += kNanosPerSec; >> + } >> + o_difference->tv_sec = sec; >> + o_difference->tv_nsec = nsec; >> +} > [Ramesh]: Above function should take care of comparing i_end and > i_start tmr values and should take appropriate action. [AndersW]: Do you mean that the function should check for underflow errors, and perform error handling in such a case? My idea was to write efficient low-level arithmetic functions without error handling. Compare this with arithmetic operators in C and C++ - they don't check for overflow/underflow either (they do check for division by zero though - but that is a feature of the processor that we get for free). I agree that error handling for arithmetic functions can be important - indeed, there is even a category of security vulnerabilities called "integer overflow". But if error handling is to be performed, the functions should also check that the parameters are normalized. Similarly, the addition function should check for overflow. But the functions will be larger, uglier, and less efficient if they include error handling. The API documentation clearly states the preconditions for calling this function, so it is up to the caller to ensure that these conditions are met. We could of course also have a safe variant that performs error handling, if performance is not important. Or we could use assertions, so that the checks are only performed in debug builds. Unfortunately we don't have the concept of debug builds in OpenSAF - assertions are always enabled. > >> + >> +static inline int osaf_timespec_compare(const struct timespec* i_end, >> + const struct timespec* i_start) >> +{ >> + if (i_end->tv_sec == i_start->tv_sec) { >> + if (i_end->tv_nsec < i_start->tv_nsec) return -1; >> + return i_end->tv_nsec != i_start->tv_nsec ? 1 : 0; >> + } >> + return i_end->tv_sec > i_start->tv_sec ? 1 : -1; >> +} >> + >> +static inline void osaf_timespec_to_timeval(const struct timespec* i_ts, >> + struct timeval* o_tv) >> +{ >> + time_t sec = i_ts->tv_sec; >> + suseconds_t usec = i_ts->tv_nsec / (kMicrosPerSec / kMillisPerSec); >> + o_tv->tv_sec = sec; >> + o_tv->tv_usec = usec; >> +} > [Ramesh]: In above function, better the expression having having > (kNanosPerSec / kMicorsPerSec) rather than (kMicrosPerSec / > kMillisPerSec). Similarly for the below function too. [AndersW]: Agree. >> + >> +static inline void osaf_timeval_to_timespec(const struct timeval* i_tv, >> + struct timespec* o_ts) >> +{ >> + time_t sec = i_tv->tv_sec; >> + long nsec = ((long) i_tv->tv_usec) * (kMicrosPerSec / kMillisPerSec); >> + o_ts->tv_sec = sec; >> + o_ts->tv_nsec = nsec; >> +} >> + >> +static inline void osaf_millis_to_timespec(uint64_t i_millis, >> + struct timespec* o_ts) >> +{ >> + o_ts->tv_sec = i_millis / kMillisPerSec; >> + o_ts->tv_nsec = (i_millis % kMillisPerSec) * (kNanosPerSec / >> + kMillisPerSec); >> +} >> + >> +static inline void osaf_micros_to_timespec(uint64_t i_micros, >> + struct timespec* o_ts) >> +{ >> + o_ts->tv_sec = i_micros / kMicrosPerSec; >> + o_ts->tv_nsec = (i_micros % kMicrosPerSec) * (kNanosPerSec / >> + kMicrosPerSec); >> +} >> + >> +static inline void osaf_nanos_to_timespec(uint64_t i_nanos, >> + struct timespec* o_ts) >> +{ >> + o_ts->tv_sec = i_nanos / kNanosPerSec; >> + o_ts->tv_nsec = i_nanos % kNanosPerSec; >> +} >> + >> +static inline void osaf_double_to_timespec(double i_seconds, >> + struct timespec* o_ts) >> +{ >> + o_ts->tv_sec = i_seconds; >> + o_ts->tv_nsec = (i_seconds - o_ts->tv_sec) * kNanosPerSec; >> + osaf_normalize_timespec(o_ts, o_ts); >> +} >> + > [Ramesh]: Not able to understand the above logic? [AndersW]: Input parameter has the unit seconds. So assign the integer part of this directly to tv_sec. Then the fractional part of a second goes into tv_nsec. Since floating point numbers are inexact, there is a risk that the fractional part is greater than 999999999, and thus we normalize to guarantee the postcondition that the result will always be normalized. >> +static inline uint64_t osaf_timespec_to_millis(const struct timespec* i_ts) >> +{ >> + return i_ts->tv_sec * (uint64_t) kMillisPerSec + i_ts->tv_nsec / >> + (kNanosPerSec / kMillisPerSec); >> +} >> + >> +static inline uint64_t osaf_timespec_to_micros(const struct timespec* i_ts) >> +{ >> + return i_ts->tv_sec * (uint64_t) kMicrosPerSec + i_ts->tv_nsec / >> + (kNanosPerSec / kMicrosPerSec); >> +} >> + >> +static inline uint64_t osaf_timespec_to_nanos(const struct timespec* i_ts) >> +{ >> + return i_ts->tv_sec * (uint64_t) kNanosPerSec + i_ts->tv_nsec; >> +} >> + >> +static inline double osaf_timespec_to_double(const struct timespec* i_ts) >> +{ >> + return i_ts->tv_sec + i_ts->tv_nsec / (double) kNanosPerSec; >> +} >> + >> +#ifdef __cplusplus >> +} >> +#endif >> + >> +#endif /* OPENSAF_BASE_OSAF_TIME_H_ */ >> diff --git a/osaf/libs/core/common/osaf_poll.c >> b/osaf/libs/core/common/osaf_poll.c >> new file mode 100644 >> --- /dev/null >> +++ b/osaf/libs/core/common/osaf_poll.c >> @@ -0,0 +1,130 @@ >> +/* -*- OpenSAF -*- >> + * >> + * (C) Copyright 2013 The OpenSAF Foundation >> + * >> + * This program is distributed in the hope that it will be useful, but >> + * WITHOUT ANY WARRANTY; without even the implied warranty of >> MERCHANTABILITY >> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed >> + * under the GNU Lesser General Public License Version 2.1, February 1999. >> + * The complete license can be accessed from the following location: >> + *http://opensource.org/licenses/lgpl-license.php >> + * See the Copying file included with the OpenSAF distribution for full >> + * licensing terms. >> + * >> + * Author(s): Ericsson AB >> + * >> + */ >> + >> +#include "osaf_poll.h" >> +#include <errno.h> >> +#include <limits.h> >> +#include "osaf_time.h" >> +#include "osaf_utility.h" >> + >> +static unsigned osaf_poll_no_timeout(struct pollfd* io_fds, nfds_t i_nfds); >> + >> +static unsigned osaf_poll_no_timeout(struct pollfd* io_fds, nfds_t i_nfds) >> +{ >> + int result; >> + for (;;) { >> + result = poll(io_fds, i_nfds, -1); >> + if (result >= 0) break; >> + if (result < 0 && errno != EINTR) osaf_abort(result); >> + } >> + return result; >> +} >> + >> +unsigned osaf_poll(struct pollfd* io_fds, nfds_t i_nfds, int i_timeout) >> +{ >> + struct timespec timeout_ts; >> + if (i_timeout < 0) return osaf_poll_no_timeout(io_fds, i_nfds); >> + osaf_millis_to_timespec(i_timeout, &timeout_ts); >> + return osaf_ppoll(io_fds, i_nfds, &timeout_ts, NULL); >> +} >> + >> +unsigned osaf_ppoll(struct pollfd* io_fds, nfds_t i_nfds, >> + const struct timespec* i_timeout_ts, const sigset_t* i_sigmask) >> +{ >> + static const struct timespec millisecond_round_up = { >> + 0, (kNanosPerSec / kMillisPerSec) - 1 >> + }; >> + static const struct timespec max_possible_timeout = { >> + INT_MAX / kMillisPerSec, >> + (INT_MAX % kMillisPerSec) * (kNanosPerSec / kMillisPerSec) >> + }; >> + struct timespec start_time; >> + struct timespec time_left_ts; >> + int result; >> + >> + if (i_sigmask != NULL) osaf_abort(EINVAL); >> + if (i_timeout_ts == NULL) return osaf_poll_no_timeout(io_fds, i_nfds); >> + >> + osaf_clock_gettime(CLOCK_MONOTONIC, &start_time); >> + time_left_ts = *i_timeout_ts; >> + >> + for (;;) { >> + struct timespec current_time; >> + struct timespec elapsed_time; >> + int time_left; >> + >> + /* We don't want to time-out too early, so round up to next even >> + * number of milliseconds. >> + */ >> + osaf_timespec_add(&time_left_ts, &millisecond_round_up, >> + &time_left_ts); >> + >> + if (osaf_timespec_compare(&time_left_ts, >> + &max_possible_timeout) < 0) { >> + time_left = osaf_timespec_to_millis(&time_left_ts); >> + } else { >> + time_left = INT_MAX; >> + } >> + >> + /* ppoll() is currently not included in LSB, so we have to use >> + * poll() here unfortunately. >> + */ >> + result = poll(io_fds, i_nfds, time_left); >> + if (result > 0 || (result == 0 && time_left < INT_MAX)) break; >> + if (result < 0 && errno != EINTR) osaf_abort(result); >> + >> + osaf_clock_gettime(CLOCK_MONOTONIC, ¤t_time); >> + osaf_timespec_subtract(¤t_time, &start_time, >> + &elapsed_time); >> + if (osaf_timespec_compare(¤t_time, &start_time) < 0) { >> + /* Handle the unlikely case that the elapsed time is >> + * negative. Shouldn't happen with a monotonic clock, >> + * but just to be on the safe side. >> + */ >> + elapsed_time.tv_sec = 0; >> + elapsed_time.tv_nsec = 0; >> + } >> + if (osaf_timespec_compare(&elapsed_time, i_timeout_ts) >= 0) { >> + result = 0; >> + break; >> + } >> + osaf_timespec_subtract(i_timeout_ts, &elapsed_time, >> + &time_left_ts); >> + } >> + return result; >> +} >> + >> +int osaf_poll_one_fd(int i_fd, int i_timeout) >> +{ >> + struct pollfd set; >> + unsigned result; >> + set.fd = i_fd; >> + set.events = POLLIN; >> + result = osaf_poll(&set, 1, i_timeout); >> + if (result == 1) { >> + if ((set.revents & POLLNVAL) != 0) osaf_abort(set.revents); >> + if ((set.revents & POLLERR) != 0) { >> + errno = EIO; >> + return -1; >> + } >> + if ((set.revents & POLLHUP) != 0) { >> + errno = EPIPE; >> + return -1; >> + } >> + } >> + return result; >> +} >> diff --git a/osaf/libs/core/common/osaf_time.c >> b/osaf/libs/core/common/osaf_time.c >> new file mode 100644 >> --- /dev/null >> +++ b/osaf/libs/core/common/osaf_time.c >> @@ -0,0 +1,52 @@ >> +/* -*- OpenSAF -*- >> + * >> + * (C) Copyright 2013 The OpenSAF Foundation >> + * >> + * This program is distributed in the hope that it will be useful, but >> + * WITHOUT ANY WARRANTY; without even the implied warranty of >> MERCHANTABILITY >> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed >> + * under the GNU Lesser General Public License Version 2.1, February 1999. >> + * The complete license can be accessed from the following location: >> + *http://opensource.org/licenses/lgpl-license.php >> + * See the Copying file included with the OpenSAF distribution for full >> + * licensing terms. >> + * >> + * Author(s): Ericsson AB >> + * >> + */ >> + >> +#include "osaf_time.h" >> +#include <errno.h> >> + >> +void osaf_nanosleep(const struct timespec* i_req) >> +{ >> + struct timespec req = *i_req; >> + struct timespec start_time; >> + osaf_clock_gettime(CLOCK_MONOTONIC, &start_time); >> + for (;;) { >> + struct timespec current_time; >> + struct timespec elapsed_time; >> + /* We could have utilised the second parameter to nanosleep(), >> + * which will return the remaining sleep time in the case >> + * nanosleep() was interrupted by a signal. But this gives >> + * inaccurate sleep time, for various reasons. See the man page >> + * of nanosleep(2) for details. >> + */ >> + int result = nanosleep(&req, NULL); >> + if (result == 0) break; >> + if (errno != EINTR) osaf_abort(result); >> + osaf_clock_gettime(CLOCK_MONOTONIC, ¤t_time); >> + osaf_timespec_subtract(¤t_time, &start_time, >> + &elapsed_time); >> + if (osaf_timespec_compare(¤t_time, &start_time) < 0) { >> + /* Handle the unlikely case that the elapsed time is >> + * negative. Shouldn't happen with a monotonic clock, >> + * but just to be on the safe side. >> + */ >> + elapsed_time.tv_sec = 0; >> + elapsed_time.tv_nsec = 0; >> + } >> + if (osaf_timespec_compare(&elapsed_time, i_req) >= 0) break; >> + osaf_timespec_subtract(i_req, &elapsed_time, &req); >> + } >> +} > ------------------------------------------------------------------------------ Android is increasing in popularity, but the open development platform that developers love is also attractive to malware creators. Download this white paper to learn more about secure code signing practices that can help keep Android apps secure. http://pubads.g.doubleclick.net/gampad/clk?id=65839951&iu=/4140/ostg.clktrk _______________________________________________ Opensaf-devel mailing list Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel