Skip to content

Commit f47fb5e

Browse files
authored
Merge pull request #27 from frengor/dev
* Update version to 0.3.0 * Add cleaners and weak pointers * Add the derive macros for `Trace` and `Finalize` * Add no-std support * Improve documentation * Remove invalid `Cc`s and rework `Cc::new_cyclic` to use weak pointers * Countless small fixes and improvements
2 parents 30ab4bc + c6e8004 commit f47fb5e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+4384
-1200
lines changed

.github/workflows/bench.yml

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ on:
55
types: [labeled]
66

77
env:
8+
IAI_CALLGRIND_VERSION: 0.7.3
89
CARGO_TERM_COLOR: always
10+
IAI_CALLGRIND_COLOR: never
911
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
1012

1113
jobs:
@@ -22,20 +24,22 @@ jobs:
2224
with:
2325
ref: ${{ github.event.pull_request.base.ref }}
2426
- uses: dtolnay/rust-toolchain@stable
27+
- uses: taiki-e/install-action@valgrind
28+
- uses: taiki-e/install-action@cargo-binstall
29+
- name: Install iai-callgrind-runner
30+
run: cargo binstall --no-confirm --no-symlinks iai-callgrind-runner --version ${IAI_CALLGRIND_VERSION}
2531
- name: Bench base branch
2632
run: |
27-
sudo apt-get update
28-
sudo apt-get install -y valgrind
2933
cargo update
30-
cargo bench -F full -q --bench bench > "${WORKSPACE}"/____old_results.txt
34+
cargo bench -q --bench bench > "${WORKSPACE}"/____old_results.txt
3135
- uses: actions/checkout@v3
3236
with:
3337
ref: ${{ github.event.pull_request.head.ref }}
3438
clean: false
3539
- name: Bench head branch
3640
run: |
3741
cargo update
38-
cargo bench -F full -q --bench bench > "${WORKSPACE}"/____results.txt
42+
cargo bench -q --bench bench > "${WORKSPACE}"/____results.txt
3943
- uses: actions/checkout@v3
4044
with:
4145
ref: ${{ github.event.pull_request.base.ref }}
@@ -44,36 +48,44 @@ jobs:
4448
run: |
4549
cargo clean
4650
cargo update
47-
cargo bench --no-default-features -F auto-collect -q --bench bench > "${WORKSPACE}"/____old_results_no_finalization.txt
51+
cargo bench --no-default-features -F std,derive,auto-collect -q --bench bench > "${WORKSPACE}"/____old_results_no_finalization.txt
4852
- uses: actions/checkout@v3
4953
with:
5054
ref: ${{ github.event.pull_request.head.ref }}
5155
clean: false
5256
- name: Bench head branch no finalization
5357
run: |
5458
cargo update
55-
cargo bench --no-default-features -F auto-collect -q --bench bench > "${WORKSPACE}"/____results_no_finalization.txt
59+
cargo bench --no-default-features -F std,derive,auto-collect -q --bench bench > "${WORKSPACE}"/____results_no_finalization.txt
5660
- name: Write comment
5761
run: |
5862
{
5963
echo '<strong>Benchmark results:</strong>'
6064
echo ''
65+
echo '```txt'
6166
cat "${WORKSPACE}"/____results.txt
67+
echo '```'
6268
echo ''
6369
echo '<details><summary><strong>Old results:</strong></summary><p>'
6470
echo ''
71+
echo '```txt'
6572
cat "${WORKSPACE}"/____old_results.txt
73+
echo '```'
6674
echo '</p></details>'
6775
echo ''
6876
echo '---'
6977
echo ''
7078
echo '<details><summary><strong>Results without finalization:</strong></summary><p>'
7179
echo ''
80+
echo '```txt'
7281
cat "${WORKSPACE}"/____results_no_finalization.txt
82+
echo '```'
7383
echo ''
7484
echo '<details><summary><strong>Old results without finalization:</strong></summary><p>'
7585
echo ''
86+
echo '```txt'
7687
cat "${WORKSPACE}"/____old_results_no_finalization.txt
88+
echo '```'
7789
echo '</p></details></p></details>'
7890
} > "${WORKSPACE}"/__result.txt
7991
- uses: thollander/[email protected]

