Weird. I did remote update and rebase origin/master before generating
the patch (I had to fix a couple of conflicts to get it to build).

Where do you get compilation error(s)?


On 6 January 2015 at 05:10, Bill Fischofer <bill.fischo...@linaro.org> wrote:
> If I try to manually apply this patch then it doesn't compile.  It does not
> appear that this patch is properly versioned against the current ODP tip.
>
> On Mon, Jan 5, 2015 at 12:55 PM, Bill Fischofer <bill.fischo...@linaro.org>
> wrote:
>>
>> This patch doesn't seem to apply on the current ODP tip.
>>
>> Bill
>>
>> On Mon, Jan 5, 2015 at 12:23 PM, Ola Liljedahl <ola.liljed...@linaro.org>
>> wrote:
>>>
>>> Signed-off-by: Ola Liljedahl <ola.liljed...@linaro.org>
>>>
>>> (This document/code contribution attached is provided under the terms of
>>> agreement LES-LTM-21309)
>>> The timer API is updated according to
>>>
>>> https://docs.google.com/a/linaro.org/document/d/1bfY_J8ecLJPsFTmYftb0NVmGnB9qkEc_NpcJ87yfaD8
>>> A major change is that timers are allocated and freed separately from
>>> timeouts being set and cancelled. The life-length of a timer normally
>>> corresponds to the life-length of the associated stateful flow while
>>> the life-length of a timeout corresponds to individual packets being
>>> transmitted and received.
>>> The reference timer implementation is lock-less for platforms with
>>> support for 128-bit (16-byte) atomic exchange and CAS operations.
>>> Otherwise a lock-based implementation (using as many locks as desired)
>>> is used but some operations (e.g. reset reusing existing timeout buffer)
>>> may still be lock-less.
>>> Updated the example example/timer/odp_timer_test.c according to the
>>> updated API.
>>> Updated the API according to Petri's review comments.
>>> ---
>>>  example/timer/odp_timer_test.c                     |  177 ++--
>>>  platform/linux-generic/include/api/odp_timer.h     |  318 ++++--
>>>  .../linux-generic/include/odp_timer_internal.h     |   59 +-
>>>  platform/linux-generic/odp_timer.c                 | 1064
>>> ++++++++++++++------
>>>  4 files changed, 1139 insertions(+), 479 deletions(-)
>>>
>>> diff --git a/example/timer/odp_timer_test.c
>>> b/example/timer/odp_timer_test.c
>>> index 2acf2fc..71f72b4 100644
>>> --- a/example/timer/odp_timer_test.c
>>> +++ b/example/timer/odp_timer_test.c
>>> @@ -26,7 +26,6 @@
>>>
>>>
>>>  #define MAX_WORKERS           32            /**< Max worker threads */
>>> -#define MSG_POOL_SIZE         (4*1024*1024) /**< Message pool size */
>>>  #define MSG_NUM_BUFS          10000         /**< Number of timers */
>>>
>>>
>>> @@ -44,69 +43,119 @@ typedef struct {
>>>  /** @private Barrier for test synchronisation */
>>>  static odp_barrier_t test_barrier;
>>>
>>> -/** @private Timer handle*/
>>> -static odp_timer_t test_timer;
>>> +/** @private Buffer pool handle */
>>> +static odp_buffer_pool_t pool;
>>>
>>> +/** @private Timer pool handle */
>>> +static odp_timer_pool_t tp;
>>> +
>>> +/** @private Number of timeouts to receive */
>>> +static odp_atomic_u32_t remain;
>>> +
>>> +/** @private Timer set status ASCII strings */
>>> +static const char *timerset2str(odp_timer_set_t val)
>>> +{
>>> +       switch (val) {
>>> +       case ODP_TIMER_SET_SUCCESS:
>>> +               return "success";
>>> +       case ODP_TIMER_SET_TOOEARLY:
>>> +               return "too early";
>>> +       case ODP_TIMER_SET_TOOLATE:
>>> +               return "too late";
>>> +       case ODP_TIMER_SET_NOBUF:
>>> +               return "no buffer";
>>> +       default:
>>> +               return "?";
>>> +       }
>>> +};
>>> +
>>> +/** @private Helper struct for timers */
>>> +struct test_timer {
>>> +       odp_timer_t tim;
>>> +       odp_buffer_t buf;
>>> +};
>>> +
>>> +/** @private Array of all timer helper structs */
>>> +static struct test_timer tt[256];
>>>
>>>  /** @private test timeout */
>>>  static void test_abs_timeouts(int thr, test_args_t *args)
>>>  {
>>> -       uint64_t tick;
>>>         uint64_t period;
>>>         uint64_t period_ns;
>>>         odp_queue_t queue;
>>> -       odp_buffer_t buf;
>>> -       int num;
>>> +       uint64_t tick;
>>> +       struct test_timer *ttp;
>>>
>>>         EXAMPLE_DBG("  [%i] test_timeouts\n", thr);
>>>
>>>         queue = odp_queue_lookup("timer_queue");
>>>
>>>         period_ns = args->period_us*ODP_TIME_USEC;
>>> -       period    = odp_timer_ns_to_tick(test_timer, period_ns);
>>> +       period    = odp_timer_ns_to_tick(tp, period_ns);
>>>
>>>         EXAMPLE_DBG("  [%i] period %"PRIu64" ticks,  %"PRIu64" ns\n",
>>> thr,
>>>                     period, period_ns);
>>>
>>> -       tick = odp_timer_current_tick(test_timer);
>>> -
>>> -       EXAMPLE_DBG("  [%i] current tick %"PRIu64"\n", thr, tick);
>>> +       EXAMPLE_DBG("  [%i] current tick %"PRIu64"\n", thr,
>>> +                   odp_timer_current_tick(tp));
>>>
>>> -       tick += period;
>>> -
>>> -       if (odp_timer_absolute_tmo(test_timer, tick, queue,
>>> ODP_BUFFER_INVALID)
>>> -           == ODP_TIMER_TMO_INVALID){
>>> -               EXAMPLE_DBG("Timeout request failed\n");
>>> +       ttp = &tt[thr - 1]; /* Thread starts at 1 */
>>> +       ttp->tim = odp_timer_alloc(tp, queue, ttp);
>>> +       if (ttp->tim == ODP_TIMER_INVALID) {
>>> +               EXAMPLE_ERR("Failed to allocate timer\n");
>>>                 return;
>>>         }
>>> +       ttp->buf = odp_buffer_alloc(pool);
>>> +       if (ttp->buf == ODP_BUFFER_INVALID) {
>>> +               EXAMPLE_ERR("Failed to allocate buffer\n");
>>> +               return;
>>> +       }
>>> +       tick = odp_timer_current_tick(tp);
>>>
>>> -       num = args->tmo_count;
>>> -
>>> -       while (1) {
>>> -               odp_timeout_t tmo;
>>> +       while ((int)odp_atomic_load_u32(&remain) > 0) {
>>> +               odp_buffer_t buf;
>>> +               odp_timer_set_t rc;
>>>
>>> -               buf = odp_schedule_one(&queue, ODP_SCHED_WAIT);
>>> +               tick += period;
>>> +               rc = odp_timer_set_abs(ttp->tim, tick, &ttp->buf);
>>> +               if (odp_unlikely(rc != ODP_TIMER_SET_SUCCESS)) {
>>> +                       /* Too early or too late timeout requested */
>>> +                       EXAMPLE_ABORT("odp_timer_set_abs() failed: %s\n",
>>> +                                     timerset2str(rc));
>>> +               }
>>>
>>> -               tmo  = odp_timeout_from_buffer(buf);
>>> +               /* Get the next expired timeout */
>>> +               buf = odp_schedule(&queue, ODP_SCHED_WAIT);
>>> +               if (odp_buffer_type(buf) != ODP_BUFFER_TYPE_TIMEOUT) {
>>> +                       /* Not a default timeout buffer */
>>> +                       EXAMPLE_ABORT("Unexpected buffer type (%u)
>>> received\n",
>>> +                                     odp_buffer_type(buf));
>>> +               }
>>> +               odp_timeout_t tmo = odp_timeout_from_buf(buf);
>>>                 tick = odp_timeout_tick(tmo);
>>> -
>>> +               ttp = odp_timeout_user_ptr(tmo);
>>> +               ttp->buf = buf;
>>> +               if (!odp_timeout_fresh(tmo)) {
>>> +                       /* Not the expected expiration tick, timer has
>>> +                        * been reset or cancelled or freed */
>>> +                       EXAMPLE_ABORT("Unexpected timeout received (timer
>>> %x, tick %"PRIu64")\n",
>>> +                                     ttp->tim, tick);
>>> +               }
>>>                 EXAMPLE_DBG("  [%i] timeout, tick %"PRIu64"\n", thr,
>>> tick);
>>>
>>> -               odp_buffer_free(buf);
>>> -
>>> -               num--;
>>> -
>>> -               if (num == 0)
>>> -                       break;
>>> -
>>> -               tick += period;
>>> -
>>> -               odp_timer_absolute_tmo(test_timer, tick,
>>> -                                      queue, ODP_BUFFER_INVALID);
>>> +               odp_atomic_dec_u32(&remain);
>>>         }
>>>
>>> -       if (odp_queue_sched_type(queue) == ODP_SCHED_SYNC_ATOMIC)
>>> -               odp_schedule_release_atomic();
>>> +       /* Cancel and free last timer used */
>>> +       (void)odp_timer_cancel(ttp->tim, &ttp->buf);
>>> +       if (ttp->buf != ODP_BUFFER_INVALID)
>>> +               odp_buffer_free(ttp->buf);
>>> +       else
>>> +               EXAMPLE_ERR("Lost timeout buffer at timer cancel\n");
>>> +       /* Since we have cancelled the timer, there is no timeout buffer
>>> to
>>> +        * return from odp_timer_free() */
>>> +       (void)odp_timer_free(ttp->tim);
>>>  }
>>>
>>>
>>> @@ -193,14 +242,14 @@ static void parse_args(int argc, char *argv[],
>>> test_args_t *args)
>>>         /* defaults */
>>>         args->cpu_count     = 0; /* all CPU's */
>>>         args->resolution_us = 10000;
>>> -       args->min_us        = args->resolution_us;
>>> +       args->min_us        = 0;
>>>         args->max_us        = 10000000;
>>>         args->period_us     = 1000000;
>>>         args->tmo_count     = 30;
>>>
>>>         while (1) {
>>>                 opt = getopt_long(argc, argv, "+c:r:m:x:p:t:h",
>>> -                                longopts, &long_index);
>>> +                                 longopts, &long_index);
>>>
>>>                 if (opt == -1)
>>>                         break;  /* No more options */
>>> @@ -244,13 +293,13 @@ int main(int argc, char *argv[])
>>>         odph_linux_pthread_t thread_tbl[MAX_WORKERS];
>>>         test_args_t args;
>>>         int num_workers;
>>> -       odp_buffer_pool_t pool;
>>>         odp_queue_t queue;
>>>         int first_cpu;
>>>         uint64_t cycles, ns;
>>>         odp_queue_param_t param;
>>> -       odp_shm_t shm;
>>>         odp_buffer_pool_param_t params;
>>> +       odp_timer_pool_param_t tparams;
>>> +       odp_timer_pool_info_t tpinfo;
>>>
>>>         printf("\nODP timer example starts\n");
>>>
>>> @@ -310,23 +359,43 @@ int main(int argc, char *argv[])
>>>         printf("timeouts:           %i\n", args.tmo_count);
>>>
>>>         /*
>>> -        * Create message pool
>>> +        * Create buffer pool for timeouts
>>>          */
>>> -       shm = odp_shm_reserve("msg_pool",
>>> -                             MSG_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
>>> -
>>>         params.buf_size  = 0;
>>>         params.buf_align = 0;
>>>         params.num_bufs  = MSG_NUM_BUFS;
>>>         params.buf_type  = ODP_BUFFER_TYPE_TIMEOUT;
>>>
>>> -       pool = odp_buffer_pool_create("msg_pool", shm, &params);
>>> +       pool = odp_buffer_pool_create("msg_pool", ODP_SHM_NULL, &params);
>>>
>>>         if (pool == ODP_BUFFER_POOL_INVALID) {
>>> -               EXAMPLE_ERR("Pool create failed.\n");
>>> +               EXAMPLE_ERR("Buffer pool create failed.\n");
>>>                 return -1;
>>>         }
>>>
>>> +       tparams.res_ns = args.resolution_us*ODP_TIME_USEC;
>>> +       tparams.min_tmo = args.min_us*ODP_TIME_USEC;
>>> +       tparams.max_tmo = args.max_us*ODP_TIME_USEC;
>>> +       tparams.num_timers = num_workers; /* One timer per worker */
>>> +       tparams.private = 0; /* Shared */
>>> +       tparams.clk_src = ODP_CLOCK_CPU;
>>> +       tp = odp_timer_pool_create("timer_pool", pool, &tparams);
>>> +       if (tp == ODP_TIMER_POOL_INVALID) {
>>> +               EXAMPLE_ERR("Timer pool create failed.\n");
>>> +               return -1;
>>> +       }
>>> +       odp_timer_pool_start();
>>> +
>>> +       odp_shm_print_all();
>>> +       (void)odp_timer_pool_info(tp, &tpinfo);
>>> +       printf("Timer pool\n");
>>> +       printf("----------\n");
>>> +       printf("  name: %s\n", tpinfo.name);
>>> +       printf("  resolution: %"PRIu64" ns\n", tpinfo.param.res_ns);
>>> +       printf("  min tmo: %"PRIu64" ticks\n", tpinfo.param.min_tmo);
>>> +       printf("  max tmo: %"PRIu64" ticks\n", tpinfo.param.max_tmo);
>>> +       printf("\n");
>>> +
>>>         /*
>>>          * Create a queue for timer test
>>>          */
>>> @@ -342,20 +411,7 @@ int main(int argc, char *argv[])
>>>                 return -1;
>>>         }
>>>
>>> -       test_timer = odp_timer_create("test_timer", pool,
>>> -                                     args.resolution_us*ODP_TIME_USEC,
>>> -                                     args.min_us*ODP_TIME_USEC,
>>> -                                     args.max_us*ODP_TIME_USEC);
>>> -
>>> -       if (test_timer == ODP_TIMER_INVALID) {
>>> -               EXAMPLE_ERR("Timer create failed.\n");
>>> -               return -1;
>>> -       }
>>> -
>>> -
>>> -       odp_shm_print_all();
>>> -
>>> -       printf("CPU freq %"PRIu64" hz\n", odp_sys_cpu_hz());
>>> +       printf("CPU freq %"PRIu64" Hz\n", odp_sys_cpu_hz());
>>>         printf("Cycles vs nanoseconds:\n");
>>>         ns = 0;
>>>         cycles = odp_time_ns_to_cycles(ns);
>>> @@ -375,6 +431,9 @@ int main(int argc, char *argv[])
>>>
>>>         printf("\n");
>>>
>>> +       /* Initialize number of timeouts to receive */
>>> +       odp_atomic_init_u32(&remain, args.tmo_count * num_workers);
>>> +
>>>         /* Barrier to sync test case execution */
>>>         odp_barrier_init(&test_barrier, num_workers);
>>>
>>> diff --git a/platform/linux-generic/include/api/odp_timer.h
>>> b/platform/linux-generic/include/api/odp_timer.h
>>> index 6cca27c..6961e81 100644
>>> --- a/platform/linux-generic/include/api/odp_timer.h
>>> +++ b/platform/linux-generic/include/api/odp_timer.h
>>> @@ -8,7 +8,7 @@
>>>  /**
>>>   * @file
>>>   *
>>> - * ODP timer
>>> + * ODP timer service
>>>   */
>>>
>>>  #ifndef ODP_TIMER_H_
>>> @@ -18,6 +18,7 @@
>>>  extern "C" {
>>>  #endif
>>>
>>> +#include <stdlib.h>
>>>  #include <odp_std_types.h>
>>>  #include <odp_buffer.h>
>>>  #include <odp_buffer_pool.h>
>>> @@ -27,140 +28,335 @@ extern "C" {
>>>   *  @{
>>>   */
>>>
>>> +struct odp_timer_pool_s; /**< Forward declaration */
>>> +
>>> +/**
>>> +* ODP timer pool handle (platform dependent)
>>> +*/
>>> +typedef struct odp_timer_pool_s *odp_timer_pool_t;
>>> +
>>>  /**
>>> - * ODP timer handle
>>> + * Invalid timer pool handle (platform dependent).
>>>   */
>>> +#define ODP_TIMER_POOL_INVALID NULL
>>> +
>>> +/**
>>> + * Clock sources for timers in timer pool.
>>> + */
>>> +typedef enum {
>>> +       /** Use CPU clock as clock source for timers */
>>> +       ODP_CLOCK_CPU,
>>> +       /** Use external clock as clock source for timers */
>>> +       ODP_CLOCK_EXT
>>> +       /* Platform dependent which other clock sources exist */
>>> +} odp_timer_clk_src_t;
>>> +
>>> +/**
>>> +* ODP timer handle (platform dependent).
>>> +*/
>>>  typedef uint32_t odp_timer_t;
>>>
>>> -/** Invalid timer */
>>> -#define ODP_TIMER_INVALID 0
>>> +/**
>>> +* ODP timeout handle (platform dependent).
>>> +*/
>>> +typedef void *odp_timeout_t;
>>>
>>> +/**
>>> + * Invalid timer handle (platform dependent).
>>> + */
>>> +#define ODP_TIMER_INVALID ((uint32_t)~0U)
>>>
>>>  /**
>>> - * ODP timeout handle
>>> + * Return values of timer set calls.
>>> + */
>>> +typedef enum {
>>> +/**
>>> + * Timer set operation succeeded
>>>   */
>>> -typedef odp_buffer_t odp_timer_tmo_t;
>>> +       ODP_TIMER_SET_SUCCESS = 0,
>>> +/**
>>> + * Timer set operation failed, expiration too early.
>>> + * Either retry with a later expiration time or process the timeout
>>> + * immediately. */
>>> +       ODP_TIMER_SET_TOOEARLY = -1,
>>>
>>> -/** Invalid timeout */
>>> -#define ODP_TIMER_TMO_INVALID 0
>>> +/**
>>> + * Timer set operation failed, expiration too late.
>>> + * Truncate the expiration time against the maximum timeout for the
>>> + * timer pool. */
>>> +       ODP_TIMER_SET_TOOLATE = -2,
>>> +/**
>>> + * Timer set operation failed because no timeout buffer specified of
>>> present
>>> + * in timer (timer inactive/expired).
>>> + */
>>> +       ODP_TIMER_SET_NOBUF = -3
>>> +} odp_timer_set_t;
>>>
>>> +/** Maximum timer pool name length in chars (including null char) */
>>> +#define ODP_TIMER_POOL_NAME_LEN  32
>>>
>>> -/**
>>> - * Timeout notification
>>> +/** Timer pool parameters
>>> + * Timer pool parameters are used when creating and querying timer
>>> pools.
>>>   */
>>> -typedef odp_buffer_t odp_timeout_t;
>>> +typedef struct {
>>> +       uint64_t res_ns; /**< Timeout resolution in nanoseconds */
>>> +       uint64_t min_tmo; /**< Minimum relative timeout in nanoseconds */
>>> +       uint64_t max_tmo; /**< Maximum relative timeout in nanoseconds */
>>> +       uint32_t num_timers; /**< (Minimum) number of supported timers */
>>> +       int private; /**< Shared (false) or private (true) timer pool */
>>> +       odp_timer_clk_src_t clk_src; /**< Clock source for timers */
>>> +} odp_timer_pool_param_t;
>>>
>>> +/**
>>> + * Create a timer pool
>>> + *
>>> + * @param name       Name of the timer pool. The string will be copied.
>>> + * @param buf_pool   Buffer pool for allocating timeouts
>>> + * @param params     Timer pool parameters. The content will be copied.
>>> + *
>>> + * @return Timer pool handle if successful, otherwise
>>> ODP_TIMER_POOL_INVALID
>>> + * and errno set
>>> + */
>>> +odp_timer_pool_t
>>> +odp_timer_pool_create(const char *name,
>>> +                     odp_buffer_pool_t buf_pool,
>>> +                     const odp_timer_pool_param_t *params);
>>>
>>>  /**
>>> - * Create a timer
>>> + * Start a timer pool
>>>   *
>>> - * Creates a new timer with requested properties.
>>> + * Start all created timer pools, enabling the allocation of timers.
>>> + * The purpose of this call is to coordinate the creation of multiple
>>> timer
>>> + * pools that may use the same underlying HW resources.
>>> + * This function may be called multiple times.
>>> + */
>>> +void odp_timer_pool_start(void);
>>> +
>>> +/**
>>> + * Destroy a timer pool
>>>   *
>>> - * @param name       Name
>>> - * @param pool       Buffer pool for allocating timeout notifications
>>> - * @param resolution Timeout resolution in nanoseconds
>>> - * @param min_tmo    Minimum timeout duration in nanoseconds
>>> - * @param max_tmo    Maximum timeout duration in nanoseconds
>>> + * Destroy a timer pool, freeing all resources.
>>> + * All timers must have been freed.
>>>   *
>>> - * @return Timer handle if successful, otherwise ODP_TIMER_INVALID
>>> + * @param tpid  Timer pool identifier
>>>   */
>>> -odp_timer_t odp_timer_create(const char *name, odp_buffer_pool_t pool,
>>> -                            uint64_t resolution, uint64_t min_tmo,
>>> -                            uint64_t max_tmo);
>>> +void odp_timer_pool_destroy(odp_timer_pool_t tpid);
>>>
>>>  /**
>>>   * Convert timer ticks to nanoseconds
>>>   *
>>> - * @param timer Timer
>>> + * @param tpid  Timer pool identifier
>>>   * @param ticks Timer ticks
>>>   *
>>>   * @return Nanoseconds
>>>   */
>>> -uint64_t odp_timer_tick_to_ns(odp_timer_t timer, uint64_t ticks);
>>> +uint64_t odp_timer_tick_to_ns(odp_timer_pool_t tpid, uint64_t ticks);
>>>
>>>  /**
>>>   * Convert nanoseconds to timer ticks
>>>   *
>>> - * @param timer Timer
>>> + * @param tpid  Timer pool identifier
>>>   * @param ns    Nanoseconds
>>>   *
>>>   * @return Timer ticks
>>>   */
>>> -uint64_t odp_timer_ns_to_tick(odp_timer_t timer, uint64_t ns);
>>> +uint64_t odp_timer_ns_to_tick(odp_timer_pool_t tpid, uint64_t ns);
>>>
>>>  /**
>>> - * Timer resolution in nanoseconds
>>> + * Current tick value
>>>   *
>>> - * @param timer Timer
>>> + * @param tpid Timer pool identifier
>>>   *
>>> - * @return Resolution in nanoseconds
>>> + * @return Current time in timer ticks
>>> + */
>>> +uint64_t odp_timer_current_tick(odp_timer_pool_t tpid);
>>> +
>>> +/**
>>> + * ODP timer pool information and configuration
>>>   */
>>> -uint64_t odp_timer_resolution(odp_timer_t timer);
>>> +
>>> +typedef struct {
>>> +       odp_timer_pool_param_t param; /**< Parameters specified at
>>> creation */
>>> +       uint32_t cur_timers; /**< Number of currently allocated timers */
>>> +       uint32_t hwm_timers; /**< High watermark of allocated timers */
>>> +       const char *name; /**< Name of timer pool */
>>> +} odp_timer_pool_info_t;
>>>
>>>  /**
>>> - * Maximum timeout in timer ticks
>>> + * Query timer pool configuration and current state
>>>   *
>>> - * @param timer Timer
>>> + * @param tpid Timer pool identifier
>>> + * @param[out] info Pointer to information buffer
>>>   *
>>> - * @return Maximum timeout in timer ticks
>>> + * @retval 0 Success
>>> + * @retval -1 Failure. Info could not be retrieved.
>>>   */
>>> -uint64_t odp_timer_maximum_tmo(odp_timer_t timer);
>>> +int odp_timer_pool_info(odp_timer_pool_t tpid,
>>> +                       odp_timer_pool_info_t *info);
>>>
>>>  /**
>>> - * Current timer tick
>>> + * Allocate a timer
>>>   *
>>> - * @param timer Timer
>>> + * Create a timer (allocating all necessary resources e.g. timeout
>>> event) from
>>> + * the timer pool. The user_ptr is copied to timeouts and can be
>>> retrieved
>>> + * using the odp_timer_userptr() call.
>>>   *
>>> - * @return Current time in timer ticks
>>> + * @param tpid     Timer pool identifier
>>> + * @param queue    Destination queue for timeout notifications
>>> + * @param user_ptr User defined pointer or NULL to be copied to timeouts
>>> + *
>>> + * @return Timer handle if successful, otherwise ODP_TIMER_INVALID and
>>> + *        errno set.
>>>   */
>>> -uint64_t odp_timer_current_tick(odp_timer_t timer);
>>> +odp_timer_t odp_timer_alloc(odp_timer_pool_t tpid,
>>> +                           odp_queue_t queue,
>>> +                           void *user_ptr);
>>>
>>>  /**
>>> - * Request timeout with an absolute timer tick
>>> + * Free a timer
>>>   *
>>> - * When tick reaches tmo_tick, the timer enqueues the timeout
>>> notification into
>>> - * the destination queue.
>>> + * Free (destroy) a timer, reclaiming associated resources.
>>> + * The timeout buffer for an active timer will be returned.
>>> + * The timeout buffer for an expired timer will not be returned. It is
>>> the
>>> + * responsibility of the application to handle this timeout when it is
>>> received.
>>>   *
>>> - * @param timer    Timer
>>> - * @param tmo_tick Absolute timer tick value which triggers the timeout
>>> - * @param queue    Destination queue for the timeout notification
>>> - * @param buf      User defined timeout notification buffer. When
>>> - *                 ODP_BUFFER_INVALID, default timeout notification is
>>> used.
>>> + * @param tim      Timer handle
>>> + * @return Buffer handle of timeout buffer or ODP_BUFFER_INVALID
>>> + */
>>> +odp_buffer_t odp_timer_free(odp_timer_t tim);
>>> +
>>> +/**
>>> + * Set a timer (absolute time) with a user-provided timeout buffer
>>> + *
>>> + * Set (arm) the timer to expire at specific time. The timeout
>>> + * buffer will be enqueued when the timer expires.
>>> + *
>>> + * Note: any invalid parameters will be treated as programming errors
>>> and will
>>> + * cause the application to abort.
>>> + *
>>> + * @param tim      Timer
>>> + * @param abs_tck  Expiration time in absolute timer ticks
>>> + * @param tmo_buf  Reference to a buffer variable that points to timeout
>>> buffer
>>> + * or NULL to reuse the existing timeout buffer
>>> + *
>>> + * @retval ODP_TIMER_SET_SUCCESS Operation succeeded
>>> + * @retval ODP_TIMER_SET_TOOEARLY Operation failed because expiration
>>> tick too
>>> + * early
>>> + * @retval ODP_TIMER_SET_TOOLATE Operation failed because expiration
>>> tick too
>>> + * late
>>> + * @retval ODP_TIMER_SET_NOBUF Operation failed because timeout buffer
>>> not
>>> + * specified in call and not present in timer
>>> + */
>>> +int odp_timer_set_abs(odp_timer_t tim,
>>> +                     uint64_t abs_tck,
>>> +                     odp_buffer_t *tmo_buf);
>>> +
>>> +/**
>>> + * Set a timer with a relative expiration time and user-provided buffer.
>>> + *
>>> + * Set (arm) the timer to expire at a relative future time.
>>> + *
>>> + * Note: any invalid parameters will be treated as programming errors
>>> and will
>>> + * cause the application to abort.
>>> + *
>>> + * @param tim      Timer
>>> + * @param rel_tck  Expiration time in timer ticks relative to current
>>> time of
>>> + *                the timer pool the timer belongs to
>>> + * @param tmo_buf  Reference to a buffer variable that points to timeout
>>> buffer
>>> + * or NULL to reuse the existing timeout buffer
>>> + *
>>> + * @retval ODP_TIMER_SET_SUCCESS Operation succeeded
>>> + * @retval ODP_TIMER_SET_TOOEARLY Operation failed because expiration
>>> tick too
>>> + * early
>>> + * @retval ODP_TIMER_SET_TOOLATE Operation failed because expiration
>>> tick too
>>> + * late
>>> + * @retval ODP_TIMER_SET_NOBUF Operation failed because timeout buffer
>>> not
>>> + * specified in call and not present in timer
>>> + */
>>> +int odp_timer_set_rel(odp_timer_t tim,
>>> +                     uint64_t rel_tck,
>>> +                     odp_buffer_t *tmo_buf);
>>> +
>>> +/**
>>> + * Cancel a timer
>>>   *
>>> - * @return Timeout handle if successful, otherwise ODP_TIMER_TMO_INVALID
>>> + * Cancel a timer, preventing future expiration and delivery. Return any
>>> + * present timeout buffer.
>>> + *
>>> + * A timer that has already expired may be impossible to cancel and the
>>> timeout
>>> + * will instead be delivered to the destination queue.
>>> + *
>>> + * Note: any invalid parameters will be treated as programming errors
>>> and will
>>> + * cause the application to abort.
>>> + *
>>> + * @param tim     Timer
>>> + * @param[out] tmo_buf Pointer to a buffer variable
>>> + * @retval 0  Success, active timer cancelled, timeout returned in
>>> '*tmo_buf'
>>> + * @retval -1 Failure, timer already expired (or inactive)
>>>   */
>>> -odp_timer_tmo_t odp_timer_absolute_tmo(odp_timer_t timer, uint64_t
>>> tmo_tick,
>>> -                                      odp_queue_t queue, odp_buffer_t
>>> buf);
>>> +int odp_timer_cancel(odp_timer_t tim, odp_buffer_t *tmo_buf);
>>>
>>>  /**
>>> - * Cancel a timeout
>>> + * Return timeout handle that is associated with timeout buffer
>>> + *
>>> + * Note: any invalid parameters will cause undefined behavior and may
>>> cause
>>> + * the application to abort or crash.
>>>   *
>>> - * @param timer Timer
>>> - * @param tmo   Timeout to cancel
>>> + * @param buf A buffer of type ODP_BUFFER_TYPE_TIMEOUT
>>> + *
>>> + * @return timeout handle
>>> + */
>>> +odp_timeout_t odp_timeout_from_buf(odp_buffer_t buf);
>>> +
>>> +/**
>>> + * Check for fresh timeout
>>> + * If the corresponding timer has been reset or cancelled since this
>>> timeout
>>> + * was enqueued, the timeout is stale (not fresh).
>>>   *
>>> - * @return 0 if successful
>>> + * @param tmo Timeout handle
>>> + * @retval 1 Timeout is fresh
>>> + * @retval 0 Timeout is stale
>>>   */
>>> -int odp_timer_cancel_tmo(odp_timer_t timer, odp_timer_tmo_t tmo);
>>> +int /*odp_bool_t*/odp_timeout_fresh(odp_timeout_t tmo);
>>>
>>>  /**
>>> - * Convert buffer handle to timeout handle
>>> + * Return timer handle for the timeout
>>>   *
>>> - * @param buf  Buffer handle
>>> + * Note: any invalid parameters will cause undefined behavior and may
>>> cause
>>> + * the application to abort or crash.
>>>   *
>>> - * @return Timeout buffer handle
>>> + * @param tmo Timeout handle
>>> + *
>>> + * @return Timer handle
>>>   */
>>> -odp_timeout_t odp_timeout_from_buffer(odp_buffer_t buf);
>>> +odp_timer_t odp_timeout_timer(odp_timeout_t tmo);
>>>
>>>  /**
>>> - * Return absolute timeout tick
>>> + * Return expiration tick for the timeout
>>> + *
>>> + * Note: any invalid parameters will cause undefined behavior and may
>>> cause
>>> + * the application to abort or crash.
>>>   *
>>> - * @param tmo Timeout buffer handle
>>> + * @param tmo Timeout handle
>>>   *
>>> - * @return Absolute timeout tick
>>> + * @return Expiration tick
>>>   */
>>>  uint64_t odp_timeout_tick(odp_timeout_t tmo);
>>>
>>>  /**
>>> + * Return user pointer for the timeout
>>> + * The user pointer was specified when the timer was allocated.
>>> + *
>>> + * Note: any invalid parameters will cause undefined behavior and may
>>> cause
>>> + * the application to abort or crash.
>>> + *
>>> + * @param tmo Timeout handle
>>> + *
>>> + * @return User pointer
>>> + */
>>> +void *odp_timeout_user_ptr(odp_timeout_t tmo);
>>> +
>>> +/**
>>>   * @}
>>>   */
>>>
>>> diff --git a/platform/linux-generic/include/odp_timer_internal.h
>>> b/platform/linux-generic/include/odp_timer_internal.h
>>> index 0d10d00..7637f85 100644
>>> --- a/platform/linux-generic/include/odp_timer_internal.h
>>> +++ b/platform/linux-generic/include/odp_timer_internal.h
>>> @@ -1,4 +1,4 @@
>>> -/* Copyright (c) 2013, Linaro Limited
>>> +/* Copyright (c) 2014, Linaro Limited
>>>   * All rights reserved.
>>>   *
>>>   * SPDX-License-Identifier:     BSD-3-Clause
>>> @@ -8,47 +8,35 @@
>>>  /**
>>>   * @file
>>>   *
>>> - * ODP timer timeout descriptor - implementation internal
>>> + * ODP timeout descriptor - implementation internal
>>>   */
>>>
>>>  #ifndef ODP_TIMER_INTERNAL_H_
>>>  #define ODP_TIMER_INTERNAL_H_
>>>
>>> -#ifdef __cplusplus
>>> -extern "C" {
>>> -#endif
>>> -
>>> -#include <odp_std_types.h>
>>> -#include <odp_queue.h>
>>> -#include <odp_buffer.h>
>>> +#include <odp_align.h>
>>> +#include <odp_debug.h>
>>>  #include <odp_buffer_internal.h>
>>>  #include <odp_buffer_pool_internal.h>
>>>  #include <odp_timer.h>
>>>
>>> -struct timeout_t;
>>> -
>>> -typedef struct timeout_t {
>>> -       struct timeout_t *next;
>>> -       int               timer_id;
>>> -       int               tick;
>>> -       uint64_t          tmo_tick;
>>> -       odp_queue_t       queue;
>>> -       odp_buffer_t      buf;
>>> -       odp_buffer_t      tmo_buf;
>>> -} timeout_t;
>>> -
>>> -
>>> -struct odp_timeout_hdr_t;
>>> -
>>>  /**
>>> - * Timeout notification header
>>> + * Internal Timeout header
>>>   */
>>> -typedef struct odp_timeout_hdr_t {
>>> +typedef struct {
>>> +       /* common buffer header */
>>>         odp_buffer_hdr_t buf_hdr;
>>>
>>> -       timeout_t meta;
>>> -
>>> -       uint8_t buf_data[];
>>> +       /* Requested expiration time */
>>> +       uint64_t expiration;
>>> +       /* User ptr inherited from parent timer */
>>> +       void *user_ptr;
>>> +       /* Parent timer */
>>> +       odp_timer_t timer;
>>> +#if __SIZEOF_POINTER__ != 4
>>> +       uint32_t pad32;
>>> +#endif
>>> +       uint8_t buf_data[0];
>>>  } odp_timeout_hdr_t;
>>>
>>>  typedef struct odp_timeout_hdr_stride {
>>> @@ -64,18 +52,11 @@ _ODP_STATIC_ASSERT(sizeof(odp_timeout_hdr_t) %
>>> sizeof(uint64_t) == 0,
>>>
>>>
>>>  /**
>>> - * Return timeout header
>>> + * Return the timeout header
>>>   */
>>> -static inline odp_timeout_hdr_t *odp_timeout_hdr(odp_timeout_t tmo)
>>> +static inline odp_timeout_hdr_t *odp_timeout_hdr(odp_buffer_t buf)
>>>  {
>>> -       odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr((odp_buffer_t)tmo);
>>> -       return (odp_timeout_hdr_t *)(uintptr_t)buf_hdr;
>>> -}
>>> -
>>> -
>>> -
>>> -#ifdef __cplusplus
>>> +       return (odp_timeout_hdr_t *)odp_buf_to_hdr(buf);
>>>  }
>>> -#endif
>>>
>>>  #endif
>>> diff --git a/platform/linux-generic/odp_timer.c
>>> b/platform/linux-generic/odp_timer.c
>>> index 65b44b9..dc386e7 100644
>>> --- a/platform/linux-generic/odp_timer.c
>>> +++ b/platform/linux-generic/odp_timer.c
>>> @@ -4,430 +4,854 @@
>>>   * SPDX-License-Identifier:     BSD-3-Clause
>>>   */
>>>
>>> -#include <odp_timer.h>
>>> -#include <odp_time.h>
>>> -#include <odp_buffer_pool_internal.h>
>>> +/**
>>> + * @file
>>> + *
>>> + * ODP timer service
>>> + *
>>> + */
>>> +
>>> +/* Check if compiler supports 16-byte atomics. GCC needs -mcx16 flag on
>>> x86 */
>>> +/* Using spin lock actually seems faster on Core2 */
>>> +#ifdef ODP_ATOMIC_U128
>>> +/* TB_NEEDS_PAD defined if sizeof(odp_buffer_t) != 8 */
>>> +#define TB_NEEDS_PAD
>>> +#define TB_SET_PAD(x) ((x).pad = 0)
>>> +#else
>>> +#define TB_SET_PAD(x) (void)(x)
>>> +#endif
>>> +
>>> +/* For snprint, POSIX timers and sigevent */
>>> +#define _POSIX_C_SOURCE 200112L
>>> +#include <assert.h>
>>> +#include <errno.h>
>>> +#include <string.h>
>>> +#include <stdlib.h>
>>> +#include <time.h>
>>> +#include <signal.h>
>>> +#include <odp_align.h>
>>> +#include <odp_align_internal.h>
>>> +#include <odp_atomic.h>
>>> +#include <odp_atomic_internal.h>
>>> +#include <odp_buffer.h>
>>>  #include <odp_buffer_inlines.h>
>>> -#include <odp_timer_internal.h>
>>> +#include <odp_buffer_pool.h>
>>> +#include <odp_buffer_pool_internal.h>
>>> +#include <odp_debug.h>
>>> +#include <odp_debug_internal.h>
>>> +#include <odp_hints.h>
>>>  #include <odp_internal.h>
>>> -#include <odp_atomic.h>
>>> +#include <odp_queue.h>
>>> +#include <odp_shared_memory.h>
>>> +#include <odp_spin_internal.h>
>>>  #include <odp_spinlock.h>
>>> +#include <odp_std_types.h>
>>>  #include <odp_sync.h>
>>> -#include <odp_debug_internal.h>
>>> -#include <odp_queue.h>
>>> +#include <odp_time.h>
>>> +#include <odp_timer.h>
>>> +#include <odp_timer_internal.h>
>>>
>>> -#include <signal.h>
>>> -#include <time.h>
>>> +#define TMO_UNUSED   ((uint64_t)0xFFFFFFFFFFFFFFFF)
>>> +/* TMO_INACTIVE is or-ed with the expiration tick to indicate an expired
>>> timer.
>>> + * The original expiration tick (63 bits) is still available so it can
>>> be used
>>> + * for checking the freshness of received timeouts */
>>> +#define TMO_INACTIVE ((uint64_t)0x8000000000000000)
>>> +
>>> +#ifdef __ARM_ARCH
>>> +#define PREFETCH(ptr) __builtin_prefetch((ptr), 0, 0)
>>> +#else
>>> +#define PREFETCH(ptr) (void)(ptr)
>>> +#endif
>>> +
>>>
>>> +/******************************************************************************
>>> + * Mutual exclusion in the absence of CAS16
>>> +
>>> *****************************************************************************/
>>> +
>>> +#ifndef ODP_ATOMIC_U128
>>> +#define NUM_LOCKS 1024
>>> +static _odp_atomic_flag_t locks[NUM_LOCKS]; /* Multiple locks per cache
>>> line! */
>>> +#define IDX2LOCK(idx) (&locks[(idx) % NUM_LOCKS])
>>> +#endif
>>> +
>>>
>>> +/******************************************************************************
>>> + * Translation between timeout buffer and timeout header
>>> +
>>> *****************************************************************************/
>>> +
>>> +static odp_timeout_hdr_t *timeout_hdr_from_buf(odp_buffer_t buf)
>>> +{
>>> +       return (odp_timeout_hdr_t *)odp_buf_to_hdr(buf);
>>> +}
>>>
>>> -#include <string.h>
>>>
>>> +/******************************************************************************
>>> + * odp_timer abstract datatype
>>> +
>>> *****************************************************************************/
>>> +
>>> +typedef struct tick_buf_s {
>>> +       odp_atomic_u64_t exp_tck;/* Expiration tick or TMO_xxx */
>>> +       odp_buffer_t tmo_buf;/* ODP_BUFFER_INVALID if timer not active */
>>> +#ifdef TB_NEEDS_PAD
>>> +       uint32_t pad;/* Need to be able to access padding for successful
>>> CAS */
>>> +#endif
>>> +} tick_buf_t
>>> +#ifdef ODP_ATOMIC_U128
>>> +ODP_ALIGNED(16) /* 16-byte atomic operations need properly aligned
>>> addresses */
>>> +#endif
>>> +;
>>> +
>>> +_ODP_STATIC_ASSERT(sizeof(tick_buf_t) == 16, "sizeof(tick_buf_t) ==
>>> 16");
>>> +
>>> +typedef struct odp_timer_s {
>>> +       void *user_ptr;
>>> +       odp_queue_t queue;/* Used for free list when timer is free */
>>> +} odp_timer;
>>> +
>>> +static void timer_init(odp_timer *tim,
>>> +               tick_buf_t *tb,
>>> +               odp_queue_t _q,
>>> +               void *_up)
>>> +{
>>> +       tim->queue = _q;
>>> +       tim->user_ptr = _up;
>>> +       tb->tmo_buf = ODP_BUFFER_INVALID;
>>> +       /* All pad fields need a defined and constant value */
>>> +       TB_SET_PAD(*tb);
>>> +       /* Release the timer by setting timer state to inactive */
>>> +       _odp_atomic_u64_store_mm(&tb->exp_tck, TMO_INACTIVE,
>>> _ODP_MEMMODEL_RLS);
>>> +}
>>>
>>> -#define NUM_TIMERS    1
>>> -#define MAX_TICKS     1024
>>> -#define MAX_RES       ODP_TIME_SEC
>>> -#define MIN_RES       (100*ODP_TIME_USEC)
>>> +/* Teardown when timer is freed */
>>> +static void timer_fini(odp_timer *tim, tick_buf_t *tb)
>>> +{
>>> +       assert(tb->exp_tck.v == TMO_UNUSED);
>>> +       assert(tb->tmo_buf == ODP_BUFFER_INVALID);
>>> +       tim->queue = ODP_QUEUE_INVALID;
>>> +       tim->user_ptr = NULL;
>>> +}
>>>
>>> +static inline uint32_t get_next_free(odp_timer *tim)
>>> +{
>>> +       /* Reusing 'queue' for next free index */
>>> +       return tim->queue;
>>> +}
>>>
>>> -typedef struct {
>>> -       odp_spinlock_t lock;
>>> -       timeout_t      *list;
>>> -} tick_t;
>>> -
>>> -typedef struct {
>>> -       int               allocated;
>>> -       volatile int      active;
>>> -       volatile uint64_t cur_tick;
>>> -       timer_t           timerid;
>>> -       odp_timer_t       timer_hdl;
>>> -       odp_buffer_pool_t pool;
>>> -       uint64_t          resolution_ns;
>>> -       uint64_t          max_ticks;
>>> -       tick_t            tick[MAX_TICKS];
>>> -
>>> -} timer_ring_t;
>>> -
>>> -typedef struct {
>>> -       odp_spinlock_t lock;
>>> -       int            num_timers;
>>> -       timer_ring_t   timer[NUM_TIMERS];
>>> +static inline void set_next_free(odp_timer *tim, uint32_t nf)
>>> +{
>>> +       assert(tim->queue == ODP_QUEUE_INVALID);
>>> +       /* Reusing 'queue' for next free index */
>>> +       tim->queue = nf;
>>> +}
>>>
>>> -} timer_global_t;
>>>
>>> +/******************************************************************************
>>> + * odp_timer_pool abstract datatype
>>> + * Inludes alloc and free timer
>>> +
>>> *****************************************************************************/
>>> +
>>> +typedef struct odp_timer_pool_s {
>>> +/* Put frequently accessed fields in the first cache line */
>>> +       odp_atomic_u64_t cur_tick;/* Current tick value */
>>> +       uint64_t min_rel_tck;
>>> +       uint64_t max_rel_tck;
>>> +       tick_buf_t *tick_buf; /* Expiration tick and timeout buffer */
>>> +       odp_timer *timers; /* User pointer and queue handle (and lock) */
>>> +       odp_atomic_u32_t high_wm;/* High watermark of allocated timers */
>>> +       odp_spinlock_t itimer_running;
>>> +       odp_spinlock_t lock;
>>> +       uint32_t num_alloc;/* Current number of allocated timers */
>>> +       uint32_t first_free;/* 0..max_timers-1 => free timer */
>>> +       uint32_t tp_idx;/* Index into timer_pool array */
>>> +       odp_timer_pool_param_t param;
>>> +       char name[ODP_TIMER_POOL_NAME_LEN];
>>> +       odp_buffer_pool_t buf_pool;
>>> +       odp_shm_t shm;
>>> +       timer_t timerid;
>>> +} odp_timer_pool;
>>> +
>>> +#define MAX_TIMER_POOLS 255 /* Leave one for ODP_TIMER_INVALID */
>>> +#define INDEX_BITS 24
>>> +static odp_atomic_u32_t num_timer_pools;
>>> +static odp_timer_pool *timer_pool[MAX_TIMER_POOLS];
>>> +
>>> +static inline odp_timer_pool *handle_to_tp(odp_timer_t hdl)
>>> +{
>>> +       uint32_t tp_idx = hdl >> INDEX_BITS;
>>> +       if (odp_likely(tp_idx < MAX_TIMER_POOLS)) {
>>> +               odp_timer_pool *tp = timer_pool[tp_idx];
>>> +               if (odp_likely(tp != NULL))
>>> +                       return timer_pool[tp_idx];
>>> +       }
>>> +       ODP_ABORT("Invalid timer handle %#x\n", hdl);
>>> +}
>>>
>>> -/* Global */
>>> -static timer_global_t odp_timer;
>>> +static inline uint32_t handle_to_idx(odp_timer_t hdl,
>>> +               struct odp_timer_pool_s *tp)
>>> +{
>>> +       uint32_t idx = hdl & ((1U << INDEX_BITS) - 1U);
>>> +       PREFETCH(&tp->tick_buf[idx]);
>>> +       if (odp_likely(idx < odp_atomic_load_u32(&tp->high_wm)))
>>> +               return idx;
>>> +       ODP_ABORT("Invalid timer handle %#x\n", hdl);
>>> +}
>>>
>>> -static void add_tmo(tick_t *tick, timeout_t *tmo)
>>> +static inline odp_timer_t tp_idx_to_handle(struct odp_timer_pool_s *tp,
>>> +               uint32_t idx)
>>>  {
>>> -       odp_spinlock_lock(&tick->lock);
>>> +       assert(idx < (1U << INDEX_BITS));
>>> +       return (tp->tp_idx << INDEX_BITS) | idx;
>>> +}
>>>
>>> -       tmo->next  = tick->list;
>>> -       tick->list = tmo;
>>> +/* Forward declarations */
>>> +static void itimer_init(odp_timer_pool *tp);
>>> +static void itimer_fini(odp_timer_pool *tp);
>>> +
>>> +static odp_timer_pool *odp_timer_pool_new(
>>> +       const char *_name,
>>> +       odp_buffer_pool_t _bp,
>>> +       const odp_timer_pool_param_t *param)
>>> +{
>>> +       uint32_t tp_idx = odp_atomic_fetch_add_u32(&num_timer_pools, 1);
>>> +       if (odp_unlikely(tp_idx >= MAX_TIMER_POOLS)) {
>>> +               /* Restore the previous value */
>>> +               odp_atomic_sub_u32(&num_timer_pools, 1);
>>> +               errno = ENFILE; /* Table overflow */
>>> +               return NULL;
>>> +       }
>>> +       size_t sz0 = ODP_ALIGN_ROUNDUP(sizeof(odp_timer_pool),
>>> +                       ODP_CACHE_LINE_SIZE);
>>> +       size_t sz1 = ODP_ALIGN_ROUNDUP(sizeof(tick_buf_t) *
>>> param->num_timers,
>>> +                       ODP_CACHE_LINE_SIZE);
>>> +       size_t sz2 = ODP_ALIGN_ROUNDUP(sizeof(odp_timer) *
>>> param->num_timers,
>>> +                       ODP_CACHE_LINE_SIZE);
>>> +       odp_shm_t shm = odp_shm_reserve(_name, sz0 + sz1 + sz2,
>>> +                       ODP_CACHE_LINE_SIZE, ODP_SHM_SW_ONLY);
>>> +       if (odp_unlikely(shm == ODP_SHM_INVALID))
>>> +               ODP_ABORT("%s: timer pool shm-alloc(%zuKB) failed\n",
>>> +                         _name, (sz0 + sz1 + sz2) / 1024);
>>> +       odp_timer_pool *tp = (odp_timer_pool *)odp_shm_addr(shm);
>>> +       odp_atomic_init_u64(&tp->cur_tick, 0);
>>> +       snprintf(tp->name, sizeof(tp->name), "%s", _name);
>>> +       tp->shm = shm;
>>> +       tp->buf_pool = _bp;
>>> +       tp->param = *param;
>>> +       tp->min_rel_tck = odp_timer_ns_to_tick(tp, param->min_tmo);
>>> +       tp->max_rel_tck = odp_timer_ns_to_tick(tp, param->max_tmo);
>>> +       tp->num_alloc = 0;
>>> +       odp_atomic_init_u32(&tp->high_wm, 0);
>>> +       tp->first_free = 0;
>>> +       tp->tick_buf = (void *)((char *)odp_shm_addr(shm) + sz0);
>>> +       tp->timers = (void *)((char *)odp_shm_addr(shm) + sz0 + sz1);
>>> +       /* Initialize all odp_timer entries */
>>> +       uint32_t i;
>>> +       for (i = 0; i < tp->param.num_timers; i++) {
>>> +               set_next_free(&tp->timers[i], i + 1);
>>> +               tp->timers[i].user_ptr = NULL;
>>> +               odp_atomic_init_u64(&tp->tick_buf[i].exp_tck,
>>> TMO_UNUSED);
>>> +               tp->tick_buf[i].tmo_buf = ODP_BUFFER_INVALID;
>>> +       }
>>> +       tp->tp_idx = tp_idx;
>>> +       odp_spinlock_init(&tp->lock);
>>> +       odp_spinlock_init(&tp->itimer_running);
>>> +       timer_pool[tp_idx] = tp;
>>> +       if (tp->param.clk_src == ODP_CLOCK_CPU)
>>> +               itimer_init(tp);
>>> +       return tp;
>>> +}
>>>
>>> -       odp_spinlock_unlock(&tick->lock);
>>> +static void odp_timer_pool_del(odp_timer_pool *tp)
>>> +{
>>> +       odp_spinlock_lock(&tp->lock);
>>> +       timer_pool[tp->tp_idx] = NULL;
>>> +       /* Wait for itimer thread to stop running */
>>> +       odp_spinlock_lock(&tp->itimer_running);
>>> +       if (tp->num_alloc != 0) {
>>> +               /* It's a programming error to attempt to destroy a */
>>> +               /* timer pool which is still in use */
>>> +               ODP_ABORT("%s: timers in use\n", tp->name);
>>> +       }
>>> +       if (tp->param.clk_src == ODP_CLOCK_CPU)
>>> +               itimer_fini(tp);
>>> +       int rc = odp_shm_free(tp->shm);
>>> +       if (rc != 0)
>>> +               ODP_ABORT("Failed to free shared memory (%d)\n", rc);
>>>  }
>>>
>>> -static timeout_t *rem_tmo(tick_t *tick)
>>> +static inline odp_timer_t timer_alloc(odp_timer_pool *tp,
>>> +                                     odp_queue_t queue,
>>> +                                     void *user_ptr)
>>>  {
>>> -       timeout_t *tmo;
>>> +       odp_timer_t hdl;
>>> +       odp_spinlock_lock(&tp->lock);
>>> +       if (odp_likely(tp->num_alloc < tp->param.num_timers)) {
>>> +               tp->num_alloc++;
>>> +               /* Remove first unused timer from free list */
>>> +               assert(tp->first_free != tp->param.num_timers);
>>> +               uint32_t idx = tp->first_free;
>>> +               odp_timer *tim = &tp->timers[idx];
>>> +               tp->first_free = get_next_free(tim);
>>> +               /* Initialize timer */
>>> +               timer_init(tim, &tp->tick_buf[idx], queue, user_ptr);
>>> +               if (odp_unlikely(tp->num_alloc >
>>> +                                odp_atomic_load_u32(&tp->high_wm)))
>>> +                       /* Update high_wm last with release model to
>>> +                        * ensure timer initialization is visible */
>>> +                       _odp_atomic_u32_store_mm(&tp->high_wm,
>>> +                                                tp->num_alloc,
>>> +                                                _ODP_MEMMODEL_RLS);
>>> +               hdl = tp_idx_to_handle(tp, idx);
>>> +       } else {
>>> +               errno = ENFILE; /* Reusing file table overflow */
>>> +               hdl = ODP_TIMER_INVALID;
>>> +       }
>>> +       odp_spinlock_unlock(&tp->lock);
>>> +       return hdl;
>>> +}
>>>
>>> -       odp_spinlock_lock(&tick->lock);
>>> +static odp_buffer_t timer_cancel(odp_timer_pool *tp,
>>> +               uint32_t idx,
>>> +               uint64_t new_state);
>>>
>>> -       tmo = tick->list;
>>> +static inline odp_buffer_t timer_free(odp_timer_pool *tp, uint32_t idx)
>>> +{
>>> +       odp_timer *tim = &tp->timers[idx];
>>>
>>> -       if (tmo)
>>> -               tick->list = tmo->next;
>>> +       /* Free the timer by setting timer state to unused and
>>> +        * grab any timeout buffer */
>>> +       odp_buffer_t old_buf = timer_cancel(tp, idx, TMO_UNUSED);
>>>
>>> -       odp_spinlock_unlock(&tick->lock);
>>> +       /* Destroy timer */
>>> +       timer_fini(tim, &tp->tick_buf[idx]);
>>>
>>> -       if (tmo)
>>> -               tmo->next = NULL;
>>> +       /* Insert timer into free list */
>>> +       odp_spinlock_lock(&tp->lock);
>>> +       set_next_free(tim, tp->first_free);
>>> +       tp->first_free = idx;
>>> +       assert(tp->num_alloc != 0);
>>> +       tp->num_alloc--;
>>> +       odp_spinlock_unlock(&tp->lock);
>>>
>>> -       return tmo;
>>> +       return old_buf;
>>>  }
>>>
>>> -/**
>>> - * Search and delete tmo entry from timeout list
>>> - * return -1 : on error.. handle not in list
>>> - *             0 : success
>>> - */
>>> -static int find_and_del_tmo(timeout_t **tmo, odp_timer_tmo_t handle)
>>> -{
>>> -       timeout_t *cur, *prev;
>>> -       prev = NULL;
>>>
>>> +/******************************************************************************
>>> + * Operations on timers
>>> + * expire/reset/cancel timer
>>> +
>>> *****************************************************************************/
>>>
>>> -       for (cur = *tmo; cur != NULL; prev = cur, cur = cur->next) {
>>> -               if (cur->tmo_buf == handle) {
>>> -                       if (prev == NULL)
>>> -                               *tmo = cur->next;
>>> -                       else
>>> -                               prev->next = cur->next;
>>> -
>>> -                       break;
>>> +static bool timer_reset(uint32_t idx,
>>> +               uint64_t abs_tck,
>>> +               odp_buffer_t *tmo_buf,
>>> +               odp_timer_pool *tp)
>>> +{
>>> +       bool success = true;
>>> +       tick_buf_t *tb = &tp->tick_buf[idx];
>>> +
>>> +       if (tmo_buf == NULL || *tmo_buf == ODP_BUFFER_INVALID) {
>>> +#ifdef ODP_ATOMIC_U128
>>> +               tick_buf_t new, old;
>>> +               do {
>>> +                       /* Relaxed and non-atomic read of current values
>>> */
>>> +                       old.exp_tck.v = tb->exp_tck.v;
>>> +                       old.tmo_buf = tb->tmo_buf;
>>> +                       TB_SET_PAD(old);
>>> +                       /* Check if there actually is a timeout buffer
>>> +                        * present */
>>> +                       if (old.tmo_buf == ODP_BUFFER_INVALID) {
>>> +                               /* Cannot reset a timer with neither old
>>> nor
>>> +                                * new timeout buffer */
>>> +                               success = false;
>>> +                               break;
>>> +                       }
>>> +                       /* Set up new values */
>>> +                       new.exp_tck.v = abs_tck;
>>> +                       new.tmo_buf = old.tmo_buf;
>>> +                       TB_SET_PAD(new);
>>> +                       /* Atomic CAS will fail if we experienced torn
>>> reads,
>>> +                        * retry update sequence until CAS succeeds */
>>> +               } while (!_odp_atomic_u128_cmp_xchg_mm(
>>> +                                       (_odp_atomic_u128_t *)tb,
>>> +                                       (_uint128_t *)&old,
>>> +                                       (_uint128_t *)&new,
>>> +                                       _ODP_MEMMODEL_RLS,
>>> +                                       _ODP_MEMMODEL_RLX));
>>> +#else
>>> +#ifdef __ARM_ARCH
>>> +               /* Since barriers are not good for C-A15, we take an
>>> +                * alternative approach using relaxed memory model */
>>> +               uint64_t old;
>>> +               /* Swap in new expiration tick, get back old tick which
>>> +                * will indicate active/inactive timer state */
>>> +               old = _odp_atomic_u64_xchg_mm(&tb->exp_tck, abs_tck,
>>> +                       _ODP_MEMMODEL_RLX);
>>> +               if ((old & TMO_INACTIVE) != 0) {
>>> +                       /* Timer was inactive (cancelled or expired),
>>> +                        * we can't reset a timer without a timeout
>>> buffer.
>>> +                        * Attempt to restore inactive state, we don't
>>> +                        * want this timer to continue as active without
>>> +                        * timeout as this will trigger unnecessary and
>>> +                        * aborted expiration attempts.
>>> +                        * We don't care if we fail, then some other
>>> thread
>>> +                        * reset or cancelled the timer. Without any
>>> +                        * synchronization between the threads, we have a
>>> +                        * data race and the behavior is undefined */
>>> +                       (void)_odp_atomic_u64_cmp_xchg_strong_mm(
>>> +                                       &tb->exp_tck,
>>> +                                       &abs_tck,
>>> +                                       old,
>>> +                                       _ODP_MEMMODEL_RLX,
>>> +                                       _ODP_MEMMODEL_RLX);
>>> +                       success = false;
>>> +               }
>>> +#else
>>> +               /* Take a related lock */
>>> +               while (_odp_atomic_flag_tas(IDX2LOCK(idx)))
>>> +                       /* While lock is taken, spin using relaxed loads
>>> */
>>> +                       while (_odp_atomic_flag_load(IDX2LOCK(idx)))
>>> +                               odp_spin();
>>> +
>>> +               /* Only if there is a timeout buffer can be reset the
>>> timer */
>>> +               if (odp_likely(tb->tmo_buf != ODP_BUFFER_INVALID)) {
>>> +                       /* Write the new expiration tick */
>>> +                       tb->exp_tck.v = abs_tck;
>>> +               } else {
>>> +                       /* Cannot reset a timer with neither old nor new
>>> +                        * timeout buffer */
>>> +                       success = false;
>>>                 }
>>> -       }
>>> -
>>> -       if (!cur)
>>> -               /* couldn't find tmo in list */
>>> -               return -1;
>>>
>>> -       /* application to free tmo_buf provided by absolute_tmo call */
>>> -       return 0;
>>> +               /* Release the lock */
>>> +               _odp_atomic_flag_clear(IDX2LOCK(idx));
>>> +#endif
>>> +#endif
>>> +       } else {
>>> +               /* We have a new timeout buffer which replaces any old
>>> one */
>>> +               odp_buffer_t old_buf = ODP_BUFFER_INVALID;
>>> +#ifdef ODP_ATOMIC_U128
>>> +               tick_buf_t new, old;
>>> +               new.exp_tck.v = abs_tck;
>>> +               new.tmo_buf = *tmo_buf;
>>> +               TB_SET_PAD(new);
>>> +               /* We are releasing the new timeout buffer to some other
>>> +                * thread */
>>> +               _odp_atomic_u128_xchg_mm((_odp_atomic_u128_t *)tb,
>>> +                                        (_uint128_t *)&new,
>>> +                                        (_uint128_t *)&old,
>>> +                                        _ODP_MEMMODEL_ACQ_RLS);
>>> +               old_buf = old.tmo_buf;
>>> +#else
>>> +               /* Take a related lock */
>>> +               while (_odp_atomic_flag_tas(IDX2LOCK(idx)))
>>> +                       /* While lock is taken, spin using relaxed loads
>>> */
>>> +                       while (_odp_atomic_flag_load(IDX2LOCK(idx)))
>>> +                               odp_spin();
>>> +
>>> +               /* Swap in new buffer, save any old buffer */
>>> +               old_buf = tb->tmo_buf;
>>> +               tb->tmo_buf = *tmo_buf;
>>> +
>>> +               /* Write the new expiration tick */
>>> +               tb->exp_tck.v = abs_tck;
>>> +
>>> +               /* Release the lock */
>>> +               _odp_atomic_flag_clear(IDX2LOCK(idx));
>>> +#endif
>>> +               /* Return old timeout buffer */
>>> +               *tmo_buf = old_buf;
>>> +       }
>>> +       return success;
>>>  }
>>>
>>> -int odp_timer_cancel_tmo(odp_timer_t timer_hdl, odp_timer_tmo_t tmo)
>>> +static odp_buffer_t timer_cancel(odp_timer_pool *tp,
>>> +               uint32_t idx,
>>> +               uint64_t new_state)
>>>  {
>>> -       int id;
>>> -       int tick_idx;
>>> -       timeout_t *cancel_tmo;
>>> -       odp_timeout_hdr_t *tmo_hdr;
>>> -       tick_t *tick;
>>> -
>>> -       /* get id */
>>> -       id = (int)timer_hdl - 1;
>>> -
>>> -       tmo_hdr = odp_timeout_hdr((odp_timeout_t) tmo);
>>> -       /* get tmo_buf to cancel */
>>> -       cancel_tmo = &tmo_hdr->meta;
>>> -
>>> -       tick_idx = cancel_tmo->tick;
>>> -       tick = &odp_timer.timer[id].tick[tick_idx];
>>> +       tick_buf_t *tb = &tp->tick_buf[idx];
>>> +       odp_buffer_t old_buf;
>>> +
>>> +#ifdef ODP_ATOMIC_U128
>>> +       tick_buf_t new, old;
>>> +       /* Update the timer state (e.g. cancel the current timeout) */
>>> +       new.exp_tck.v = new_state;
>>> +       /* Swap out the old buffer */
>>> +       new.tmo_buf = ODP_BUFFER_INVALID;
>>> +       TB_SET_PAD(new);
>>> +       _odp_atomic_u128_xchg_mm((_odp_atomic_u128_t *)tb,
>>> +                                (_uint128_t *)&new, (_uint128_t *)&old,
>>> +                                _ODP_MEMMODEL_RLX);
>>> +       old_buf = old.tmo_buf;
>>> +#else
>>> +       /* Take a related lock */
>>> +       while (_odp_atomic_flag_tas(IDX2LOCK(idx)))
>>> +               /* While lock is taken, spin using relaxed loads */
>>> +               while (_odp_atomic_flag_load(IDX2LOCK(idx)))
>>> +                       odp_spin();
>>> +
>>> +       /* Update the timer state (e.g. cancel the current timeout) */
>>> +       tb->exp_tck.v = new_state;
>>> +
>>> +       /* Swap out the old buffer */
>>> +       old_buf = tb->tmo_buf;
>>> +       tb->tmo_buf = ODP_BUFFER_INVALID;
>>> +
>>> +       /* Release the lock */
>>> +       _odp_atomic_flag_clear(IDX2LOCK(idx));
>>> +#endif
>>> +       /* Return the old buffer */
>>> +       return old_buf;
>>> +}
>>>
>>> -       odp_spinlock_lock(&tick->lock);
>>> -       /* search and delete tmo from tick list */
>>> -       if (find_and_del_tmo(&tick->list, tmo) != 0) {
>>> -               odp_spinlock_unlock(&tick->lock);
>>> -               ODP_DBG("Couldn't find the tmo (%d) in tick list\n",
>>> (int)tmo);
>>> -               return -1;
>>> +static unsigned timer_expire(odp_timer_pool *tp, uint32_t idx, uint64_t
>>> tick)
>>> +{
>>> +       odp_timer *tim = &tp->timers[idx];
>>> +       tick_buf_t *tb = &tp->tick_buf[idx];
>>> +       odp_buffer_t tmo_buf = ODP_BUFFER_INVALID;
>>> +       uint64_t exp_tck;
>>> +#ifdef ODP_ATOMIC_U128
>>> +       /* Atomic re-read for correctness */
>>> +       exp_tck = _odp_atomic_u64_load_mm(&tb->exp_tck,
>>> _ODP_MEMMODEL_RLX);
>>> +       /* Re-check exp_tck */
>>> +       if (odp_likely(exp_tck <= tick)) {
>>> +               /* Attempt to grab timeout buffer, replace with inactive
>>> timer
>>> +                * and invalid buffer */
>>> +               tick_buf_t new, old;
>>> +               old.exp_tck.v = exp_tck;
>>> +               old.tmo_buf = tb->tmo_buf;
>>> +               TB_SET_PAD(old);
>>> +               /* Set the inactive/expired bit keeping the expiration
>>> tick so
>>> +                * that we can check against the expiration tick of the
>>> timeout
>>> +                * when it is received */
>>> +               new.exp_tck.v = exp_tck | TMO_INACTIVE;
>>> +               new.tmo_buf = ODP_BUFFER_INVALID;
>>> +               TB_SET_PAD(new);
>>> +               int succ = _odp_atomic_u128_cmp_xchg_mm(
>>> +                               (_odp_atomic_u128_t *)tb,
>>> +                               (_uint128_t *)&old, (_uint128_t *)&new,
>>> +                               _ODP_MEMMODEL_RLS, _ODP_MEMMODEL_RLX);
>>> +               if (succ)
>>> +                       tmo_buf = old.tmo_buf;
>>> +               /* Else CAS failed, something changed => skip timer
>>> +                * this tick, it will be checked again next tick */
>>> +       }
>>> +       /* Else false positive, ignore */
>>> +#else
>>> +       /* Take a related lock */
>>> +       while (_odp_atomic_flag_tas(IDX2LOCK(idx)))
>>> +               /* While lock is taken, spin using relaxed loads */
>>> +               while (_odp_atomic_flag_load(IDX2LOCK(idx)))
>>> +                       odp_spin();
>>> +       /* Proper check for timer expired */
>>> +       exp_tck = tb->exp_tck.v;
>>> +       if (odp_likely(exp_tck <= tick)) {
>>> +               /* Verify that there is a timeout buffer */
>>> +               if (odp_likely(tb->tmo_buf != ODP_BUFFER_INVALID)) {
>>> +                       /* Grab timeout buffer, replace with inactive
>>> timer
>>> +                        * and invalid buffer */
>>> +                       tmo_buf = tb->tmo_buf;
>>> +                       tb->tmo_buf = ODP_BUFFER_INVALID;
>>> +                       /* Set the inactive/expired bit keeping the
>>> expiration
>>> +                        * tick so that we can check against the
>>> expiration
>>> +                        * tick of the timeout when it is received */
>>> +                       tb->exp_tck.v |= TMO_INACTIVE;
>>> +               }
>>> +               /* Else somehow active timer without user buffer */
>>> +       }
>>> +       /* Else false positive, ignore */
>>> +       /* Release the lock */
>>> +       _odp_atomic_flag_clear(IDX2LOCK(idx));
>>> +#endif
>>> +       if (odp_likely(tmo_buf != ODP_BUFFER_INVALID)) {
>>> +               /* Fill in metadata fields in system timeout buffer */
>>> +               if (odp_buffer_type(tmo_buf) == ODP_BUFFER_TYPE_TIMEOUT)
>>> {
>>> +                       /* Convert from buffer to timeout hdr */
>>> +                       odp_timeout_hdr_t *tmo_hdr =
>>> +                               timeout_hdr_from_buf(tmo_buf);
>>> +                       tmo_hdr->timer = tp_idx_to_handle(tp, idx);
>>> +                       tmo_hdr->expiration = exp_tck;
>>> +                       tmo_hdr->user_ptr = tim->user_ptr;
>>> +               }
>>> +               /* Else ignore buffers of other types */
>>> +               /* Post the timeout to the destination queue */
>>> +               int rc = odp_queue_enq(tim->queue, tmo_buf);
>>> +               if (odp_unlikely(rc != 0))
>>> +                       ODP_ABORT("Failed to enqueue timeout buffer
>>> (%d)\n",
>>> +                                 rc);
>>> +               return 1;
>>> +       } else {
>>> +               /* Else false positive, ignore */
>>> +               return 0;
>>>         }
>>> -       odp_spinlock_unlock(&tick->lock);
>>> -
>>> -       return 0;
>>>  }
>>>
>>> -static void notify_function(union sigval sigval)
>>> +static unsigned odp_timer_pool_expire(odp_timer_pool_t tpid, uint64_t
>>> tick)
>>>  {
>>> -       uint64_t cur_tick;
>>> -       timeout_t *tmo;
>>> -       tick_t *tick;
>>> -       timer_ring_t *timer;
>>> -
>>> -       timer = sigval.sival_ptr;
>>> -
>>> -       if (timer->active == 0) {
>>> -               ODP_DBG("Timer (%u) not active\n", timer->timer_hdl);
>>> -               return;
>>> +       tick_buf_t *array = &tpid->tick_buf[0];
>>> +       uint32_t high_wm = _odp_atomic_u32_load_mm(&tpid->high_wm,
>>> +                       _ODP_MEMMODEL_ACQ);
>>> +       unsigned nexp = 0;
>>> +       uint32_t i;
>>> +
>>> +       assert(high_wm <= tpid->param.num_timers);
>>> +       for (i = 0; i < high_wm;) {
>>> +#ifdef __ARM_ARCH
>>> +               /* As a rare occurence, we can outsmart the HW prefetcher
>>> +                * and the compiler (GCC -fprefetch-loop-arrays) with
>>> some
>>> +                * tuned manual prefetching (32x16=512B ahead), seems to
>>> +                * give 30% better performance on ARM C-A15 */
>>> +               PREFETCH(&array[i + 32]);
>>> +#endif
>>> +               /* Non-atomic read for speed */
>>> +               uint64_t exp_tck = array[i++].exp_tck.v;
>>> +               if (odp_unlikely(exp_tck <= tick)) {
>>> +                       /* Attempt to expire timer */
>>> +                       nexp += timer_expire(tpid, i - 1, tick);
>>> +               }
>>>         }
>>> +       return nexp;
>>> +}
>>>
>>> -       /* ODP_DBG("Tick\n"); */
>>> -
>>> -       cur_tick = timer->cur_tick++;
>>> -
>>> -       odp_sync_stores();
>>> -
>>> -       tick = &timer->tick[cur_tick % MAX_TICKS];
>>> -
>>> -       while ((tmo = rem_tmo(tick)) != NULL) {
>>> -               odp_queue_t  queue;
>>> -               odp_buffer_t buf;
>>> -
>>> -               queue = tmo->queue;
>>> -               buf   = tmo->buf;
>>> -
>>> -               if (buf != tmo->tmo_buf)
>>> -                       odp_buffer_free(tmo->tmo_buf);
>>>
>>> +/******************************************************************************
>>> + * POSIX timer support
>>> + * Functions that use Linux/POSIX per-process timers and related
>>> facilities
>>> +
>>> *****************************************************************************/
>>>
>>> -               odp_queue_enq(queue, buf);
>>> +static void timer_notify(sigval_t sigval)
>>> +{
>>> +       odp_timer_pool *tp = (odp_timer_pool *)sigval.sival_ptr;
>>> +#ifdef __ARM_ARCH
>>> +       odp_timer *array = &tp->timers[0];
>>> +       uint32_t i;
>>> +       /* Prefetch initial cache lines (match 32 above) */
>>> +       for (i = 0; i < 32; i += ODP_CACHE_LINE_SIZE / sizeof(array[0]))
>>> +               PREFETCH(&array[i]);
>>> +#endif
>>> +       uint64_t prev_tick = odp_atomic_fetch_inc_u64(&tp->cur_tick);
>>> +       /* Attempt to acquire the lock, check if the old value was clear
>>> */
>>> +       if (odp_spinlock_trylock(&tp->itimer_running)) {
>>> +               /* Scan timer array, looking for timers to expire */
>>> +               (void)odp_timer_pool_expire(tp, prev_tick);
>>> +               odp_spinlock_unlock(&tp->itimer_running);
>>>         }
>>> +       /* Else skip scan of timers. cur_tick was updated and next itimer
>>> +        * invocation will process older expiration ticks as well */
>>>  }
>>>
>>> -static void timer_start(timer_ring_t *timer)
>>> +static void itimer_init(odp_timer_pool *tp)
>>>  {
>>>         struct sigevent   sigev;
>>>         struct itimerspec ispec;
>>>         uint64_t res, sec, nsec;
>>>
>>> -       ODP_DBG("\nTimer (%u) starts\n", timer->timer_hdl);
>>> +       ODP_DBG("Creating POSIX timer for timer pool %s, period %"
>>> +               PRIu64" ns\n", tp->name, tp->param.res_ns);
>>>
>>>         memset(&sigev, 0, sizeof(sigev));
>>>         memset(&ispec, 0, sizeof(ispec));
>>>
>>>         sigev.sigev_notify          = SIGEV_THREAD;
>>> -       sigev.sigev_notify_function = notify_function;
>>> -       sigev.sigev_value.sival_ptr = timer;
>>> +       sigev.sigev_notify_function = timer_notify;
>>> +       sigev.sigev_value.sival_ptr = tp;
>>>
>>> -       if (timer_create(CLOCK_MONOTONIC, &sigev, &timer->timerid)) {
>>> -               ODP_DBG("Timer create failed\n");
>>> -               return;
>>> -       }
>>> +       if (timer_create(CLOCK_MONOTONIC, &sigev, &tp->timerid))
>>> +               ODP_ABORT("timer_create() returned error %s\n",
>>> +                         strerror(errno));
>>>
>>> -       res  = timer->resolution_ns;
>>> +       res  = tp->param.res_ns;
>>>         sec  = res / ODP_TIME_SEC;
>>> -       nsec = res - sec*ODP_TIME_SEC;
>>> +       nsec = res - sec * ODP_TIME_SEC;
>>>
>>>         ispec.it_interval.tv_sec  = (time_t)sec;
>>>         ispec.it_interval.tv_nsec = (long)nsec;
>>>         ispec.it_value.tv_sec     = (time_t)sec;
>>>         ispec.it_value.tv_nsec    = (long)nsec;
>>>
>>> -       if (timer_settime(timer->timerid, 0, &ispec, NULL)) {
>>> -               ODP_DBG("Timer set failed\n");
>>> -               return;
>>> -       }
>>> -
>>> -       return;
>>> +       if (timer_settime(&tp->timerid, 0, &ispec, NULL))
>>> +               ODP_ABORT("timer_settime() returned error %s\n",
>>> +                         strerror(errno));
>>>  }
>>>
>>> -int odp_timer_init_global(void)
>>> +static void itimer_fini(odp_timer_pool *tp)
>>>  {
>>> -       ODP_DBG("Timer init ...");
>>> -
>>> -       memset(&odp_timer, 0, sizeof(timer_global_t));
>>> -
>>> -       odp_spinlock_init(&odp_timer.lock);
>>> -
>>> -       ODP_DBG("done\n");
>>> -
>>> -       return 0;
>>> +       if (timer_delete(tp->timerid) != 0)
>>> +               ODP_ABORT("timer_delete() returned error %s\n",
>>> +                         strerror(errno));
>>>  }
>>>
>>> -int odp_timer_disarm_all(void)
>>>
>>> +/******************************************************************************
>>> + * Public API functions
>>> + * Some parameter checks and error messages
>>> + * No modificatios of internal state
>>> +
>>> *****************************************************************************/
>>> +odp_timer_pool_t
>>> +odp_timer_pool_create(const char *name,
>>> +                     odp_buffer_pool_t buf_pool,
>>> +                     const odp_timer_pool_param_t *param)
>>>  {
>>> -       int timers;
>>> -       struct itimerspec ispec;
>>> +       /* Verify that buffer pool can be used for timeouts */
>>> +       odp_buffer_t buf = odp_buffer_alloc(buf_pool);
>>> +       if (buf == ODP_BUFFER_INVALID)
>>> +               ODP_ABORT("%s: Failed to allocate buffer\n", name);
>>> +       if (odp_buffer_type(buf) != ODP_BUFFER_TYPE_TIMEOUT)
>>> +               ODP_ABORT("%s: Buffer pool wrong type\n", name);
>>> +       odp_buffer_free(buf);
>>> +       odp_timer_pool_t tp = odp_timer_pool_new(name, buf_pool, param);
>>> +       return tp;
>>> +}
>>>
>>> -       odp_spinlock_lock(&odp_timer.lock);
>>> +void odp_timer_pool_start(void)
>>> +{
>>> +       /* Nothing to do here, timer pools are started by the create call
>>> */
>>> +}
>>>
>>> -       timers = odp_timer.num_timers;
>>> +void odp_timer_pool_destroy(odp_timer_pool_t tpid)
>>> +{
>>> +       odp_timer_pool_del(tpid);
>>> +}
>>>
>>> -       ispec.it_interval.tv_sec  = 0;
>>> -       ispec.it_interval.tv_nsec = 0;
>>> -       ispec.it_value.tv_sec     = 0;
>>> -       ispec.it_value.tv_nsec    = 0;
>>> +uint64_t odp_timer_tick_to_ns(odp_timer_pool_t tpid, uint64_t ticks)
>>> +{
>>> +       return ticks * tpid->param.res_ns;
>>> +}
>>>
>>> -       for (; timers >= 0; timers--) {
>>> -               if (timer_settime(odp_timer.timer[timers].timerid,
>>> -                                 0, &ispec, NULL)) {
>>> -                       ODP_DBG("Timer reset failed\n");
>>> -                       odp_spinlock_unlock(&odp_timer.lock);
>>> -                       return -1;
>>> -               }
>>> -               odp_timer.num_timers--;
>>> -       }
>>> +uint64_t odp_timer_ns_to_tick(odp_timer_pool_t tpid, uint64_t ns)
>>> +{
>>> +       return (uint64_t)(ns / tpid->param.res_ns);
>>> +}
>>>
>>> -       odp_spinlock_unlock(&odp_timer.lock);
>>> +uint64_t odp_timer_current_tick(odp_timer_pool_t tpid)
>>> +{
>>> +       /* Relaxed atomic read for lowest overhead */
>>> +       return odp_atomic_load_u64(&tpid->cur_tick);
>>> +}
>>>
>>> +int odp_timer_pool_info(odp_timer_pool_t tpid,
>>> +                       odp_timer_pool_info_t *buf)
>>> +{
>>> +       buf->param = tpid->param;
>>> +       buf->cur_timers = tpid->num_alloc;
>>> +       buf->hwm_timers = odp_atomic_load_u32(&tpid->high_wm);
>>> +       buf->name = tpid->name;
>>>         return 0;
>>>  }
>>>
>>> -odp_timer_t odp_timer_create(const char *name, odp_buffer_pool_t pool,
>>> -                            uint64_t resolution_ns, uint64_t min_ns,
>>> -                            uint64_t max_ns)
>>> +odp_timer_t odp_timer_alloc(odp_timer_pool_t tpid,
>>> +                           odp_queue_t queue,
>>> +                           void *user_ptr)
>>>  {
>>> -       uint32_t id;
>>> -       timer_ring_t *timer;
>>> -       odp_timer_t timer_hdl;
>>> -       int i;
>>> -       uint64_t max_ticks;
>>> -       (void) name;
>>> -
>>> -       if (resolution_ns < MIN_RES)
>>> -               resolution_ns = MIN_RES;
>>> -
>>> -       if (resolution_ns > MAX_RES)
>>> -               resolution_ns = MAX_RES;
>>> -
>>> -       max_ticks = max_ns / resolution_ns;
>>> -
>>> -       if (max_ticks > MAX_TICKS) {
>>> -               ODP_DBG("Maximum timeout too long: %"PRIu64" ticks\n",
>>> -                       max_ticks);
>>> -               return ODP_TIMER_INVALID;
>>> -       }
>>> -
>>> -       if (min_ns < resolution_ns) {
>>> -               ODP_DBG("Min timeout %"PRIu64" ns < resolution %"PRIu64"
>>> ns\n",
>>> -                       min_ns, resolution_ns);
>>> -               return ODP_TIMER_INVALID;
>>> -       }
>>> -
>>> -       odp_spinlock_lock(&odp_timer.lock);
>>> -
>>> -       if (odp_timer.num_timers >= NUM_TIMERS) {
>>> -               odp_spinlock_unlock(&odp_timer.lock);
>>> -               ODP_DBG("All timers allocated\n");
>>> -               return ODP_TIMER_INVALID;
>>> -       }
>>> -
>>> -       for (id = 0; id < NUM_TIMERS; id++) {
>>> -               if (odp_timer.timer[id].allocated == 0)
>>> -                       break;
>>> -       }
>>> -
>>> -       timer = &odp_timer.timer[id];
>>> -       timer->allocated = 1;
>>> -       odp_timer.num_timers++;
>>> -
>>> -       odp_spinlock_unlock(&odp_timer.lock);
>>> -
>>> -       timer_hdl = id + 1;
>>> -
>>> -       timer->timer_hdl     = timer_hdl;
>>> -       timer->pool          = pool;
>>> -       timer->resolution_ns = resolution_ns;
>>> -       timer->max_ticks     = MAX_TICKS;
>>> -
>>> -       for (i = 0; i < MAX_TICKS; i++) {
>>> -               odp_spinlock_init(&timer->tick[i].lock);
>>> -               timer->tick[i].list = NULL;
>>> +       if (odp_unlikely(queue == ODP_QUEUE_INVALID))
>>> +               ODP_ABORT("%s: Invalid queue handle\n", tpid->name);
>>> +       /* We don't care about the validity of user_ptr because we will
>>> not
>>> +        * attempt to dereference it */
>>> +       odp_timer_t hdl = timer_alloc(tpid, queue, user_ptr);
>>> +       if (odp_likely(hdl != ODP_TIMER_INVALID)) {
>>> +               /* Success */
>>> +               return hdl;
>>>         }
>>> -
>>> -       timer->active = 1;
>>> -       odp_sync_stores();
>>> -
>>> -       timer_start(timer);
>>> -
>>> -       return timer_hdl;
>>> +       /* errno set by timer_alloc() */
>>> +       return ODP_TIMER_INVALID;
>>>  }
>>>
>>> -odp_timer_tmo_t odp_timer_absolute_tmo(odp_timer_t timer_hdl, uint64_t
>>> tmo_tick,
>>> -                                      odp_queue_t queue, odp_buffer_t
>>> buf)
>>> +odp_buffer_t odp_timer_free(odp_timer_t hdl)
>>>  {
>>> -       int id;
>>> -       uint64_t tick;
>>> -       uint64_t cur_tick;
>>> -       timeout_t *new_tmo;
>>> -       odp_buffer_t tmo_buf;
>>> -       odp_timeout_hdr_t *tmo_hdr;
>>> -       timer_ring_t *timer;
>>> -
>>> -       id = (int)timer_hdl - 1;
>>> -       timer = &odp_timer.timer[id];
>>> -
>>> -       cur_tick = timer->cur_tick;
>>> -       if (tmo_tick <= cur_tick) {
>>> -               ODP_DBG("timeout too close\n");
>>> -               return ODP_TIMER_TMO_INVALID;
>>> -       }
>>> -
>>> -       if ((tmo_tick - cur_tick) > MAX_TICKS) {
>>> -               ODP_DBG("timeout too far: cur %"PRIu64" tmo %"PRIu64"\n",
>>> -                       cur_tick, tmo_tick);
>>> -               return ODP_TIMER_TMO_INVALID;
>>> -       }
>>> -
>>> -       tick = tmo_tick % MAX_TICKS;
>>> -
>>> -       tmo_buf = odp_buffer_alloc(timer->pool);
>>> -       if (tmo_buf == ODP_BUFFER_INVALID) {
>>> -               ODP_DBG("tmo buffer alloc failed\n");
>>> -               return ODP_TIMER_TMO_INVALID;
>>> -       }
>>> -
>>> -       tmo_hdr = odp_timeout_hdr((odp_timeout_t) tmo_buf);
>>> -       new_tmo = &tmo_hdr->meta;
>>> -
>>> -       new_tmo->timer_id = id;
>>> -       new_tmo->tick     = (int)tick;
>>> -       new_tmo->tmo_tick = tmo_tick;
>>> -       new_tmo->queue    = queue;
>>> -       new_tmo->tmo_buf  = tmo_buf;
>>> +       odp_timer_pool *tp = handle_to_tp(hdl);
>>> +       uint32_t idx = handle_to_idx(hdl, tp);
>>> +       odp_buffer_t old_buf = timer_free(tp, idx);
>>> +       return old_buf;
>>> +}
>>>
>>> -       if (buf != ODP_BUFFER_INVALID)
>>> -               new_tmo->buf = buf;
>>> +int odp_timer_set_abs(odp_timer_t hdl,
>>> +                     uint64_t abs_tck,
>>> +                     odp_buffer_t *tmo_buf)
>>> +{
>>> +       odp_timer_pool *tp = handle_to_tp(hdl);
>>> +       uint32_t idx = handle_to_idx(hdl, tp);
>>> +       uint64_t cur_tick = odp_atomic_load_u64(&tp->cur_tick);
>>> +       if (odp_unlikely(abs_tck < cur_tick + tp->min_rel_tck))
>>> +               return ODP_TIMER_SET_TOOEARLY;
>>> +       if (odp_unlikely(abs_tck > cur_tick + tp->max_rel_tck))
>>> +               return ODP_TIMER_SET_TOOLATE;
>>> +       if (timer_reset(idx, abs_tck, tmo_buf, tp))
>>> +               return ODP_TIMER_SET_SUCCESS;
>>>         else
>>> -               new_tmo->buf = tmo_buf;
>>> -
>>> -       add_tmo(&timer->tick[tick], new_tmo);
>>> -
>>> -       return tmo_buf;
>>> +               return ODP_TIMER_SET_NOBUF;
>>>  }
>>>
>>> -uint64_t odp_timer_tick_to_ns(odp_timer_t timer_hdl, uint64_t ticks)
>>> +int odp_timer_set_rel(odp_timer_t hdl,
>>> +                     uint64_t rel_tck,
>>> +                     odp_buffer_t *tmo_buf)
>>>  {
>>> -       uint32_t id;
>>> -
>>> -       id = timer_hdl - 1;
>>> -       return ticks * odp_timer.timer[id].resolution_ns;
>>> +       odp_timer_pool *tp = handle_to_tp(hdl);
>>> +       uint32_t idx = handle_to_idx(hdl, tp);
>>> +       uint64_t abs_tck = odp_atomic_load_u64(&tp->cur_tick) + rel_tck;
>>> +       if (odp_unlikely(rel_tck < tp->min_rel_tck))
>>> +               return ODP_TIMER_SET_TOOEARLY;
>>> +       if (odp_unlikely(rel_tck > tp->max_rel_tck))
>>> +               return ODP_TIMER_SET_TOOLATE;
>>> +       if (timer_reset(idx, abs_tck, tmo_buf, tp))
>>> +               return ODP_TIMER_SET_SUCCESS;
>>> +       else
>>> +               return ODP_TIMER_SET_NOBUF;
>>>  }
>>>
>>> -uint64_t odp_timer_ns_to_tick(odp_timer_t timer_hdl, uint64_t ns)
>>> +int odp_timer_cancel(odp_timer_t hdl, odp_buffer_t *tmo_buf)
>>>  {
>>> -       uint32_t id;
>>> -
>>> -       id = timer_hdl - 1;
>>> -       return ns / odp_timer.timer[id].resolution_ns;
>>> +       odp_timer_pool *tp = handle_to_tp(hdl);
>>> +       uint32_t idx = handle_to_idx(hdl, tp);
>>> +       /* Set the expiration tick of the timer to TMO_INACTIVE */
>>> +       odp_buffer_t old_buf = timer_cancel(tp, idx, TMO_INACTIVE);
>>> +       if (old_buf != ODP_BUFFER_INVALID) {
>>> +               *tmo_buf = old_buf;
>>> +               return 0; /* Active timer cancelled, timeout returned */
>>> +       } else {
>>> +               return -1; /* Timer already expired, no timeout returned
>>> */
>>> +       }
>>>  }
>>>
>>> -uint64_t odp_timer_resolution(odp_timer_t timer_hdl)
>>> +odp_timeout_t odp_timeout_from_buf(odp_buffer_t buf)
>>>  {
>>> -       uint32_t id;
>>> -
>>> -       id = timer_hdl - 1;
>>> -       return odp_timer.timer[id].resolution_ns;
>>> +       /* This check not mandated by the API specification */
>>> +       if (odp_buffer_type(buf) != ODP_BUFFER_TYPE_TIMEOUT)
>>> +               ODP_ABORT("Buffer not a timeout");
>>> +       return (odp_timeout_t)timeout_hdr_from_buf(buf);
>>>  }
>>>
>>> -uint64_t odp_timer_maximum_tmo(odp_timer_t timer_hdl)
>>> +int odp_timeout_fresh(odp_timeout_t tmo)
>>>  {
>>> -       uint32_t id;
>>> -
>>> -       id = timer_hdl - 1;
>>> -       return odp_timer.timer[id].max_ticks;
>>> +       const odp_timeout_hdr_t *hdr = (odp_timeout_hdr_t *)tmo;
>>> +       odp_timer_t hdl = hdr->timer;
>>> +       odp_timer_pool *tp = handle_to_tp(hdl);
>>> +       uint32_t idx = handle_to_idx(hdl, tp);
>>> +       tick_buf_t *tb = &tp->tick_buf[idx];
>>> +       uint64_t exp_tck = odp_atomic_load_u64(&tb->exp_tck);
>>> +       /* Return true if the timer still has the same expiration tick
>>> +        * (ignoring the inactive/expired bit) as the timeout */
>>> +       return hdr->expiration == (exp_tck & ~TMO_INACTIVE);
>>>  }
>>>
>>> -uint64_t odp_timer_current_tick(odp_timer_t timer_hdl)
>>> +odp_timer_t odp_timeout_timer(odp_timeout_t tmo)
>>>  {
>>> -       uint32_t id;
>>> +       const odp_timeout_hdr_t *hdr = (odp_timeout_hdr_t *)tmo;
>>> +       return hdr->timer;
>>> +}
>>>
>>> -       id = timer_hdl - 1;
>>> -       return odp_timer.timer[id].cur_tick;
>>> +uint64_t odp_timeout_tick(odp_timeout_t tmo)
>>> +{
>>> +       const odp_timeout_hdr_t *hdr = (odp_timeout_hdr_t *)tmo;
>>> +       return hdr->expiration;
>>>  }
>>>
>>> -odp_timeout_t odp_timeout_from_buffer(odp_buffer_t buf)
>>> +void *odp_timeout_user_ptr(odp_timeout_t tmo)
>>>  {
>>> -       return (odp_timeout_t) buf;
>>> +       const odp_timeout_hdr_t *hdr = (odp_timeout_hdr_t *)tmo;
>>> +       return hdr->user_ptr;
>>>  }
>>>
>>> -uint64_t odp_timeout_tick(odp_timeout_t tmo)
>>> +int odp_timer_init_global(void)
>>>  {
>>> -       odp_timeout_hdr_t *tmo_hdr = odp_timeout_hdr(tmo);
>>> -       return tmo_hdr->meta.tmo_tick;
>>> +#ifndef ODP_ATOMIC_U128
>>> +       uint32_t i;
>>> +       for (i = 0; i < NUM_LOCKS; i++)
>>> +               _odp_atomic_flag_clear(&locks[i]);
>>> +#else
>>> +       ODP_DBG("Using lock-less timer implementation\n");
>>> +#endif
>>> +       odp_atomic_init_u32(&num_timer_pools, 0);
>>> +       return 0;
>>>  }
>>> --
>>> 1.9.1
>>>
>>>
>>> _______________________________________________
>>> lng-odp mailing list
>>> lng-odp@lists.linaro.org
>>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>
>>
>

_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to