Kernel/timers - Debugging output changes
[tpg/acess2.git] / KernelLand / Kernel / time.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang) 
4  *
5  * Timer Code
6  */
7 #define SANITY  1       // Enable ASSERTs
8 #define DEBUG   0
9 #include <acess.h>
10 #include <timers.h>
11 #include <timers_int.h>
12 #include <events.h>
13 #include <hal_proc.h>   // Proc_GetCurThread
14 #include <workqueue.h>
15 #include <threads_int.h>        // Used to get thread timer
16
17 // === PROTOTYPES ===
18 void    Timer_CallbackThread(void *Unused);
19 void    Timer_CallTimers(void);
20 #if 0
21 tTimer  *Time_CreateTimer(int Delta, tTimerCallback *Callback, void *Argument);
22 void    Time_ScheduleTimer(tTimer *Timer, int Delta);
23 void    Time_RemoveTimer(tTimer *Timer);
24 tTimer  *Time_AllocateTimer(tTimerCallback *Callback, void *Argument);
25 #endif
26 void    Time_InitTimer(tTimer *Timer, tTimerCallback *Callback, void *Argument);
27 #if 0
28 void    Time_FreeTimer(tTimer *Timer);
29 void    Time_Delay(int Time);
30 #endif
31
32 // === GLOBALS ===
33 volatile Uint64 giTicks = 0;
34 volatile Sint64 giTimestamp = 0;
35 volatile Uint64 giPartMiliseconds = 0;
36 tTimer  *gTimers;
37 tWorkqueue      gTimers_CallbackQueue;
38 tShortSpinlock  gTimers_ListLock;
39
40 // === CODE ===
41 void Timer_CallbackThread(void *Unused)
42 {
43         Threads_SetName("Timer Callback Thread");
44         Workqueue_Init(&gTimers_CallbackQueue, "Timer Callbacks", offsetof(tTimer, Next));
45
46         for(;;)
47         {
48                 tTimer *timer = Workqueue_GetWork(&gTimers_CallbackQueue);
49         
50                 if( !timer->Callback ) {
51                         LOG("Timer %p doesn't have a callback", timer);
52                         ASSERT( timer->Callback );
53                 }
54
55                 // Save callback and argument (because once the mutex is released
56                 // the timer may no longer be valid)
57                 tTimerCallback  *cb = timer->Callback;
58                 void    *arg = timer->Argument;
59                 
60                 LOG("Callback fire %p", timer);
61         
62                 // Allow Time_RemoveTimer to be called safely
63                 timer->bActive = 0;
64                 
65                 // Fire callback
66                 cb(arg);
67
68                 // Mark timer as no longer needed
69         }
70 }
71
72 /**
73  * \fn void Timer_CallTimers()
74  */
75 void Timer_CallTimers()
76 {
77         SHORTLOCK(&gTimers_ListLock);
78         while( gTimers && gTimers->FiresAfter < now() )
79         {
80                 ASSERT( gTimers != gTimers->Next );     
81                 // Get timer from list
82                 tTimer  *timer = gTimers;
83                 gTimers = gTimers->Next;
84         
85                 // Perform event
86                 if( timer->Callback ) {
87                         LOG("Callback schedule %p", timer);
88                         Workqueue_AddWork(&gTimers_CallbackQueue, timer);
89                 }
90                 else {
91                         LOG("Event fire %p", timer);
92                         ASSERT( timer->Argument );
93                         Threads_PostEvent(timer->Argument, THREAD_EVENT_TIMER);
94                         timer->bActive = 0;
95                 }
96         }
97         SHORTREL(&gTimers_ListLock);
98 }
99
100 /**
101  * \brief Schedule an action (Legacy)
102  */
103 tTimer *Time_CreateTimer(int Delta, tTimerCallback *Callback, void *Argument)
104 {
105         tTimer  *ret = malloc(sizeof(tTimer));
106         if( !ret )      return NULL;
107         Time_InitTimer(ret, Callback, Argument);
108         Time_ScheduleTimer(ret, Delta);
109         return ret;
110 }
111
112 /**
113  * \brief Schedule a timer to fire
114  */
115 void Time_ScheduleTimer(tTimer *Timer, int Delta)
116 {
117         tTimer  *t;
118         tTimer  **prev_next;
119
120         // Sanity checks
121         if( !Timer )    return ;
122
123         if( Timer->bActive )    return;
124         
125         // Set time
126         Timer->FiresAfter = now() + Delta;
127         
128         // Debug
129         LOG("%p added timer %p - %i ms (ts=%lli)",
130                 __builtin_return_address(0), Timer, Delta, Timer->FiresAfter);
131
132         // Add into list (sorted)
133         SHORTLOCK(&gTimers_ListLock);
134 //      Mutex_Release( &Timer->Lock );  // Prevent deadlocks
135         for( prev_next = &gTimers, t = gTimers; t; prev_next = &t->Next, t = t->Next )
136         {
137                 ASSERT( prev_next != &t->Next );
138                 ASSERT( CheckMem(t, sizeof(tTimer)) );
139                 if( t == Timer )
140                 {
141                         LOG("Double schedule - increasing delta");
142                         SHORTREL(&gTimers_ListLock);
143                         return ;
144                 }
145                 LOG(" t = %p ts:%lli", t, t->FiresAfter);
146                 if( t->FiresAfter > Timer->FiresAfter ) break;
147         }
148         Timer->Next = t;
149         *prev_next = Timer;
150         Timer->bActive = 1;
151         LOG(" prev_next=%p Timer=%p next=%p", prev_next, Timer, t);
152         SHORTREL(&gTimers_ListLock);
153 }
154
155 /**
156  * \brief Delete a timer from the running list
157  */
158 void Time_RemoveTimer(tTimer *Timer)
159 {
160         tTimer  *t;
161         tTimer  **prev_next;
162
163         if( !Timer )    return ;
164         
165         SHORTLOCK(&gTimers_ListLock);
166         for( prev_next = &gTimers, t = gTimers; t; prev_next = &t->Next, t = t->Next )
167         {
168                 ASSERT( prev_next != &t->Next );
169                 ASSERT( CheckMem(t, sizeof(tTimer)) );
170                 if( t == Timer )
171                 {
172                         *prev_next = t->Next;
173                         break ;
174                 }
175         }
176         SHORTREL(&gTimers_ListLock);
177
178         if( t ) {
179                 Timer->bActive = 0;
180                 LOG("%p removed %p", __builtin_return_address(0), Timer);
181         }
182         else
183                 LOG("%p tried to remove %p (already complete)", __builtin_return_address(0), Timer);
184 }
185
186 /**
187  * \brief Allocate a timer object, but don't schedule it
188  */
189 tTimer *Time_AllocateTimer(tTimerCallback *Callback, void *Argument)
190 {
191         tTimer  *ret = malloc(sizeof(tTimer));
192         if( !ret )      return NULL;
193         Time_InitTimer(ret, Callback, Argument);
194         return ret;
195 }
196
197 /**
198  * \brief Initialise a timer
199  * \note Mostly an internal function
200  */
201 void Time_InitTimer(tTimer *Timer, tTimerCallback *Callback, void *Argument)
202 {
203         if(Callback == NULL)
204                 Argument = Proc_GetCurThread();
205         Timer->FiresAfter = 0;
206         Timer->Callback = Callback;
207         Timer->Argument = Argument;
208 //      memset( &Timer->Lock, 0, sizeof(Timer->Lock) );
209         Timer->bActive = 0;
210         LOG("Initialised timer %p (cb=%p,arg=%p)", Timer, Callback, Argument);
211 }
212
213 /**
214  * \brief Free an allocated timer
215  */
216 void Time_FreeTimer(tTimer *Timer)
217 {
218         if( !Timer )    return ;
219         Time_RemoveTimer( Timer );      // Just in case
220
221         // Ensures that we don't free until the timer callback has started
222         while( Timer->bActive ) Threads_Yield();
223         // Release won't be needed, as nothing should be waiting on it
224 //      Mutex_Acquire( &Timer->Lock );
225         
226         // Free timer
227         free(Timer);
228         LOG("%p deallocated %p", __builtin_return_address(0), Timer);
229 }
230
231 /**
232  * \fn void Time_Delay(int Delay)
233  * \brief Delay for a small ammount of time
234  */
235 void Time_Delay(int Delay)
236 {
237         LOG("(%i)", Delay);
238         tTimer  *t = &Proc_GetCurThread()->ThreadTimer;
239         Time_InitTimer(t, NULL, NULL);
240         Time_ScheduleTimer(t, Delay);
241         Threads_WaitEvents(THREAD_EVENT_TIMER);
242 }
243
244 // === EXPORTS ===
245 //EXPORT(Time_CreateTimer);
246 EXPORT(Time_ScheduleTimer);
247 EXPORT(Time_RemoveTimer);
248 EXPORT(Time_AllocateTimer);
249 //EXPORT(Time_InitTimer);
250 EXPORT(Time_FreeTimer);
251 EXPORT(Time_Delay);

UCC git Repository :: git.ucc.asn.au