.github/workflows/build.yml

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,42 @@ on: [push, pull_request, workflow_dispatch]
55
env:
66
CARGO_TERM_COLOR: always
77
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
8+
RUSTDOCFLAGS: -D warnings
89

910
jobs:
10-
build-on-stable:
11+
on-stable:
1112
runs-on: ubuntu-latest
13+
env:
14+
RUSTFLAGS: -D warnings
1215
steps:
1316
- uses: actions/checkout@v3
1417
- uses: dtolnay/rust-toolchain@stable
15-
- name: Build
18+
with:
19+
components: clippy
20+
- uses: taiki-e/install-action@cargo-hack
21+
- name: Check and Clippy
22+
# Keep "std" feature always enabled on stable to avoid needing the no-std related nightly features
1623
run: |
17-
cargo build --no-default-features --verbose --workspace
18-
cargo build --verbose --workspace
19-
cargo build -F full --verbose --workspace
20-
build-on-nightly:
24+
cargo hack check --all-targets --feature-powerset --ignore-unknown-features --workspace --skip nightly --clean-per-run --verbose -F std
25+
cargo hack check --all-targets --feature-powerset --ignore-unknown-features --workspace --skip nightly --clean-per-run --verbose -F std --release
26+
cargo hack clippy --all-targets --feature-powerset --ignore-unknown-features --workspace --skip nightly --clean-per-run --verbose -F std -- -D warnings
27+
on-nightly:
2128
runs-on: ubuntu-latest
2229
steps:
2330
- uses: actions/checkout@v3
2431
- uses: dtolnay/rust-toolchain@nightly
25-
- name: Build
32+
with:
33+
components: clippy
34+
- uses: taiki-e/install-action@cargo-hack
35+
- name: Check and Clippy (nightly)
2636
run: |
27-
cargo build --no-default-features -F nightly --verbose --workspace
28-
cargo build -F nightly --verbose --workspace
29-
cargo build -F full,nightly --verbose --workspace
37+
cargo hack check --all-targets --feature-powerset --ignore-unknown-features --workspace --clean-per-run --verbose -F nightly
38+
cargo hack clippy --all-targets --feature-powerset --ignore-unknown-features --workspace --clean-per-run --verbose -F nightly
39+
# cargo hack clippy --all-targets --feature-powerset --ignore-unknown-features --workspace --clean-per-run --verbose -F nightly -- -D warnings
40+
docs:
41+
runs-on: ubuntu-latest
42+
steps:
43+
- uses: actions/checkout@v3
44+
- uses: dtolnay/rust-toolchain@nightly
45+
- name: Build docs
46+
run: cargo doc --no-deps --all-features --verbose

.github/workflows/miri.yml

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ jobs:
1717
rustup toolchain install nightly --component miri
1818
rustup override set nightly
1919
cargo miri setup
20-
- name: Run tests (no features)
21-
run: cargo miri test --no-default-features -F pedantic-debug-assertions --verbose --workspace
22-
- name: Run tests (default features)
23-
run: cargo miri test -F pedantic-debug-assertions --verbose --workspace
24-
- name: Run tests (feature full)
25-
run: cargo miri test -F full,pedantic-debug-assertions --verbose --workspace
26-
- name: Run tests (every feature)
27-
run: cargo miri test --all-features --verbose --workspace
20+
- uses: taiki-e/install-action@cargo-hack
21+
# Always skip "derive" since derive macro tests are skipped on Miri
22+
# Also always keep "pedantic-debug-assertions" enabled to reduce build times
23+
# Note: no need to use --workspace here, since there's no unsafe in rust-cc-derive
24+
- name: Run tests
25+
# Keep "std" feature always enabled here to avoid needing the no-std related nightly features
26+
run: cargo hack miri test --feature-powerset --skip nightly,derive --verbose -F std,pedantic-debug-assertions
27+
- name: Run tests (nightly)
28+
run: cargo hack miri test --feature-powerset --skip derive --verbose -F nightly,pedantic-debug-assertions

.github/workflows/test.yml

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,21 @@ env:
77
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
88

