Skip to content

Fiber: fiber storage・スケジューラ・backtrace 系の 14 メソッドを追加#3299

Open
Watson1978 wants to merge 4 commits into
rurema:masterfrom
Watson1978:fiber-scheduler-storage-backtrace
Open

Fiber: fiber storage・スケジューラ・backtrace 系の 14 メソッドを追加#3299
Watson1978 wants to merge 4 commits into
rurema:masterfrom
Watson1978:fiber-scheduler-storage-backtrace

Conversation

@Watson1978

Copy link
Copy Markdown
Contributor

概要

Ruby 4.0 に存在するのにリファレンスに項目が無い [c:Fiber] のメソッド 14 個を追加しました。
あわせて [m:Fiber.new] のキーワード引数 (blocking: / storage:) と、
クラスの説明に「ノンブロッキングファイバーとスケジューラ」の節を追加しています。

追加したメソッド

Ruby 3.0 で追加:

  • Fiber.blocking?
  • Fiber.schedule
  • Fiber.scheduler
  • Fiber.set_scheduler
  • Fiber#backtrace
  • Fiber#backtrace_locations
  • Fiber#blocking?

Ruby 3.1 で追加:

  • Fiber.current_scheduler

Ruby 3.2 で追加:

  • Fiber.[]
  • Fiber.[]=
  • Fiber.blocking
  • Fiber#storage
  • Fiber#storage=

Ruby 3.3 で追加:

  • Fiber#kill

登場バージョンの確認

各メソッドが定義されているかを 2.7 / 3.1 / 3.2 / 3.3 / 3.4 / 4.0 の実機で確認し、
3.0 と 3.1 の切り分けは ruby/ruby の cont.crb_define_singleton_method
追加されたコミットと、それを含む最初のタグから判断しました。

  • Fiber.blockingIntroduce Fiber.blocking{} for bypassing the fiber scheduler (v3_2_0)
  • Fiber.current_scheduler … v3_1_0 に含まれるコミットで追加
  • Fiber#storage 系 … Introduce Fiber#storage for inheritable fiber-scoped variables (v3_2_0)
  • Fiber#killAdd Fiber#kill, similar to Thread#kill. (v3_3_0)

実機の挙動が rdoc と異なる点

記述は実機に合わせています。

  1. Fiber#backtrace は終了後に空の配列を返します。
    rdoc の例には # It is nil after the fiber is finished とありますが、
    3.1 / 3.2 / 3.3 / 3.4 / 4.0 のいずれでも [] が返りました。
  2. Fiber#kill の返り値は rdoc では nil となっていますが、実際は self を返します
    (すでに kill 済みのファイバーに対しては false)。3.3 / 3.4 / 4.0 で確認しました。
  3. Fiber.[] / Fiber.[]= のキーは 3.3 までは Symbol のみですが、
    3.4 以降は String も受け付けます (Symbol に変換されます)。
    この差は #@since 3.4 で分岐しました。
    なお Fiber.new(storage:) に渡す Hash のキーは 4.0 でも Symbol のみです。

記述の方針

docs/HowToWriteMethodEntry.md にならい、Fiber#storageFiber#storage=
getter/setter の対として 1 つのエントリにまとめました。
Fiber.[]Fiber.[]= は引数と説明が異なるため、
[c:Hash] や [c:Ractor] の既存エントリと同様に分けています。

補足

  • Fiber.new は既定でノンブロッキングなファイバーを生成します
    (Fiber.new {}.blocking? は false)。誤解しやすい点なので、
    クラスの説明の節と blocking: の説明の両方で触れています。
  • スケジューラの実体である Fiber::Scheduler は Ruby では定数として定義されておらず
    (rdoc 専用)、るりまにも項目がありません。そのため [c:...] のリンクにはせず、
    「Ruby 本体の Fiber::Scheduler のドキュメントを参照」という書き方にしています。

検証

  • rake check_format / check_blank_lines / check_indent_in_samplecode / check_single_space_indent
  • bitclust update --markdowntree=manual/api を 2.7.0 / 3.0 / 3.2 / 3.4 / 4.0 で実行し、
    エラーが出ないこと、および各バージョンで登録されるメソッドが上記の追加バージョンと
    一致することを確認しました。
  • 記載したサンプルコードはすべて実機で実行し、出力を確認しています。

