Rather than using an array, which requires a lot of iteration over it to
check whether a particular network is present. Using a hash table only
requires iteration in the can_reach() case, where we need to match a
mask in the networks array, rather than equal it.
This should improve performance for large numbers of routes.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Fixes: #1925
Using the same approach as we have for code style checks (the
`style-check-diff` CI job), check the diff for any banned keywords like
‘TODO’, and also check the commit messages.
The keyword ‘TODO’ is often used by developers to indicate a part of a
commit which needs further work, and hence which shouldn’t yet be merged.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Fixes: #1551
g_setenv() and g_unsetenv() can never be thread-safe, so emit a message if
they are used after any threads have been spawned.
This can’t catch interactions between setenv() and g_thread_new(), or
between g_setenv() and pthread_create(), but it’ll catch most
misbehaviour in GLib-centric code.
Currently, the message is a `g_debug()` call. Eventually, I’d like to
upgrade it to a `g_warning()`, but there are a number of GLib tests
which call g_setenv() after threads have been created, and they need to
be fixed first. Emitting a `g_debug()` message gives people an
opportunity to start fixing their code.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Helps: #715
This will be used in a following commit to warn if setenv() is used
after another thread has been created.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Helps: #715
Following on from #978, it seems that #1232 is another instance of the
same problem: signals emitted across threads can’t guarantee their user
data is kept alive between committing to emitting the signal and
actually invoking the callback in the relevant thread.
Fix that by using weak refs to the `GDBusObjectManagerClient` as the
user data for its signals, rather than no refs. Strong refs would create
an unbreakable reference count cycle.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Fixes: #1232
It’s possible for `g_bus_unwatch_name()` to be called after a
name-appeared or name-vanished handler has been scheduled to be called
in another thread, but before that callback is actually invoked. If so,
the subscribing thread will receive a callback after it’s called
`g_bus_unwatch_name()`, which is unexpected and could cause bugs.
Double-check `client->cancelled` in the target thread before actually
invoking the callback.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Fixes: #604
This is a partial revert of commit 595e12b5fb for macOS only, since we
can’t run a VM image on that CI runner, and hence can’t easily
pre-populate it with cached dependencies.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
This fixes the following build failure on FreeBSD:
```
In file included from ../gio/tests/win32-appinfo.c:24:
/usr/include/malloc.h:3:2: error: "<malloc.h> has been replaced by <stdlib.h>"
#error "<malloc.h> has been replaced by <stdlib.h>"
```
Hopefully it doesn’t break Windows.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
As with all D-Bus signal subscriptions, it’s possible for a signal
callback to be invoked in one thread (T1) while another thread (T2) is
unsubscribing from that signal. In this case, T1 is the main thread, and
T2 is the D-Bus connection worker thread which is unsubscribing all
signals as it’s in the process of closing.
Due to this possibility, all `user_data` for signal callbacks needs to
be referenced outside the lifecycle of the code which
subscribes/unsubscribes the signal. In other words, it’s not safe to
subscribe to a signal, store the subscription ID in a struct,
unsubscribe from the signal when freeing the struct, and dereference the
struct in the signal callback. The data passed to the signal callback
has to have its own strong reference.
Instead, it’s safe to subscribe to a signal and add a strong reference
to the struct, store the subscription ID in that struct, and unsubscribe
from the signal when the last external reference to your struct is
dropped. That unsubscription should break the refcount cycle between the
signal connection and the struct, and allow the struct to be completely
freed. Only with that approach is it safe to dereference the struct in
the signal callback, if there’s any possibility that the signal might be
unsubscribed from a separate thread.
The tests need specific additional main loop cycles to completely emit
the NameLost signal callback. Ideally they need refactoring, but this
will do (1000 test cycles passed).
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Fixes: #978
This just removes a now-redundant intermediate array. This means that
the `SignalSubscriber` instances are now potentially freed a little
sooner, inside the locked segment, but they are already careful to only
call their `user_data_free_func` in the right thread. So that should not
deadlock.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Helps: #978
It’s now used unconditionally for `shared_thread_scheduler_settings` in
`gthreadpool.c`, so it actually needs to have a storage definition.
Fixes a build failure on FreeBSD.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Instead of storing a copy of the `callback` and `user_data` from a
`SignalSubscriber` in a `SignalInstance` struct (which is the closure
for signal callback data as it’s sent from the D-Bus worker thread to
the thread which originally subscribed to a signal), store a strong
reference to the `SignalSubscriber` struct itself.
This keeps the `SignalSubscriber` alive until the emission is
complete, which ensures that the `user_data` is not freed prematurely.
It also slightly reduces the allocation size of `SignalInstance` (not
that it matters).
This is threadsafe because the fields in `SignalSubscriber` are all
immutable after construction.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Helps: #978
Tie the destruction of the `user_data` to the destruction of the
`SignalSubscriber` struct. This is tidier, and ensures that the fields
in `SignalSubscriber` are all immutable after being set, so the
structure can safely be used across threads without locking.
It doesn’t matter which thread we call `call_destroy_notify()` in, since
it always defers calling `user_data_free_func` to the user-provided
`GMainContext`.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Helps: #978
The `SignalSubscriber` structs contain the callback and `user_data` of each
subscriber to a signal, along with the `guint id` token held by that
subscriber to identify their subscription. There are one or more
`SignalSubscriber` structs for a given signal match rule, which is
represented as a `SignalData` struct.
Previously, the `SignalSubscriber` structs were stored in a `GArray` in
the `SignalData` struct, to reduce the number of allocations needed
when subscribing to a signal.
However, this means that a `SignalSubscriber` struct cannot have a
lifetime which exceeds the `SignalData` which contains it. In order to
fix the race in #978, one thread needs to be able to unsubscribe from a
signal (destroying the `SignalData` struct) while zero or more other
threads are in the process of calling the callbacks from a previous
emission of that signal (using the callback and `user_data` from zero or
more `SignalSubscriber` structs). Multiple threads could be calling
callbacks because callbacks are invoked in the `GMainContext` which
originally made a subscription, and GDBus supports subscribing to a
signal from multiple threads. In that case, the callbacks are dispatched
to multiple threads.
In order to allow the `SignalSubscriber` structs to outlive the
`SignalData` which contained their old match rule, store them in a
`GPtrArray` in the `SignalData` struct, and refcount them individually.
This commit in itself should make no functional changes to how GDBus
works, but will allow following commits to do so.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Helps: #978
On Linux the sched_getattr syscall might be available at compile-time
but not actually work at runtime (e.g. because an older kernel is
running or valgrind is used). Instead of killing the process, return
FALSE and handle this gracefully at runtime with some fallback code.
Fixes https://gitlab.gnome.org/GNOME/glib/issues/2007
This adds support for specifying multiple directories in the
GSETTINGS_SCHEMA_DIR environment variable by separating the values
using G_SEARCHPATH_SEPARATOR_S (colon on UNIX-like systems).
While programs could already register multiple custom GSettings schema
directories, it was not possible to achieve the same without writing
custom code, e.g. when using the gsettings command line tool.
Fixes#1998.
The CI should not waste resources in downloading subprojects for each
task. It should also not rely on external hosts to be available.
Windows case will be handled in MR #402 by migrating to docker.