Compare commits

...

6 Commits

Author SHA1 Message Date
Marco Trevisan
8ceae00c44 Merge branch 'atomic-gcancellable' into 'main'
GCancellable: Use per-instance mutex logic instead of global critical sections

Closes #2309 and #2313

See merge request GNOME/glib!2765
2024-07-15 21:25:00 +00:00
Philip Withnall
d3cb9d638d Merge branch 'traverse-diagrams' into 'main'
docs(GNode): Traversal diagrams, color & dark-mode

See merge request GNOME/glib!4157
2024-07-15 15:58:45 +00:00
Philip Withnall
a931a75c4f docs(GNode): Traversal diagrams, color & dark-mode
* Create a dark-mode variant of each traversal diagram, with the
  traversal path colorized `--primary` blue, instead of the original
  black.
* Apply the same colorizations to the light-mode diagrams, but
  using the light-theme `--primary` blue.
* Add SPDX license/copyright comments to all eight SVG files.
* Add new files to documentation configs in `glib.toml.in`.
* Update documentation comment in `gnode.c` to embed both color
  variants via picture tags, instead of markdown image embeds.
* Add alt text to all four images.
* Add additional blank lines to documentation comment, so that
  a. First item in bulleted list does not get folded into
     preceding intro paragraph
  b. Intro paragraph and diagrams are not part of first paragraph
     in documentation. (This also gets them out of the top-level
     table-of-contents/index list, where they previously appeared
     in full.)
