Re: Moving main loop to GLib.



On 20 Nov 1998, Owen Taylor wrote:

> Prioritized events where in that proposal... for instance, I
> have:
> 
>  guint     g_idle_add_full       (gint                 priority,
>                                   GFunc                function,
>                                   gpointer             data,
>                                   GDestroyNotify       destroy);
> 
> and the same for timeouts and input functions.

OK, good, I missed that.

[Just one note: my understanding is that select(), and perhaps poll(),
will not always return all events that are available. Due to OS
features/bugs it may be impossible to rely on any but the first returned
descriptor.]

> Hmmm, I suppose one could replace the input_add() functionality
> with a poll_add():
> 
>  gint      g_poll_add      (gint                 source,
>                             GPollEvents          events,
>                             GPollFunction        function
>                             gpointer             data);
> 
> I'm a little nervous about this, since it only really is
> an advantage if one says that one can use the platform
> specific constants for 'events'. One could, alternatively,
> just add some more of the common poll events into
> GInputCondition. (Though one can't assume that they will
> be honored, since the entire poll, might, in any case,
> be emulated via select().

Yes, I'm thinking specifically of the situation where poll() is provided
by the OS, and additional poll() constants are available. (This shouldn't
be rare: I wouldn't be surprised if Linux does exactly this, soon.) In
that case, using poll() and platform specific events is very like the
_only_ way to do something, and it needs to be available if some code is
to be written using GLib/Gtk at all. 

At any rate, this would be a "low-level" function, available, but normally
not used directly.

(This gets back to my feelings about portability: just because something
is portable doesn't mean it has to completely abstract away all platform
details. That tends to make for code that runs everywhere, but doesn't
work _perfectly_ anywhere. I much prefer to use a common portable code
base and integrate it with OS & UI specific code.)

> Unix certainly has events that don't fit well into the poll() / select()
> model. The two most interesting examples are SIGCHILD and signalling
> between threads. Unfortunately, I don't know of _any_ good way
> of handling these together with FDs, except for using fork()
> or extra threads and communicating with the main thread via
> pipes.

Also, all of the SysV stuff (mutexes, message queues, etc.) is equally
dissimilar. You're right, it should be possible to build a technique using
kernel threads/tasks and pipes/sockets to hide the problem, but I'm not
aware of anybody yet doing it, and I can't see it being extraordinarily
efficient. 

It's easy to see why Plan9 was based on the idea of _everything_ being a
proper blockable file, and making it easy for tasks to make blocking
descriptors usable by other tasks. 

Heck, just looking up DNS records is a pain, under UNIX. 

> The point of the central poll() is not that every sort of
> interesting event occurs via a file descriptor, but, rather
> that you can only wait in one place. I'd go so far as to
> say that in fact, the whole point of an 'event loop' is not
> the events but the waiting.

Actually, I've tried to avoid the term "event loop", as that usually means
something like the Gdk event loop, which is a message queue. We are
talking about a "main loop", which mediates access to blocking OS
resources. (Not to say there shouldn't be an easy way to implement a
message queue in the main loop...)

> You can add as many polling (in the sense of spin-waiting)
> event sources - they merely specify timeouts of 0. But, as
> far as I can see, it doesn't make sense to add another 
> type of event source that has a different mechanism for waiting.

I'm not positive I agree with this. It seems possible that if two (or
more) incompatible event monitor calls were available (each of which block
for a timeout period, none of which is interrupted by incoming events of
another type) that you would want to wait in each call in turn for a
portion of the total wait period. 

(Obviously this greatly increases latency, and is hardly ideal. However,
the assumption is that the OS facilities are already completely broken, so
the best needs to be made of a bad situation. Will this sort of thing
actually come up anywhere? I don't know.)

> > Even more confusing is interacting providers: one provider might only be
> > able to say whether the event is ready now or not (just a peek), but the
> > OS is capable of interrupting _other_ provider timeouts when the event
> > becomes ready. 
> 
> If the OS can do this, then the single-point-of-waiting model 
> works fine.

True, although the code model has to be very careful about getting the
time right, so that truncated calls don't confuse anything.

> It looks like the Tcl/Tk code is pretty similar to my proposal,
> all things considered; there is preparation, a central "wait stage",
> and then a check stage afterwords. The main difference is
> that the 'GSource' structures are platform independent, and
> the on Unix sources use a separate mechanism to register
> interest in particular fd's. 

Yes, that sounds about right, though I've always felt it split the
portable/non-portable stuff in a poor manner. (Though I suppose most of
this is due to the stdio replacement that is being used, along with
everything else.) Of course, I've never liked Tcl/Tk's approach to hiding
all of the internals, making it _extremely_ difficult to add stuff to it.
I hope to avoid that.

Hmm... Actually, that reminds me of something: I _do_ want to be able to
add new event "providers" at run time, and ideally be able to override the
existing ones. I ran into this writing pilot-debug (a Tcl/Tk app that uses
my pilot-link library to act as a debugging console for the PalmPilot),
which currently ties into GNU readline (in a proper main loop way) and
monitors a serial fd, and will, eventually, need to use a special version
of the select() call, to deal properly with the user-level file descriptor
that pilot-link creates.

So I guess it does make sense to be able to override various portions of
the main loop code, in a reasonably portable manner, and without (I
sincerely hope) resorting to the Tcl/Tk "just patch the library" approach.

> Thanks for the reference.
> 
> [ This similarity is probably not completely coincidental.
>   I based my proposal on Graham Barr's Event:: module
>   for Perl, and, I think, came out of discussions related
>   to the Perl/Tk ]

I'm not positive, but I think I remember having discussions with Graham
about that module in the first place. :-)

> [ Really off-topic: select/poll-on-directory should work fine for
>   fitting directory changes into the Unix model. I believe it even 
>   has been  blessed as a "good idea" for going into future
>   Linux kernels ]

I'm not sure if it'll work with select(), or whether it'll be a new poll()
flag. But yes, this certainly seems to be in the works.

> I'm not sure that my GSource's _are_ indeed different things
> than your GProviders.
> 
> As I see it, the structure of the main loop is:
> 
> - There are various event types (idles, input functions, etc.) -
>   Modulo things like file descriptors, these event types
>   can be reasonably cross-platform.

Might as well add stdio and sfio now, and be done with it. (Perl shows how
to tie into stdio's buffering routines in a reasonably portable manner,
and I assume sfio has the necessary abilities out-of-the-box.)

> - The event types map into specific platform-specific mechansims
>   for waiting and notification
> 
> - There is a generic interface (g_main_run() and friends) for
>   controlling the process of waiting and notification.
> 
> Because the mapping from an event type to a wait-mechanism
> is by its very nature platform-specific, I don't think
> it makes sense to have a platform-indepedent interface for the 
> middle layer, which, it seems, is what your GProvider is.
> 
> Instead, I think the middle layer probably has to be
> platform specific. GSource (perhaps it should be
> GUnixSource), is a generic, but Unix-centric middle layer.
> 
> It might, however, be possible to structure things so the 
> GSource's are platform independent, as in Tk, though that 
> mostly is a question of shoving the platform-dependence 
> somewhere else in the API.

Hmm... At this stage, as long we both understand what is involved, I doubt
the precise arrangement matters. My thinking was to make it simple for
dissimilar things to be portably categorized (FILE*'s go into slot A,
descriptors into slot B, etc.), but this probably really isn't too
important -- especially since it isn't necessarily accurate. Socket
handles and file descriptors are different things under Win'95, for
example.

(Which in turn means that, like Tcl/Tk, a stdio replacement that
understands different implementations is almost certainly a good idea, and
a file descriptor abstraction might not hurt either. But these should be
strictly optional, unlike Tcl/Tk.) 

-- 
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]