Commit Graph

529 Commits

Author SHA1 Message Date
Philip Withnall
be12b1a200 gmain: Reformat docs to fully use gi-docgen and match style guide
https://developer.gnome.org/documentation/guidelines/devel-docs.html#writing-api-references

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: #3250
2025-08-19 15:01:39 +01:00
Philip Withnall
b6c2a877e2 gmain: Add (not nullable) to g_main_context_ref_thread_default()
This might be the default, but let’s be explicit about it, since the
non-nullability of the return value is explicitly mentioned in the prose
of the documentation.

This contrasts with the `(nullable)` on the return value of
`g_main_context_get_thread_default()`.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2025-08-19 12:54:12 +01:00
Philip Withnall
1778e412a4 gmain: Add a couple of missing (nullable) annotations
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2025-08-19 12:54:06 +01:00
Philip Withnall
33c009676f gmain: Add missing (transfer full) annotations to constructors
These might be the implicit default for constructors, but it’s clearer
to be explicit about them.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2025-08-19 12:54:00 +01:00
Matthew Waters
fe1c7dfdc6 gmain: move source destroy write unlock slightly earlier
If a source is using g_source_set_callback_indirect(), then performing
GSource operations within GSourceCallbackFuncs::unref should not cause a
deadlock.

Fixes https://gitlab.gnome.org/GNOME/glib/-/issues/3725
2025-07-09 11:59:17 +10:00
Matthew Waters
a235350bc0 source: minimise direct access to source->context
Doing so can cause a use-after-free as the main context referenced can
be destroyed by another thread freeing the GMainContext.

Fixes https://gitlab.gnome.org/GNOME/glib/-/issues/803
2025-05-11 10:40:10 +10:00
Matthew Waters
9251e99cdc glib: add a proper weak-ref-like relationship between GSource and GMainContext
Like the GWeakRef's in GObject, there is a global lock that is consulted
whenever g_main_context_unref() or g_source_destroy() or
g_source_unref() is called to retrieve a reference to the associated
GMainContext.

There are a number of actual races that are fixed by this change.
1. Racing GSource destruction with g_main_context_unref() is solved
   by holding the global source_weak_locations lock while setting
   source->context = NULL and while g_source_destroy() attempts to
   retrieve source->context;
2. Same race as 1. but inside g_source_unref()
3. Theoretical race of double freeing the contents of
   context->pending_dispatches if both g_source_destroy() and
   g_main_context_unref() both free resources inside g_main_context_unref().

A couple of implementation notes:
1. Unlocking source_weak_locations too early in g_main_context_unref()
   (before g_source_destroy_internal() is called) may have a race of the
   G_HOOK_FLAG_ACTIVE state of the source and cause a leak of the source.
   This is why source_weak_locations is also held over the calls to
   g_source_destroy_internal() in g_main_context_unref().  So that
   either g_main_context_unref() or g_source_destroy() (but only 1) has
   the chance to free the resources associated with the GMainContext.
2. g_main_context_unref() now needs to be more of a dispose()
   implementation as it can be called multiple times with losing the
   last ref.

Fixes: https://gitlab.gnome.org/GNOME/glib/-/issues/803
2025-05-11 10:40:10 +10:00
Marco Trevisan (Treviño)
ee836d7723 gmain: Use atomic logic to init the ref counting
Ensure we're consistent with the field usage
2025-02-19 19:38:12 +01:00
Marco Trevisan (Treviño)
42283ffb45 gmain: Use atomic logic to set and use dispose function
It can be read/written in a racy way, so let's be safer.
2025-02-19 19:38:12 +01:00
Marco Trevisan (Treviño)
a5bc497021 gmain: Use atomic logic to handle internal GSource flags
We use flags in both locked paths and in public ones (to check if a
source is destroyed or running), but those checks are not using atomic
logic, thus they lead to races in various tests.

Fix them by atomically change and read the values.
And this fixes various tests in thread sanitizer.
2025-02-19 19:36:21 +01:00
Marco Trevisan (Treviño)
7097359597 gmain: Ensure old reference is valid during unref
We were checking this already, leading to an extra atomic read that
isn't needed.
2025-02-19 19:03:29 +01:00
Marco Trevisan (Treviño)
5d117b021a gmain: Avoid unneeded atomic read on GSource ref
In g_source_ref() we can just ensure that the value we've referenced was
valid, instead of checking it before, since if get to such state the
GSource is broken anyways, but at least we can avoid doing an unneeded
atomic read.

