Commit Graph

2357 Commits

Author SHA1 Message Date
Calvin Walton
013980d839 Use the python found by meson as the interpreter for installed scripts
The python interpreter found by `/usr/bin/env python3` is not
necessarily the same installation as the one that's found by meson's
`pymod.find_installation('python')`. This means that even though meson
is checking that the python installation it found includes the
'packaging' module, the scripts might not have access to that module
when run.

For distribution packaging, it's usually desirable to have python script
interpreters be fully specified paths, rather than use `/usr/bin/env`,
to ensure the scripts run using the expected python installation (i.e.
the one where the python 'packaging' dependency is installed).

The easiest way to fix this is to set the script interpreter to the
`full_path()` of the python interpreter found by meson. The specific
python interpreter that will be used can be selected through the use of
a meson machine file by overriding the "python" program. Many
distributions already have this set up using meson packaging helpers.
2024-03-25 15:17:59 -04:00
Philip Withnall
e83e4c5535 tests: Mark several additional tests as can_fail on GNU Hurd
These consistently fail on scheduled CI runs, which is not helping our
ability to catch Hurd regressions.

For example, https://gitlab.gnome.org/GNOME/glib/-/jobs/3709402

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

See: #3148
2024-03-19 13:01:26 +00:00
Philip Withnall
5b9dac546e Merge branch 'th/performance' into 'main'
[th/performance] add script for combining performance results

See merge request GNOME/glib!3954
2024-03-18 15:07:03 +00:00
Thomas Haller
4d5047e0e7 tests/performance: add performance-run.sh script for running performance test
The main use of the performance test is to run it for two (or more) commits
and compare the results. Doing that manually, is cumbersome.

Add a (very hacky) script to help with that. For usage, see the comment
on top of the script.

Example:

  # first:
  meson build -Dprefix=/tmp/glib/ -Db_lto=true --buildtype release -Ddebug=true

  # then:
  GLIB_PERFORMANCE_FACTOR=17.06 \
  PERF='perf stat -r 4 -B' \
  PATCH="2.80.0..th/performance" \
  COMMITS="2.79.3 2.80.0" \
  /tmp/performance-run.sh -s 1 property-get property-set

This will build the requested $COMMITS and print something like:

  ...
  >>> combined result > /tmp/glib-performance-output.all
  Running test property-get
  property-get: Property get per second: 35742719 37208288 (+4.1%)
  Running test property-set
  property-set: Property set per second: 32341232 36942399 (+14.2%)
  Running test property-get
  property-get: Property get per second: 36934401 37143479 (+0.566%)
  Running test property-set
  property-set: Property set per second: 38046387 38165548 (+0.313%)
  Running test property-get
  property-get: Property get per second: 34759576 36359761 (+4.6%)
  Running test property-set
  property-set: Property set per second: 35262505 37651733 (+6.78%)
  Running test property-get
  property-get: Property get per second: 37014537 32870906 (-11.2%)
  Running test property-set
  property-set: Property set per second: 36633026 38216846 (+4.32%)

   Performance counter stats for './build/gobject/tests/performance/performance -s 1 property-get property-set' (4 runs):

            1,312.18 msec task-clock:u                     #    1.000 CPUs utilized               ( +-  4.82% )
                   0      context-switches:u               #    0.000 /sec
                   0      cpu-migrations:u                 #    0.000 /sec
                 121      page-faults:u                    #   92.213 /sec                        ( +-  0.24% )
       5,221,701,009      cycles:u                         #    3.979 GHz                         ( +-  2.61% )
      19,035,814,175      instructions:u                   #    3.65  insn per cycle              ( +-  0.00% )
       4,335,306,010      branches:u                       #    3.304 G/sec                       ( +-  0.00% )
              13,031      branch-misses:u                  #    0.00% of all branches             ( +-  4.17% )
                          TopdownL1                 #     10.3 %  tma_backend_bound
                                                    #      5.3 %  tma_bad_speculation
                                                    #     11.4 %  tma_frontend_bound
                                                    #     73.1 %  tma_retiring             ( +-  2.15% )

  [1]             1.3127 +- 0.0634 seconds time elapsed  ( +-  4.83% )
  [2]             1.2631 +- 0.0253 seconds time elapsed  ( +-  2.00% )

  property-get: Property get per second: 35742719 , 36934401 , 34759576 , 37014537  ;  37208288 , 37143479 , 36359761 , 32870906  ;
  property-set: Property set per second: 32341232 , 38046387 , 35262505 , 36633026  ;  36942399 , 38165548 , 37651733 , 38216846  ;
