root/Whitix/trunk/kernel/timer.c

Revision 1763, 4.1 KB (checked in by mwhitworth, 3 years ago)

Add extra checks, add TimerThreadExit that removes timers from a dying thread.

Line 
1/*  This file is part of Whitix.
2 *
3 *  Whitix is free software; you can redistribute it and/or modify
4 *  it under the terms of the GNU General Public License as published by
5 *  the Free Software Foundation; either version 2 of the License, or
6 *  (at your option) any later version.
7 *
8 *  Whitix is distributed in the hope that it will be useful,
9 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 *  GNU General Public License for more details.
12 *
13 *  You should have received a copy of the GNU General Public License
14 *  along with Whitix; if not, write to the Free Software
15 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16 *
17 */
18
19#include <timer.h>
20#include <llist.h>
21#include <console.h>
22#include <module.h>
23#include <error.h>
24#include <task.h>
25#include <malloc.h>
26
27LIST_HEAD(timerList);
28Spinlock timerLock;
29
30/***********************************************************************
31 *
32 * FUNCTION: TimerAdd
33 *
34 * DESCRIPTION: Add a timer to the list.
35 *
36 * PARAMETERS: timer - timer in question.
37 *
38 * RETURNS: Usual error codes.
39 *
40 ***********************************************************************/
41
42void TimerAdd(struct Timer* timer)
43{
44        SpinLockIrq(&timerLock);
45        struct Timer* curr, *curr2;
46
47        if (ListEmpty(&timerList))
48                ListAdd(&timer->list, &timerList);
49        else{
50                ListForEachEntrySafe(curr, curr2, &timerList,list)
51                {
52                        if (curr->expires >= timer->expires)
53                        {
54                                if (curr->list.prev != &timerList)
55                                        timer->expires-=ListEntry(curr->list.prev,struct Timer,list)->expires;
56
57                                curr->expires -= timer->expires;
58
59                                /* Add before the current timer. */
60                                DoListAdd(&timer->list,curr->list.prev,&curr->list);
61                                goto out;
62                        }
63                }
64
65                /* Add to end of list */
66                if (curr->list.prev != &timerList)
67                        timer->expires-=ListEntry(curr->list.prev,struct Timer,list)->expires;
68
69                ListAddTail(&timer->list, &timerList);
70        }
71
72out:
73        SpinUnlockIrq(&timerLock);
74}
75
76SYMBOL_EXPORT(TimerAdd);
77
78/***********************************************************************
79 *
80 * FUNCTION: TimerRemove
81 *
82 * DESCRIPTION: Remove a timer and update other timers.
83 *
84 * PARAMETERS: timer - timer in question.
85 *
86 * RETURNS: Usual error codes.
87 *
88 ***********************************************************************/
89
90int TimerRemove(struct Timer* timer)
91{
92        int err=0;
93
94        SpinLockIrq(&timerLock);
95
96        if (timer->list.next == NULL || timer->list.prev == NULL)
97                goto out;
98
99        if (ListEmpty(&timerList))
100                err=-EINVAL;
101        else{
102                struct Timer* curr, *curr2;
103                               
104                ListForEachEntrySafe(curr, curr2, &timerList, list)
105                {
106                        if (curr == timer)
107                        {
108                                ListRemove(&curr->list);
109                                timer->list.prev = timer->list.next = NULL;
110
111                                if (curr->expires > 0 && &curr2->list != &timerList /* TODO: Check */)
112                                        curr2->expires += curr->expires;
113                       
114                                goto out;
115                        }
116                }
117        }
118
119out:
120        SpinUnlockIrq(&timerLock);
121
122        return err;
123}
124
125SYMBOL_EXPORT(TimerRemove);
126
127void TimerThreadExit(struct Thread* thread)
128{
129        struct Timer* curr, *curr2;
130       
131        ListForEachEntrySafe(curr, curr2, &timerList, list)
132        {
133                if (curr->owner == thread)
134                        TimerRemove(curr);
135        }
136}
137
138/***********************************************************************
139 *
140 * FUNCTION: UpdateTimers
141 *
142 * DESCRIPTION: Update the list of timers.
143 *
144 * PARAMETERS: None.
145 *
146 * RETURNS: Nothing.
147 *
148 ***********************************************************************/
149
150/* TODO: Does it really need to run in an IRQ? */
151
152void UpdateTimers()
153{
154        struct Timer* timer;
155
156        if (ListEmpty(&timerList))
157                return;
158       
159        /* Get head of the list */
160        timer=ListEntry(timerList.next, struct Timer, list);
161        timer->expires-=10; /* The timeslice */
162
163        if (timer->expires <= 0)
164        {
165                ListRemove(&timer->list);
166                timer->list.prev = timer->list.next = NULL;
167       
168                timer->func(timer->data);
169        }
170}
171
172void SleepWakeup(void* data)
173{
174        struct Thread* thread=(struct Thread*)data;
175       
176        ThrResumeThread(thread);
177}
178
179SYMBOL_EXPORT(SleepWakeup);
180
181void Sleep(int milliSeconds)
182{
183        struct Timer timer;
184
185        timer.func = SleepWakeup;
186        timer.expires = milliSeconds;
187        timer.data = currThread;
188        timer.owner = currThread;
189       
190        TimerAdd(&timer);
191        ThrSuspendThread(currThread);
192        ThrSchedule();
193       
194        TimerRemove(&timer);
195}
196
197SYMBOL_EXPORT(Sleep);
Note: See TracBrowser for help on using the browser.