Reason why we don't bother resetting the reference in case of failure.
2025-02-19 19:03:29 +01:00
Marco Trevisan (Treviño)
6052374c78 gmain: Go back to using the standard unref logic if the final unref failed
If going from 1 -> 0 references failed, then we should restart the unref
process, by potentially re-entering in the dispose function again if
instead something else re-references us and we're going to drop the last
one again.
2025-02-19 19:03:29 +01:00
Marco Trevisan (Treviño)
7b61cc8277 glib/gmain: Avoid potential dispose race on GSource due to refcount dance
During g_source_unref() we might end up calling dispose from
multiple threads, and due to the ref/unref dance we were doing we could
end up initiating a GSource finalization while another thread was about
to revive the source.

This was because we were unreffing a source in a thread, and potentially
re-reffing it, at the same time, but it was not guaranteed that the
final decrement and test couldn't be followed by a further re-ref.

To avoid this, do not do any ref/unref/re-ref/re-unref dance while we're
about to dispose, but instead follow a bit more the g_object_unref()
logic, and start the disposal phase only if we're about to drop the last
reference, and only after the potential disposal call is done, we do an
actual ref count decrement, which may lead to the finalization or not.

We don't bother following the same logic at later point, since after
disposal we should really have just one thread running and revival of a
finalizing GSource isn't supported anyways.

With this logic we can also avoid doing unneeded context locking when
we've enough references on a GSource that disposal is unlikely to
happen.

Closes: #3612
2025-02-19 18:59:33 +01:00
Mavroudis Chatzilazaridis
cb1502ed66 docs: Fix invalid references and broken links
This commit fixes quite a few broken links and references, minor typos,
and improves wording in some sections.
2025-02-05 22:28:26 +02:00
Parth Patel
0924a2e881 gmain: Include poll.h as early as possible
On AIX, the system poll.h redefines the names of struct members,
for example `#define events reqevents`. This means that accesses
to GPollFD will fail to compile if poll.h was included after
glib/gpoll.h.

We can't simply add `#include <poll.h>` in glib/gpoll.h, because
that wouldn't work on platforms where poll.h doesn't exist, and
GLib supports some platforms in that category.

Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/3500
2024-10-19 01:52:32 -05:00
Luca Bacci
13f20f1546 Win32: Do not define STRICT
It's defined automatically by system headers (both Windows SDK and mingw-w64)
2024-10-09 11:26:20 +02:00
Philip Withnall
f9d1f614a9 gmain: Move doc comment for g_steal_fd() to be next to the code
Nobody’s going to keep it up to date if it’s floating about in an
unrelated place, not next to the code.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-10-01 14:29:25 +01:00
Luca Bacci
84c2d64436 docs: Don't reference Unix-only method GLib.Source.add_unix_fd
gi-docgen won't find the method on Windows
2024-08-23 15:57:13 +02:00
Niels De Graef
10d4edea2e gmain: Adapt to gi-docgen comments
Now that we've switched to `gi-docgen`, let's make sure our docs are
getting updated. This commit fixes most of the previous gtk-doc
references so that they now follow gi-docgen syntax.

Some exceptions are functions or types that are referenced, but are
generated by a higher level layer like `Gio`, `GObject` or `Gtk`.
2024-08-01 18:38:57 +02:00
Tanmay Patil
37333d63d6 docs: Fix docs reference to main-loop
Signed-off-by: Tanmay Patil <tanmaynpatil105@gmail.com>
2024-05-28 14:27:43 +05:30
Marco Trevisan (Treviño)
137db219a7 gmain: Use alternate signal stack if the application provides one
Some applications, toolkits or languages may define an alternative stack
to use for traces. This is for example the case of go.

So, in case an application defines an alternate signal stack, GLib should
use that instead of the default one to receive signals otherwise it may
break the application expectations and write where it's not allowed to.
2024-04-15 17:06:05 +02:00
Philip Withnall
3bf2875ce4 Revert "gmain: Use alternate signal stack if the application provides one"
This reverts commit 280c8d41fb.

