Hi Anders.

Ack with minor comments.

  * Its very likely that user may pass some invalid value (say.. fd
    value) for which the current implementation is doing osaf_abort().
    Why it can't be considered error with return of "EINVAL".
  * Better to document that the following function won't allow periodic
    expiration notifications.  Otherwise, there is a possibility of user
    setting /utmr->it_interval.tv_(n)sec/ to non-zero.

    /void osaf_timerfd_settime(int ufd, int flags,//
    //                          const struct itimerspec* utmr,//
    //                          struct itimerspec* otmr)//
    //{//
    //        if ((flags != 0 && flags != OSAF_TFD_TIMER_ABSTIME) ||//
    //            utmr->it_interval.tv_sec != 0 ||//
    //            utmr->it_interval.tv_nsec != 0) {/

Thanks and Regards.
Ramesh.

On 12/22/2015 9:33 PM, Anders Widell wrote:
>   osaf/libs/core/common/Makefile.am            |    1 +
>   osaf/libs/core/common/include/Makefile.am    |    1 +
>   osaf/libs/core/common/include/osaf_timerfd.h |  131 +++++++++++++
>   osaf/libs/core/common/osaf_timerfd.c         |  264 
> +++++++++++++++++++++++++++
>   4 files changed, 397 insertions(+), 0 deletions(-)
>
>
> Add the utility functions osaf_timerfd_create(), osaf_timerfd_settime(),
> osaf_timerfd_gettime() and osaf_timerfd_close(), which have functionality
> corresponding to the Linux functions timerfd_create(), timerfd_settime(),
> timerfd_gettime() and close(), respectively.
>
> The main reason for implementing these functions here is that they are missing
> in LSB (Linux Standard Base), which means that the use these Linux functions 
> are
> currently prohibited in OpenSAF. As an additional benefit, the variants
> implemented here can never fail (they will abort() on failure), which means 
> that
> the user does not have implement code for error handling.
>
> 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
> @@ -34,6 +34,7 @@ libopensaf_common_la_SOURCES = \
>       osaf_utility.c \
>       osaf_poll.c \
>       osaf_time.c \
> +     osaf_timerfd.c \
>       osaf_extended_name.c \
>       nid_start_util.c \
>       saf_edu.c \
> diff --git a/osaf/libs/core/common/include/Makefile.am 
> b/osaf/libs/core/common/include/Makefile.am
> --- a/osaf/libs/core/common/include/Makefile.am
> +++ b/osaf/libs/core/common/include/Makefile.am
> @@ -34,5 +34,6 @@ noinst_HEADERS = \
>       osaf_unicode.h \
>       osaf_poll.h \
>       osaf_time.h \
> +     osaf_timerfd.h \
>       saf_error.h \
>       osaf_secutil.h
> diff --git a/osaf/libs/core/common/include/osaf_timerfd.h 
> b/osaf/libs/core/common/include/osaf_timerfd.h
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/common/include/osaf_timerfd.h
> @@ -0,0 +1,131 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2015 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 Linux functions
> + * timerfd_create(), timerfd_settime() and timerfd_gettime(). The main reason
> + * for implementing these functions here is that they are missing in LSB 
> (Linux
> + * Standard Base), which means that the use these Linux functions are 
> currently
> + * prohibited in OpenSAF. As an additional benefit, the variants implemented
> + * here can never fail (they will abort() on failure), which means that the 
> user
> + * does not have implement code for error handling.
> + *
> + * When using the functions declared in this header file, you must be 
> consistent
> + * and always use them (i.e. not mix the usage of these functions with the 
> Linux
> + * conuterparts). Also, when using the flags parameter to 
> osaf_timerfd_create()
> + * and osaf_timerfd_settime(), you must add the OSAF_ prefix to any flag 
> value
> + * that you use, e.g. use OSAF_TFD_TIMER_ABSTIME instead of 
> TFD_TIMER_ABSTIME.
> + *
> + * Note that these functions are currently implemented using a linear search
> + * algorithm to find the internal timer data structures. Therefore, they will
> + * not be able to handle a large number of timers efficiently. The
> + * reccomendation is to use a maximum of around ten timers per Linux 
> process. If
> + * more timers are needed, then these functions should be improved to use a 
> more
> + * efficient data structure.
> + *
> + * The definitions in this file are for internal use within OpenSAF only.
> + */
> +
> +#ifndef OPENSAF_BASE_OSAF_TIMERFD_H_
> +#define OPENSAF_BASE_OSAF_TIMERFD_H_
> +
> +#include <time.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +enum {
> +  OSAF_TFD_CLOEXEC = 0x80000,
> +  OSAF_TFD_NONBLOCK = 0x800
> +};
> +
> +enum {
> +  OSAF_TFD_TIMER_ABSTIME = 0x1
> +};
> +
> +#define OSAF_TFD_CLOEXEC OSAF_TFD_CLOEXEC
> +#define OSAF_TFD_NONBLOCK OSAF_TFD_NONBLOCK
> +#define OSAF_TFD_TIMER_ABSTIME OSAF_TFD_TIMER_ABSTIME
> +
> +/**
> + * @brief Create a timer.
> + *
> + * This is a convenience function that behaves exactly like the Linux 
> function
> + * timerfd_create(2), except that it will abort the process instead of 
> returning
> + * an error code in case of a failure. Note that you must use the
> + * osaf_timerfd_settime(), osaf_timerfd_gettime() and osaf_timerfd_close()
> + * functions instead of the standard Linux functions timerfd_settime(),
> + * timerfd_gettime() and close() for manipulating timers created using this
> + * function.
> + *
> + * The @a flags parameter can be a bitwise OR of the two flags 
> OSAF_TFD_CLOEXEC
> + * and OSAF_TFD_NONBLOCK, which have the meaning corresponding to the
> + * TFD_CLOEXEC and TFD_NONBLOCK flags of timerfd_create(), respectively.
> + *
> + * The return value will always be greater than or equal to zero (i.e. this
> + * function will never fail). To free the allocated timer, call
> + * osaf_timerfd_close().
> + */
> +extern int osaf_timerfd_create(clockid_t clock_id, int flags)
> +    __attribute__ ((__nothrow__, __leaf__));
> +
> +/**
> + * @brief Start, stop or change the time-out value of a timer.
> + *
> + * This is a convenience function that behaves exactly like the Linux 
> function
> + * timerfd_settime(2), except that it will abort the process instead of
> + * returning an error code in case of a failure. Aslo, it currently has the
> + * restriction that utmr->it_interval must be zero. This function can only be
> + * used with timers created using the osaf_timerfd_create() function.
> + *
> + * The @a flags parameter can be either zero or have the value
> + * OSAF_TFD_TIMER_ABSTIME, which has the meaning corresponding to the
> + * TFD_TIMER_ABSTIME flag of the timerfd_settime() function.
> + */
> +extern void osaf_timerfd_settime(int ufd, int flags,
> +                                 const struct itimerspec* utmr,
> +                                 struct itimerspec* otmr)
> +    __attribute__ ((__nothrow__, __leaf__));
> +
> +/**
> + * @brief Start, stop or change the time-out value of a timer.
> + *
> + * This is a convenience function that behaves exactly like the Linux 
> function
> + * timerfd_gettime(2), except that it will abort the process instead of
> + * returning an error code in case of a failure. This function can only be 
> used
> + * with timers created using the osaf_timerfd_create() function.
> + */
> +extern void osaf_timerfd_gettime(int ufd, struct itimerspec* otmr)
> +    __attribute__ ((__nothrow__, __leaf__));
> +
> +/**
> + * @brief Delete a timer.
> + *
> + * This function is a convenience function that behaves exactly like the 
> Linux
> + * function close(2), except that it will abort the process instead of 
> returning
> + * an error code in case of a failure. This function can only be used with
> + * timers created using the osaf_timerfd_create() function.
> + */
> +extern void osaf_timerfd_close(int ufd);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif  /* OPENSAF_BASE_OSAF_TIMERFD_H_ */
> diff --git a/osaf/libs/core/common/osaf_timerfd.c 
> b/osaf/libs/core/common/osaf_timerfd.c
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/common/osaf_timerfd.c
> @@ -0,0 +1,264 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2015 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
> + *
> + */
> +
> +#ifndef _GNU_SOURCE
> +#define _GNU_SOURCE
> +#endif
> +#include "osaf_timerfd.h"
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <pthread.h>
> +#include <stdint.h>
> +#include <time.h>
> +#include <signal.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +#include "osaf_utility.h"
> +#include "osaf_time.h"
> +
> +// Define a few constants that are missing in the LSB compiler
> +#ifndef MSG_DONTWAIT
> +enum {
> +     MSG_DONTWAIT = 0x40
> +};
> +#define MSG_DONTWAIT MSG_DONTWAIT
> +#endif
> +#ifndef SOCK_CLOEXEC
> +enum {
> +     SOCK_CLOEXEC = 0x80000
> +};
> +#define SOCK_CLOEXEC SOCK_CLOEXEC
> +#endif
> +#ifndef SOCK_NONBLOCK
> +enum {
> +     SOCK_NONBLOCK = 0x800
> +};
> +#define SOCK_NONBLOCK SOCK_NONBLOCK
> +#endif
> +#ifndef sigev_notify_function
> +#define sigev_notify_function   _sigev_un._sigev_thread._function
> +#endif
> +#ifndef sigev_notify_attributes
> +#define sigev_notify_attributes _sigev_un._sigev_thread._attribute
> +#endif
> +
> +/*
> + *  A data structure that keeps information about allocated timers.
> + */
> +struct Timer {
> +     /*
> +      *  Seqence number of this timer. Used by the event handler as a key to
> +      *  find the timer related to the event. If the timer has already been
> +      *  deleted when the event handler is called, then the event is ignored.
> +      */
> +     int sequence_no;
> +     /*
> +      *  The file descriptor that we return to the user. Part of a socket
> +      *  pair together with write_socket.
> +      */
> +     int read_socket;
> +     /*
> +      *  The opposite file descriptor to read_socket, which both form a
> +      *  socket pair. We use this file descriptor for writing, to signal that
> +      *  a timer has expired.
> +      */
> +     int write_socket;
> +     /*
> +      *  The timer that we have allocated using timer_create().
> +      */
> +     timer_t timer_id;
> +     /*
> +      *  Next timer in the linked list pointed to by the variable timer_list.
> +      */
> +     struct Timer* next_timer;
> +};
> +
> +static struct Timer* FindTimer(int read_socket);
> +static void EventHandler(union sigval value);
> +
> +/*
> + *  Mutex that protects all the shared data (i.e. all other static variables 
> in
> + *  this file).
> + */
> +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
> +
> +/*
> + *  Pointer to the first entry in a single linked list of allocated Timer
> + *  structures. The member next_timer in the Timer structure points to the 
> next
> + *  Timer in the list.
> + */
> +static struct Timer* timer_list = NULL;
> +
> +/*
> + *  Next seqence number to be used when allocating a new timer. The sequence
> + *  number will be stored in the member sequence_no and is used by the event
> + *  handler as a key for finding the timer related to the event. This 
> variable
> + *  is initialized to a randomly chosen integer.
> + */
> +static int next_sequence_no = 2124226019;
> +
> +/*
> + * Return a pointer to the timer whose read socket (the socket we return to 
> the
> + * user) equals @a read_socket.
> + */
> +static struct Timer* FindTimer(int read_socket)
> +{
> +     struct Timer* timer;
> +     for (timer = timer_list; timer != NULL; timer = timer->next_timer) {
> +             if (timer->read_socket == read_socket) return timer;
> +     }
> +     // Not found
> +     osaf_abort(read_socket);
> +}
> +
> +/*
> + * Event handler for the timers. This function will be called in a separate
> + * thread when a timer has expired. The sequence number of the expired timer 
> is
> + * found in the parameter value.sival_int, and is used as a key for looking 
> up
> + * the timer in the single linked list timer_list. If the timer is not found 
> in
> + * the list (since it has already been deleted), then the event will be 
> ignored.
> + */
> +static void EventHandler(union sigval value)
> +{
> +     osaf_mutex_lock_ordie(&mutex);
> +     struct Timer* timer = timer_list;
> +     while (timer != NULL && timer->sequence_no != value.sival_int) {
> +             timer = timer->next_timer;
> +     }
> +     if (timer != NULL) {
> +             uint64_t expirations = 1;
> +             ssize_t result;
> +             do {
> +                     result = send(timer->write_socket,
> +                                   &expirations, sizeof(expirations),
> +                                   MSG_DONTWAIT | MSG_NOSIGNAL);
> +             } while (result == -1 && errno == EINTR);
> +             if (result != sizeof(expirations)) osaf_abort(result);
> +     }
> +     osaf_mutex_unlock_ordie(&mutex);
> +}
> +
> +int osaf_timerfd_create(clockid_t clock_id, int flags)
> +{
> +     // Validate input parameters, abort on error
> +     if ((clock_id != CLOCK_REALTIME && clock_id != CLOCK_MONOTONIC) ||
> +         (flags & ~(int) (OSAF_TFD_NONBLOCK | OSAF_TFD_CLOEXEC)) != 0) {
> +             osaf_abort(flags);
> +     }
> +
> +     int sockflags = SOCK_DGRAM;
> +     if ((flags & OSAF_TFD_NONBLOCK) == OSAF_TFD_NONBLOCK) {
> +             sockflags |= SOCK_NONBLOCK;
> +     }
> +     if ((flags & OSAF_TFD_CLOEXEC) == OSAF_TFD_CLOEXEC) {
> +             sockflags |= SOCK_CLOEXEC;
> +     }
> +
> +     int sfd[2];
> +     if (socketpair(AF_UNIX, sockflags, 0, sfd) != 0) osaf_abort(0);
> +
> +     struct Timer* timer = (struct Timer*) malloc(sizeof(struct Timer));
> +     if (timer == NULL) osaf_abort(0);
> +     osaf_mutex_lock_ordie(&mutex);
> +     timer->sequence_no = next_sequence_no++;
> +     osaf_mutex_unlock_ordie(&mutex);
> +     timer->read_socket = sfd[0];
> +     timer->write_socket = sfd[1];
> +
> +     struct sigevent event;
> +     event.sigev_notify = SIGEV_THREAD;
> +     event.sigev_value.sival_int = timer->sequence_no;
> +     event.sigev_notify_function = EventHandler;
> +     event.sigev_notify_attributes = NULL;
> +     int result;
> +     for (;;) {
> +             result = timer_create(clock_id, &event, &timer->timer_id);
> +             if (result != -1 || errno != EAGAIN) break;
> +             static const struct timespec sleep_time = { 0, 10000000 };
> +             osaf_nanosleep(&sleep_time);
> +     }
> +     if (result != 0) osaf_abort(clock_id);
> +
> +     osaf_mutex_lock_ordie(&mutex);
> +     timer->next_timer = timer_list;
> +     timer_list = timer;
> +     osaf_mutex_unlock_ordie(&mutex);
> +     return sfd[0];
> +}
> +
> +void osaf_timerfd_settime(int ufd, int flags,
> +                       const struct itimerspec* utmr,
> +                       struct itimerspec* otmr)
> +{
> +     if ((flags != 0 && flags != OSAF_TFD_TIMER_ABSTIME) ||
> +         utmr->it_interval.tv_sec != 0 ||
> +         utmr->it_interval.tv_nsec != 0) {
> +             osaf_abort(flags);
> +     }
> +
> +     osaf_mutex_lock_ordie(&mutex);
> +     struct Timer* timer = FindTimer(ufd);
> +     for (;;) {
> +             uint64_t expirations;
> +             if (recv(timer->read_socket, &expirations,
> +                      sizeof(expirations), MSG_DONTWAIT) < 0) {
> +                     if (errno == EINTR) continue;
> +                     if (errno == EAGAIN || errno == EWOULDBLOCK) break;
> +                     osaf_abort(timer->read_socket);
> +             }
> +     }
> +     if (timer_settime(timer->timer_id,
> +                       flags == OSAF_TFD_TIMER_ABSTIME ? TIMER_ABSTIME : 0,
> +                       utmr,
> +                       otmr) != 0) {
> +             osaf_abort(flags);
> +     }
> +     osaf_mutex_unlock_ordie(&mutex);
> +}
> +
> +void osaf_timerfd_gettime(int ufd, struct itimerspec* otmr)
> +{
> +     osaf_mutex_lock_ordie(&mutex);
> +     struct Timer* timer = FindTimer(ufd);
> +     if (timer_gettime(timer->timer_id, otmr) != 0) osaf_abort(ufd);
> +     osaf_mutex_unlock_ordie(&mutex);
> +}
> +
> +void osaf_timerfd_close(int ufd)
> +{
> +     osaf_mutex_lock_ordie(&mutex);
> +     struct Timer** prev = &timer_list;
> +     struct Timer* timer;
> +     for (;;) {
> +             timer = *prev;
> +             if (timer == NULL) osaf_abort(ufd);
> +             if (timer->read_socket == ufd) {
> +                     *prev = timer->next_timer;
> +                     break;
> +             }
> +             prev = &timer->next_timer;
> +     }
> +     osaf_mutex_unlock_ordie(&mutex);
> +
> +     if (timer_delete(timer->timer_id) != 0 ||
> +         (close(timer->write_socket) != 0 && errno != EINTR) ||
> +         (close(timer->read_socket) != 0 && errno != EINTR)) {
> +             osaf_abort(ufd);
> +     }
> +     free(timer);
> +}

------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140
_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to