docs: Move GMainLoop documentation to Markdown

Helps: #3037
This commit is contained in:
Matthias Clasen 2023-10-09 23:15:08 +01:00 committed by Philip Withnall
parent 6c6337aa27
commit d8b25ecda3
4 changed files with 110 additions and 128 deletions

View File

@ -47,11 +47,13 @@ content_files = [
"conversion-macros.md",
"error-reporting.md",
"logging.md",
"main-loop.md",
"reference-counting.md",
"threads.md",
]
content_images = [
"file-name-encodings.png",
"mainloop-states.gif",
"Sorted_binary_tree_breadth-first_traversal.svg",
"Sorted_binary_tree_inorder.svg",
"Sorted_binary_tree_postorder.svg",

View File

@ -0,0 +1,107 @@
Title: The Main Event Loop
# The Main Event Loop
The main event loop manages all the available sources of events for GLib and
GTK applications. These events can come from any number of different types
of sources such as file descriptors (plain files, pipes or sockets) and
timeouts. New types of event sources can also be added using
`g_source_attach()`.
To allow multiple independent sets of sources to be handled in different
threads, each source is associated with a `GMainContext`. A `GMainContext`
can only be running in a single thread, but sources can be added to it and
removed from it from other threads. All functions which operate on a
`GMainContext` or a built-in `GSource` are thread-safe.
Each event source is assigned a priority. The default priority,
`G_PRIORITY_DEFAULT`, is 0. Values less than 0 denote higher priorities.
Values greater than 0 denote lower priorities. Events from high priority
sources are always processed before events from lower priority sources.
Idle functions can also be added, and assigned a priority. These will be run
whenever no events with a higher priority are ready to be processed.
The `GMainLoop` data type represents a main event loop. A GMainLoop is
created with `g_main_loop_new()`. After adding the initial event sources,
`g_main_loop_run()` is called. This continuously checks for new events from
each of the event sources and dispatches them. Finally, the processing of an
event from one of the sources leads to a call to `g_main_loop_quit()` to
exit the main loop, and `g_main_loop_run()` returns.
It is possible to create new instances of `GMainLoop` recursively. This is
often used in GTK applications when showing modal dialog boxes. Note that
event sources are associated with a particular `GMainContext`, and will be
checked and dispatched for all main loops associated with that GMainContext.
Libraries may contain wrappers of some of these functions, e.g.
`gtk_main()`, `gtk_main_quit()` and `gtk_events_pending()`.
## Creating new source types
One of the unusual features of the `GMainLoop` functionality is that new
types of event source can be created and used in addition to the builtin
type of event source. A new event source type is used for handling GDK
events. A new source type is created by "deriving" from the `GSource`
structure. The derived type of source is represented by a structure that has
the `GSource` structure as a first element, and other elements specific to
the new source type. To create an instance of the new source type, call
`g_source_new()` passing in the size of the derived structure and a table of
functions. These `GSourceFuncs` determine the behavior of the new source
type.
New source types basically interact with the main context in two ways. Their
prepare function in `GSourceFuncs` can set a timeout to determine the
maximum amount of time that the main loop will sleep before checking the
source again. In addition, or as well, the source can add file descriptors
to the set that the main context checks using `g_source_add_poll()`.
## Customizing the main loop iteration
Single iterations of a `GMainContext` can be run with
`g_main_context_iteration()`. In some cases, more detailed control of
exactly how the details of the main loop work is desired, for instance, when
integrating the `GMainLoop` with an external main loop. In such cases, you
can call the component functions of `g_main_context_iteration()` directly.
These functions are `g_main_context_prepare()`, `g_main_context_query()`,
`g_main_context_check()` and `g_main_context_dispatch()`.
## State of a Main Context
The operation of these functions can best be seen in terms of a state
diagram, as shown in this image.
![](mainloop-states.gif)
On UNIX, the GLib mainloop is incompatible with `fork()`. Any program using
the mainloop must either `exec()` or `exit()` from the child without
returning to the mainloop.
## Memory management of sources
There are two options for memory management of the user data passed to a
`GSource` to be passed to its callback on invocation. This data is provided
in calls to `g_timeout_add()`, `g_timeout_add_full()`, `g_idle_add()`, etc.
and more generally, using `g_source_set_callback()`. This data is typically
an object which owns the timeout or idle callback, such as a widget or a
network protocol implementation. In many cases, it is an error for the
callback to be invoked after this owning object has been destroyed, as that
results in use of freed memory.
The first, and preferred, option is to store the source ID returned by
functions such as `g_timeout_add()` or `g_source_attach()`, and explicitly
remove that source from the main context using `g_source_remove()` when the
owning object is finalized. This ensures that the callback can only be
invoked while the object is still alive.
The second option is to hold a strong reference to the object in the
callback, and to release it in the callbacks `GDestroyNotify`. This ensures
that the object is kept alive until after the source is finalized, which is
guaranteed to be after it is invoked for the final time. The
`GDestroyNotify` is another callback passed to the full variants of
`GSource` functions (for example, `g_timeout_add_full()`). It is called when
the source is finalized, and is designed for releasing references like this.
One important caveat of this second approach is that it will keep the object
alive indefinitely if the main loop is stopped before the `GSource` is
invoked, which may be undesirable.

View File

@ -156,6 +156,7 @@ expand_content_files = [
'error-reporting.md',
'i18n.md',
'logging.md',
'main-loop.md',
'reference-counting.md',
'threads.md',
]

View File

@ -127,134 +127,6 @@
#include "glib-init.h"
#include "glib-private.h"
/**
* SECTION:main
* @title: The Main Event Loop
* @short_description: manages all available sources of events
*
* The main event loop manages all the available sources of events for
* GLib and GTK applications. These events can come from any number of
* different types of sources such as file descriptors (plain files,
* pipes or sockets) and timeouts. New types of event sources can also
* be added using g_source_attach().
*
* To allow multiple independent sets of sources to be handled in
* different threads, each source is associated with a #GMainContext.
* A #GMainContext can only be running in a single thread, but
* sources can be added to it and removed from it from other threads. All
* functions which operate on a #GMainContext or a built-in #GSource are
* thread-safe.
*
* Each event source is assigned a priority. The default priority,
* %G_PRIORITY_DEFAULT, is 0. Values less than 0 denote higher priorities.
* Values greater than 0 denote lower priorities. Events from high priority
* sources are always processed before events from lower priority sources: if
* several sources are ready to dispatch, the ones with equal-highest priority
* will be dispatched on the current #GMainContext iteration, and the rest wait
* until a subsequent #GMainContext iteration when they have the highest
* priority of the sources which are ready for dispatch.
*
* Idle functions can also be added, and assigned a priority. These will
* be run whenever no events with a higher priority are ready to be dispatched.
*
* The #GMainLoop data type represents a main event loop. A GMainLoop is
* created with g_main_loop_new(). After adding the initial event sources,
* g_main_loop_run() is called. This continuously checks for new events from
* each of the event sources and dispatches them. Finally, the processing of
* an event from one of the sources leads to a call to g_main_loop_quit() to
* exit the main loop, and g_main_loop_run() returns.
*
* It is possible to create new instances of #GMainLoop recursively.
* This is often used in GTK applications when showing modal dialog
* boxes. Note that event sources are associated with a particular
* #GMainContext, and will be checked and dispatched for all main
* loops associated with that GMainContext.
*
* GTK contains wrappers of some of these functions, e.g. gtk_main(),
* gtk_main_quit() and gtk_events_pending().
*
* ## Creating new source types
*
* One of the unusual features of the #GMainLoop functionality
* is that new types of event source can be created and used in
* addition to the builtin type of event source. A new event source
* type is used for handling GDK events. A new source type is created
* by "deriving" from the #GSource structure. The derived type of
* source is represented by a structure that has the #GSource structure
* as a first element, and other elements specific to the new source
* type. To create an instance of the new source type, call
* g_source_new() passing in the size of the derived structure and
* a table of functions. These #GSourceFuncs determine the behavior of
* the new source type.
*
* New source types basically interact with the main context
* in two ways. Their prepare function in #GSourceFuncs can set a timeout
* to determine the maximum amount of time that the main loop will sleep
* before checking the source again. In addition, or as well, the source
* can add file descriptors to the set that the main context checks using
* g_source_add_poll().
*
* ## Customizing the main loop iteration
*
* Single iterations of a #GMainContext can be run with
* g_main_context_iteration(). In some cases, more detailed control
* of exactly how the details of the main loop work is desired, for
* instance, when integrating the #GMainLoop with an external main loop.
* In such cases, you can call the component functions of
* g_main_context_iteration() directly. These functions are
* g_main_context_prepare(), g_main_context_query(),
* g_main_context_check() and g_main_context_dispatch().
*
* If the event loop thread releases #GMainContext ownership until the results
* required by g_main_context_check() are ready you must create a context with
* the flag %G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING or else you'll lose
* g_source_attach() notifications. This happens for instance when you integrate
* the GLib event loop into implementations that follow the proactor pattern
* (i.e. in these contexts the `poll()` implementation will reclaim the thread for
* other tasks until the results are ready). One example of the proactor pattern
* is the Boost.Asio library.
*
* ## State of a Main Context # {#mainloop-states}
*
* The operation of these functions can best be seen in terms
* of a state diagram, as shown in this image.
*
* ![](mainloop-states.gif)
*
* On UNIX, the GLib mainloop is incompatible with fork(). Any program
* using the mainloop must either exec() or exit() from the child
* without returning to the mainloop.
*
* ## Memory management of sources # {#mainloop-memory-management}
*
* There are two options for memory management of the user data passed to a
* #GSource to be passed to its callback on invocation. This data is provided
* in calls to g_timeout_add(), g_timeout_add_full(), g_idle_add(), etc. and
* more generally, using g_source_set_callback(). This data is typically an
* object which owns the timeout or idle callback, such as a widget or a
* network protocol implementation. In many cases, it is an error for the
* callback to be invoked after this owning object has been destroyed, as that
* results in use of freed memory.
*
* The first, and preferred, option is to store the source ID returned by
* functions such as g_timeout_add() or g_source_attach(), and explicitly
* remove that source from the main context using g_source_remove() when the
* owning object is finalized. This ensures that the callback can only be
* invoked while the object is still alive.
*
* The second option is to hold a strong reference to the object in the
* callback, and to release it in the callbacks #GDestroyNotify. This ensures
* that the object is kept alive until after the source is finalized, which is
* guaranteed to be after it is invoked for the final time. The #GDestroyNotify
* is another callback passed to the full variants of #GSource functions (for
* example, g_timeout_add_full()). It is called when the source is finalized,
* and is designed for releasing references like this.
*
* One important caveat of this second approach is that it will keep the object
* alive indefinitely if the main loop is stopped before the #GSource is
* invoked, which may be undesirable.
*/
/* Types */
typedef struct _GIdleSource GIdleSource;