The Pedigree Project  0.1
Delay.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 "pedigree/kernel/machine/Machine.h"
21 #include "pedigree/kernel/machine/Timer.h"
22 #include "pedigree/kernel/process/Event.h"
23 #include "pedigree/kernel/process/PerProcessorScheduler.h"
24 #include "pedigree/kernel/process/Thread.h"
25 #include "pedigree/kernel/process/eventNumbers.h"
26 #include "pedigree/kernel/processor/Processor.h"
27 #include "pedigree/kernel/processor/ProcessorInformation.h"
28 #include "pedigree/kernel/processor/types.h"
29 #include "pedigree/kernel/time/Time.h"
30 #include "pedigree/kernel/utilities/assert.h"
31 #include "pedigree/kernel/utilities/new"
32 
33 namespace Time
34 {
35 static void delayTimerFired(uint8_t *pBuffer)
36 {
37  Processor::information().getCurrentThread()->setInterrupted(true);
38 }
39 
40 class DelayTimerEvent : public Event
41 {
42  public:
44  virtual ~DelayTimerEvent();
45 
46  virtual size_t serialize(uint8_t *pBuffer);
47  static bool unserialize(uint8_t *pBuffer, DelayTimerEvent &event);
48  virtual size_t getNumber();
49 };
50 
51 bool delay(Timestamp nanoseconds)
52 {
53  Thread *pThread = Processor::information().getCurrentThread();
54  void *handle = addAlarm(nanoseconds);
55 
57  while (true)
58  {
59  if (!pThread->wasInterrupted())
60  Processor::information().getScheduler().sleep(0);
61 
62  if (pThread->wasInterrupted())
63  {
64  removeAlarm(handle);
65  break;
66  }
67  else if (pThread->getUnwindState() != Thread::Continue)
68  {
69  removeAlarm(handle);
70  return false;
71  }
72 
73  pThread->setInterrupted(false);
74  }
75 
76  return true;
77 }
78 
79 void *addAlarm(Timestamp nanoseconds)
80 {
81  Event *pEvent = new DelayTimerEvent();
82  uint64_t usecs = nanoseconds / Multiplier::Microsecond;
83  if (!usecs)
84  ++usecs;
85 
86  Thread *pThread = Processor::information().getCurrentThread();
87  pThread->setInterrupted(false);
88  Machine::instance().getTimer()->addAlarm(pEvent, 0, usecs);
89 
90  return pEvent;
91 }
92 
93 void removeAlarm(void *handle)
94 {
95  assert(handle != nullptr);
96 
97  Thread *pThread = Processor::information().getCurrentThread();
98  Event *pEvent = reinterpret_cast<Event *>(handle);
99  Machine::instance().getTimer()->removeAlarm(pEvent);
100 
101  // Handle a race condition where the timeout triggers but hasn't been
102  // handled by the time we clean up the alarm. That leaves the deleted event
103  // in this thread's event queue. We also do so after removing the alarm
104  // from the Machine implementation so that we don't get new events added
105  // after our cull.
106  pThread->cullEvent(pEvent);
107 
108  delete pEvent;
109 }
110 
111 DelayTimerEvent::DelayTimerEvent()
112  : Event(reinterpret_cast<uintptr_t>(&delayTimerFired), false)
113 {
114 }
115 DelayTimerEvent::~DelayTimerEvent()
116 {
117 }
118 
119 size_t DelayTimerEvent::serialize(uint8_t *pBuffer)
120 {
121  return 0;
122 }
123 
124 bool DelayTimerEvent::unserialize(uint8_t *pBuffer, DelayTimerEvent &event)
125 {
126  return true;
127 }
128 
130 {
131  return EventNumbers::DelayTimer;
132 }
133 } // namespace Time
void cullEvent(Event *pEvent)
Definition: Thread.cc:580
bool wasInterrupted()
Definition: Thread.h:229
virtual size_t serialize(uint8_t *pBuffer)
Definition: Delay.cc:119
virtual void removeAlarm(class Event *pEvent)=0
virtual size_t getNumber()
Definition: Delay.cc:129
virtual Timer * getTimer()=0
static ProcessorInformation & information()
Definition: Processor.cc:45
#define assert(x)
Definition: assert.h:37
No unwind necessary, carry on as normal.
Definition: Thread.h:243
Definition: fat.h:143
Definition: Thread.h:54
Definition: Event.h:48
void setInterrupted(bool b)
Definition: Thread.h:235
virtual void addAlarm(class Event *pEvent, size_t alarmSecs, size_t alarmUsecs=0)=0
UnwindType getUnwindState()
Definition: Thread.h:261
Event(uintptr_t handlerAddress, bool isDeletable, size_t specificNestingLevel=~0UL)
Definition: Event.cc:31
Definition: Stopwatch.h:25