* (Accidental change I didn't realize I was making): Convert line
  endings in breadth-first diagram from CRLF to LF.
2024-07-15 15:58:45 +00:00
Marco Trevisan (Treviño)
cc6448b66b gcancellable: Reference the object before locking when doing signal emission
On g_cancellable_cancel() we were increasing the GCancellable ref count
before emitting the ::cancelled signal, this is a safe thing to do but
it was happening while the cancellable was locked, and this may have
potentially waken up some toggle notifications.

To prevent this, reference the GCancellable just before locking.
2024-05-05 17:00:00 +02:00
Marco Trevisan (Treviño)
1e1b082930 GCancellable: Use per-instance mutex logic instead of global critical sections
GCancellable is meant to be used in multi-thread operations but all the
cancellable instances were sharing a single mutex to synchronize them
which can be less optimal when many instances are in place.
Especially when we're doing a lock/unlock dances that may leave another
thread to take the control of a critical section in an unexpected way.

This in fact was leading to some races in GCancellableSources causing
leaks because we were assuming that the "cancelled" callback was always
called before our dispose implementation.

As per this, use per-instance mutexes.

The lock is also now used only to protect the calls that may interact
with cancelled state or that depends on that, as per this we can just
reduce it to the cancel and reset case, other than to the connect one to
prevent the race that we could have when connecting to a cancellable
that is reset from another thread.

We don't really need to release the locks during callbacks now as they
are per instance, and there's really no function that we allowed to call
during a ::cancelled signal callback that may require an unlocked state.
This could been done in case with a recursive lock, that is easy enough
to implement but not really needed for this case.

Fixes: #2309, #2313
2024-05-05 16:59:59 +02:00
Marco Trevisan (Treviño)
92e6602053 gio/tests: Ensure that a GCancellableSource can be used muliple times
Related to: #774
2024-05-05 16:59:59 +02:00
13 changed files with 2808 additions and 324 deletions

View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
SPDX-License-Identifier: CC0-1.0
SPDX-FileCopyrightText: Rory O'Kane at Wikimedia Commons
<https://commons.wikimedia.org/wiki/File:Sorted_binary_tree_breadth-first_traversal.svg>
SPDX-FileCopyrightText: 2024 Frank Dana
-->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="266px" height="212px" viewBox="0 0 266 212" enable-background="new 0 0 266 212" xml:space="preserve">
<g>
<g>
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" x1="27.23" y1="23.192" x2="29.23" y2="23.192"/>
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9562,3.9562" x1="33.187" y1="23.192" x2="236.932" y2="23.192"/>
<polyline fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" points="238.91,23.192 240.91,23.192
238.97,23.677 "/>
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="24.646" x2="27.971" y2="76.427"/>
<polyline fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" points="26.035,76.912 24.095,77.396
26.095,77.396 "/>
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0154,4.0154" x1="30.11" y1="77.396" x2="236.902" y2="77.396"/>
<polyline fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" points="238.91,77.396 240.91,77.396
238.97,77.881 "/>
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="78.85" x2="27.971" y2="130.631"/>
<polyline fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" points="26.035,131.114 24.095,131.6
26.095,131.6 "/>
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0154,4.0154" x1="30.11" y1="131.6" x2="236.902" y2="131.6"/>
<polyline fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" points="238.91,131.6 240.91,131.6
238.97,132.085 "/>
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="133.053" x2="27.971" y2="184.835"/>
<polyline fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" points="26.035,185.318 24.095,185.804
26.095,185.804 "/>
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0086,4.0086" x1="30.104" y1="185.804" x2="228.53" y2="185.804"/>
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" x1="230.534" y1="185.804" x2="232.534" y2="185.804"/>
<g>
<rect fill="#90c2ff" x="24.095" y="19.892" width="6.602" height="6.602"/>
</g>
<g>
<path fill="#90c2ff" d="M238.569,185.804c-2.84,1.054-6.363,2.852-8.548,4.756l1.721-4.756l-1.721-4.755
C232.206,182.953,235.729,184.751,238.569,185.804z"/>
</g>
</g>
</g>
<g id="graph0">
<title>sorted_binary_tree</title>
<g id="node1">
<title>C</title>
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="60.23" cy="185.804" rx="18.067" ry="18.067"/>
<text transform="matrix(1 0 0 1 55.5435 190.8223)" font-family="'Times-Roman'" font-size="14.0528">C</text>
</g>
<g id="node2">
<title>E</title>
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="132.502" cy="185.804" rx="18.067" ry="18.067"/>
<text transform="matrix(1 0 0 1 128.21 190.8223)" font-family="'Times-Roman'" font-size="14.0528">E</text>
</g>
<g id="node3">
<title>H</title>
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="204.773" cy="185.804" rx="17.064" ry="18.067"/>
<text transform="matrix(1 0 0 1 199.6992 190.8223)" font-family="'Times-Roman'" font-size="14.0528">H</text>
</g>
<g id="node4">
<title>A</title>
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="24.094" cy="131.6" rx="17.064" ry="18.068"/>
<text transform="matrix(1 0 0 1 19.02 136.6191)" font-family="'Times-Roman'" font-size="14.0528">A</text>
</g>
<g id="node5">
<title>D</title>
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="96.366" cy="131.6" rx="17.064" ry="18.068"/>
<text transform="matrix(1 0 0 1 91.292 136.6191)" font-family="'Times-Roman'" font-size="14.0528">D</text>
</g>
<g id="edge6">
<title>D-&gt;C</title>
<path fill="none" stroke="#ffffff" d="M86.328,147.66c-3.011,4.016-7.026,9.034-10.038,14.053"/>
<polygon fill="#ffffff" stroke="#ffffff" points="78.298,164.725 70.268,170.747 73.279,160.709 "/>
</g>
<g id="edge8">
<title>D-&gt;E</title>
<path fill="none" stroke="#ffffff" d="M106.404,147.66c3.011,4.016,7.026,9.034,10.038,14.053"/>
<polygon fill="#ffffff" stroke="#ffffff" points="119.453,160.709 122.464,170.747 114.434,164.725 "/>
</g>
<g id="node6">
<title>I</title>
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="240.909" cy="131.6" rx="18.068" ry="18.068"/>
<text transform="matrix(1 0 0 1 238.5693 136.6191)" font-family="'Times-Roman'" font-size="14.0528">I</text>
</g>
<g id="edge12">
<title>I-&gt;H</title>
<path fill="none" stroke="#ffffff" d="M230.871,146.656c-3.011,5.02-6.021,10.038-10.037,15.057"/>
<polygon fill="#ffffff" stroke="#ffffff" points="223.846,163.721 214.812,169.743 217.822,159.705 "/>
</g>
<g id="node7">
<title>B</title>
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="60.23" cy="77.396" rx="18.068" ry="18.068"/>
<text transform="matrix(1 0 0 1 55.5435 82.415)" font-family="'Times-Roman'" font-size="14.0528">B</text>
</g>
<g id="edge3">
<title>B-&gt;A</title>
<path fill="none" stroke="#ffffff" d="M50.192,92.453c-3.011,5.019-6.022,10.038-10.038,15.057"/>
<polygon fill="#ffffff" stroke="#ffffff" points="43.166,109.518 34.132,115.539 37.144,105.502 "/>
</g>
<g id="edge5">
<title>B-&gt;D</title>
<path fill="none" stroke="#ffffff" d="M70.268,92.453c3.011,5.019,6.022,10.038,10.038,15.057"/>
<polygon fill="#ffffff" stroke="#ffffff" points="83.317,105.502 86.328,115.539 77.294,109.518 "/>
</g>
<g id="node8">
<title>G</title>
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="204.773" cy="77.396" rx="17.064" ry="18.068"/>
<text transform="matrix(1 0 0 1 199.6992 82.415)" font-family="'Times-Roman'" font-size="14.0528">G</text>
</g>
<g id="edge11">
<title>G-&gt;I</title>
<path fill="none" stroke="#ffffff" d="M214.812,93.457c3.011,4.015,7.026,9.034,10.038,14.053"/>
<polygon fill="#ffffff" stroke="#ffffff" points="227.86,106.506 230.871,116.543 222.842,110.521 "/>
</g>
<g id="node9">
<title>F</title>
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="132.502" cy="23.192" rx="18.068" ry="18.068"/>
<text transform="matrix(1 0 0 1 128.5942 28.2109)" font-family="'Times-Roman'" font-size="14.0528">F</text>
</g>
<g id="edge2">
<title>F-&gt;B</title>
<path fill="none" stroke="#ffffff" d="M117.445,34.234c-11.042,8.03-23.087,17.064-34.128,26.098"/>
<polygon fill="#ffffff" stroke="#ffffff" points="85.325,63.343 75.287,66.354 81.31,57.321 "/>
</g>
<g id="edge10">
<title>F-&gt;G</title>
<path fill="none" stroke="#ffffff" d="M147.559,34.234c11.041,8.03,23.087,17.064,34.129,26.098"/>
<polygon fill="#ffffff" stroke="#ffffff" points="183.694,57.321 189.717,66.354 179.68,63.343 "/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -1,134 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="266px" height="212px" viewBox="0 0 266 212" enable-background="new 0 0 266 212" xml:space="preserve">
<g>
<g>
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" x1="27.23" y1="23.192" x2="29.23" y2="23.192"/>
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9562,3.9562" x1="33.187" y1="23.192" x2="236.932" y2="23.192"/>
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="238.91,23.192 240.91,23.192
238.97,23.677 "/>
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="24.646" x2="27.971" y2="76.427"/>
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="26.035,76.912 24.095,77.396
26.095,77.396 "/>
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0154,4.0154" x1="30.11" y1="77.396" x2="236.902" y2="77.396"/>
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="238.91,77.396 240.91,77.396
238.97,77.881 "/>
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="78.85" x2="27.971" y2="130.631"/>
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="26.035,131.114 24.095,131.6
26.095,131.6 "/>
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0154,4.0154" x1="30.11" y1="131.6" x2="236.902" y2="131.6"/>
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="238.91,131.6 240.91,131.6
238.97,132.085 "/>
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="133.053" x2="27.971" y2="184.835"/>
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="26.035,185.318 24.095,185.804
26.095,185.804 "/>
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0086,4.0086" x1="30.104" y1="185.804" x2="228.53" y2="185.804"/>
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" x1="230.534" y1="185.804" x2="232.534" y2="185.804"/>
<g>
<rect x="24.095" y="19.892" width="6.602" height="6.602"/>
</g>
<g>
<path d="M238.569,185.804c-2.84,1.054-6.363,2.852-8.548,4.756l1.721-4.756l-1.721-4.755
C232.206,182.953,235.729,184.751,238.569,185.804z"/>
</g>
</g>
</g>
<g id="graph0">
<title>sorted_binary_tree</title>
<g id="node1">
<title>C</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="60.23" cy="185.804" rx="18.067" ry="18.067"/>
<text transform="matrix(1 0 0 1 55.5435 190.8223)" font-family="'Times-Roman'" font-size="14.0528">C</text>
</g>
<g id="node2">
<title>E</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="132.502" cy="185.804" rx="18.067" ry="18.067"/>
<text transform="matrix(1 0 0 1 128.21 190.8223)" font-family="'Times-Roman'" font-size="14.0528">E</text>
</g>
<g id="node3">
<title>H</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="204.773" cy="185.804" rx="17.064" ry="18.067"/>
<text transform="matrix(1 0 0 1 199.6992 190.8223)" font-family="'Times-Roman'" font-size="14.0528">H</text>
</g>
<g id="node4">
<title>A</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="24.094" cy="131.6" rx="17.064" ry="18.068"/>
<text transform="matrix(1 0 0 1 19.02 136.6191)" font-family="'Times-Roman'" font-size="14.0528">A</text>
</g>
<g id="node5">
<title>D</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="96.366" cy="131.6" rx="17.064" ry="18.068"/>
<text transform="matrix(1 0 0 1 91.292 136.6191)" font-family="'Times-Roman'" font-size="14.0528">D</text>
</g>
<g id="edge6">
<title>D-&gt;C</title>
<path fill="none" stroke="#000000" d="M86.328,147.66c-3.011,4.016-7.026,9.034-10.038,14.053"/>
<polygon stroke="#000000" points="78.298,164.725 70.268,170.747 73.279,160.709 "/>
</g>
<g id="edge8">
<title>D-&gt;E</title>
<path fill="none" stroke="#000000" d="M106.404,147.66c3.011,4.016,7.026,9.034,10.038,14.053"/>
<polygon stroke="#000000" points="119.453,160.709 122.464,170.747 114.434,164.725 "/>
</g>
<g id="node6">
<title>I</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="240.909" cy="131.6" rx="18.068" ry="18.068"/>
<text transform="matrix(1 0 0 1 238.5693 136.6191)" font-family="'Times-Roman'" font-size="14.0528">I</text>
</g>
<g id="edge12">
<title>I-&gt;H</title>
<path fill="none" stroke="#000000" d="M230.871,146.656c-3.011,5.02-6.021,10.038-10.037,15.057"/>
<polygon stroke="#000000" points="223.846,163.721 214.812,169.743 217.822,159.705 "/>
</g>
<g id="node7">
<title>B</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="60.23" cy="77.396" rx="18.068" ry="18.068"/>
<text transform="matrix(1 0 0 1 55.5435 82.415)" font-family="'Times-Roman'" font-size="14.0528">B</text>
</g>
<g id="edge3">
<title>B-&gt;A</title>
<path fill="none" stroke="#000000" d="M50.192,92.453c-3.011,5.019-6.022,10.038-10.038,15.057"/>
<polygon stroke="#000000" points="43.166,109.518 34.132,115.539 37.144,105.502 "/>
</g>
<g id="edge5">
<title>B-&gt;D</title>
<path fill="none" stroke="#000000" d="M70.268,92.453c3.011,5.019,6.022,10.038,10.038,15.057"/>
<polygon stroke="#000000" points="83.317,105.502 86.328,115.539 77.294,109.518 "/>
</g>
<g id="node8">
<title>G</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="204.773" cy="77.396" rx="17.064" ry="18.068"/>
<text transform="matrix(1 0 0 1 199.6992 82.415)" font-family="'Times-Roman'" font-size="14.0528">G</text>
</g>
<g id="edge11">
<title>G-&gt;I</title>
<path fill="none" stroke="#000000" d="M214.812,93.457c3.011,4.015,7.026,9.034,10.038,14.053"/>
<polygon stroke="#000000" points="227.86,106.506 230.871,116.543 222.842,110.521 "/>
</g>
<g id="node9">
<title>F</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="132.502" cy="23.192" rx="18.068" ry="18.068"/>
<text transform="matrix(1 0 0 1 128.5942 28.2109)" font-family="'Times-Roman'" font-size="14.0528">F</text>
</g>
<g id="edge2">
<title>F-&gt;B</title>
<path fill="none" stroke="#000000" d="M117.445,34.234c-11.042,8.03-23.087,17.064-34.128,26.098"/>
<polygon stroke="#000000" points="85.325,63.343 75.287,66.354 81.31,57.321 "/>
</g>
<g id="edge10">
<title>F-&gt;G</title>
<path fill="none" stroke="#000000" d="M147.559,34.234c11.041,8.03,23.087,17.064,34.129,26.098"/>
<polygon stroke="#000000" points="183.694,57.321 189.717,66.354 179.68,63.343 "/>
</g>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!--
SPDX-License-Identifier: CC0-1.0
SPDX-FileCopyrightText: Rory O'Kane at Wikimedia Commons
<https://commons.wikimedia.org/wiki/File:Sorted_binary_tree_breadth-first_traversal.svg>
SPDX-FileCopyrightText: 2024 Frank Dana
-->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="266px" height="212px" viewBox="0 0 266 212" enable-background="new 0 0 266 212" xml:space="preserve">
<g>
<g>
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" x1="27.23" y1="23.192" x2="29.23" y2="23.192"/>
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9562,3.9562" x1="33.187" y1="23.192" x2="236.932" y2="23.192"/>
<polyline fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" points="238.91,23.192 240.91,23.192
238.97,23.677 "/>
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="24.646" x2="27.971" y2="76.427"/>
<polyline fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" points="26.035,76.912 24.095,77.396
26.095,77.396 "/>
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0154,4.0154" x1="30.11" y1="77.396" x2="236.902" y2="77.396"/>
<polyline fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" points="238.91,77.396 240.91,77.396
238.97,77.881 "/>
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="78.85" x2="27.971" y2="130.631"/>
<polyline fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" points="26.035,131.114 24.095,131.6
26.095,131.6 "/>
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0154,4.0154" x1="30.11" y1="131.6" x2="236.902" y2="131.6"/>
<polyline fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" points="238.91,131.6 240.91,131.6
238.97,132.085 "/>
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="133.053" x2="27.971" y2="184.835"/>
<polyline fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" points="26.035,185.318 24.095,185.804
26.095,185.804 "/>
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0086,4.0086" x1="30.104" y1="185.804" x2="228.53" y2="185.804"/>
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" x1="230.534" y1="185.804" x2="232.534" y2="185.804"/>
<g>
<rect fill="#1c76e4" x="24.095" y="19.892" width="6.602" height="6.602"/>
</g>
<g>
<path fill="#1c76e4" d="M238.569,185.804c-2.84,1.054-6.363,2.852-8.548,4.756l1.721-4.756l-1.721-4.755
C232.206,182.953,235.729,184.751,238.569,185.804z"/>
</g>
</g>
</g>
<g id="graph0">
<title>sorted_binary_tree</title>
<g id="node1">
<title>C</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="60.23" cy="185.804" rx="18.067" ry="18.067"/>
<text transform="matrix(1 0 0 1 55.5435 190.8223)" font-family="'Times-Roman'" font-size="14.0528">C</text>
</g>
<g id="node2">
<title>E</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="132.502" cy="185.804" rx="18.067" ry="18.067"/>
<text transform="matrix(1 0 0 1 128.21 190.8223)" font-family="'Times-Roman'" font-size="14.0528">E</text>
</g>
<g id="node3">
<title>H</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="204.773" cy="185.804" rx="17.064" ry="18.067"/>
<text transform="matrix(1 0 0 1 199.6992 190.8223)" font-family="'Times-Roman'" font-size="14.0528">H</text>
</g>
<g id="node4">
<title>A</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="24.094" cy="131.6" rx="17.064" ry="18.068"/>
<text transform="matrix(1 0 0 1 19.02 136.6191)" font-family="'Times-Roman'" font-size="14.0528">A</text>
</g>
<g id="node5">
<title>D</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="96.366" cy="131.6" rx="17.064" ry="18.068"/>
<text transform="matrix(1 0 0 1 91.292 136.6191)" font-family="'Times-Roman'" font-size="14.0528">D</text>
</g>
<g id="edge6">
<title>D-&gt;C</title>
<path fill="none" stroke="#000000" d="M86.328,147.66c-3.011,4.016-7.026,9.034-10.038,14.053"/>
<polygon stroke="#000000" points="78.298,164.725 70.268,170.747 73.279,160.709 "/>
</g>
<g id="edge8">
<title>D-&gt;E</title>
<path fill="none" stroke="#000000" d="M106.404,147.66c3.011,4.016,7.026,9.034,10.038,14.053"/>
<polygon stroke="#000000" points="119.453,160.709 122.464,170.747 114.434,164.725 "/>
</g>
<g id="node6">
<title>I</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="240.909" cy="131.6" rx="18.068" ry="18.068"/>
<text transform="matrix(1 0 0 1 238.5693 136.6191)" font-family="'Times-Roman'" font-size="14.0528">I</text>
</g>
<g id="edge12">
<title>I-&gt;H</title>
<path fill="none" stroke="#000000" d="M230.871,146.656c-3.011,5.02-6.021,10.038-10.037,15.057"/>
<polygon stroke="#000000" points="223.846,163.721 214.812,169.743 217.822,159.705 "/>
</g>
<g id="node7">
<title>B</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="60.23" cy="77.396" rx="18.068" ry="18.068"/>
<text transform="matrix(1 0 0 1 55.5435 82.415)" font-family="'Times-Roman'" font-size="14.0528">B</text>
</g>
<g id="edge3">
<title>B-&gt;A</title>
<path fill="none" stroke="#000000" d="M50.192,92.453c-3.011,5.019-6.022,10.038-10.038,15.057"/>
<polygon stroke="#000000" points="43.166,109.518 34.132,115.539 37.144,105.502 "/>
</g>
<g id="edge5">
<title>B-&gt;D</title>
<path fill="none" stroke="#000000" d="M70.268,92.453c3.011,5.019,6.022,10.038,10.038,15.057"/>
<polygon stroke="#000000" points="83.317,105.502 86.328,115.539 77.294,109.518 "/>
</g>
<g id="node8">
<title>G</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="204.773" cy="77.396" rx="17.064" ry="18.068"/>
<text transform="matrix(1 0 0 1 199.6992 82.415)" font-family="'Times-Roman'" font-size="14.0528">G</text>
</g>
<g id="edge11">
<title>G-&gt;I</title>
<path fill="none" stroke="#000000" d="M214.812,93.457c3.011,4.015,7.026,9.034,10.038,14.053"/>
<polygon stroke="#000000" points="227.86,106.506 230.871,116.543 222.842,110.521 "/>
</g>
<g id="node9">
<title>F</title>
<ellipse fill="#FFFFFF" stroke="#000000" cx="132.502" cy="23.192" rx="18.068" ry="18.068"/>
<text transform="matrix(1 0 0 1 128.5942 28.2109)" font-family="'Times-Roman'" font-size="14.0528">F</text>
</g>
<g id="edge2">
<title>F-&gt;B</title>
<path fill="none" stroke="#000000" d="M117.445,34.234c-11.042,8.03-23.087,17.064-34.128,26.098"/>
<polygon stroke="#000000" points="85.325,63.343 75.287,66.354 81.31,57.321 "/>
</g>
<g id="edge10">
<title>F-&gt;G</title>
<path fill="none" stroke="#000000" d="M147.559,34.234c11.041,8.03,23.087,17.064,34.129,26.098"/>
<polygon stroke="#000000" points="183.694,57.321 189.717,66.354 179.68,63.343 "/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -99,6 +99,10 @@ content_images = [
"Sorted_binary_tree_inorder.svg",
"Sorted_binary_tree_postorder.svg",
"Sorted_binary_tree_preorder.svg",
"Sorted_binary_tree_breadth-first_traversal-dark.svg",
"Sorted_binary_tree_inorder-dark.svg",
"Sorted_binary_tree_postorder-dark.svg",
"Sorted_binary_tree_preorder-dark.svg",
]
[[object]]

View File

@ -1,6 +1,7 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
* Copyright (C) 2022-2024 Canonical, Ltd.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
@ -18,6 +19,7 @@
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Alexander Larsson <alexl@redhat.com>
* Author: Marco Trevisan <marco.trevisan@canonical.com>
*/
#include "config.h"
@ -45,14 +47,12 @@ enum {
struct _GCancellablePrivate
{
/* Atomic so that g_cancellable_is_cancelled does not require holding the mutex. */
/* Atomic so that we don't require holding global mutexes for independent ops. */
gboolean cancelled;
/* Access to fields below is protected by cancellable_mutex. */
guint cancelled_running : 1;
guint cancelled_running_waiting : 1;
unsigned cancelled_emissions;
unsigned cancelled_emissions_waiting : 1;
int cancelled_running;
/* Access to fields below is protected by cancellable's mutex. */
GMutex mutex;
guint fd_refcount;
GWakeup *wakeup;
};
@ -62,7 +62,6 @@ static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (GCancellable, g_cancellable, G_TYPE_OBJECT)
static GPrivate current_cancellable;
static GMutex cancellable_mutex;
static GCond cancellable_cond;
static void
@ -70,9 +69,15 @@ g_cancellable_finalize (GObject *object)
{
GCancellable *cancellable = G_CANCELLABLE (object);
/* We're at finalization phase, so only one thread can be here.
* Thus there's no need to lock. In case something is locking us, then we've
* a bug, and g_mutex_clear() will make this clear aborting.
*/
if (cancellable->priv->wakeup)
GLIB_PRIVATE_CALL (g_wakeup_free) (cancellable->priv->wakeup);
g_mutex_clear (&cancellable->priv->mutex);
G_OBJECT_CLASS (g_cancellable_parent_class)->finalize (object);
}
@ -154,6 +159,8 @@ static void
g_cancellable_init (GCancellable *cancellable)
{
cancellable->priv = g_cancellable_get_instance_private (cancellable);
g_mutex_init (&cancellable->priv->mutex);
}
/**
@ -265,28 +272,17 @@ g_cancellable_reset (GCancellable *cancellable)
g_return_if_fail (G_IS_CANCELLABLE (cancellable));
g_mutex_lock (&cancellable_mutex);
priv = cancellable->priv;
while (priv->cancelled_running || priv->cancelled_emissions > 0)
{
if (priv->cancelled_running)
priv->cancelled_running_waiting = TRUE;
g_mutex_lock (&priv->mutex);
if (priv->cancelled_emissions > 0)
priv->cancelled_emissions_waiting = TRUE;
g_cond_wait (&cancellable_cond, &cancellable_mutex);
}
if (g_atomic_int_exchange (&priv->cancelled, FALSE))
if (g_atomic_int_compare_and_exchange (&priv->cancelled, TRUE, FALSE))
{
if (priv->wakeup)
GLIB_PRIVATE_CALL (g_wakeup_acknowledge) (priv->wakeup);
}
g_mutex_unlock (&cancellable_mutex);
g_mutex_unlock (&priv->mutex);
}
/**
@ -404,26 +400,29 @@ g_cancellable_get_fd (GCancellable *cancellable)
gboolean
g_cancellable_make_pollfd (GCancellable *cancellable, GPollFD *pollfd)
{
GCancellablePrivate *priv;
g_return_val_if_fail (pollfd != NULL, FALSE);
if (cancellable == NULL)
return FALSE;
g_return_val_if_fail (G_IS_CANCELLABLE (cancellable), FALSE);
g_mutex_lock (&cancellable_mutex);
priv = cancellable->priv;
cancellable->priv->fd_refcount++;
g_mutex_lock (&priv->mutex);
if (cancellable->priv->wakeup == NULL)
if ((priv->fd_refcount++) == 0)
{
cancellable->priv->wakeup = GLIB_PRIVATE_CALL (g_wakeup_new) ();
priv->wakeup = GLIB_PRIVATE_CALL (g_wakeup_new) ();
if (g_atomic_int_get (&cancellable->priv->cancelled))
GLIB_PRIVATE_CALL (g_wakeup_signal) (cancellable->priv->wakeup);
if (g_atomic_int_get (&priv->cancelled))
GLIB_PRIVATE_CALL (g_wakeup_signal) (priv->wakeup);
}
GLIB_PRIVATE_CALL (g_wakeup_get_pollfd) (cancellable->priv->wakeup, pollfd);
g_assert (priv->wakeup);
GLIB_PRIVATE_CALL (g_wakeup_get_pollfd) (priv->wakeup, pollfd);
g_mutex_unlock (&cancellable_mutex);
g_mutex_unlock (&priv->mutex);
return TRUE;
}
@ -447,26 +446,22 @@ g_cancellable_make_pollfd (GCancellable *cancellable, GPollFD *pollfd)
void
g_cancellable_release_fd (GCancellable *cancellable)
{
GCancellablePrivate *priv;
if (cancellable == NULL)
return;
g_return_if_fail (G_IS_CANCELLABLE (cancellable));
priv = cancellable->priv;
g_mutex_lock (&cancellable->priv->mutex);
g_mutex_lock (&cancellable_mutex);
g_assert (priv->fd_refcount > 0);
g_assert (cancellable->priv->fd_refcount > 0);
priv->fd_refcount--;
if (priv->fd_refcount == 0)
if ((cancellable->priv->fd_refcount--) == 1)
{
GLIB_PRIVATE_CALL (g_wakeup_free) (priv->wakeup);
priv->wakeup = NULL;
GLIB_PRIVATE_CALL (g_wakeup_free) (cancellable->priv->wakeup);
cancellable->priv->wakeup = NULL;
}
g_mutex_unlock (&cancellable_mutex);
g_mutex_unlock (&cancellable->priv->mutex);
}
/**
@ -495,37 +490,35 @@ g_cancellable_cancel (GCancellable *cancellable)
{
GCancellablePrivate *priv;
if (cancellable == NULL || g_cancellable_is_cancelled (cancellable))
if (cancellable == NULL || g_atomic_int_get (&cancellable->priv->cancelled))
return;
priv = cancellable->priv;
g_mutex_lock (&cancellable_mutex);
/* We add a reference before locking, to avoid that potential toggle
* notifications on the object might happen while we're locked.
*/
g_object_ref (cancellable);
g_mutex_lock (&priv->mutex);
if (g_atomic_int_exchange (&priv->cancelled, TRUE))
if (!g_atomic_int_compare_and_exchange (&priv->cancelled, FALSE, TRUE))
{
g_mutex_unlock (&cancellable_mutex);
g_mutex_unlock (&priv->mutex);
g_object_unref (cancellable);
return;
}
priv->cancelled_running = TRUE;
g_atomic_int_inc (&priv->cancelled_running);
if (priv->wakeup)
GLIB_PRIVATE_CALL (g_wakeup_signal) (priv->wakeup);
g_mutex_unlock (&cancellable_mutex);
g_object_ref (cancellable);
g_signal_emit (cancellable, signals[CANCELLED], 0);
g_mutex_lock (&cancellable_mutex);
priv->cancelled_running = FALSE;
if (priv->cancelled_running_waiting)
if (g_atomic_int_dec_and_test (&priv->cancelled_running))
g_cond_broadcast (&cancellable_cond);
priv->cancelled_running_waiting = FALSE;
g_mutex_unlock (&cancellable_mutex);
g_mutex_unlock (&priv->mutex);
g_object_unref (cancellable);
}
@ -571,7 +564,7 @@ g_cancellable_connect (GCancellable *cancellable,
g_return_val_if_fail (G_IS_CANCELLABLE (cancellable), 0);
g_mutex_lock (&cancellable_mutex);
g_mutex_lock (&cancellable->priv->mutex);
if (g_atomic_int_get (&cancellable->priv->cancelled))
{
@ -581,23 +574,10 @@ g_cancellable_connect (GCancellable *cancellable,
_callback = (void *)callback;
id = 0;
cancellable->priv->cancelled_emissions++;
g_mutex_unlock (&cancellable_mutex);
_callback (cancellable, data);
if (data_destroy_func)
data_destroy_func (data);
g_mutex_lock (&cancellable_mutex);
if (cancellable->priv->cancelled_emissions_waiting)
g_cond_broadcast (&cancellable_cond);
cancellable->priv->cancelled_emissions--;
g_mutex_unlock (&cancellable_mutex);
}
else
{
@ -605,10 +585,9 @@ g_cancellable_connect (GCancellable *cancellable,
callback, data,
(GClosureNotify) data_destroy_func,
G_CONNECT_DEFAULT);
g_mutex_unlock (&cancellable_mutex);
}
g_mutex_unlock (&cancellable->priv->mutex);
return id;
}
@ -644,33 +623,26 @@ g_cancellable_disconnect (GCancellable *cancellable,
if (handler_id == 0 || cancellable == NULL)
return;
g_mutex_lock (&cancellable_mutex);
priv = cancellable->priv;
while (priv->cancelled_running || priv->cancelled_emissions)
{
if (priv->cancelled_running)
priv->cancelled_running_waiting = TRUE;
g_mutex_lock (&priv->mutex);
if (priv->cancelled_emissions)
priv->cancelled_emissions_waiting = TRUE;
while (g_atomic_int_get (&priv->cancelled_running) != 0)
g_cond_wait (&cancellable_cond, &priv->mutex);
g_cond_wait (&cancellable_cond, &cancellable_mutex);
}
g_mutex_unlock (&priv->mutex);
g_signal_handler_disconnect (cancellable, handler_id);
g_mutex_unlock (&cancellable_mutex);
}
typedef struct {
GSource source;
/* Atomic: */
GCancellable *cancellable;
gulong cancelled_handler;
/* Protected by cancellable_mutex: */
gboolean resurrected_during_cancellation;
/* Atomic: */
gboolean cancelled_callback_called;
} GCancellableSource;
/*
@ -691,26 +663,32 @@ cancellable_source_cancelled (GCancellable *cancellable,
GSource *source = user_data;
GCancellableSource *cancellable_source = (GCancellableSource *) source;
g_mutex_lock (&cancellable_mutex);
/* Drop the reference added in cancellable_source_dispose(); see the comment there.
* The reference must be dropped after unlocking @cancellable_mutex since
* it could be the final reference, and the dispose function takes
* @cancellable_mutex. */
if (cancellable_source->resurrected_during_cancellation)
{
cancellable_source->resurrected_during_cancellation = FALSE;
g_mutex_unlock (&cancellable_mutex);
g_source_unref (source);
return;
}
g_source_ref (source);
g_mutex_unlock (&cancellable_mutex);
g_source_set_ready_time (source, 0);
g_assert (g_atomic_int_compare_and_exchange (
&cancellable_source->cancelled_callback_called, FALSE, TRUE));
g_source_unref (source);
}
static gboolean
cancellable_source_prepare (GSource *source,
gint *timeout)
{
GCancellableSource *cancellable_source = (GCancellableSource *) source;
GCancellable *cancellable;
if (timeout)
*timeout = -1;
cancellable = g_atomic_pointer_get (&cancellable_source->cancellable);
if (cancellable && !g_atomic_int_get (&cancellable->priv->cancelled_running))
g_atomic_int_set (&cancellable_source->cancelled_callback_called, FALSE);
return FALSE;
}
static gboolean
cancellable_source_dispatch (GSource *source,
GSourceFunc callback,
@ -727,12 +705,13 @@ static void
cancellable_source_dispose (GSource *source)
{
GCancellableSource *cancellable_source = (GCancellableSource *)source;
GCancellable *cancellable;
g_mutex_lock (&cancellable_mutex);
cancellable = g_atomic_pointer_exchange (&cancellable_source->cancellable, NULL);
if (cancellable_source->cancellable)
if (cancellable)
{
if (cancellable_source->cancellable->priv->cancelled_running)
if (g_atomic_int_get (&cancellable->priv->cancelled_running))
{
/* There can be a race here: if thread A has called
* g_cancellable_cancel() and has got as far as committing to call
@ -744,21 +723,21 @@ cancellable_source_dispose (GSource *source)
* will then be left in a state where its committed to using a
* dangling GCancellableSource pointer.
*
* Eliminate that race by resurrecting the #GSource temporarily, and
* then dropping that reference in cancellable_source_cancelled(),
* which should be guaranteed to fire because were inside a
* @cancelled_running block.
* Eliminate that race by waiting to ensure that our cancelled
* callback has been called, keeping a temporary ref, so that
* there's no risk that we're unreffing something that is still
* going to be used.
*/
g_source_ref (source);
cancellable_source->resurrected_during_cancellation = TRUE;
while (!g_atomic_int_get (&cancellable_source->cancelled_callback_called))
;
g_source_unref (source);
}
g_clear_signal_handler (&cancellable_source->cancelled_handler,
cancellable_source->cancellable);
g_clear_object (&cancellable_source->cancellable);
g_clear_signal_handler (&cancellable_source->cancelled_handler, cancellable);
g_object_unref (cancellable);
}
g_mutex_unlock (&cancellable_mutex);
}
static gboolean
@ -787,7 +766,7 @@ cancellable_source_closure_callback (GCancellable *cancellable,
static GSourceFuncs cancellable_source_funcs =
{
NULL,
cancellable_source_prepare,
NULL,
cancellable_source_dispatch,
NULL,

View File

@ -262,11 +262,6 @@ threaded_dispose_thread_cb (gpointer user_data)
static void
test_cancellable_source_threaded_dispose (void)
{
#ifdef _GLIB_ADDRESS_SANITIZER
g_test_incomplete ("FIXME: Leaks lots of GCancellableSource objects, see glib#2309");
(void) cancelled_cb;
(void) threaded_dispose_thread_cb;
#else
ThreadedDisposeData data;
GThread *thread = NULL;
guint i;
@ -276,6 +271,10 @@ test_cancellable_source_threaded_dispose (void)
"(in one thread) and cancelling the GCancellable it refers "
"to (in another thread)");
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1841");
#ifdef _GLIB_ADDRESS_SANITIZER
g_test_message ("We also ensure that no GCancellableSource are leaked");
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/2309");
#endif
#ifdef ENABLE_VALGRIND
if (RUNNING_ON_VALGRIND)
@ -341,7 +340,6 @@ test_cancellable_source_threaded_dispose (void)
g_cond_clear (&data.cond);
g_ptr_array_unref (cancellables_pending_unref);
#endif
}
static void
@ -796,6 +794,63 @@ test_cancellable_cancel_reset_connect_races (void)
g_object_unref (cancellable);
}
static gboolean
source_cancelled_counter_cb (GCancellable *cancellable,
gpointer user_data)
{
guint *n_calls = user_data;
*n_calls = *n_calls + 1;
return G_SOURCE_CONTINUE;
}
static void
test_cancellable_source_can_be_fired_multiple_times (void)
{
GCancellable *cancellable;
GSource *source;
guint n_calls = 0;
g_test_summary ("Test a cancellable source callback can be called multiple times");
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/774");
cancellable = g_cancellable_new ();
source = g_cancellable_source_new (cancellable);
g_source_set_callback (source, G_SOURCE_FUNC (source_cancelled_counter_cb),
&n_calls, NULL);
g_source_attach (source, NULL);
g_cancellable_cancel (cancellable);
g_assert_cmpuint (n_calls, ==, 0);
while (g_main_context_pending (NULL))
g_main_context_iteration (NULL, TRUE);
g_assert_cmpuint (n_calls, ==, 1);
g_cancellable_cancel (cancellable);
g_timeout_add_once (100, g_free, NULL);
while (g_main_context_pending (NULL))
g_main_context_iteration (NULL, TRUE);
g_assert_cmpuint (n_calls, ==, 1);
g_cancellable_reset (cancellable);
g_cancellable_cancel (cancellable);
g_assert_cmpuint (n_calls, ==, 1);
while (g_main_context_pending (NULL))
g_main_context_iteration (NULL, TRUE);
g_assert_cmpuint (n_calls, ==, 2);
g_source_unref (source);
g_object_unref (cancellable);
}
int
main (int argc, char *argv[])
{
@ -811,6 +866,7 @@ main (int argc, char *argv[])
g_test_add_func ("/cancellable/cancel-reset-races", test_cancellable_cancel_reset_races);
g_test_add_func ("/cancellable/cancel-reset-connect-races", test_cancellable_cancel_reset_connect_races);
g_test_add_func ("/cancellable-source/threaded-dispose", test_cancellable_source_threaded_dispose);
g_test_add_func ("/cancellable-source/can-be-fired-multiple-times", test_cancellable_source_can_be_fired_multiple_times);
return g_test_run ();
}

View File

@ -1007,17 +1007,16 @@ test_dbus_roundtrip (void)
static void
test_dbus_peer_roundtrip (void)
{
#ifdef _GLIB_ADDRESS_SANITIZER
g_test_incomplete ("FIXME: Leaks a GCancellableSource, see glib#2313");
(void) peer_connection_up;
(void) peer_connection_down;
#else
PeerConnection peer;
#ifdef _GLIB_ADDRESS_SANITIZER
g_test_message ("Ensure that no GCancellableSource are leaked");
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/2313");
#endif
peer_connection_up (&peer);
do_roundtrip (peer.server_connection, peer.client_connection);
peer_connection_down (&peer);
#endif
}
static gint items_changed_count;
@ -1146,17 +1145,16 @@ test_dbus_subscriptions (void)
static void
test_dbus_peer_subscriptions (void)
{
#ifdef _GLIB_ADDRESS_SANITIZER
g_test_incomplete ("FIXME: Leaks a GCancellableSource, see glib#2313");
(void) peer_connection_up;
(void) peer_connection_down;
#else
PeerConnection peer;
#ifdef _GLIB_ADDRESS_SANITIZER
g_test_message ("Ensure that no GCancellableSource are leaked");
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/2313");
#endif
peer_connection_up (&peer);
do_subscriptions (peer.server_connection, peer.client_connection);
peer_connection_down (&peer);
#endif
}
static void

View File

@ -800,16 +800,38 @@ g_node_depth_traverse_level (GNode *node,
* efficient than the other orders.
*
* Specifies the type of traversal performed by g_tree_traverse(),
* g_node_traverse() and g_node_find(). The different orders are
* illustrated here:
* g_node_traverse() and g_node_find().
*
* The different orders are illustrated here:
*
* - In order: A, B, C, D, E, F, G, H, I
* ![](Sorted_binary_tree_inorder.svg)
* <picture>
* <source srcset="Sorted_binary_tree_inorder-dark.svg"
* media="(prefers-color-scheme: dark)">
* <img src="Sorted_binary_tree_inorder.svg"
* alt="Sorted binary tree, in-order traversal">
* </picture>
* - Pre order: F, B, A, D, C, E, G, I, H
* ![](Sorted_binary_tree_preorder.svg)
* <picture>
* <source srcset="Sorted_binary_tree_preorder-dark.svg"
* media="(prefers-color-scheme: dark)">
* <img src="Sorted_binary_tree_preorder.svg"
* alt="Sorted binary tree, pre-order traversal">
* </picture>
* - Post order: A, C, E, D, B, H, I, G, F
* ![](Sorted_binary_tree_postorder.svg)
* <picture>
* <source srcset="Sorted_binary_tree_postorder-dark.svg"
* media="(prefers-color-scheme: dark)">
* <img src="Sorted_binary_tree_postorder.svg"
* alt="Sorted binary tree, post-order traversal">
* </picture>
* - Level order: F, B, G, A, D, I, C, E, H
* ![](Sorted_binary_tree_breadth-first_traversal.svg)
* <picture>
* <source srcset="Sorted_binary_tree_breadth-first_traversal-dark.svg"
* media="(prefers-color-scheme: dark)">
* <img src="Sorted_binary_tree_breadth-first_traversal.svg"
* alt="Sorted binary tree, breadth-first level order traversal">
* </picture>
*/
/**