Compare commits
6 Commits
2d0a0683fb
...
8ceae00c44
Author | SHA1 | Date | |
---|---|---|---|
|
8ceae00c44 | ||
|
d3cb9d638d | ||
|
a931a75c4f | ||
|
cc6448b66b | ||
|
1e1b082930 | ||
|
92e6602053 |
@ -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->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->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->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->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->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->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->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->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 |
@ -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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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 |
758
docs/reference/glib/Sorted_binary_tree_inorder-dark.svg
Normal file
After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
755
docs/reference/glib/Sorted_binary_tree_postorder-dark.svg
Normal file
After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
755
docs/reference/glib/Sorted_binary_tree_preorder-dark.svg
Normal file
After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
@ -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]]
|
||||
|
@ -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 it’s 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 we’re 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,
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
@ -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
|
||||
|
34
glib/gnode.c
@ -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>
|
||||
*/
|
||||
|
||||
/**
|
||||
|