It breaks the unit tests on macOS (see #3314) and no fix has been
forthcoming.

The alternate stack changes can be resubmitted once they include a
working unit test on macOS, as evidently its treatment of alternate
stacks differs from that on Linux, and hence needs testing.

Helps: #3314
2024-04-08 12:26:40 +01:00
Marco Trevisan (Treviño)
280c8d41fb gmain: Use alternate signal stack if the application provides one
Some applications, toolkits or languages may define an alternative stack
to use for traces. This is for example the case of go.

So, in case an application defines an alternate signal stack, GLib should
use that instead of the default one to receive signals otherwise it may
break the application expectations and write where it's not allowed to.
2024-03-26 16:29:39 +01:00
Christian Hergert
368cb7eb7b glib/gmain: use ppoll() when possible
If our GPollFunc is set to g_poll() then we can optionally use a poll()
alternative with higher precision. ppoll() provides poll() equivalence
but with timeouts in nanoseconds.

With more precise polling timouts, frame clocks and other timing sensitive
APIs are not restricted to a minimum of 1 millisecond timeout.
2024-03-21 23:46:20 +00:00
Christian Hergert
c840d75395 glib/gmain: plumb timeout as microseconds
This gets access to the timeout as microseconds up until we are about to
enter the GPollFunc. This is useful so that alternative means may be used
to poll with more precision for timeout.
2024-03-21 23:46:20 +00:00
Philip Withnall
c17090275c Merge branch 'th/main-sources-dict-as-set' into 'main'
gmain: optimize "context->sources" hash table to use as set

See merge request GNOME/glib!3664
2023-11-06 15:05:43 +00:00
Sergey Bugaev
a3d02ad565 gmain: Correct g_source_get_ready_time () doc
Mention that ready time being equal to the current time means the source
will fire immediately.

Related to https://gitlab.gnome.org/GNOME/glib/-/issues/3148

Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
2023-11-06 15:14:07 +03:00
Thomas Haller
b067c43b00 gmain: optimize "context->sources" hash table to use as set
Instead of tracking a "(guint,GSource*)" tuple in the "context->sources"
dictionary, only track pointers to the "source_id".

With this we use the GHashTable as Set (g_hash_table_add()), which is
optimized and avoids storing a separate value array.

It's simple enough to do, because there are literally 5 references to
"context->sources". It's easy to review those usages and reason that the
handling is correct.

While at it, in g_main_context_find_source_by_id() move the check for
SOURCE_DESTROYED() inside the lock. It's not obvious that doing this
without a lock was correct in every case. But doing the check with
a lock should be fast enough to not worry about whether it's absolutely
necessary.
2023-11-06 08:48:12 +01:00
Matthias Clasen
d8b25ecda3 docs: Move GMainLoop documentation to Markdown
Helps: #3037
2023-10-11 14:01:29 +01:00
Philip Withnall
da278bdd0b Merge branch 'wip/chergert/queue-for-sourcelist' into 'main'
gmain: avoid a GList traversal when removing source

See merge request GNOME/glib!3620
2023-10-04 22:40:58 +00:00
Christian Hergert
5e96ed64c9 gmain: avoid a GList traversal when removing source
Currently the GSourceList has it's own allocation plus a secondary
allocation for the GList which contains it (from GMainContext). Not only
are these a pointer chase, but they are on separate cachelines too. Without
changing the code much we can at least keep things on the same cacheline
so that the pointer chase matters less.

Since the GList becomes embedded in the GSourceList you can use a
g_queue_unlink() directly removing the link without traversing the GList
like was done before.

Furthermore, we can simplify some code with g_queue_push_tail_link()
instead of some extra branching.
2023-10-04 13:37:06 -07:00
Alex Richardson
a1dfecf11f Use g_once_init_{enter,leave}_pointer where appropriate
This should not result in any functional changes, but will eventually
allow glib to be functional on CHERI-enabled systems such as Morello.

Helps: https://gitlab.gnome.org/GNOME/glib/-/issues/2842
2023-10-04 13:57:16 +01:00
Thomas Haller
89b55fa9bc gmain: improve g_warning() for failure in g_child_watch_dispatch()
Print the PID, the errno and the pidfd in case of an unexpected failure
in g_child_watch_dispatch().

This is always(?) caused by a bug in the user application. Also hint to
g_child_watch_source_new() documentation for possible causes.

Also use G_PID_FORMAT for printing GPid values.
2023-08-17 19:12:23 +02:00
Jonas Ådahl
8d78fa7887 main: Don't treat si_pid from pidfd as child exiting
We might repeatedly get si_pid == 0 for a child that hasn't exited,
meaning we won't get a correct exit status. This seems to happen when
the glib application tracks a ptrace():ed child process; the correct
exit status of the process using e.g. a BPF program, where one can
observe that glib appears to get it wrong.

Fixes: #3071
2023-08-12 19:08:46 +01:00
Thomas Haller
07f8a5daa3 gmain: drop owner check assertion in g_main_context_release()
As commit 44616ebafd ('gmain: More explicitly document
g_main_context_release() prereqs') correctly notes, you need to have the
context acquired before releasing it (just like a ref must match an
unref).

Commit 3926af723a ('gmain: Add precondition assertions to
g_main_context_release()') then goes one step further, and requires that
the calling thread is also the owner (the thread, that acquired the
context).

This is something which has been documented by g_main_context_release()
for years:
> Releases ownership of a context previously acquired **by this thread**

With acquire/release and g_main_context_is_owner() we track the thread
that acquired the context. That is mainly useful for asserting
correctness to not accessing the context from an unexpected thread.
Note that g_main_context_acquire() returns FALSE and does nothing when
the context is already acquired from another thread. Methods like
g_main_context_{prepare,query,dispatch}() require that the calling
thread is the owner (although, they don't assert for that, which they
maybe should).

With the assertion, it means you cannot pass an acquired context to
another thread for release. Obviously, if you pass on an acquired
context to another thread, the only next thing you can do is
g_main_context_release() (no acquire,prepare,query,dispatch). But it's
still useful to be able to release it, and to be able to keep it
acquired for a prolonged time.

libnm needs that, as it integrates a GMainContext into another
GMainContext. For that, it needs to acquire the inner context and keep
it acquired for as long as the context is integrated. Otherwise, when a
source gets attached to the inner context, the inner context is not
woken up (see g_source_attach_unlocked()). In commit e26a8a5981 ('Add
G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING'), a flag was introduced to solve
that same problem, without keeping the inner context acquired all the
time. Note that G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING is a flag of the
GMainContext, so it only works if the user who integrates the inner
context also controls how the context was created.  For libnm, having
the inner context acquired at all times is no problem, because it's
understood that the user gives up agency on the inner context while it's
integrated. The only thing to consider is that the outer context might
be iterated on another thread. When calling prepare,query,dispatch on
the inner context, the code will notice it, release the inner context
and re-acquire it on the new thread ([1]).  This works just fine, but it
requires that g_main_context_release() works from any thread.

So, in order to not break NetworkManager, let’s drop the ownership
assertion. However, NetworkManager is strictly breaking the API contract
here, and GLib reserves the right to re-add this assertion in future.

Still keep the assertion for the owner_count.

(Commit and commit message significantly updated by Philip Withnall; all
errors are his.)

[1] 9f01cff04f/src/libnm-glib-aux/nm-shared-utils.c (L4944)

Related: 3926af723a ('gmain: Add precondition assertions to g_main_context_release()')
Related: c67dd9d3fe ('gmain: Add a missing return on error path in g_main_context_release()')

Closes #3054
2023-07-30 11:53:34 +03:00
Philip Withnall
c67dd9d3fe gmain: Add a missing return on error path in g_main_context_release()
This should have been in commit
3926af723a.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>

Fixes: #3054
2023-07-18 11:31:01 +01:00
Simon McVittie
c97348428f gmain: Document that g_steal_fd() preserves errno
This is useful when writing similarly low-level code, and was always true
as implemented here; let's document it so that other codebases can rely
on it.

Signed-off-by: Simon McVittie <smcv@collabora.com>
2023-05-30 16:02:16 +01:00
Thomas Haller
3694dac983 gmain: ensure boolean value in g_child_watch_check() is strictly 0 or 1
No problem in practice, but it seems nice to ensure that a gboolean is
always either FALSE or TRUE.
2023-05-18 11:26:33 +02:00
Thomas Haller
d5d6ef8f1b gmain: drop redundant using_pidfd field from GChildWatchSource
It's redundant, which leads to impossible code like:

   if (child_watch_source->using_pidfd)
     {
       if (child_watch_source->poll.fd >= 0)
         close (child_watch_source->poll.fd);
2023-05-18 11:26:33 +02:00
Thomas Haller
cecbb25eeb gmain: fix race with waitpid() and child watcher sources
GChildWatchSource uses waitpid(), among pidfd and GetExitCodeProcess().
It thus only works for child processes which the user must ensure to
exist and not being reaped yet. Also, the user must not kill() the PID
after the child process is reaped and must not race kill() against
waitpid(). Also, the user must not call waitpid()/kill() after the child
process is reaped.

Previously, GChildWatchSource would call waitpid() already when adding
the source (g_child_watch_source_new()) and from the worker thread
(dispatch_unix_signals_unlocked()). That is racy:

- if a child watcher is attached and did not yet fire, you cannot call
  kill() on the PID without racing against the PID being reaped on the
  worker thread. That would then lead to ESRCH or even worse, killing
  the wrong process.

- if you g_source_destroy() the source that didn't fire yet, the user
  doesn't know whether the PID was reaped in the background. Any
  subsequent kill()/waitpid() may fail with ESRCH/ECHILD or even address
  the wrong process.

The race is most visible on Unix without pidfd support, because then the
process gets reaped on the worker thread or during g_child_watch_source_new().
But it's also with Windows and pidfd, because we would have waited for
the process in g_child_watch_check(), where other callbacks could fire
between reaping the process status and emitting the source's callback.

Fix all that by calling waitpid() right before dispatching the callback.
2023-05-18 11:26:33 +02:00
Thomas Haller
cdda194844 gmain: remove unnecessary initialization of *timeout in prepare() callbacks
Note that the prepare callback only has one caller, which pre-initializes
the timeout argument to -1. That may be an implementation detail and not
publicly promised, but it wouldn't make sense to do it any other way in
the caller.

Also, note that g_unix_signal_watch_prepare() and the UNIX branch of
g_child_watch_prepare() already relied on that.
2023-05-18 11:26:33 +02:00
Thomas Haller
30b5418608 gmain: remove unnecessary initialization of source_timeout in g_main_context_prepare_unlocked()
Note that the variable source_timeout is already initialized upon
definition, at the beginning of the block.

It's easy to see, that no code changes the variable between the variable
definition, and the place where it was initialized. It was thus
unnecessary.

It's not about dropping the unnecessary code (the compiler could do that
just fine too). It's that there is the other branch of the "if/else", where
the variable is also not initialized. But the other branch also requires
that the variable is in fact initialized to -1, because prepare()
callbacks are free not to explicitly set the output value. So both
branches require the variable to be initialized to -1, but only one of
them did. This poses unnecessary questions about whether anything is
wrong. Avoid that by dropping the redundant code.
2023-05-18 11:26:33 +02:00
Thomas Haller
a71b0c0461 gmain: simplify handling child watchers in dispatch_unix_signals_unlocked()
- if a child watch source has "using_pidfd", it is never linked in the
  unix_child_watches list. Drop that check.
- replace the deep nested if, with an early "continue" in the loop,
  if we detect there is nothing to do. It makes the code easier to
  read.
2023-05-18 11:26:33 +02:00
Thomas Haller
9315a211fa gmain: unify win/unix implementations for child watcher
Let's move the difference between the win/unix implementations closer to
where the difference is. Thereby, we easier see the two implementations
side by side. Splitting it at a higher layer makes the code harder to
read.

This is just a preparation for what comes next.
2023-05-18 11:26:33 +02:00
Arnaud Rebillout
f722f11e57 Rename GTK+ to GTK (mostly comments and documentation)
GTK lost it's '+' suffix back in 2019, according to
<https://mail.gnome.org/archives/gtk-devel-list/2019-February/msg00000.html>

This commit can be re-generated with:

    git grep -l GTK+ \
    | grep -v -e ^NEWS -e ^glib/tests/collate.c \
    | xargs sed -i 's/GTK+/GTK/g'

Most of the changes are in comments and documentation.
2023-05-10 10:56:44 +07:00
Peter Eisenmann
467b917719 gtimeout: use helper for seconds_full variant
Use timeout_add_full() helper to deduplicate code
2023-05-02 13:42:54 +02:00
Peter Eisenmann
3abf23b2a7 add g_timeout_add_seconds_once
Add a new call combing behaviors of g_timeout_add_seconds and
g_timeout_add_once.
2023-05-02 13:42:54 +02:00
Philip Withnall
c176fcf2eb Merge branch 'doc-indentation' into 'main'
Fix small issues in docs

See merge request GNOME/glib!3393
2023-04-24 12:58:08 +00:00
Philip Withnall
3926af723a gmain: Add precondition assertions to g_main_context_release()
As with the previous commit.

The logic has to be a little contorted here to avoid leaving the context
locked after emitting the critical warning. Execution does (and should)
continue after a critical warning by default, so we should do our best
to recover.

Inspired by https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3302.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
2023-04-24 13:02:36 +01:00