From patchwork Tue Mar 11 14:11:40 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petri Savolainen X-Patchwork-Id: 26021 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qc0-f198.google.com (mail-qc0-f198.google.com [209.85.216.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id A3E79202E1 for ; Tue, 11 Mar 2014 14:10:10 +0000 (UTC) Received: by mail-qc0-f198.google.com with SMTP id r5sf20937326qcx.1 for ; Tue, 11 Mar 2014 07:10:10 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:to:cc:subject:date:message-id :x-original-sender:x-original-authentication-results:precedence :mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe:content-type; bh=BRD4P4xJHSgjyWoc1fsvi1gSSf600dDDlbqVGIh/4yA=; b=EClXxdEKK5eEtzuOqoPEHgy1RnBNvmYAAqBvM8NaeWwIvgs+P4K1X/mryCu8mRQynF Ny8LhMa4OmFlCAaS1hNdxRydoAufRr/Pqwsxu4G/0pMZFPEcc7Z7aX+FHXHwT5opMEj2 u7o29W1EpQvxhM9deI0xHKBhnMXOnjlBgr+oNtXin/fEDjQHih41ODcI0V4UsxdRSn0u d1rePAzmJA7wdBsd/BKVO418WgoNtbYQXBLTDHLnB3Jj4vnS5olvHbDAvfwPi9z4JpHl IWJAecoQnMZl65vHvoruDqyxXuc+bC3OROTUVm5PF+vZa4AjCi0xPsaufBGyhb44SiNQ nahg== X-Gm-Message-State: ALoCoQkz40gzE2CI5q+eEMDTX2CnH3o3615p9oGncs+/AlsHNcrSDuCdcOynjO4UNC87GuseDiZg X-Received: by 10.59.8.226 with SMTP id dn2mr13163377ved.30.1394547010445; Tue, 11 Mar 2014 07:10:10 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: lng-odp@linaro.org Received: by 10.140.31.139 with SMTP id f11ls2450755qgf.71.gmail; Tue, 11 Mar 2014 07:10:10 -0700 (PDT) X-Received: by 10.140.89.99 with SMTP id u90mr2541384qgd.93.1394547010267; Tue, 11 Mar 2014 07:10:10 -0700 (PDT) Received: from mail-qc0-f176.google.com (mail-qc0-f176.google.com [209.85.216.176]) by mx.google.com with ESMTPS id z2si11247075qad.129.2014.03.11.07.10.10 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 11 Mar 2014 07:10:10 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.216.176 is neither permitted nor denied by best guess record for domain of petri.savolainen@linaro.org) client-ip=209.85.216.176; Received: by mail-qc0-f176.google.com with SMTP id m20so9555537qcx.35 for ; Tue, 11 Mar 2014 07:10:10 -0700 (PDT) X-Received: by 10.224.89.71 with SMTP id d7mr19019483qam.54.1394547010054; Tue, 11 Mar 2014 07:10:10 -0700 (PDT) Received: from localhost.localdomain (ec2-23-23-178-99.compute-1.amazonaws.com. [23.23.178.99]) by mx.google.com with ESMTPSA id v75sm14671741qge.6.2014.03.11.07.10.07 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 11 Mar 2014 07:10:09 -0700 (PDT) From: Petri Savolainen To: lng-odp@linaro.org Cc: Petri Savolainen Subject: [lng-odp] [PATCH] Timer implementation first draft Date: Tue, 11 Mar 2014 16:11:40 +0200 Message-Id: <1394547100-30886-1-git-send-email-petri.savolainen@linaro.org> X-Mailer: git-send-email 1.8.5.3 X-Original-Sender: petri.savolainen@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.216.176 is neither permitted nor denied by best guess record for domain of petri.savolainen@linaro.org) smtp.mail=petri.savolainen@linaro.org Precedence: list Mailing-list: list lng-odp@linaro.org; contact lng-odp+owners@linaro.org List-ID: X-Google-Group-Id: 474323889996 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Very simple implementation. Does not implement cancel_tmo. Test included into example app. Signed-off-by: Petri Savolainen --- include/odp.h | 1 + include/odp_timer.h | 2 +- platform/linux-generic/source/odp_timer.c | 291 ++++++++++++++++++++++++++++++ test/example/odp_example.c | 68 +++++++ 4 files changed, 361 insertions(+), 1 deletion(-) diff --git a/include/odp.h b/include/odp.h index 6a52346..9bb68a2 100644 --- a/include/odp.h +++ b/include/odp.h @@ -292,6 +292,7 @@ extern "C" { #include #include #include +#include #include #include #include diff --git a/include/odp_timer.h b/include/odp_timer.h index ff54b8e..f051f71 100644 --- a/include/odp_timer.h +++ b/include/odp_timer.h @@ -35,7 +35,7 @@ typedef uint32_t odp_timer_t; /** * ODP timeout handle */ -typedef uint32_t odp_timer_tmo_t; +typedef uint64_t odp_timer_tmo_t; #define ODP_TIMER_TMO_INVALID 0 diff --git a/platform/linux-generic/source/odp_timer.c b/platform/linux-generic/source/odp_timer.c index b090257..fceb086 100644 --- a/platform/linux-generic/source/odp_timer.c +++ b/platform/linux-generic/source/odp_timer.c @@ -6,9 +6,300 @@ #include #include +#include +#include +#include +#include + +#include +#include + +#include + + +#define NUM_TIMERS 1 +#define MAX_TICKS 1024 +#define RESOLUTION_NS 1000000 + +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; + +typedef struct { + odp_spinlock_t lock; + timeout_t *list; +} tick_t; + +typedef struct { + volatile int active; + volatile uint64_t cur_tick; + timer_t timerid; + odp_buffer_pool_t pool; + uint64_t resolution_ns; + uint64_t max_ticks; + tick_t tick[MAX_TICKS]; + +} timer_ring_t; + + +typedef struct { + timer_ring_t timer[NUM_TIMERS]; + odp_atomic_int_t num_timers; +} timer_global_t; + + + +/* Global */ +timer_global_t odp_timer; + + +static void add_tmo(tick_t *tick, timeout_t *tmo) +{ + odp_spinlock_lock(&tick->lock); + + tmo->next = tick->list; + tick->list = tmo; + + odp_spinlock_unlock(&tick->lock); +} + + +static timeout_t *rem_tmo(tick_t *tick) +{ + timeout_t *tmo; + + odp_spinlock_lock(&tick->lock); + + tmo = tick->list; + + if (tmo) + tick->list = tmo->next; + + odp_spinlock_unlock(&tick->lock); + + if (tmo) + tmo->next = NULL; + + return tmo; +} + + + +static void notify_function(union sigval sigval) +{ + (void) sigval; + uint64_t cur_tick; + timeout_t *tmo; + tick_t *tick; + + if (odp_timer.timer[0].active == 0) + return; + + /* ODP_DBG("Tick\n"); */ + + cur_tick = odp_timer.timer[0].cur_tick++; + + tick = &odp_timer.timer[0].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); + + odp_queue_enq(queue, buf); + } +} + + +static void timer_init(void) +{ + struct sigevent sigev; + struct itimerspec ispec; + + ODP_DBG("Timer thread starts\n"); + + memset(&sigev, 0, sizeof(sigev)); + memset(&ispec, 0, sizeof(ispec)); + + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_function = notify_function; + + if (timer_create(CLOCK_MONOTONIC, &sigev, + &odp_timer.timer[0].timerid)) { + ODP_DBG("Timer create failed\n"); + return; + } + + ispec.it_interval.tv_sec = 0; + ispec.it_interval.tv_nsec = RESOLUTION_NS; + ispec.it_value.tv_sec = 0; + ispec.it_value.tv_nsec = RESOLUTION_NS; + + if (timer_settime(odp_timer.timer[0].timerid, 0, &ispec, NULL)) { + ODP_DBG("Timer set failed\n"); + return; + } + + return; +} int odp_timer_init_global(void) { + int i; + + memset(&odp_timer, 0, sizeof(timer_global_t)); + + for (i = 0; i < MAX_TICKS; i++) + odp_spinlock_init(&odp_timer.timer[0].tick[i].lock); + + timer_init(); + + return 0; } + + + +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) +{ + int id; + (void) name; (void) resolution; (void) min_tmo; (void) max_tmo; + + if (odp_timer.num_timers >= NUM_TIMERS) + return ODP_TIMER_INVALID; + + id = odp_atomic_fetch_inc_int(&odp_timer.num_timers); + + if (id >= NUM_TIMERS) + return ODP_TIMER_INVALID; + + odp_timer.timer[id].pool = pool; + odp_timer.timer[id].resolution_ns = RESOLUTION_NS; + odp_timer.timer[id].max_ticks = MAX_TICKS; + + odp_sync_stores(); + + odp_timer.timer[id].active = 1; + + return id + 1; +} + + +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 id; + uint64_t tick; + uint64_t cur_tick; + timeout_t *new_tmo; + odp_buffer_t tmo_buf; + + id = timer - 1; + + cur_tick = odp_timer.timer[id].cur_tick; + + if (tmo_tick <= cur_tick) { + ODP_DBG("timeout too close\n"); + return ODP_TIMER_TMO_INVALID; + } + + tick = tmo_tick - cur_tick; + + if (tick > MAX_TICKS) { + ODP_DBG("timeout too far\n"); + return ODP_TIMER_TMO_INVALID; + } + + tick = (cur_tick + tick) % MAX_TICKS; + + tmo_buf = odp_buffer_alloc(odp_timer.timer[id].pool); + + if (tmo_buf == ODP_BUFFER_INVALID) { + ODP_DBG("alloc failed\n"); + return ODP_TIMER_TMO_INVALID; + } + + new_tmo = (timeout_t *)odp_buffer_addr(tmo_buf); + + 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; + + if (buf != ODP_BUFFER_INVALID) + new_tmo->buf = buf; + else + new_tmo->buf = tmo_buf; + + add_tmo(&odp_timer.timer[id].tick[tick], new_tmo); + + return (odp_timer_tmo_t) new_tmo; +} + + + +uint64_t odp_timer_tick_to_ns(odp_timer_t timer, uint64_t ticks) +{ + int id; + + id = timer - 1; + + return ticks * odp_timer.timer[id].resolution_ns; +} + + +uint64_t odp_timer_ns_to_tick(odp_timer_t timer, uint64_t ns) +{ + int id; + + id = timer - 1; + + return ns / odp_timer.timer[id].resolution_ns; +} + + +uint64_t odp_timer_resolution(odp_timer_t timer) +{ + int id; + + id = timer - 1; + + return odp_timer.timer[id].resolution_ns; +} + + +uint64_t odp_timer_maximum_tmo(odp_timer_t timer) +{ + int id; + + id = timer - 1; + + return odp_timer.timer[id].max_ticks; +} + + +uint64_t odp_timer_current_tick(odp_timer_t timer) +{ + int id; + + id = timer - 1; + + return odp_timer.timer[id].cur_tick; +} diff --git a/test/example/odp_example.c b/test/example/odp_example.c index 0f421a3..4764657 100644 --- a/test/example/odp_example.c +++ b/test/example/odp_example.c @@ -53,6 +53,11 @@ typedef struct { static odp_barrier_t test_barrier; +/* #define TEST_TIMEOUTS */ +#ifdef TEST_TIMEOUTS +static odp_timer_t test_timer; +#endif + /* * Clear all scheduled queues. Retry to be sure that all * buffers have been scheduled. @@ -71,6 +76,48 @@ static void clear_sched_queues(void) } } +#ifdef TEST_TIMEOUTS +static void test_timeouts(int thr) +{ + uint64_t tick; + odp_queue_t queue; + odp_buffer_t buf; + int num = 10; + + ODP_DBG(" [%i] test_timeouts\n", thr); + + queue = odp_queue_lookup("timer_queue"); + + tick = odp_timer_current_tick(test_timer); + + ODP_DBG(" [%i] current tick %"PRIu64"\n", thr, tick); + + tick += 100; + + odp_timer_absolute_tmo(test_timer, tick, + queue, ODP_BUFFER_INVALID); + + + while (1) { + while ((buf = odp_queue_deq(queue) == ODP_BUFFER_INVALID)) + ; + + /* ODP_DBG(" [%i] timeout\n", thr); */ + + odp_buffer_free(buf); + + num--; + + if (num == 0) + break; + + tick = odp_timer_current_tick(test_timer) + 100; + + odp_timer_absolute_tmo(test_timer, tick, + queue, ODP_BUFFER_INVALID); + } +} +#endif /* * Test single buffer alloc and free @@ -522,6 +569,12 @@ static void *run_thread(void *arg) ODP_SCHED_PRIO_LOWEST)) return NULL; +#ifdef TEST_TIMEOUTS + odp_barrier_sync(&test_barrier); + + test_timeouts(thr); +#endif + printf("Thread %i exits\n", thr); fflush(NULL); return arg; @@ -724,6 +777,21 @@ int main(int argc, char *argv[]) } +#ifdef TEST_TIMEOUTS + /* + * Create a queue for timer test + */ + queue = odp_queue_create("timer_queue", ODP_QUEUE_TYPE_SCHED, NULL); + + if (queue == ODP_QUEUE_INVALID) { + ODP_ERR("Timer queue create failed.\n"); + return -1; + } + + test_timer = odp_timer_create("test_timer", pool, + 1000000, 1000000, 1000000000000); +#endif + /* * Create queues for schedule test. QUEUES_PER_PRIO per priority. */