🤖 Generated with Claude Code

実機で登場バージョンを確認し、それぞれ #@SInCE で分岐した。

3.0 で追加:
  Fiber.blocking?            現在の実行コンテキストがブロッキングか
  Fiber.schedule             スケジューラ経由でノンブロッキングに実行
  Fiber.scheduler            現在のスレッドのスケジューラ
  Fiber.set_scheduler        スケジューラの設定
  Fiber#backtrace            ファイバーごとの実行スタック
  Fiber#backtrace_locations  同上 (Thread::Backtrace::Location の配列)
  Fiber#blocking?            self がブロッキングなファイバーか

3.1 で追加:
  Fiber.current_scheduler    ノンブロッキング時のみ返るスケジューラ

3.2 で追加:
  Fiber.[] / Fiber.[]=       fiber storage の読み書き
  Fiber.blocking             ブロックの実行中だけブロッキングにする
  Fiber#storage / #storage=  fiber storage 全体の取得と設定

3.3 で追加:
  Fiber#kill                 ファイバーの終了

Fiber#storage と Fiber#storage= は getter/setter の対なので、
docs/HowToWriteMethodEntry.md にならって 1 つのエントリにまとめた。
Fiber.[] と Fiber.[]= は引数と説明が異なるため、Hash や Ractor の
既存エントリと同様に分けている。

あわせて Fiber.new のキーワード引数 (blocking: / storage:) をバージョンごとに
分岐して追加し、クラスの説明に「ノンブロッキングファイバーとスケジューラ」の
節を設けた。スケジューラ関連のメソッドは単体では説明しづらいため、この節から
参照する形にしている。Fiber.new が既定でノンブロッキングなファイバーを生成する
点は誤解しやすいので、節と blocking: の説明の両方で触れた。

rdoc と実機の挙動が食い違う箇所は実機に合わせた。
  - Fiber#backtrace は終了後 nil ではなく [] を返す (3.1〜4.0 で確認)
  - Fiber#kill の返り値は nil ではなく self (kill 済みなら false)
また Fiber.[] のキーは 3.4 以降 String も受け付けるため、その旨を #@SInCE 3.4 で
分けて書いている (Fiber.new(storage:) に渡す Hash のキーは 4.0 でも Symbol のみ)。

なお Fiber::Scheduler は Ruby では定数として定義されておらず rdoc 上の存在なので、
[c:...] のリンクにはせず本文で参照する形にした。

bitclust のデータベース生成を 2.7.0 / 3.0 / 3.1 / 3.2 / 3.3 / 3.4 / 4.0 で実行して
エラーが出ないこと、および登録されるメソッドが 0 / 7 / 8 / 13 / 14 / 14 / 14 件と
追加バージョンどおりになることを確認済み。4.0 の静的 HTML も生成し、リンクが
すべて解決されること (compileerror が出ないこと) を確認した。サンプルコードは
すべて実機で実行して出力を確認している。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@znz

znz commented Jul 24, 2026

Copy link
Copy Markdown
Member

レビューしました。385 行の大きな追加ですが、since の版分岐(3.0/3.1/3.2/3.3/3.4)・Fiber.new のシグネチャ3分岐・backtrace の引用符分岐など、細部までほぼ正確でした。1 箇所だけ小さな修正提案があります。

