windows-nt/Source/XPSP1/NT/base/fs/sis/groveler/etimer.cpp
2020-09-26 16:20:57 +08:00

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;
}