1bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo *
3bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * Redistribution and use in source and binary forms, with or without
4bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * modification, are permitted provided that the following conditions are
5bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * met:
6bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo *     * Redistributions of source code must retain the above copyright
7bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo *       notice, this list of conditions and the following disclaimer.
8bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo *     * Redistributions in binary form must reproduce the above
9bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo *       copyright notice, this list of conditions and the following
10bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo *       disclaimer in the documentation and/or other materials provided
11bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo *       with the distribution.
12bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo *     * Neither the name of The Linux Foundation, nor the names of its
13bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo *       contributors may be used to endorse or promote products derived
14bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo *       from this software without specific prior written permission.
15bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo *
16bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo *
28bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo */
29bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
30bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo#include<stdio.h>
31bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo#include<stdlib.h>
32bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo#include<sys/time.h>
33bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo#include "loc_timer.h"
34bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo#include<time.h>
35bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo#include<errno.h>
36bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
37bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russoenum timer_state {
38bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    READY = 100,
39bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    WAITING,
40bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    DONE,
41bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    ABORT
42bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo};
43bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
44bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russotypedef struct {
45bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    loc_timer_callback callback_func;
46bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    void *user_data;
47bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    unsigned int time_msec;
48bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    pthread_cond_t timer_cond;
49bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    pthread_mutex_t timer_mutex;
50bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    enum timer_state state;
51bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo}timer_data;
52bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
53bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russostatic void *timer_thread(void *thread_data)
54bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo{
55bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    int ret = -ETIMEDOUT;
56bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    struct timespec ts;
57bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    struct timeval tv;
58bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    timer_data* t = (timer_data*)thread_data;
59bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
60bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    LOC_LOGD("%s:%d]: Enter. Delay = %d\n", __func__, __LINE__, t->time_msec);
61bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
62bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    gettimeofday(&tv, NULL);
63bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    clock_gettime(CLOCK_REALTIME, &ts);
64bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    if(t->time_msec >= 1000) {
65bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        ts.tv_sec += t->time_msec/1000;
66bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        t->time_msec = t->time_msec % 1000;
67bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    }
68bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    if(t->time_msec)
69bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        ts.tv_nsec += t->time_msec * 1000000;
70bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    if(ts.tv_nsec > 999999999) {
71bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        LOC_LOGD("%s:%d]: Large nanosecs\n", __func__, __LINE__);
72bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        ts.tv_sec += 1;
73bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        ts.tv_nsec -= 1000000000;
74bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    }
75bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    LOC_LOGD("%s:%d]: ts.tv_sec:%d; ts.tv_nsec:%d\n"
76bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo             "\t Current time: %d sec; %d nsec",
77bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo             __func__, __LINE__, (int)ts.tv_sec, (int)ts.tv_nsec,
78bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo             (int)tv.tv_sec, (int)tv.tv_usec*1000);
79bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
80bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    pthread_mutex_lock(&(t->timer_mutex));
81bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    if (READY == t->state) {
82bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        t->state = WAITING;
83bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        ret = pthread_cond_timedwait(&t->timer_cond, &t->timer_mutex, &ts);
84bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        t->state = DONE;
85bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    }
86bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    pthread_mutex_unlock(&(t->timer_mutex));
87bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
88bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    switch (ret) {
89bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    case ETIMEDOUT:
90bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        LOC_LOGV("%s:%d]: loc_timer timed out",  __func__, __LINE__);
91bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        break;
92bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    case 0:
93bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        LOC_LOGV("%s:%d]: loc_timer stopped",  __func__, __LINE__);
94bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        break;
95bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    case -ETIMEDOUT:
96bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        LOC_LOGV("%s:%d]: loc_timer cancelled",  __func__, __LINE__);
97bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        break;
98bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    default:
99bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        LOC_LOGE("%s:%d]: Call to pthread timedwait failed; ret=%d\n",
100bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo                 __func__, __LINE__, ret);
101bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        break;
102bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    }
103bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
104bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    pthread_mutex_destroy(&t->timer_mutex);
105bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    pthread_cond_destroy(&t->timer_cond);
106bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
107bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    if(ETIMEDOUT == ret)
108bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        t->callback_func(t->user_data, ret);
109bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
110bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    free(t);
111bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    LOC_LOGD("%s:%d]: Exit\n", __func__, __LINE__);
112bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    return NULL;
113bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo}
114bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
115bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russovoid* loc_timer_start(unsigned int msec, loc_timer_callback cb_func,
116bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo                      void* caller_data)
117bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo{
118bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    timer_data *t=NULL;
119bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    pthread_attr_t tattr;
120bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    pthread_t id;
121bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    LOC_LOGD("%s:%d]: Enter\n", __func__, __LINE__);
122bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    if(cb_func == NULL || msec == 0) {
123bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        LOC_LOGE("%s:%d]: Error: Wrong parameters\n", __func__, __LINE__);
124bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        goto _err;
125bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    }
126bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    t = (timer_data *)calloc(1, sizeof(timer_data));
127bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    if(t == NULL) {
128bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        LOC_LOGE("%s:%d]: Could not allocate memory. Failing.\n",
129bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo                 __func__, __LINE__);
130bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        goto _err;
131bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    }
132bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
133bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    if(pthread_cond_init(&(t->timer_cond), NULL)) {
134bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        LOC_LOGE("%s:%d]: Pthread cond init failed\n", __func__, __LINE__);
135bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        goto t_err;
136bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    }
137bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    if(pthread_mutex_init(&(t->timer_mutex), NULL)) {
138bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        LOC_LOGE("%s:%d]: Pthread mutex init failed\n", __func__, __LINE__);
139bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        goto cond_err;
140bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    }
141bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
142bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    t->callback_func = cb_func;
143bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    t->user_data = caller_data;
144bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    t->time_msec = msec;
145bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    t->state = READY;
146bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
147bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    if (pthread_attr_init(&tattr)) {
148bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        LOC_LOGE("%s:%d]: Pthread mutex init failed\n", __func__, __LINE__);
149bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        goto mutex_err;
150bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    }
151bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
152bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
153bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    if(pthread_create(&(id), &tattr, timer_thread, (void *)t)) {
154bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        LOC_LOGE("%s:%d]: Could not create thread\n", __func__, __LINE__);
155bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        goto attr_err;
156bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    }
157bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
158bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    LOC_LOGD("%s:%d]: Created thread with id: %d\n",
159bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo             __func__, __LINE__, (int)id);
160bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    goto _err;
161bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
162bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russoattr_err:
163bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    pthread_attr_destroy(&tattr);
164bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russomutex_err:
165bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    pthread_mutex_destroy(&t->timer_mutex);
166bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russocond_err:
167bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    pthread_cond_destroy(&t->timer_cond);
168bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russot_err:
169bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    free(t);
170bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo_err:
171bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    LOC_LOGD("%s:%d]: Exit\n", __func__, __LINE__);
172bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    return t;
173bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo}
174bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
175bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russovoid loc_timer_stop(void* handle) {
176bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    timer_data* t = (timer_data*)handle;
177bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo
178bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    if (NULL != t && (READY == t->state || WAITING == t->state)) {
179bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        pthread_mutex_lock(&(t->timer_mutex));
180bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        if (READY == t->state || WAITING == t->state) {
181bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo            pthread_cond_signal(&t->timer_cond);
182bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo            t->state = ABORT;
183bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        }
184bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo        pthread_mutex_unlock(&(t->timer_mutex));
185bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo    }
186bfff6343845ad9ff062c5fd97bb3b9be1053340eDante Russo}
187