2024-03-18 13:56:03 +00:00
Thomas Haller
7b9e6d4949 tests/performance: add "refcount-toggle" test
Performance test for emitting toggle reference notifications.
2024-03-18 13:56:03 +00:00
Thomas Haller
2b1a7e30b1 tests/performance: avoid check for toggle notification in "property-{get,set}"
Bumping the reference count from 1 to 2 (and back) is more expensive,
due to the check for toggle notifications.

We have a performance test already that hits that code path. Avoid that
for he "property-{get,set}" tests, so we avoid the known overhead and
test more relevant parts.
2024-03-18 13:56:02 +00:00
Thomas Haller
b6789dd1ea tests/performance: add "refcount-1" test
When an object has ref-count 1, then calling g_object_ref() requires a
check for toggle references. That is slower. Add a test for that case.
2024-03-18 13:56:02 +00:00
Thomas Haller
282d536fd2 tests/performance: ensure to always warm up for 2 seconds
Despite all the efforts, there still seems to be a lot of noise in the
performance measurement. Especially, the first iterations seem to run
faster. Maybe that is because the kernel didn't yet determine that the
process is CPU bound and is less likely to schedule it out Or maybe it's
because burning the cycles heats up the CPU and it gets throttled after
a while. It's unclear why, and it's even unclear whether this really
happens. But from my observations, it seems to do.

Hence, more warm up.

- the first time we enter the test, ensure that we keep the CPU busy for
  at 2 seconds. This additional warm up (WARM_UP_ALWAYS_SEC) is
  global, and not per test.

- for each test, ignore the first 5% of the runs. It seems those tend to
  run faster, thus skewing the results.

- if the user specifies a "--factor", the warm up operations are the
  same and independent from external factors (such as time
  measurements).

Note that this matters the most, when you want to run the executable
twice in a row and compare the results.
2024-03-18 13:56:02 +00:00
Thomas Haller
29a69d5a1b tests/performance: add "factor" argument to performance test
By default, the test estimates a run factor for each test. This means,
if you run performance under `perf`, the results are not comparable,
as the run time depends on the estimated factor.

Add an option, to set a fixed factor.

Of course, there is only one factor argument for all tests.  Quite
possibly, you would want to run each test individually with a factor
appropriate for the test. On the other hand, all tests should be tuned
so that the same factor gives a similar test duration. So this may not
be a concern, or the tests should be adjusted. In any case, the option
is most useful when running only one test explicitly.

You can get a suitable factor by running the test once with "--verbose".

Another use case is if you run the benchmark under valgrind. Valgrind
slows down the run so much, that the estimated factor would be quite
off. As a result, the chosen code paths are different from the real run.
By setting the factor, the timing measurements don't affect the executed
code.
2024-03-18 13:56:02 +00:00
Thomas Haller
e5e3c37d22 tests/performance: add "--quiet" argument to performance
The default output is annoyingly verbose. You see

  Running test simple-construction
  simple-construction: Millions of constructed objects per second: 33.498
  Running test simple-construction1
  simple-construction1: Millions of constructed objects per second: 142.493
  Running test complex-construction
  complex-construction: Millions of constructed objects per second: 14.304
  Running test complex-construction1
  ...

where the "Running test" lines just clutter the output. In fact so much
so, that my terminal fills up and I don't see the output of all tests in
one page. The "Running test" line is not so useful, because I mostly
care about the test result, and that line already contains the test
name.

Add an option to silence this.
2024-03-18 13:56:02 +00:00
Thomas Haller
65a59bde57 tests/performance: print result in unique line
Previously, the result lines are not unique, for example

  Running test simple-construction
  Millions of constructed objects per second: 27.629
  Running test simple-construction1
  Millions of constructed objects per second: 151.879
  ...

That is undesirable, because we might want to parse the test results
with a script, and that's easier when the line is unique.

Change to:

  Running test simple-construction
  simple-construction: Millions of constructed objects per second: 27.629
  Running test simple-construction1
  simple-construction1: Millions of constructed objects per second: 151.879
  ...
2024-03-18 13:56:02 +00:00
Thomas Haller
1b298d1db1 gobject: add code comment about unlock and toggle_refs_check_and_ref_or_deref()
It may not be obvious, but the moment unlock is called, the locker
instance may be destroyed.

