1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 #include "cras_types.h" 7 #include "cras_util.h" 8 #include "utlist.h" 9 10 #include <time.h> 11 12 /* Represents an armed timer. 13 * Members: 14 * ts - timespec at which the timer should fire. 15 * cb - Callback to call when the timer expires. 16 * cb_data - Data passed to the callback. 17 */ 18 struct cras_timer { 19 struct timespec ts; 20 void (*cb)(struct cras_timer *t, void *data); 21 void *cb_data; 22 struct cras_timer *next, *prev; 23 }; 24 25 /* Timer Manager, keeps a list of active timers. */ 26 struct cras_tm { 27 struct cras_timer *timers; 28 }; 29 30 /* Local Functions. */ 31 32 /* Adds ms milliseconds to ts. */ 33 static inline void add_ms_ts(struct timespec *ts, unsigned int ms) 34 { 35 if (ms >= 1000) { 36 ts->tv_sec += ms / 1000; 37 ms %= 1000; 38 } 39 ts->tv_nsec += ms * 1000000L; 40 if (ts->tv_nsec >= 1000000000L) { 41 ts->tv_sec += ts->tv_nsec / 1000000000L; 42 ts->tv_nsec %= 1000000000L; 43 } 44 } 45 46 /* Checks if timespec a is less than b. */ 47 static inline int timespec_sooner(const struct timespec *a, 48 const struct timespec *b) 49 { 50 return (a->tv_sec < b->tv_sec || 51 (a->tv_sec == b->tv_sec && a->tv_nsec <= b->tv_nsec)); 52 } 53 54 /* Exported Interface. */ 55 56 struct cras_timer *cras_tm_create_timer( 57 struct cras_tm *tm, 58 unsigned int ms, 59 void (*cb)(struct cras_timer *t, void *data), 60 void *cb_data) 61 { 62 struct cras_timer *t; 63 64 t = calloc(1, sizeof(*t)); 65 if (!t) 66 return NULL; 67 68 t->cb = cb; 69 t->cb_data = cb_data; 70 71 clock_gettime(CLOCK_MONOTONIC_RAW, &t->ts); 72 add_ms_ts(&t->ts, ms); 73 74 DL_APPEND(tm->timers, t); 75 76 return t; 77 } 78 79 void cras_tm_cancel_timer(struct cras_tm *tm, struct cras_timer *t) 80 { 81 DL_DELETE(tm->timers, t); 82 free(t); 83 } 84 85 struct cras_tm *cras_tm_init() 86 { 87 return calloc(1, sizeof(struct cras_tm)); 88 } 89 90 void cras_tm_deinit(struct cras_tm *tm) 91 { 92 struct cras_timer *t; 93 94 DL_FOREACH(tm->timers, t) { 95 DL_DELETE(tm->timers, t); 96 free(t); 97 } 98 free(tm); 99 } 100 101 int cras_tm_get_next_timeout(const struct cras_tm *tm, struct timespec *ts) 102 { 103 struct cras_timer *t; 104 struct timespec now; 105 struct timespec *min; 106 107 if (!tm->timers) 108 return 0; 109 110 min = &tm->timers->ts; 111 DL_FOREACH(tm->timers, t) 112 if (timespec_sooner(&t->ts, min)) 113 min = &t->ts; 114 115 clock_gettime(CLOCK_MONOTONIC_RAW, &now); 116 117 if (timespec_sooner(min, &now)) { 118 /* Timer already expired. */ 119 ts->tv_sec = ts->tv_nsec = 0; 120 return 1; 121 } 122 123 subtract_timespecs(min, &now, ts); 124 return 1; 125 } 126 127 void cras_tm_call_callbacks(struct cras_tm *tm) 128 { 129 struct timespec now; 130 struct cras_timer *t, *next; 131 132 clock_gettime(CLOCK_MONOTONIC_RAW, &now); 133 134 /* Don't use DL_FOREACH to iterate timers because in each loop the 135 * next timer pointer is stored for later access but it could be 136 * cancelled and freed in current timer's callback causing invalid 137 * memory access. */ 138 t = tm->timers; 139 while (t) { 140 next = t->next; 141 if (timespec_sooner(&t->ts, &now)) { 142 t->cb(t, t->cb_data); 143 /* Update next timer because it could have been modified 144 * in t->cb(). */ 145 next = t->next; 146 cras_tm_cancel_timer(tm, t); 147 } 148 t = next; 149 } 150 } 151