273 lines
7.2 KiB
C++
273 lines
7.2 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1998 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
etimer.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
SIS Groveler event timer
|
||
|
|
||
|
Authors:
|
||
|
|
||
|
John Douceur, 1998
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
User Mode
|
||
|
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "all.hxx"
|
||
|
|
||
|
#define NEW_HeapSegment(segment_size) \
|
||
|
((HeapSegment *)(new BYTE[sizeof(HeapSegment) + \
|
||
|
((segment_size) - 1) * sizeof(Event)]))
|
||
|
|
||
|
#define DELETE_HeapSegment(heap_segment) delete[] ((BYTE *)(heap_segment))
|
||
|
|
||
|
EventTimer::EventTimer()
|
||
|
{
|
||
|
ASSERT(this != 0);
|
||
|
first_segment = NEW_HeapSegment(1);
|
||
|
first_segment->previous = 0;
|
||
|
first_segment->next = 0;
|
||
|
last_segment = first_segment;
|
||
|
population = 0;
|
||
|
segment_size = 1;
|
||
|
heap_ok = false;
|
||
|
}
|
||
|
|
||
|
EventTimer::~EventTimer()
|
||
|
{
|
||
|
ASSERT(this != 0);
|
||
|
ASSERT(first_segment != 0);
|
||
|
ASSERT(last_segment != 0);
|
||
|
ASSERT(population >= 0);
|
||
|
ASSERT(segment_size > 0);
|
||
|
ASSERT((segment_size & (segment_size - 1)) == 0); // power of 2
|
||
|
ASSERT(population >= segment_size - 1);
|
||
|
ASSERT(!heap_ok || population >= segment_size);
|
||
|
ASSERT(population < 2 * segment_size);
|
||
|
ASSERT(first_segment != last_segment || segment_size == 1);
|
||
|
ASSERT(first_segment == last_segment || segment_size > 1);
|
||
|
while (first_segment != 0)
|
||
|
{
|
||
|
HeapSegment *next_segment = first_segment->next;
|
||
|
ASSERT(first_segment != 0);
|
||
|
DELETE_HeapSegment(first_segment);
|
||
|
first_segment = next_segment;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
EventTimer::run()
|
||
|
{
|
||
|
ASSERT(this != 0);
|
||
|
running = true;
|
||
|
while (running && population > 0)
|
||
|
{
|
||
|
ASSERT(first_segment != 0);
|
||
|
ASSERT(last_segment != 0);
|
||
|
ASSERT(population >= 0);
|
||
|
ASSERT(segment_size > 0);
|
||
|
ASSERT((segment_size & (segment_size - 1)) == 0); // power of 2
|
||
|
ASSERT(population >= segment_size - 1);
|
||
|
ASSERT(!heap_ok || population >= segment_size);
|
||
|
ASSERT(population < 2 * segment_size);
|
||
|
ASSERT(first_segment != last_segment || segment_size == 1);
|
||
|
ASSERT(first_segment == last_segment || segment_size > 1);
|
||
|
if (!heap_ok)
|
||
|
{
|
||
|
int final_position = (population + 1) % segment_size;
|
||
|
unsigned int final_time =
|
||
|
last_segment->events[final_position].event_time;
|
||
|
HeapSegment *segment = first_segment;
|
||
|
HeapSegment *next_segment = segment->next;
|
||
|
int position = 0;
|
||
|
int next_position = 0;
|
||
|
while (segment != last_segment
|
||
|
&& (next_segment != last_segment
|
||
|
|| next_position < final_position))
|
||
|
{
|
||
|
if ((next_segment != last_segment ||
|
||
|
next_position + 1 < final_position) &&
|
||
|
signed(next_segment->events[next_position].event_time -
|
||
|
next_segment->events[next_position + 1].event_time) > 0)
|
||
|
{
|
||
|
next_position++;
|
||
|
}
|
||
|
if (signed(final_time -
|
||
|
next_segment->events[next_position].event_time) <= 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
segment->events[position] = next_segment->events[next_position];
|
||
|
segment = next_segment;
|
||
|
next_segment = segment->next;
|
||
|
position = next_position;
|
||
|
next_position = 2 * position;
|
||
|
}
|
||
|
segment->events[position] = last_segment->events[final_position];
|
||
|
if (population < segment_size)
|
||
|
{
|
||
|
segment_size /= 2;
|
||
|
last_segment = last_segment->previous;
|
||
|
}
|
||
|
heap_ok = true;
|
||
|
}
|
||
|
ASSERT(first_segment != 0);
|
||
|
ASSERT(last_segment != 0);
|
||
|
ASSERT(population >= 0);
|
||
|
ASSERT(segment_size > 0);
|
||
|
ASSERT((segment_size & (segment_size - 1)) == 0); // power of 2
|
||
|
ASSERT(population >= segment_size - 1);
|
||
|
ASSERT(!heap_ok || population >= segment_size);
|
||
|
ASSERT(population < 2 * segment_size);
|
||
|
ASSERT(first_segment != last_segment || segment_size == 1);
|
||
|
ASSERT(first_segment == last_segment || segment_size > 1);
|
||
|
unsigned int current_time = GET_TICK_COUNT();
|
||
|
int sleep_time = __max(
|
||
|
signed(first_segment->events[0].event_time - current_time), 0);
|
||
|
do
|
||
|
{
|
||
|
bool event_triggered = sync_event.wait(sleep_time);
|
||
|
if (event_triggered)
|
||
|
{
|
||
|
SERVICE_FOLLOW_COMMAND();
|
||
|
if (!running)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
current_time = GET_TICK_COUNT();
|
||
|
sleep_time = __max(
|
||
|
signed(first_segment->events[0].event_time - current_time), 0);
|
||
|
} while (sleep_time > 0);
|
||
|
heap_ok = false;
|
||
|
population--;
|
||
|
(*first_segment->events[0].callback)(first_segment->events[0].context);
|
||
|
bool ok = shared_data->send_values();
|
||
|
if (!ok)
|
||
|
{
|
||
|
PRINT_DEBUG_MSG((_T("GROVELER: SharedData::send_values() failed\n")));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
EventTimer::halt()
|
||
|
{
|
||
|
ASSERT(this != 0);
|
||
|
ASSERT(first_segment != 0);
|
||
|
ASSERT(last_segment != 0);
|
||
|
ASSERT(population >= 0);
|
||
|
ASSERT(segment_size > 0);
|
||
|
ASSERT((segment_size & (segment_size - 1)) == 0); // power of 2
|
||
|
ASSERT(population >= segment_size - 1);
|
||
|
ASSERT(!heap_ok || population >= segment_size);
|
||
|
ASSERT(population < 2 * segment_size);
|
||
|
ASSERT(first_segment != last_segment || segment_size == 1);
|
||
|
ASSERT(first_segment == last_segment || segment_size > 1);
|
||
|
running = false;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
EventTimer::schedule(
|
||
|
unsigned int event_time,
|
||
|
void *context,
|
||
|
EventCallback callback)
|
||
|
{
|
||
|
ASSERT(this != 0);
|
||
|
ASSERT(first_segment != 0);
|
||
|
ASSERT(last_segment != 0);
|
||
|
ASSERT(population >= 0);
|
||
|
ASSERT(segment_size > 0);
|
||
|
ASSERT((segment_size & (segment_size - 1)) == 0); // power of 2
|
||
|
ASSERT(population >= segment_size - 1);
|
||
|
ASSERT(!heap_ok || population >= segment_size);
|
||
|
ASSERT(population < 2 * segment_size);
|
||
|
ASSERT(first_segment != last_segment || segment_size == 1);
|
||
|
ASSERT(first_segment == last_segment || segment_size > 1);
|
||
|
population++;
|
||
|
HeapSegment *segment;
|
||
|
int position;
|
||
|
if (heap_ok)
|
||
|
{
|
||
|
if (population >= 2 * segment_size)
|
||
|
{
|
||
|
segment_size *= 2;
|
||
|
if (last_segment->next == 0)
|
||
|
{
|
||
|
last_segment->next = NEW_HeapSegment(segment_size);
|
||
|
last_segment->next->previous = last_segment;
|
||
|
last_segment->next->next = 0;
|
||
|
}
|
||
|
last_segment = last_segment->next;
|
||
|
}
|
||
|
segment = last_segment;
|
||
|
HeapSegment *previous_segment = segment->previous;
|
||
|
position = population % segment_size;
|
||
|
int next_position = position >> 1;
|
||
|
while (previous_segment != 0 && signed(event_time
|
||
|
- previous_segment->events[next_position].event_time) < 0)
|
||
|
{
|
||
|
segment->events[position] = previous_segment->events[next_position];
|
||
|
segment = previous_segment;
|
||
|
previous_segment = segment->previous;
|
||
|
position = next_position;
|
||
|
next_position >>= 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int final_position = population % segment_size + 1;
|
||
|
segment = first_segment;
|
||
|
HeapSegment *next_segment = segment->next;
|
||
|
position = 0;
|
||
|
int next_position = 0;
|
||
|
while (segment != last_segment
|
||
|
&& (next_segment != last_segment
|
||
|
|| next_position < final_position))
|
||
|
{
|
||
|
if ((next_segment != last_segment ||
|
||
|
next_position + 1 < final_position) &&
|
||
|
signed(next_segment->events[next_position].event_time -
|
||
|
next_segment->events[next_position + 1].event_time) > 0)
|
||
|
{
|
||
|
next_position++;
|
||
|
}
|
||
|
if (signed(event_time -
|
||
|
next_segment->events[next_position].event_time) <= 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
segment->events[position] = next_segment->events[next_position];
|
||
|
segment = next_segment;
|
||
|
next_segment = segment->next;
|
||
|
position = next_position;
|
||
|
next_position = 2 * position;
|
||
|
}
|
||
|
}
|
||
|
segment->events[position].event_time = event_time;
|
||
|
segment->events[position].context = context;
|
||
|
segment->events[position].callback = callback;
|
||
|
heap_ok = true;
|
||
|
ASSERT(first_segment != 0);
|
||
|
ASSERT(last_segment != 0);
|
||
|
ASSERT(population >= 0);
|
||
|
ASSERT(segment_size > 0);
|
||
|
ASSERT((segment_size & (segment_size - 1)) == 0); // power of 2
|
||
|
ASSERT(population >= segment_size);
|
||
|
ASSERT(population < 2 * segment_size);
|
||
|
ASSERT(first_segment != last_segment || segment_size == 1);
|
||
|
ASSERT(first_segment == last_segment || segment_size > 1);
|
||
|
return;
|
||
|
}
|