[MUD-Dev] Re: [CODE] [LANGUAGE/PLATFORM SPECIFIC] My Event Engine
s001gmu at nova.wright.edu
s001gmu at nova.wright.edu
Tue Jul 21 09:48:19 CEST 1998
On Tue, 21 Jul 1998, Oliver Jowett wrote:
> On Mon, 20 Jul 1998 s001gmu at nova.wright.edu wrote:
>
> > On Sat, 18 Jul 1998 oliver at jowett.manawatu.planet.co.nz wrote:
> >
> > > Why not move this to a separate layer? At the lowest level, select() on
> > > ALL sockets with a timeout equal to the time to next pending event. When
> > > input arrives, read and buffer; when output is possible, write from a
> > > buffer; when exceptions occur, set an appropriate flag. Loop back and
> > > repeat the select. Then when the event actually goes off, you check and
> > > modify the buffers.
> >
> > This works nicely, as long as you have a tick based event queue. The
> > model I use is based on the system clock, and uses a linked list as the
> > main structure. With one cpu, it is physically quite impossible to
> > schedule two events at exactly the same time (and with multiple it is
> > quite unlikely), so I don't need any auxiliary linked lists to handle
> > collisions. The problem is that my event driver sleeps until the next
> > event is scheduled to go off, OR another event is placed first in the
> > list. If the later happens, not only would I have to wake up the event
> > driver, but I'd also have to interrupt the select, and then reschedule it
> > with a new timeout.
>
> I'm not quite clear about how your timing system works - it sounds like a
> "tick-based" system which has a much finer (and externally-run, although
> that shouldn't affect much) timing resolution?
To be honest, it is tick based, I just use the system clock as my
'ticker'. :) What I do is schedule events with an offset:
EventHandler E = new EventHandler ();
...
E.AddEvent(new UselessEvent(), 300);
where 300 is the offset. EventHandler::AddEvent takes the offset and adds
it to the current system time, and then places the event in the queue
based on the resulting ripening time:
EventHandler::AddEvent(Event e, int offset)
{
...
TIME t = current_time();
t += offset;
e.ripens = t;
<insert into linked list, orderd on e.ripens>
...
}
so, yes, it is 'tick-based', but only inasmuch as the computer is tick
based. I don't impose any artificial ticks on top of the system ticker.
:) I do allow for the definition of a GRAIN, but that is only for
shorthand. It gets a bit cumbersome to schedule an event to go off in one
week of real time if you have to measure it down to the nanosecond. The
Grain is just an int multiplied to the offset before it is added to the
current time:
t += offset * GRAIN;
> If you're working with a single thread - how do events get added without
> either I/O occuring or an event happening first? Signals, I guess.
> Personally I avoid using signals for anything short of exceptional
> external circumstances where possible :)
I am working with multiple threads.
> With multiple threads I'm not quite sure why you'd want to have the event
> system timing tied into I/O waits anyway.
And the above was exactly my point, for the way I have my driver set up.
In Todd's design, he imposes a 'ticker' on top of the system clock, where
each tick is of a fixed and known length. Therefore, as long as he
doesn't try to remove that design spec, he should be ok in putting the
select call to sleep for the length of one of those ticks.
I dislike this approach, because it ties the socket handler and the event
driver together (as I've stated before). I do like the idea of having a
single event for each socket, as discussed in my last post, but I want to
do some test runs to see how it would work out... I am unsure how well it
will scale, and at what point the event handler would get swammped with
I/O events.
-Greg
More information about the mud-dev-archive
mailing list