検証できた点(実機 3.0.7〜4.0.6 + 描画)

  • since マトリクス完全一致: blocking?/#blocking?/schedule/scheduler/set_scheduler/#backtrace/#backtrace_locations=3.0、current_scheduler=3.1、[]/[]=/blocking/storage/storage==3.2、kill=3.3。Fiber.newstorage: は 3.2 から受理(3.0 は ArgumentError: unknown keyword: :storage)。
  • Fiber.blocking?(クラス)は 1(Integer)/Fiber#blocking?(インスタンス)は true(bool) の区別を実測で確認(記載どおり)。
  • Fiber#kill(戻り値 self/false・ensure 実行・開始前 kill も終了状態化)、schedule(No scheduler is available!)、set_scheduler(Scheduler must implement #block)、storage= の実験警告(Fiber#storage= is experimental ...-W:no-experimental で抑制)をすべて確認。
  • backtrace の引用符分岐: 3.3 以前 `yield'/`level3'、3.4 以降 'Fiber.yield'/'Object#level3' を版別に実測確認。
  • 描画: 入れ子ディレクティブ・Fiber.new の3分岐(各版で1署名のみ)・[m:Fiber.\[\]] 等のエスケープ参照・[ref:c:Fiber#nonblocking] アンカーとも正常、compileerror なし。

修正提案: Fiber#storage の「例: 取得」の出力が 3.4 前提

Fiber#storage の「例: 取得」の

p Fiber.current.storage # => {key: 1}

の出力ですが、storage は 3.2 からのメソッドである一方、この {key: 1} という Hash の inspect 表記は Ruby 3.4 からです。3.2/3.3 で実行すると {:key=>1} になります(実測確認)。このファイルの他の箇所(backtrace など)は #@since 3.4/#@else で表記を出し分けているので、ここも同様に分岐すると 3.2/3.3 のページでも正確になります。

#@since 3.4
p Fiber.current.storage # => {key: 1}
#@else
p Fiber.current.storage # => {:key=>1}
#@end

Fiber.new(storage: {key: 2}) { ... }.resume # => 2 のように出力が 2 のものは影響ありません。該当は Fiber#storage の取得例のこの1箇所だけです。)

🤖 Generated with Claude Code

@Watson1978

Copy link
Copy Markdown
Contributor Author

Ruby 3.0 の実機を用意できたので、版ゲートの根拠を取り直しました。
PR 本文では 3.1〜4.0 での確認と書きましたが、3.0 でも確認済みです。

ruby 3.0.7p220 (2024-04-23 revision 724a071175) [arm64-darwin27] での結果です。

クラスメソッド:       [:blocking?, :schedule, :scheduler, :set_scheduler, :yield]
インスタンスメソッド: [:backtrace, :backtrace_locations, :blocking?, :inspect, :raise, :resume, :to_s]

#@since 3.0 とした 7 件がすべて存在し、それより後の版で追加したものは
いずれも 3.0 に存在しないことを確認しました。

メソッド 記述した版 3.0 での有無
Fiber.blocking? / .schedule / .scheduler / .set_scheduler 3.0 あり
Fiber#backtrace / #backtrace_locations / #blocking? 3.0 あり
Fiber.current_scheduler 3.1 なし
Fiber.[] / .[]= / .blocking / Fiber#storage / #storage= 3.2 なし
Fiber#kill 3.3 なし

Fiber.new のキーワード引数も版ごとに分岐させています。

# ruby 3.0.7
p Fiber.new(blocking: true) {}.blocking?  # => true
Fiber.new(storage: {a: 1}) {}             # ~> ArgumentError: unknown keyword: :storage

rdoc と挙動が異なる点の補足

本文に書いた 2 点について、3.0 でも同じであることを確認しました。

1. Fiber#backtrace は終了後に空の配列を返します。

rdoc の例には # It is nil after the fiber is finished とありますが、
3.0 / 3.1 / 3.2 / 3.3 / 3.4 / 4.0 / 4.1-dev のいずれでも [] でした。

f = Fiber.new { Fiber.yield }
f.resume
f.resume
p f.alive?    # => false
p f.backtrace # => []

2. Fiber.new は既定でノンブロッキングです。

Fiber.new {}.blocking? は 3.0 の時点から false を返します。
誤解しやすいところなので、クラスの説明の節と blocking: の説明の両方で触れています。

なお Fiber#kill の返り値も rdoc では nil となっていますが、実際は self を返し、
すでに kill 済みのファイバーに対しては false を返します (3.3 / 3.4 / 4.0 / 4.1-dev で確認)。

🤖 Generated with Claude Code

Fiber#storage の「例: 取得」で

  p Fiber.current.storage # => {key: 1}

としていたが、この Hash の inspect 表記は 3.4 からのもので、storage が
存在する 3.2 / 3.3 では {:key=>1} になる。同じファイルの backtrace の例と
同様に #@SInCE 3.4 / #@else で出し分けた。

3.2 / 3.3 / 3.4 / 4.0 でデータベースを生成し、3.3 以前では {:key=>1}、
3.4 以降では {key: 1} が出ることを確認済み。

追加した他の例は出力が数値・nil・bool のみで、この影響を受けない。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Watson1978

Copy link
Copy Markdown
Contributor Author

レビューありがとうございます。ご指摘の 1 箇所を修正しました (a104095)。

Fiber#storage の「例: 取得」の出力

おっしゃるとおりでした。storage は 3.2 からのメソッドですが、
{key: 1} という Hash の inspect 表記は 3.4 からで、3.2 / 3.3 では {:key=>1} になります。
手元でも確認しました。

3.2.11: {:key=>1}
3.3.12: {:key=>1}
3.4.10: {key: 1}
4.0.6:  {key: 1}

ご提案どおり、同じファイルの backtrace の例と揃えて #@since 3.4 / #@else で分岐しました。

Fiber[:key] = 1
#@since 3.4
p Fiber.current.storage # => {key: 1}
#@else
p Fiber.current.storage # => {:key=>1}
#@end

3.2 / 3.3 / 3.4 / 4.0 でデータベースを生成し、版ごとに意図した表記が出ることを確認しています。

3.2: p Fiber.current.storage # => {:key=>1}
3.3: p Fiber.current.storage # => {:key=>1}
3.4: p Fiber.current.storage # => {key: 1}
4.0: p Fiber.current.storage # => {key: 1}

該当が 1 箇所だけという点も一致しました。追加した他の例は出力が数値・nil・bool のみで、
Hash や Symbol の inspect 表記が変わった影響を受けません。

出力の表記が版によって変わる点は見落としていました。メソッドの有無だけでなく、
例の出力についても版差を確認するようにします。

🤖 Generated with Claude Code

@znz

znz commented Jul 25, 2026

Copy link
Copy Markdown
Member

修正(a104095)を確認しました。マージ可と考えます。 対応ありがとうございます。

Fiber#storage の「例: 取得」を #@since 3.4 / #@else で分岐し、3.4 以降は {key: 1}、3.2/3.3 は {:key=>1} になる形を確認しました(同ファイルの backtrace の分岐と揃っていて良いと思います)。他の追加例は出力が数値・nil・bool のみで表記の版差の影響を受けない、という点も一致します。

3.0 実機での since 根拠の取り直しや、Fiber#backtrace が終了後 [] を返す点・Fiber#kill の戻り値が self/false である点(rdoc と異なる)の補足も、こちらの実測と一致しています。丁寧な確認ありがとうございました。

🤖 Generated with Claude Code

Comment thread manual/api/_builtin/Fiber.md Outdated
Comment thread manual/api/_builtin/Fiber.md Outdated
znz さんの suggestion 2 件を反映した。

- クラス説明の「Fiber::Scheduler のドキュメント」を、rdoc への
  リンク (https://docs.ruby-lang.org/en/4.0/Fiber/Scheduler.html) にした。
- Fiber.blocking? のシグネチャを `-> bool | Integer` から
  `-> false | 1` にした。返り値は実装上 false か 1 に固定されており
  (cont.c の rb_fiber_s_blocking_p が Qfalse か INT2NUM(blocking) を返す)、
  3.0〜4.0 の実機でも false / 1 以外は返らないことを確認済み。
  本文も「真を返す」から「1 を返す」に合わせた。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Watson1978 added a commit to Watson1978/doctree that referenced this pull request Jul 25, 2026
リンク切れの指摘への対応。IO::Buffer は段階的に追加している途中なので、
未収録のものは収録する回までコードスパンにし、#@# コメントを残した。

- IO::Buffer#set_value / IO::Buffer.map (指摘のあった2件)
- IO::Buffer.for (4箇所。うち2箇所は rurema#3301 由来)
- IO::Buffer#locked (rurema#3295 由来)。LOCKED 定数の説明が
  「[m:IO::Buffer#locked] を参照してください」だけだったので、
  本 PR で追加する locked? で調べられる旨の説明に書き換えた
- Fiber::Scheduler (rurema#3278 由来) は rdoc へのリンクにした (rurema#3299 と同じ扱い)

あわせて、参考として指摘のあった IO::Buffer.new の説明を
「PAGE_SIZE より大きい場合」から「PAGE_SIZE 以上の場合」に修正した。
io_buffer.c は size >= RUBY_IO_BUFFER_PAGE_SIZE で判定しており、
実機でも 3.1〜4.0 のすべてで size == PAGE_SIZE のとき mapped? が true になる。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- [m:Kernel#caller] / [m:Kernel#caller_locations] (3箇所) は、caller と
  caller_locations が functions.md で module_function として定義されているため
  /method/Kernel/i/... を指してリンク切れになる。[m:Kernel?.caller] /
  [m:Kernel?.caller_locations] に修正した。rurema#3308 での同種の指摘を受けたもの。
- Fiber.scheduler は 3.0 から存在するが、その SEE が参照する
  Fiber.current_scheduler は 3.1 から (3.0.7 では respond_to? が false)。
  3.0 のページでリンク切れになるため、SEE 行を分けて #@SInCE 3.1 で囲んだ。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Watson1978

Copy link
Copy Markdown
Contributor Author

別 PR (#3308) のレビューで [m:Kernel#caller_locations] がリンク切れになるとご指摘
いただき、同じ問題がこの PR にもあることに気づいたので直しました。

Kernel のモジュール関数への参照を修正

Fiber.md の 3 箇所です。caller / caller_locations はどちらも functions.md
module_function として定義されているため、Kernel#... と書くと
/method/Kernel/i/... を指してリンク切れになります。

480:引数の意味は [m:Kernel#caller] と同じです。
520:- **SEE** [m:Fiber#backtrace_locations], [m:Kernel#caller]
541:- **SEE** [m:Fiber#backtrace], [m:Kernel#caller_locations]

記法は .# ではなく ?. にしています。docs/ReferenceManualFormatDigest.md
「モジュール関数 [m:Kernel?.open] (旧記法の「.#」は「?.」に変わりました)」と
あり、manual/api 配下の実使用も ?. が 724 箇所に対して .# が 3 箇所なので、
移行後の記法に揃えました。

Fiber.scheduler の SEE が 3.0 で切れていた点も直しました

上の修正のついでに版ごとの突き合わせをしたところ、#3309 でご指摘いただいたのと
同じ型の切れがもう 1 件見つかりました。

Fiber.scheduler は 3.0 から存在しますが、その - **SEE** が参照している
Fiber.current_scheduler は 3.1 からです(実機でも 3.0.7 は
Fiber.respond_to?(:current_scheduler) が false)。そのため 3.0 のページで
リンク切れになっていました。

- **SEE** [m:Fiber.set_scheduler]
#@since 3.1
- **SEE** [m:Fiber.current_scheduler]
#@end

と分けています。

検証

版ごとの DB のエントリ本文を走査して、Fiber.md 由来の全エントリの
[m:...] / [c:...] を突き合わせました。2.7.0 / 3.0 / 3.1 / 4.0 のいずれも NG 0 件です
(修正前は 3.0 で [m:Fiber.current_scheduler] が NG になります)。

rake check_formatcheck_blank_lines / check_indent_in_samplecode /
check_single_space_indent も通っています。

🤖 Generated with Claude Code

@znz

znz commented Jul 25, 2026

Copy link
Copy Markdown
Member

追加の修正ありがとうございます。Fiber.md[m:Kernel#caller] / [m:Kernel#caller_locations](3 箇所)が [m:Kernel?.caller] / [m:Kernel?.caller_locations] に直っているのを確認しました。caller / caller_locationsfunctions.mdmodule_function なので、module function 記法(?.)が正しく、生成後の href も method/Kernel/m/caller.html / caller_locations.html に解決します。ファイル内に [m:Kernel#...] の module function 参照が残っていないことも確認しました。

3.0 / 4.0 で statichtml をビルドして compileerror 0・該当ページのリンク解決も確認済みです。マージ可と考えます。 ありがとうございました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants