The Pedigree Project  0.1
hosted/Timer.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "Timer.h"
21 #include "pedigree/kernel/compiler.h"
22 #include "pedigree/kernel/machine/Machine.h"
23 #include "pedigree/kernel/process/Event.h"
24 #include "pedigree/kernel/process/Thread.h"
25 #include "pedigree/kernel/processor/Processor.h"
26 
27 #include "pedigree/kernel/core/SlamAllocator.h"
28 
29 // Millisecond interval (tick every ms)
30 #define INTERVAL 1000000
31 
32 using namespace __pedigree_hosted;
33 
34 // Set by PhysicalMemoryManager.
35 extern size_t g_FreePages;
36 extern size_t g_AllocedPages;
37 
39 
40 uint8_t daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
41 
42 void HostedTimer::addAlarm(Event *pEvent, size_t alarmSecs, size_t alarmUsecs)
43 {
44  Alarm *pAlarm = new Alarm(
45  pEvent, alarmSecs * 1000000 + alarmUsecs + getTickCount(),
46  Processor::information().getCurrentThread());
47  m_Alarms.pushBack(pAlarm);
48 }
49 
51 {
52  for (List<Alarm *>::Iterator it = m_Alarms.begin(); it != m_Alarms.end();
53  it++)
54  {
55  if ((*it)->m_pEvent == pEvent)
56  {
57  m_Alarms.erase(it);
58  return;
59  }
60  }
61 }
62 
63 size_t HostedTimer::removeAlarm(class Event *pEvent, bool bRetZero)
64 {
65  size_t currTime = getTickCount();
66 
67  for (List<Alarm *>::Iterator it = m_Alarms.begin(); it != m_Alarms.end();
68  it++)
69  {
70  if ((*it)->m_pEvent == pEvent)
71  {
72  size_t ret = 0;
73  if (!bRetZero)
74  {
75  size_t alarmEndTime = (*it)->m_Time;
76 
77  // Is it later than the end of the alarm?
78  if (alarmEndTime < currTime)
79  ret = 0;
80  else
81  {
82  size_t diff = alarmEndTime - currTime;
83  ret = (diff / 1000) + 1;
84  }
85  }
86 
87  m_Alarms.erase(it);
88  return ret;
89  }
90  }
91 
92  return 0;
93 }
94 
95 bool HostedTimer::registerHandler(TimerHandler *handler)
96 {
97  // find a spare spot and install
98  size_t nHandler;
99  for (nHandler = 0; nHandler < MAX_TIMER_HANDLERS; nHandler++)
100  {
101  if (m_Handlers[nHandler] == 0)
102  {
103  m_Handlers[nHandler] = handler;
104  return true;
105  }
106  }
107 
108  // no room!
109  return false;
110 }
111 
112 bool HostedTimer::unregisterHandler(TimerHandler *handler)
113 {
114  // find a spare spot and install
115  size_t nHandler;
116  for (nHandler = 0; nHandler < MAX_TIMER_HANDLERS; nHandler++)
117  {
118  if (m_Handlers[nHandler] == handler)
119  {
120  m_Handlers[nHandler] = 0;
121  return true;
122  }
123  }
124 
125  // not found
126  return false;
127 }
128 
130 {
131  return m_Year;
132 }
133 
135 {
136  return m_Month;
137 }
138 
140 {
141  return m_DayOfMonth;
142 }
143 
145 {
146  return m_DayOfWeek;
147 }
148 
150 {
151  return m_Hour;
152 }
153 
155 {
156  return m_Minute;
157 }
158 
160 {
161  return m_Second;
162 }
163 
165 {
166  return m_Nanosecond;
167 }
168 
170 {
171  struct timespec tv;
172  clock_gettime(CLOCK_MONOTONIC, &tv);
173  return (tv.tv_sec * 1000ULL) + (tv.tv_nsec / 1000ULL);
174 }
175 
177 {
178  struct timespec tv;
179  clock_gettime(CLOCK_MONOTONIC, &tv);
180  return (tv.tv_sec * 1000000000ULL) + (tv.tv_nsec);
181 }
182 
184 {
185  synchronise();
186 
187  ByteSet(m_Handlers, 0, sizeof(TimerHandler *) * MAX_TIMER_HANDLERS);
188 
189  struct sigevent sv;
190  ByteSet(&sv, 0, sizeof(sv));
191  sv.sigev_notify = SIGEV_SIGNAL;
192  sv.sigev_signo = SIGUSR1;
193  sv.sigev_value.sival_ptr = this;
194  int r = timer_create(CLOCK_MONOTONIC, &sv, &m_Timer);
195  if (r != 0)
196  {
198  return false;
199  }
200 
201  struct itimerspec interval;
202  ByteSet(&interval, 0, sizeof(interval));
203  interval.it_interval.tv_nsec = INTERVAL;
204  interval.it_value.tv_nsec = INTERVAL;
205  r = timer_settime(m_Timer, 0, &interval, 0);
206  if (r != 0)
207  {
208  timer_delete(m_Timer);
209  return false;
210  }
211 
212  IrqManager &irqManager = *Machine::instance().getIrqManager();
213  m_IrqId = irqManager.registerIsaIrqHandler(0, this);
214  if (m_IrqId == 0)
215  {
216  timer_delete(m_Timer);
217  return false;
218  }
219 
220  return true;
221 }
222 
224 {
225  if (tohw)
226  return;
227 
228  struct timespec tv;
229  clock_gettime(CLOCK_REALTIME, &tv);
230  struct tm *t = gmtime(&tv.tv_sec);
231 
232  m_Nanosecond = tv.tv_nsec;
233  m_Second = t->tm_sec;
234  m_Minute = t->tm_min;
235  m_Hour = t->tm_hour;
236  m_DayOfMonth = t->tm_mday;
237  m_Month = t->tm_mon;
238  m_Year = t->tm_year + 1900; // Years since 1900.
239  m_DayOfWeek = t->tm_wday;
240 }
241 
243 {
244  synchronise();
245 
246  timer_delete(m_Timer);
247 
248  // Unregister the irq
249  IrqManager &irqManager = *Machine::instance().getIrqManager();
250  irqManager.unregisterHandler(m_IrqId, this);
251 }
252 
254  : m_Year(0), m_Month(0), m_DayOfMonth(0), m_DayOfWeek(0), m_Hour(0),
255  m_Minute(0), m_Second(0), m_Nanosecond(0), m_IrqId(0), m_Handlers(),
256  m_Alarms()
257 {
258 }
259 
260 bool HostedTimer::irq(irq_id_t number, InterruptState &state)
261 {
262  // Should we handle this?
263  uint64_t opaque = state.getRegister(0);
264  if (opaque != reinterpret_cast<uint64_t>(this))
265  {
266  return false;
267  }
268 
269  // Update tick count.
270  uint64_t delta = INTERVAL;
271 
272  // Calculate the new time/date
273  m_Nanosecond += delta;
274 
275  // Check for alarms.
276  while (true)
277  {
278  bool bDispatched = false;
279  for (List<Alarm *>::Iterator it = m_Alarms.begin();
280  it != m_Alarms.end(); it++)
281  {
282  Alarm *pA = *it;
283  if (pA->m_Time <= getTickCount())
284  {
285  pA->m_pThread->sendEvent(pA->m_pEvent);
286  m_Alarms.erase(it);
287  bDispatched = true;
288  break;
289  }
290  }
291  if (!bDispatched)
292  break;
293  }
294 
295  if (UNLIKELY(m_Nanosecond >= 1000000ULL))
296  {
297  // Every millisecond, unblock any interrupts which were halted and halt
298  // any which need to be halted.
299  Machine::instance().getIrqManager()->tick();
300  }
301 
302  if (UNLIKELY(m_Nanosecond >= 1000000000ULL))
303  {
304  ++m_Second;
305  m_Nanosecond -= 1000000000ULL;
306 
307 #ifdef MEMORY_LOGGING_ENABLED
308  Serial *pSerial = Machine::instance().getSerial(1);
309  NormalStaticString str;
310  str += "Heap: ";
311  str += SlamAllocator::instance().heapPageCount() * 4;
312  str += "K\tPages: ";
313  str += (g_AllocedPages * 4096) / 1024;
314  str += "K\t Free: ";
315  str += (g_FreePages * 4096) / 1024;
316  str += "K\n";
317 
318  pSerial->write(str);
319 #endif
320 
321  if (UNLIKELY(m_Second == 60))
322  {
323  ++m_Minute;
324  m_Second = 0;
325 
326  if (UNLIKELY(m_Minute == 60))
327  {
328  ++m_Hour;
329  m_Minute = 0;
330 
331  if (UNLIKELY(m_Hour == 24))
332  {
333  ++m_DayOfMonth;
334  m_Hour = 0;
335 
336  // Are we in a leap year
337  bool isLeap = ((m_Year % 4) == 0) & (((m_Year % 100) != 0) |
338  ((m_Year % 400) == 0));
339 
340  if (UNLIKELY(
341  ((m_DayOfMonth > daysPerMonth[m_Month - 1]) &&
342  ((m_Month != 2) || isLeap == false)) ||
343  (m_DayOfMonth > (daysPerMonth[m_Month - 1] + 1))))
344  {
345  ++m_Month;
346  m_DayOfMonth = 1;
347 
348  if (UNLIKELY(m_Month > 12))
349  {
350  ++m_Year;
351  m_Month = 1;
352  }
353  }
354  }
355  }
356  }
357  }
358 
359  // call handlers
360  size_t nHandler;
361  for (nHandler = 0; nHandler < MAX_TIMER_HANDLERS; nHandler++)
362  {
363  // timer delta is in nanoseconds
364  if (m_Handlers[nHandler])
365  m_Handlers[nHandler]->timer(delta, state);
366  }
367 
368  return true;
369 }
virtual Serial * getSerial(size_t n)=0
virtual uint64_t getTickCount()
virtual uint64_t getTickCountNano()
virtual void synchronise(bool tohw=false)
static ProcessorInformation & information()
Definition: Processor.cc:45
virtual void removeAlarm(class Event *pEvent)
Definition: hosted/Timer.cc:50
virtual uint8_t getSecond()
static HostedTimer m_Instance
bool sendEvent(Event *pEvent)
Definition: Thread.cc:529
bool initialise() INITIALISATION_ONLY
virtual uint8_t getMinute()
List< Alarm * > m_Alarms
HostedTimer() INITIALISATION_ONLY
::Iterator< T, node_t > Iterator
Definition: List.h:71
virtual void addAlarm(class Event *pEvent, size_t alarmSecs, size_t alarmUsecs=0)
Definition: hosted/Timer.cc:42
virtual void unregisterHandler(irq_id_t Id, IrqHandler *handler)=0
virtual uint64_t getNanosecond()
void uninitialise()
virtual bool irq(irq_id_t number, InterruptState &state)
virtual uint8_t getMonth()
virtual void timer(uint64_t delta, InterruptState &state)=0
virtual uint8_t getDayOfMonth()
TimerHandler * m_Handlers[MAX_TIMER_HANDLERS]
Definition: Event.h:48
virtual irq_id_t registerIsaIrqHandler(uint8_t irq, IrqHandler *handler, bool bEdge=false)=0
virtual uint8_t getHour()
virtual void tick()
Definition: IrqManager.cc:25
virtual size_t getYear()
virtual uint8_t getDayOfWeek()