IBNOS
timer.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Michael Müller
3  * Copyright (c) 2014, Sebastian Lackner
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27 
28 #include <process/timer.h>
29 #include <process/object.h>
30 #include <memory/allocator.h>
31 #include <interrupt/interrupt.h>
32 #include <hardware/pic.h>
33 #include <hardware/pit.h>
34 #include <util/list.h>
35 #include <util/util.h>
36 
42 #define TIMER_INTERRUPT_FREQUENCY 82 /* Hz */
43 #define TIMER_INTERRUPT_DELTA 12 /* ms */
44 
45 static uint64_t currentKernelTimestamp;
46 
47 struct linkedList timerList = LL_INIT(timerList);
48 
49 static void __timerDestroy(struct object *obj);
50 static void __timerShutdown(struct object *obj, UNUSED uint32_t mode);
51 static int32_t __timerGetStatus(struct object *obj, UNUSED uint32_t mode);
52 static struct linkedList *__timerWait(struct object *obj, UNUSED uint32_t mode, uint32_t *result);
53 static void __timerSignal(struct object *obj, UNUSED uint32_t result);
54 static int32_t __timerWrite(struct object *obj, uint8_t *buf, uint32_t length);
55 
56 static const struct objectFunctions timerFunctions =
57 {
58  __timerDestroy,
59  NULL, /* getMinHandle */
60  __timerShutdown,
61  __timerGetStatus,
62  __timerWait,
63  __timerSignal,
64  __timerWrite,
65  NULL, /* read */
66  NULL, /* insert */
67  NULL, /* remove */
68 };
69 
70 /* disables the timer in the global timerList */
71 static inline void __timerDeactivate(struct timer *t)
72 {
73  if (t->active)
74  {
75  ll_remove(&t->obj.entry);
76  t->active = false;
77  }
78 }
79 
80 /* enables the timer in the global timerList */
81 static inline void __timerActivate(struct timer *t)
82 {
83  if (!t->active)
84  {
85  struct timer *cur_t;
86  LL_FOR_EACH(cur_t, &timerList, struct timer, obj.entry)
87  {
88  if (cur_t->timeout > t->timeout) break;
89  }
90  ll_add_before(&cur_t->obj.entry, &t->obj.entry);
91  t->active = true;
92  }
93 }
94 
95 /* updates the timer in the global timerList */
96 static inline void __timerUpdate(struct timer *t)
97 {
98  __timerDeactivate(t);
99  __timerActivate(t);
100 }
101 
112 {
113  struct timer *t;
114 
115  /* allocate some new memory */
116  if (!(t = heapAlloc(sizeof(*t))))
117  return NULL;
118 
119  /* initialize general object info */
120  __objectInit(&t->obj, &timerFunctions);
121  ll_init(&t->waiters);
122  t->active = false;
123  t->timeout = 0;
124  t->interval = 0;
125  t->wakeupAll = wakeupAll;
126 
127  return t;
128 }
129 
135 static void __timerDestroy(struct object *obj)
136 {
137  struct timer *t = objectContainer(obj, struct timer, &timerFunctions);
138 
139  /* deactivate the timer and let all waiting objects return */
140  __timerDeactivate(t);
141  queueWakeup(&t->waiters, true, -1);
142  assert(ll_empty(&t->waiters));
143 
144  /* release timer memory */
145  t->obj.functions = NULL;
146  heapFree(t);
147 }
148 
158 static void __timerShutdown(struct object *obj, UNUSED uint32_t mode)
159 {
160  struct timer *t = objectContainer(obj, struct timer, &timerFunctions);
161 
162  /* deactivate the timer and let all waiting objects return */
163  __timerDeactivate(t);
164  queueWakeup(&t->waiters, true, -1);
165 }
166 
178 static int32_t __timerGetStatus(struct object *obj, UNUSED uint32_t mode)
179 {
180  struct timer *t = objectContainer(obj, struct timer, &timerFunctions);
181  if (t->interval) return -1;
182  return !t->active;
183 }
184 
195 static struct linkedList *__timerWait(struct object *obj, UNUSED uint32_t mode, uint32_t *result)
196 {
197  struct timer *t = objectContainer(obj, struct timer, &timerFunctions);
198  uint32_t eventCount;
199 
200  /* wait for event */
201  if (t->timeout > currentKernelTimestamp)
202  {
203  __timerActivate(t);
204  return &t->waiters;
205  }
206 
207  /* Calculate the number of occurances since the timeout elapsed the last time */
208  if (t->interval)
209  {
210  eventCount = (currentKernelTimestamp - t->timeout) / t->interval + 1;
211  t->timeout += eventCount * t->interval;
212  __timerUpdate(t);
213  }
214  else
215  {
216  eventCount = t->active;
217  __timerDeactivate(t);
218  }
219 
220  /* Return number of occurances */
221  *result = eventCount;
222  return NULL;
223 }
224 
235 static void __timerSignal(struct object *obj, UNUSED uint32_t result)
236 {
237  struct timer *t = objectContainer(obj, struct timer, &timerFunctions);
238  queueWakeup(&t->waiters, t->wakeupAll, 0);
239 }
240 
251 static int32_t __timerWrite(struct object *obj, uint8_t *buf, uint32_t length)
252 {
253  struct timer *t = objectContainer(obj, struct timer, &timerFunctions);
254  struct timerInfo *info = (struct timerInfo *)buf;
255  if (length != sizeof(struct timerInfo)) return -1;
256 
257  /* update timer structure */
258  t->timeout = currentKernelTimestamp + info->timeout;
259  t->interval = info->interval;
260 
261  /* update the timer */
262  __timerUpdate(t);
263  return length;
264 }
265 
274 static uint32_t timer_irq(UNUSED uint32_t irq)
275 {
276  struct timer *t;
277  uint32_t eventCount;
278 
279  currentKernelTimestamp += TIMER_INTERRUPT_DELTA;
280 
281  for (t = LL_ENTRY(timerList.next, struct timer, obj.entry); &t->obj.entry != &timerList;)
282  {
283  if (t->timeout > currentKernelTimestamp) break;
284 
285  /* Calculate the number of occurances since the timeout elapsed the last time */
286  if (t->interval)
287  {
288  eventCount = (currentKernelTimestamp - t->timeout) / t->interval + 1;
289  t->timeout += eventCount * t->interval;
290  __timerUpdate(t);
291  }
292  else
293  {
294  eventCount = 1;
295  __timerDeactivate(t);
296  }
297 
298  /* wake up waiters */
299  queueWakeup(&t->waiters, t->wakeupAll, eventCount);
300 
301  /* get next timer */
302  t = LL_ENTRY(timerList.next, struct timer, obj.entry);
303  }
304 
305  /* continue with the next thread */
306  return INTERRUPT_YIELD;
307 }
308 
313 void timerInit()
314 {
316  picReserveIRQ(IRQ_PIT, timer_irq);
317 }
318 
326 {
327  return currentKernelTimestamp;
328 }
329 
const struct objectFunctions * functions
Definition: object.h:72
void * heapAlloc(uint32_t length)
Allocates a block of kernel memory.
Definition: allocator.c:363
uint32_t interval
Definition: timer.h:55
#define assert(ex)
Definition: util.h:61
#define IRQ_PIT
Definition: pic.h:65
struct linkedList timerList
Definition: timer.c:47
#define UNUSED
Definition: util.h:39
struct linkedList waiters
Definition: timer.h:51
void heapFree(void *addr)
Deallocates a block of kernel memory.
Definition: allocator.c:385
#define TIMER_INTERRUPT_DELTA
Definition: timer.c:43
Definition: timer.h:48
#define LL_INIT(list)
Initializes a linkedList.
Definition: list.h:124
#define INTERRUPT_YIELD
Definition: interrupt.h:50
uint64_t timeout
Definition: timer.h:35
bool wakeupAll
Definition: timer.h:57
#define LL_ENTRY(element, type, field)
Definition: list.h:127
bool picReserveIRQ(uint32_t irq, irq_callback callback)
Assign a callback function to an IRQ.
Definition: pic.c:151
void pitSetFrequency(uint32_t channel, uint32_t frequency)
Set frequency of the programmable interval timer.
Definition: pit.c:72
#define TIMER_INTERRUPT_FREQUENCY
Definition: timer.c:42
uint32_t interval
Definition: timer.h:36
struct linkedList * next
Definition: list.h:36
#define objectContainer(p, type, functions)
Definition: object.h:66
struct linkedList entry
Definition: object.h:73
struct timer * timerCreate(bool wakeupAll)
Creates a new kernel timer object.
Definition: timer.c:111
void timerInit()
Initializes the system timer.
Definition: timer.c:313
uint64_t timeout
Definition: timer.h:54
struct object obj
Definition: timer.h:50
bool active
Definition: timer.h:52
char mode[8]
Definition: filesystem.h:65
#define LL_FOR_EACH(element, list, type, field)
Allows to iterate a linkedList similar to a for-loop.
Definition: list.h:138
uint64_t timerGetTimestamp()
Returns the current kernel timestamp.
Definition: timer.c:325