@@ -70,6 +70,9 @@ static _odp_atomic_flag_t locks[NUM_LOCKS]; /* Multiple locks per cache line! */
#define IDX2LOCK(idx) (&locks[(idx) % NUM_LOCKS])
#endif
+/* Timer resolution in nanoseconds */
+static uint64_t timer_res;
+
/******************************************************************************
* Translation between timeout buffer and timeout header
*****************************************************************************/
@@ -188,6 +191,7 @@ typedef struct odp_timer_pool_s {
#define MAX_TIMER_POOLS 255 /* Leave one for ODP_TIMER_INVALID */
#define INDEX_BITS 24
+#define TIMER_RES_TEST_LOOP_COUNT 10
static odp_atomic_u32_t num_timer_pools;
static odp_timer_pool *timer_pool[MAX_TIMER_POOLS];
@@ -738,6 +742,80 @@ static void *timer_thread(void *arg)
return NULL;
}
+/* Get the max timer resolution without overrun and fill in timer_res variable.
+ *
+ * Set timer's interval with candidate resolutions to get the max resolution
+ * that the timer would not be overrun.
+ * The candidate resolution value is from 1ms to 100us, 10us...1ns etc.
+ */
+static int timer_res_init(void)
+{
+ struct sigevent sigev;
+ timer_t timerid;
+ uint64_t res, sec, nsec;
+ struct itimerspec ispec;
+ sigset_t sigset;
+ siginfo_t si;
+ int loop_cnt;
+ struct timespec tmo;
+
+ sigev.sigev_notify = SIGEV_THREAD_ID;
+ sigev._sigev_un._tid = (pid_t)syscall(SYS_gettid);
+ sigev.sigev_signo = SIGUSR1;
+
+ /* Create timer */
+ if (timer_create(CLOCK_MONOTONIC, &sigev, &timerid))
+ ODP_ABORT("timer_create() returned error %s\n",
+ strerror(errno));
+
+ /* Timer resolution start from 1ms */
+ res = ODP_TIME_MSEC_IN_NS;
+ /* Set initial value of timer_res */
+ timer_res = res;
+ sigemptyset(&sigset);
+ /* Add SIGUSR1 to sigset */
+ sigaddset(&sigset, SIGUSR1);
+ sigprocmask(SIG_BLOCK, &sigset, NULL);
+
+ while(res > 0) {
+ /* Loop for 10 times to test the result */
+ loop_cnt = TIMER_RES_TEST_LOOP_COUNT;
+ sec = res / ODP_TIME_SEC_IN_NS;
+ nsec = res - sec * ODP_TIME_SEC_IN_NS;
+
+ memset(&ispec, 0, sizeof(ispec));
+ 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(timerid, 0, &ispec, NULL))
+ ODP_ABORT("timer_settime() returned error %s\n",
+ strerror(errno));
+ /* Set signal wait timeout to 10*res */
+ tmo.tv_sec = 0;
+ tmo.tv_nsec = res * 10;
+ while (loop_cnt--) {
+ if (sigtimedwait(&sigset, &si, &tmo) > 0) {
+ if(timer_getoverrun(timerid))
+ /* overrun at this resolution, goto the end */
+ goto timer_res_init_done;
+ }
+ }
+ /* Set timer_res */
+ timer_res = res;
+ /* Test the next timer resolution candidate */
+ res /= 10;
+ }
+timer_res_init_done:
+ if (timer_delete(timerid) != 0)
+ ODP_ABORT("timer_delete() returned error %s\n",
+ strerror(errno));
+ sigemptyset(&sigset);
+ sigprocmask(SIG_BLOCK, &sigset, NULL);
+ return 0;
+}
+
static void itimer_init(odp_timer_pool *tp)
{
struct sigevent sigev;
@@ -795,6 +873,18 @@ static void itimer_fini(odp_timer_pool *tp)
* Some parameter checks and error messages
* No modificatios of internal state
*****************************************************************************/
+int odp_timer_capability(odp_timer_clk_src_t clk_src, odp_timer_capability_t *capa)
+{
+ int ret = 0;
+ if (clk_src == ODP_CLOCK_CPU)
+ capa->res_ns = timer_res;
+ else {
+ ODP_ERR("ODP timer system doesn't support external clock source currently\n");
+ ret = -1;
+ }
+ return ret;
+}
+
odp_timer_pool_t
odp_timer_pool_create(const char *name,
const odp_timer_pool_param_t *param)
@@ -1003,6 +1093,8 @@ int odp_timer_init_global(void)
#endif
odp_atomic_init_u32(&num_timer_pools, 0);
+ timer_res_init();
+
block_sigalarm();
return 0;
Implement a new internal function timer_res_init() to detect the max timer resolution without overrun at the ODP init stage. It will check timer resolution from 1ms to 100us, 10us...1ns until the timer is overrun. Signed-off-by: Kevin Wang <kevin.wang@linaro.org> --- platform/linux-generic/odp_timer.c | 92 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) -- 1.9.1