See g_object_unref(), which calls toggle_refs_check_and_ref_or_deref().
It will check for toggle references while dropping the ref count from 2
to 1.  It must decrement the ref count while holding the lock, but it
also must still unlock afterwards.

Note that the locker instance is on the object itself. Once we decrement
the ref count we give up our reference and another thread may race
against destroying the object. We thus must not touch object anymore.
How can we then still unlock?

This works correctly because:

- unlock operations must not touch the locker instance after unlocking.

- assume that another thread races g_object_unref() to destroy the
  object, while we are about to call object_bit_unlock() in
  toggle_refs_check_and_ref_or_deref(). Then that other thread will also
  need to acquire the same lock (during g_object_notify_queue_freeze()).
  It thus is blocked to destroy the object.

Add code comments about that.
2024-03-18 13:55:36 +00:00
Thomas Haller
f17cfcf930 gobject: extract duplicate code for toggle reference in g_object_unref()
Move comment logic to one place. Add toggle_refs_check_and_ref_or_deref().
2024-03-18 13:55:36 +00:00
Thomas Haller
1bb5661198 gobject: fix racy assertion for toggle-refs
We can only assert for having one toggle reference, after we confirmed
(under lock) that the ref count was in the toggle case.

Otherwise, if another thread refs/unrefs the object, we can hit a wrong
g_critical() assertion about

  if (tstackptr->n_toggle_refs != 1)
    {
      g_critical ("Unexpected number of toggle-refs. g_object_add_toggle_ref() must be paired with g_object_remove_toggle_ref()");

Fixes: 9ae43169cf ('gobject: fix race in toggle ref during g_object_ref()')
2024-03-18 13:55:36 +00:00
Philip Withnall
a60e6bedae docs: Document that signal connection functions cannot fail
The documentation previously implied that they could. That’s not really
true though: they can only fail if preconditions fail, i.e. they’re
passed invalid input. That’s a programmer error, which is not something
we want to encourage people to check for at runtime (e.g. by dynamically
checking for a 0 return value).

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-03-07 13:12:07 +00:00
Philip Withnall
fafe1a14a8 docs: Minor reformatting / gi-docgenification of signals docs
This is nowhere near a complete check-through and gi-docgenification of
the signals docs, just a few bits I was looking at anyway.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: #3250
2024-03-07 13:12:07 +00:00
Philip Withnall
3c39a23a7e tests: Speed up threaded toggle notify test unless -m slow is passed
On a fast laptop, this test currently takes about 7s to run, which is a
significant portion of the overall test suite time.

On a slower CI machine, especially running the test under valgrind, the
test can time out.

There’s no need to always run so many iterations: we run the tests under
CI so often that it’s likely a failure will eventually be hit (if there
is a bug) even with fewer iterations. We also now run the tests once a
week with `-m slow`, so the original iteration count will also still be
used then.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-02-13 08:52:15 +00:00
Philip Withnall
5f6b1516ae tests: Rework how slow param test is skipped
It’s more helpful to always register the test, even if it’s normally
skipped, since then the skip is recorded in the test logs so people can
see what’s ‘missing’ from them.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-02-06 11:01:46 +00:00
Philip Withnall
3f4e6ddcd8 Merge branch 'thorough-tests-in-ci' into 'main'
build: Add thorough test setup

See merge request GNOME/glib!3838
2024-02-02 14:33:22 +00:00
Thomas Haller
d8e4f39aa8 gobject: track GWeakRef in object's WeakRefData with an array
GSList doesn't seem the best choice here. It's benefits are that it's
relatively convenient to use (albeit not very efficient) and that an
empty list requires only the pointer to the list's head.

But for non-empty list, we need to allocate GSList elements. We can do
better, by writing more code.

I think it's worth optimizing GObject, at the expense of a bit(?) more
complicated code. The complicated code is still entirely self-contained,
so unless you review WeakRefData usage, it doesn't need to bother you.
Note that this can be easily measure to be a bit faster. But I think the
more important part is to safe some allocations. Often objects are
long-lived, and the GWeakRef will be tracked for a long time. It is
interesting, to optimize the memory usage of that.

- if the list only contains one weak reference, it's interned/embedded in
  WeakRefData.list.one. Otherwise, an array is allocated and tracked
  at WeakRefData.list.many.

- when the buffer grows, we double the size. When the buffer shrinks,
  we reallocate to 50% when 75% are empty. When the buffer shrinks to
  length 1, we free it (so that "list.one" is always used with a length
  of 1).
  That means, at worst case we waste 75% of the allocated buffer,
  which is a choice in the hope that future weak references will be
  registered, and that this is a suitable strategy.

- on architectures like x86_68, does this not increase the size of
  WeakRefData.

Also, the number of weak-refs is now limited to 65535, and now an
assertion fails when you try to register more than that. But note that
the internal tracking just uses a linear search, so you really don't
want to register thousands of weak references on an object. If you do
that, the current implementation is not suitable anyway and you must
rethink your approach. Nor does it make sense to optimize the
implementation for such a use case. Instead, the implementation is
optimized for a few (one!) weak reference per object.
2024-02-02 14:49:09 +01:00
Thomas Haller
637c2a08ce gobject: combine ref_count/lock_field in WeakRefData
We can safely combine this, and use bit 30 of the ref-count for locking.

This leaves still 2^30-1 for the ref-count, which is more than enough,
because these references are only taken for a short time in
g_weak_ref_get() and g_weak_ref_set(). Note that one thread can at most
take one reference at a time, so the ref-count will always a smaller
number.

Also note, that obviously we will only take a bit lock while also
holding a reference. That means, when weak_ref_data_unref() decreases
the ref-count to zero, the bit will be unlocked as well.

The reason to do this is to free up some space in WeakRefData. Note that
(on x86_64) this doesn't actually make the struct smaller.  It's
probably not reasonably possible to make WeakRefData smaller than it
already is (on x86_64). However, by combining the fields we have some
space for reuse without increasing the struct size. That space will be
used next.
2024-02-02 14:49:09 +01:00
Thomas Haller
824c4da44b gobject/tests: add test that creates a large number of weak references
The implementation of GWeakRef tracks weak references in a way, that
requires linear search. That is probably best, for an expected low
number of entries (e.g. compared to the overhead of having a hash
table). However, it means, if you create thousands of weak references,
performance start to degrade.

Add a test that creates 64k weak references. Just to see how it goes.
2024-02-02 14:49:09 +01:00
Philip Withnall
2638f97b3e Merge branch 'th/weak-ref-lock-2' into 'main'
[th/weak-ref-lock-2] gobject: use per-object bit-lock instead of global RWLock for GWeakRef

Closes #743

See merge request GNOME/glib!3834
2024-01-31 16:51:50 +00:00
Thomas Haller
7382cc4383 gobject: use per-object bit-lock instead of global RWLock for GWeakRef
Replace the global RWLock with per-object locking. Note that there are
three places where we needed to take the globlal lock. g_weak_ref_get(),
g_weak_ref_set() and in _object_unref_clear_weak_locations(), during
g_object_unref(). The calls during g_object_unref() seem the most
relevant here, where we would want to avoid a global lock. Luckily, that
global lock only had to be taken if the object ever had a GWeakRef
registered, so most objects wouldn't care. The global lock only affects
objects, that are ever set via g_weak_ref_set(). Still, try to avoid that
global lock.

Related to GWeakRef, there are various moments when we don't hold a
strong reference to the object. So the per-object lock cannot be on the
object itself, because when we want to unlock we no longer have access
to the object. And we cannot take a strong reference on the GObject
either, because that triggers toggle notifications. And worse, when one
thread holds the last strong reference of an object and decides to
destroy it, then a `g_weak_ref_set(weak_ref, NULL)` on another thread
could acquire a temporary reference, and steal the destruction of the
object from the other thread.

Instead, we already had a "quark_weak_locations" GData and an allocated
structure for tracking the GSList with GWeakRef. Extend that to be
ref-counted and have a separate lifetime from the object. This
WeakRefData now contains the per-object mutex for locking. We can
request the WeakRefData from an object, take a reference to keep it
alive, and use it to hold the lock without having the object alive.

We also need a bitlock on GWeakRef itself. So to set or get a
GWeakRef we must take the per-object lock on the WeakRefData and the
lock on the GWeakRef (in this order). During g_weak_ref_set() there may
be of course two objects (and two WeakRefData) involved, the previous
and the new object.

Note that now once an object gets a WeakRefData allocated, it can no
longer be freed. It must stick until the object gets destroyed. This
allocation happens, once an object is set via g_weak_ref_set(). In
other words, objects involved with GWeakRef will have extra data
allocated.

It may be possible to also release the WeakRefData once it's no longer
needed. However, that would be quite complicated, and require additional
atomic operations, so it's not clear to be worth it. So it's not done.
Instead, the WeakRefData sticks on the object once it's set.
2024-01-31 17:30:28 +01:00
Thomas Haller
092be080c5 gobject: avoid global GRWLock for weak locations in g_object_unref() in some cases
_object_unref_clear_weak_locations() is called twice during
g_object_unref(). In both cases, it is when we expect that the reference
count is 1 and we are either about to call dispose() or finalize().

At this point, we must check for GWeakRef to avoid a race that the ref
count gets increased just at that point.

However, we can do something better than to always take the global lock.

On the object, whenever an object is set to a GWeakRef, set a flag
OPTIONAL_FLAG_EVER_HAD_WEAK_REF. Most objects are not involved with weak
references and won't have this flag set.

If we reach _object_unref_clear_weak_locations() we just (atomically)
checked that the ref count is one. If the object at this point never had
a GWeakRef registered, we know that nobody else could have raced against
obtaining another reference. In this case, we can skip taking the lock
and checking for weak locations.

As most object don't ever have a GWeakRef registered, this significantly
avoids unnecessary work during _object_unref_clear_weak_locations().

This even fixes a hard to hit race in the do_unref=FALSE case.
Previously, if do_unref=FALSE there were code paths where we avoided
taking the global lock. We do so, when quark_weak_locations is unset.
However, that is not race free. If we enter
_object_unref_clear_weak_locations() with a ref-count of 1 and one
GWeakRef registered, another thread can take a strong reference and
unset the GWeakRef. Then quark_weak_locations will be unset, and
_object_unref_clear_weak_locations() misses the fact that the ref count
is now bumped to two. That is now fixed, because once
OPTIONAL_FLAG_EVER_HAD_WEAK_REF is set, it will stick.

Previously, there was an optimization to first take a read lock to check
whether there are weak locations to clear. It's not clear that this is
worth it, because we now already have a hint that there might be a weak
location. Unfortunately, GRWLock does not support an upgradable lock, so
we cannot take an (upgradable) read lock, and when necessary upgrade
that to a write lock.
2024-01-31 17:30:28 +01:00
Philip Withnall
7b5bcf62b8 Merge branch 'th/gobject-carray-comment' into 'main'
[th/gobject-carray-comment] gobject: remove obsolete code comment about CArray

See merge request GNOME/glib!3866
2024-01-31 14:09:04 +00:00
Thomas Haller
81107da210 gobject: remove obsolete code comment about CArray
It's not clear what this code comment tries to tell us. Yes, when we
make changes, we must take care that the changes are correct and update
the relevant places.

It seems long obsolete. Drop it.

This partly reverts commit d7dd9aefd8 ('placed a comment about not
changing CArray until we have').
2024-01-31 13:34:37 +01:00
Thomas Haller
970325b92d gobject/tests: add test checking that GWeakRef is cleared in GWeakNotify
g_object_weak_ref() documentation refers to GWeakRef as thread-safe
replacement.  However, it's not clear to me, how GWeakRef is a
replacement for a callback. I think, it means, that you combine
g_object_weak_ref() with GWeakRef, to both hold a (thread-safe) weak
reference and get a notification on destruction.

Add a test, that GWeakRef is already cleared inside the GWeakNotify
callback.
2024-01-31 12:42:02 +01:00
Philip Withnall
a4b9b41afc tests: Fix a double-free in param test
This isn’t normally hit because it’s in a test which is disabled unless
run with `-m thorough`.

The data is owned by `g_test_add_data_func_full()` until the end of the
process.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-01-18 17:22:09 +00:00
Philip Withnall
d738dcc76f tests: Fix an expected message in param test
This isn’t normally hit because it’s in a test which is disabled unless
run with `-m thorough`.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-01-18 17:22:09 +00:00
Philip Withnall
5d38f3ebd4 tests: Fix a double-unref in params tests
This isn’t normally hit because it’s in a test which is disabled unless
run with `-m thorough`.

The `GParamSpec` is initially floating, but its floating ref is sunk by
`g_object_interface_install_property()` (regardless of whether that call
succeeds or aborts). The behaviour of
`g_object_interface_install_property()` in this respect may have changed
more recently than the test was written.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-01-18 17:22:09 +00:00
Philip Withnall
f70b3a91d3 Merge branch 'th/g-pointer-bit-lock-ext' into 'main'
[th/g-pointer-bit-lock-ext] glib: add g_pointer_bit_unlock_and_set() and g_pointer_bit_lock_mask_ptr()

See merge request GNOME/glib!3802
2024-01-16 13:43:54 +00:00
Thomas Haller
5609370de9 gbitlock: add g_pointer_bit_lock_and_get()
Usually, after g_pointer_bit_lock() we want to read the pointer that we
have. In many cases, when we g_pointer_bit_lock() a pointer, we can
access it afterwards without atomic, as nobody is going to modify the
pointer then.

However, gdataset also supports g_datalist_set_flags(), so the pointer
may change at any time and we must always use atomics to read it. For
that reason, g_datalist_lock_and_get() does an atomic read right after
g_pointer_bit_lock().

g_pointer_bit_lock() can easily access the value that it just set. Add
g_pointer_bit_lock_and_get() which can return the value that gets set
afterwards.

Aside from saving the second atomic-get in certain scenarios, the
returned value is also atomically the one that we just set.
2024-01-16 12:50:31 +01:00
Thomas Haller
c4c76d77cb gbitlock: add g_pointer_bit_unlock_and_set() and g_pointer_bit_lock_mask_ptr()
The existing g_pointer_bit_lock() and g_pointer_bit_unlock() API
requires the user to understand/reimplement how bits of the pointer get
mangled. Add helper functions for that.

The useful thing to do with g_pointer_bit_lock() API is to get/set
pointers while having it locked. For example, to set the pointer a user
can do:

    g_pointer_bit_lock (&lockptr, lock_bit);
    ptr2 = set_bit_pointer_as_if_locked(ptr, lock_bit);
    g_atomic_pointer_set (&lockptr, ptr2);
    g_pointer_bit_unlock (&lockptr, lock_bit);

That has several problems:

- it requires one extra atomic operations (3 instead of 2, in the
  non-contended case).

- the first g_atomic_pointer_set() already wakes blocked threads,
  which find themselves still being locked and needs to go back to
  sleep.

- the user needs to re-implement how bit-locking mangles the pointer so
  that it looks as if it were locked.

- while the user tries to re-implement what glib does to mangle the
  pointer for bitlocking, there is no immediate guarantee that they get
  it right.

Now we can do instead:

  g_pointer_bit_lock(&lockptr, lock_bit);
  g_pointer_bit_unlock_and_set(&lockptr, lock_bit, ptr, 0);

This will also emit a critical if @ptr has the locked bit set.
g_pointer_bit_lock() really only works with pointers that have a certain
alignment, and the lowest bits unset. Otherwise, there is no space to
encode both the locking and all pointer values. The new assertion helps
to catch such bugs.

Also, g_pointer_bit_lock_mask_ptr() is here, so we can do:

  g_pointer_bit_lock(&lockptr, lock_bit);
  /* set a pointer separately, when g_pointer_bit_unlock_and_set() is unsuitable. */
  g_atomic_pointer_set(&lockptr, g_pointer_bit_lock_mask_ptr(ptr, lock_bit, TRUE, 0, NULL));
  ...
  g_pointer_bit_unlock(&lockptr, lock_bit);

and:

  g_pointer_bit_lock(&lockptr, lock_bit);
  /* read the real pointer after getting the lock. */
  ptr = g_pointer_bit_lock_mask_ptr(lockptr, lock_bit, FALSE, 0, NULL));
  ...
  g_pointer_bit_unlock(&lockptr, lock_bit);
2024-01-16 12:16:42 +01:00
Philip Withnall
571636538b Merge branch 'optional-flags' into 'main'
gobject: define HAVE_OPTIONAL_FLAGS for sizeof(void*) > 8

See merge request GNOME/glib!3813
2024-01-16 09:02:22 +00:00
Alex Richardson
dfa0d60db2 genums: use g_once_init_enter_pointer for GType initializers
GType is either an integer or a pointer, so we have to use the _pointer
version here to support architectures such as Morello.

These two lines were missed in 5ecd3cbe52
and allows the gobject/enums test to pass on CheriBSD (Morello).

Helps: https://gitlab.gnome.org/GNOME/glib/-/issues/2842
2024-01-15 17:32:11 -08:00
Alex Richardson
6e51c2e150 gobject: define HAVE_OPTIONAL_FLAGS for sizeof(void*) > 8
The padding space for this extra field is also available if void* is
larger than 8 bytes.
2024-01-15 16:27:06 -08:00
Alex Richardson
9769cd0d24 gsignal.c: drop an optimization that is undefined behaviour
Comparing reallocated pointers is UB, but this happens to work for now
on most compilers. However, for CHERI systems if g_bsearch_array_insert()
reallocs in-place then the new `hlbsa` pointer may have larger bounds
than `o` and using the old pointer with the smaller bounds can result
in a bounds error. I don't think this code is performance critical, so
removing the optimization and inserting unconditionally should be fine.

Currently, this realloc() UB rarely causes issues, but newer versions of
GCC with _FORTIFY_SOURCE=3 might also be able to observe the valid
memory range (assuming sufficient inlining).
See https://developers.redhat.com/articles/2022/09/17/gccs-new-fortification-level
2024-01-05 16:46:29 -08:00
Thomas Haller
e05623001b gobject: fix deadlock with g_weak_ref_set()
In general, we must not call out to external, unknown code while holding
a lock. That is prone to dead lock.

g_object_ref() can emit a toggle notification. In g_weak_ref_set(), we
must not do that while holding the lock.
2024-01-04 16:42:59 +01:00
Thomas Haller
b397ef2122 gobject: use per-object bit-lock instead of global mutex for closure array 2024-01-04 16:32:09 +01:00
Thomas Haller
ab202a2c1c gobject: use per-object bit-lock instead of global mutex for toggle refs 2024-01-04 16:32:09 +01:00
Thomas Haller
cf044ba7ad gobject: use per-object bit-lock instead of global mutex for notify-queue 2024-01-04 16:32:09 +01:00
Thomas Haller
c66880e46f gobject: use per-object bit-lock instead of global mutex for weak-refs 2024-01-04 16:32:09 +01:00
Thomas Haller
bfb829231f gobject: never access optional flags without atomic
The optional flags should be used for bit locks. That means,
we must only use atomic operations when updating the flags.

Having a variant of _X methods that update the flags without
locks (_X), means that we must take care not to take bit locks
during construction.

That is hard to get right. There is so much happening during object
construction, that it's unclear when it's really safe to access the
flags without atomic. Don't do this.
2024-01-04 16:32:09 +01:00
Thomas Haller
777606d9c4 gobject: add private data for GObject and use it for optional flags
Add a GObjectPrivate struct and let GObject have private data.

On architectures where we have an alignment gap in GObject struct (64
bit), we use the gap for "optional_flags". Use the private data for
those optional flags, on architectures where we don't have them.

For now, private data is only added for those optional flags (and not on
architectures, where the flags fit inside GObject). In the future, we
may add additional fields there, and add the private struct always.

The main purpose will be to replace all the global locks with per-object
locks, and make "optional_flags" also available on 32bit.
2024-01-04 16:32:09 +01:00
Thomas Haller
6c389738d3 gobject/tests/reference: add tests for concurrent g_weak_ref_set()
GWeakRef methods are thread safe. Add test for calling g_weak_ref_set()
concurrently.
2024-01-04 16:32:09 +01:00
Thomas Haller
787861761d gobject/tests/reference: add test for deadlock related to GWeakRef and toggle reference
GWeakRef calls g_object_ref() while holding a read lock.
g_object_ref() can emit a toggle notification.

If you then inside the toggle notification setup a GWeakRef
(to the same or another object), the code will try to get
a write lock. Deadlock will happen.

Add a test to "show" that (the breaking part is commented out).
Will be fixed next.
2024-01-04 16:17:13 +01:00
Philip Withnall
dd2b6d7e3f Merge branch 'th/g-object-unref-ref' into 'main'
[th/g-object-unref-ref] fix race in g_object_unref()

Closes #3064

See merge request GNOME/glib!3769
2024-01-03 23:39:24 +00:00
Philip Withnall
bf7ccbde9e tests: Fix a minor leak in the new GParamSpecPool test
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-01-03 12:04:16 +00:00
Tanmay
dbbd9c60ba Add boxed GType for GRand
Signed-off-by: Tanmay Patil <tanmaynpatil105@gmail.com>
2023-12-31 09:09:48 +00:00