99
jobs:
10-
test:
10+
on-stable:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v3
14+
- uses: dtolnay/rust-toolchain@stable
15+
- uses: taiki-e/install-action@cargo-hack
16+
- name: Run tests
17+
# Keep "std" feature always enabled on stable to avoid needing the no-std related nightly features
18+
run: |
19+
cargo hack test --feature-powerset --ignore-unknown-features --workspace --skip nightly --verbose -F std
20+
on-nightly:
1121
runs-on: ubuntu-latest
1222
steps:
1323
- uses: actions/checkout@v3
1424
- uses: dtolnay/rust-toolchain@nightly
15-
- name: Build (no features)
16-
run: cargo build --no-default-features -F pedantic-debug-assertions --verbose --workspace
17-
- name: Run tests (no features)
18-
run: cargo test --no-default-features -F pedantic-debug-assertions --verbose --workspace
19-
- name: Build (default features)
20-
run: cargo build -F pedantic-debug-assertions --verbose --workspace
21-
- name: Run tests (default features)
22-
run: cargo test -F pedantic-debug-assertions --verbose --workspace
23-
- name: Build (feature full)
24-
run: cargo build -F full,pedantic-debug-assertions --verbose --workspace
25-
- name: Run tests (feature full)
26-
run: cargo test -F full,pedantic-debug-assertions --verbose --workspace
27-
- name: Build (every feature)
28-
run: cargo build --all-features --verbose --workspace
29-
- name: Run tests (every feature)
30-
run: cargo test --all-features --verbose --workspace
25+
- uses: taiki-e/install-action@cargo-hack
26+
- name: Run tests
27+
run: cargo hack test --feature-powerset --ignore-unknown-features --workspace --verbose -F nightly

CONTRIBUTING.md

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,20 @@ The core idea behind the algorithm is the same as the one presented by Lins in [
1212
and by Bacon and Rajan in ["Concurrent Cycle Collection in Reference Counted Systems"](https://pages.cs.wisc.edu/~cymen/misc/interests/Bacon01Concurrent.pdf).
1313
However, the implementation differs in order to make the collector faster and more resilient to random panics and failures in general.
1414

15-
> **N.B.:** `rust-cc` is *not* strictly an implementation of the algorithm shown in the linked papers and it's never been
15+
> [!IMPORTANT]
16+
> `rust-cc` is *not* strictly an implementation of the algorithm shown in the linked papers and it's never been
1617
> intended as such. Feel free to propose any kind of improvement!
1718
1819
The following is a summarized version of the collection algorithm:
1920
When a `Cc` smart pointer is dropped, the reference count (RC) is decreased by 1. If it reaches 0, then the allocated
20-
object pointed by the `Cc` (called `CcOnHeap`) is dropped, otherwise the `Cc` is put into the `POSSIBLE_CYCLES` list.
21+
object pointed by the `Cc` (called `CcBox`) is dropped, otherwise the `Cc` is put into the `POSSIBLE_CYCLES` list.
2122
The `POSSIBLE_CYCLES` is an (intrusive) list which contains the possible roots of cyclic garbage.
2223
Sometimes (see [`crate::trigger_collection`](./src/lib.rs)), when creating a new `Cc` or when `collect_cycles` is called,
2324
the objects inside the `POSSIBLE_CYCLES` list are checked to see if they are part of a garbage cycle.
2425

2526
Therefore, they undergo two tracing passes:
2627
- **Trace Counting:** during this phase, starting from the elements inside `POSSIBLE_CYCLES`,
27-
objects are traced to count the amount of pointers to each `CcOnHeap` that are reachable from the list's `Cc`s.
28+
objects are traced to count the amount of pointers to each `CcBox` that is reachable from the list's `Cc`s.
2829
The `tracing_counter` "field" (see the [`counter_marker` module](./src/counter_marker.rs) for more info) is used to keep track of this number.
2930
<details>
3031
<summary>About tracing_counter</summary>
@@ -33,20 +34,32 @@ Therefore, they undergo two tracing passes:
3334
The invariant regarding this second counter is that it must always be between 0 and RC inclusively.
3435
</p>
3536
</details>
36-
- **Trace Roots:** now, every `CcOnHeap` which has the RC strictly greater than `tracing_counter` can be considered a root,
37+
- **Trace Roots:** now, every `CcBox` which has the RC strictly greater than `tracing_counter` can be considered a root,
3738
since it must exist a `Cc` pointer which points at it that hasn't been traced before. Thus, a trace is started from these roots,
3839
and all objects not reached during this trace are finalized/deallocated (the story is more complicated because of possible
39-
object resurrections, see comments at the end of the [`collect` function](./src/lib.rs)).
40+
object resurrections, see the comments in [lib.rs](./src/lib.rs)).
4041
Note that this second phase is correct only if the graph formed by the pointers is not changed between the two phases. Thus,
4142
this is a key requirement of the `Trace` trait and one of the reasons it is marked `unsafe`.
4243

43-
### Future improvements
44+
# Writing documentation
4445

45-
If you're interested in the project, there are some additions which would be nice to have:
46-
- weak pointers
47-
- cleaners (https://docs.oracle.com/javase/9/docs/api/java/lang/ref/Cleaner.html)
48-
- weak pointers and cleaners as optional features to explicitly enable
49-
- `Cc::new_cyclic` as optional feature (enabled by default) maybe?
46+
Docs are always built with every feature enabled. This makes it easier to write and maintain the documentation.
5047

51-
**Already done:**
52-
- finalization as optional feature
48+
However, this also makes it more difficult to write examples, as those must pass CI even when some of the features they
49+
require are disabled. As such, examples are marked as `ignore`d if a feature they need is missing:
50+
```rust
51+
#![cfg_attr(
52+
feature = "derive",
53+
doc = r"```rust"
54+
)]
55+
#![cfg_attr(
56+
not(feature = "derive"),
57+
doc = r"```rust,ignore"
58+
)]
59+
#![doc = r"# use rust_cc::*;
60+
# use rust_cc_derive::*;
61+
62+
// Example code
63+
64+
```"]
65+
```

Cargo.toml

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,64 @@ authors.workspace = true
66
readme = "README.md"
77
repository.workspace = true
88
categories.workspace = true
9-
keywords = ["cycle", "cycles", "collector", "garbage", "memory"]
9+
keywords = ["cycle-collector", "garbage-collector", "gc", "reference-counting", "memory"]
1010
license.workspace = true
1111
edition.workspace = true
1212

1313
[workspace]
1414
members = ["derive"]
1515

1616
[workspace.package]
17-
version = "0.2.0"
17+
version = "0.3.0" # Also update in [dependencies.rust-cc-derive.version]
1818
authors = ["fren_gor <[email protected]>"]
1919
repository = "https://github.com/frengor/rust-cc"
20-
categories = ["memory-management"]
20+
categories = ["memory-management", "no-std"]
2121
license = "MIT OR Apache-2.0"
2222
edition = "2021"
2323

24-
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
25-
2624
[features]
27-
default = ["auto-collect", "finalization"]
28-
full = ["auto-collect", "finalization"] # Every feature except for "nightly" and "pedantic-debug-assertions"
25+
default = ["auto-collect", "finalization", "derive", "std"]
26+
27+
# Enables support for nightly-only features
2928
nightly = []
29+
30+
# Enables the derive macros for the Trace and Finalize traits
31+
derive = ["dep:rust-cc-derive"]
32+
33+
# Enables automatic executions of the collection algorithm
3034
auto-collect = []
35+
36+
# Enables finalization
3137
finalization = []
38+
39+
# Enables weak pointers
40+
weak-ptr = []
41+
42+
# Enables cleaners
43+
cleaners = ["dep:slotmap", "weak-ptr"]
44+
45+
# Enables support for stdlib, disable for no-std support (requires ELF TLS and nightly)
46+
std = ["slotmap?/std", "thiserror/std"]
47+
48+
# (Internal use only) Enables more debug assertions useful for debugging
3249
pedantic-debug-assertions = []
3350

3451
[dependencies]
35-
thiserror = "1.0.37"
52+
rust-cc-derive = { path = "./derive", version = "=0.3.0", optional = true }
53+
slotmap = { version = "1.0", optional = true }
54+
thiserror = { version = "1.0", package = "thiserror-core", default-features = false }
3655

3756
[dev-dependencies]
38-
iai = "0.1.1"
57+
iai-callgrind = "=0.7.3" # Also update IAI_CALLGRIND_VERSION in .github/workflows/bench.yml
3958
rand = "0.8.3"
59+
trybuild = "1.0.85"
60+
test-case = "3.3.1"
4061

4162
[[bench]]
4263
name = "bench"
4364
harness = false
65+
required-features = ["std", "derive"]
66+
67+
[package.metadata.docs.rs]
68+
all-features = true
69+
rustdoc-args = ["--cfg", "doc_auto_cfg", "--generate-link-to-definition"]

0 commit comments

Comments
 (0)