From 099df0b40b215b2fc5db59569d45c59ee48111a7 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Tue, 22 Jul 2025 16:12:46 +0200 Subject: [PATCH 01/22] CI: ubuntu.yml: Add GitHub Actions s390x case Add the s390x case using GitHub Actions ppc64le/s390x service. https://github.com/IBM/actionspz We can run the ppc64le/s390x cases only in the registered upstream repositories. https://github.com/IBM/actionspz/blob/main/docs/FAQ.md#what-about-forked-repos The following matrix upstream logic is to skip the ppc64le/s390x in the downstream (fork) repositories. ``` + upstream: + - ${{ github.repository == 'ruby/ruby' }} ``` Use the "os" list to determine the excluded ppc64le/s390x cases by using the "exclude" syntax. Because the "exclude" syntax are executed before the "include" syntax. Add the ubuntu-24.04-ppc64le as a comment, because the GitHub Actions ppc64le case has the following test errors and failures. https://bugs.ruby-lang.org/issues/21534 --- .github/workflows/ubuntu.yml | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index fa271e5cb57c61..ed56cd6600779f 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -24,6 +24,22 @@ jobs: make: strategy: matrix: + test_task: [check] + configure: [''] + arch: [''] + os: + - ubuntu-24.04 + - ubuntu-24.04-arm + # FIXME Comment out ppc64le due to failing tests on GitHub Actions + # ppc64le + # https://bugs.ruby-lang.org/issues/21534 + # - ubuntu-24.04-ppc64le + - ubuntu-24.04-s390x + # The ppc64le/s390x runners work only in the registered repositories. + # They don't work in forked repositories. + # https://github.com/IBM/actionspz/blob/main/docs/FAQ.md#what-about-forked-repos + upstream: + - ${{ github.repository == 'ruby/ruby' }} include: - test_task: check configure: 'cppflags=-DVM_CHECK_MODE' @@ -36,10 +52,11 @@ jobs: - test_task: test-bundler-parallel timeout: 50 - test_task: test-bundled-gems - - test_task: check - os: ubuntu-24.04 - - test_task: check - os: ubuntu-24.04-arm + exclude: + - os: ubuntu-24.04-ppc64le + upstream: false + - os: ubuntu-24.04-s390x + upstream: false fail-fast: false env: @@ -72,7 +89,15 @@ jobs: with: ruby-version: '3.1' bundler: none - if: ${{ !endsWith(matrix.os, 'arm') }} + if: ${{ !endsWith(matrix.os, 'arm') && !endsWith(matrix.os, 'ppc64le') && !endsWith(matrix.os, 's390x') }} + + # Avoid possible test failures with the zlib applying the following patch + # on s390x CPU architecture. + # https://github.com/madler/zlib/pull/410 + - name: Disable DFLTCC + run: echo "DFLTCC=0" >> $GITHUB_ENV + working-directory: + if: ${{ endsWith(matrix.os, 's390x') }} - uses: ./.github/actions/setup/directories with: From 05b654b43f6d0e92fbc3e1e908d811f031d59e40 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Tue, 22 Jul 2025 16:12:46 +0200 Subject: [PATCH 02/22] CI: ubuntu.yml: Set HOME env on ppc64le and s390x This is a temporary workaround. --- .github/workflows/ubuntu.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index ed56cd6600779f..749a3f3531a453 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -99,6 +99,16 @@ jobs: working-directory: if: ${{ endsWith(matrix.os, 's390x') }} + # A temporary workaround: Set HOME env to pass the step + # ./.github/actions/setup/directories. + # https://github.com/IBM/actionspz/issues/30 + - name: Set HOME env + run: | + echo "HOME: #{HOME}" + echo "HOME=$(ls -d ~)" >> $GITHUB_ENV + working-directory: + if: ${{ endsWith(matrix.os, 'ppc64le') || endsWith(matrix.os, 's390x') }} + - uses: ./.github/actions/setup/directories with: srcdir: src From 9fa87a668836f83ab836d0cbcefb4056622a0ed6 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Tue, 12 Aug 2025 12:32:49 +0200 Subject: [PATCH 03/22] CI: ubuntu.yml: Skip user ground id test on ppc64le and s390x This is a temporary workaround. --- .github/workflows/ubuntu.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 749a3f3531a453..e17d6dc3ed0efb 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -157,6 +157,17 @@ jobs: continue-on-error: true timeout-minutes: 3 + # A temporary workaround: Skip user ground id test + # There is a mismatch between the group IDs of "id -g" and C function + # getpwuid(uid_t uid) pw_gid. + # https://github.com/IBM/actionspz/issues/31 + - name: Skip user group id test + run: | + sed -i.orig '/^ it "returns user group id" do/a\ skip' \ + ../src/spec/ruby/library/etc/struct_passwd_spec.rb + diff -u ../src/spec/ruby/library/etc/struct_passwd_spec.rb{.orig,} || : + if: ${{ endsWith(matrix.os, 'ppc64le') || endsWith(matrix.os, 's390x') }} + - name: make ${{ matrix.test_task }} run: | test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}") From 0019e7c7020e616fae7fb06745d995e3f682683a Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Mon, 11 Aug 2025 11:01:24 -0400 Subject: [PATCH 04/22] Use rb_gc_mark_and_move for autoload_const --- variable.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/variable.c b/variable.c index 76b16b04cb3968..b5ad8343d73db1 100644 --- a/variable.c +++ b/variable.c @@ -2777,27 +2777,15 @@ static const rb_data_type_t autoload_data_type = { }; static void -autoload_const_compact(void *ptr) +autoload_const_mark_and_move(void *ptr) { struct autoload_const *ac = ptr; - ac->module = rb_gc_location(ac->module); - ac->autoload_data_value = rb_gc_location(ac->autoload_data_value); - ac->value = rb_gc_location(ac->value); - ac->file = rb_gc_location(ac->file); - ac->namespace = rb_gc_location(ac->namespace); -} - -static void -autoload_const_mark(void *ptr) -{ - struct autoload_const *ac = ptr; - - rb_gc_mark_movable(ac->module); - rb_gc_mark_movable(ac->autoload_data_value); - rb_gc_mark_movable(ac->value); - rb_gc_mark_movable(ac->file); - rb_gc_mark_movable(ac->namespace); + rb_gc_mark_and_move(&ac->module); + rb_gc_mark_and_move(&ac->autoload_data_value); + rb_gc_mark_and_move(&ac->value); + rb_gc_mark_and_move(&ac->file); + rb_gc_mark_and_move(&ac->namespace); } static size_t @@ -2817,7 +2805,7 @@ autoload_const_free(void *ptr) static const rb_data_type_t autoload_const_type = { "autoload_const", - {autoload_const_mark, autoload_const_free, autoload_const_memsize, autoload_const_compact,}, + {autoload_const_mark_and_move, autoload_const_free, autoload_const_memsize, autoload_const_mark_and_move,}, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY }; From 814eaf336adca17dbad79717519ac06ee22edb4f Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Mon, 11 Aug 2025 11:03:25 -0400 Subject: [PATCH 05/22] Use rb_gc_mark_and_move for autoload_data --- variable.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/variable.c b/variable.c index b5ad8343d73db1..e0a85b8f483ef1 100644 --- a/variable.c +++ b/variable.c @@ -2734,21 +2734,12 @@ struct autoload_data { }; static void -autoload_data_compact(void *ptr) +autoload_data_mark_and_move(void *ptr) { struct autoload_data *p = ptr; - p->feature = rb_gc_location(p->feature); - p->mutex = rb_gc_location(p->mutex); -} - -static void -autoload_data_mark(void *ptr) -{ - struct autoload_data *p = ptr; - - rb_gc_mark_movable(p->feature); - rb_gc_mark_movable(p->mutex); + rb_gc_mark_and_move(&p->feature); + rb_gc_mark_and_move(&p->mutex); } static void @@ -2772,7 +2763,7 @@ autoload_data_memsize(const void *ptr) static const rb_data_type_t autoload_data_type = { "autoload_data", - {autoload_data_mark, autoload_data_free, autoload_data_memsize, autoload_data_compact}, + {autoload_data_mark_and_move, autoload_data_free, autoload_data_memsize, autoload_data_mark_and_move}, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED }; From 37e991b02c8664875007779352aa45e9924f3528 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 12 Aug 2025 23:33:46 +0900 Subject: [PATCH 06/22] [DOC] Use the specified revision RDoc --- .github/workflows/check_misc.yml | 41 ++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/.github/workflows/check_misc.yml b/.github/workflows/check_misc.yml index 4b0da6a0fe9c9a..5267bd35f1c92a 100644 --- a/.github/workflows/check_misc.yml +++ b/.github/workflows/check_misc.yml @@ -61,14 +61,11 @@ jobs: exit $fail working-directory: include - - name: Generate docs - id: docs + - name: Check if to generate documents + id: rdoc run: | - $RDOC -C -x ^ext -x ^lib . - $RDOC --op html . - echo htmlout=ruby-html-${GITHUB_SHA:0:10} >> $GITHUB_OUTPUT - env: - RDOC: ruby -W0 --disable-gems tool/rdoc-srcdir -q + ref=$(sed 's/#.*//;/^rdoc /!d' gems/bundled_gems | awk '{print $4}') + echo ref=$ref >> $GITHUB_OUTPUT # Generate only when document commit/PR if: >- ${{false @@ -80,6 +77,36 @@ jobs: || contains(github.event.pull_request.labels.*.name, 'Documentation') }} + - name: Checkout rdoc + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + repository: ruby/rdoc + ref: ${{ steps.rdoc.outputs.ref }} + path: .bundle/gems/rdoc-0 + if: ${{ steps.rdoc.outputs.ref != '' }} + + - name: Generate rdoc + run: | + set -x + gempath=$(ruby -e 'print Gem.user_dir, "/bin"') + PATH=$gempath:$PATH + gem install --user bundler + bundle config --local path vendor/bundle + bundle install --jobs 4 + bundle exec rake generate + working-directory: .bundle/gems/rdoc-0 + if: ${{ steps.rdoc.outputs.ref != '' }} + + - name: Generate docs + id: docs + run: | + $RDOC -C -x ^ext -x ^lib . + $RDOC --op html . + echo htmlout=ruby-html-${GITHUB_SHA:0:10} >> $GITHUB_OUTPUT + env: + RDOC: ruby -W0 --disable-gems tool/rdoc-srcdir -q + if: ${{ steps.rdoc.outcome == 'success' }} + - name: Upload docs uses: actions/upload-artifact@v4 with: From 8f6f9e88c70bbae08b2830d2bec63c89d6367b27 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 12 Aug 2025 20:41:08 +0900 Subject: [PATCH 07/22] [DOC] Try the latest RDoc --- gems/bundled_gems | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gems/bundled_gems b/gems/bundled_gems index 4fed6a994d8766..4c59614011428c 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -39,7 +39,7 @@ ostruct 0.6.3 https://github.com/ruby/ostruct pstore 0.2.0 https://github.com/ruby/pstore benchmark 0.4.1 https://github.com/ruby/benchmark logger 1.7.0 https://github.com/ruby/logger -rdoc 6.14.2 https://github.com/ruby/rdoc +rdoc 6.14.2 https://github.com/ruby/rdoc f4a90c6010b2346cb5426d4496f5a37a136a82fb # for markdown win32ole 1.9.2 https://github.com/ruby/win32ole irb 1.15.2 https://github.com/ruby/irb 331c4e851296b115db766c291e8cf54a2492fb36 reline 0.6.2 https://github.com/ruby/reline From 58dbfe5285f3b85c6181875220191289087d5603 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 12 Aug 2025 20:02:14 +0900 Subject: [PATCH 08/22] [DOC] Fix a typo --- doc/globals.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/globals.md b/doc/globals.md index db23831a102265..b0bc02b8a6ab58 100644 --- a/doc/globals.md +++ b/doc/globals.md @@ -272,7 +272,7 @@ returns: - `[:rb, _path_]`, where +path+ is the path to the Ruby file to be loaded for the given +feature+. -- `[:so+ _path_]`, where +path+ is the path to the shared object file +- `[:so, _path_]`, where +path+ is the path to the shared object file to be loaded for the given +feature+. - +nil+ if there is no such +feature+ and +path+. From e07510d1a3b07438bcb0aef2b6a913d58f06ff9f Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 12 Aug 2025 20:04:23 +0900 Subject: [PATCH 09/22] [DOC] Markup constants as code --- doc/globals.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/globals.md b/doc/globals.md index b0bc02b8a6ab58..b4ade2f8cbe05d 100644 --- a/doc/globals.md +++ b/doc/globals.md @@ -431,7 +431,7 @@ STDERR # => #> ## Environment -### ENV +### `ENV` A hash of the contains current environment variables names and values: @@ -445,7 +445,7 @@ ENV.take(5) ["GDMSESSION", "ubuntu"]] ``` -### ARGF +### `ARGF` The virtual concatenation of the files given on the command line, or from `$stdin` if no files were given, `"-"` is given, or after From 74b45dc3eebe14582dd0a5aaf3641de07b89adc2 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 12 Aug 2025 20:23:54 +0900 Subject: [PATCH 10/22] [DOC] Use backticks instead of `+` in markdown mode --- doc/globals.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/doc/globals.md b/doc/globals.md index b4ade2f8cbe05d..99429e293ded7a 100644 --- a/doc/globals.md +++ b/doc/globals.md @@ -181,7 +181,7 @@ Aliased as `$-0`. ### `$\\` (Output Record Separator) -An output record separator, initially +nil+. +An output record separator, initially `nil`. English - `$OUTPUT_RECORD_SEPARATOR`, `$ORS`. @@ -256,7 +256,7 @@ English - `$PROCESS_ID`, `$PID`. ### `$?` (Child Status) -Initially +nil+, otherwise the Process::Status object +Initially `nil`, otherwise the Process::Status object created for the most-recently exited child process; thread-local. @@ -270,11 +270,11 @@ by Kernel#load and Kernel#require. Singleton method `$LOAD_PATH.resolve_feature_path(feature)` returns: -- `[:rb, _path_]`, where +path+ is the path to the Ruby file - to be loaded for the given +feature+. -- `[:so, _path_]`, where +path+ is the path to the shared object file - to be loaded for the given +feature+. -- +nil+ if there is no such +feature+ and +path+. +- `[:rb, _path_]`, where `path` is the path to the Ruby file + to be loaded for the given `feature`. +- `[:so, _path_]`, where `path` is the path to the shared object file + to be loaded for the given `feature`. +- `nil` if there is no such `feature` and `path`. Examples: @@ -318,23 +318,23 @@ The value returned by method ARGF.filename. ### `$DEBUG` -Initially +true+ if command-line option `-d` or `--debug` is given, -otherwise initially +false+; +Initially `true` if command-line option `-d` or `--debug` is given, +otherwise initially `false`; may be set to either value in the running program. -When +true+, prints each raised exception to `$stderr`. +When `true`, prints each raised exception to `$stderr`. Aliased as `$-d`. ### `$VERBOSE` -Initially +true+ if command-line option `-v` or `-w` is given, -otherwise initially +false+; -may be set to either value, or to +nil+, in the running program. +Initially `true` if command-line option `-v` or `-w` is given, +otherwise initially `false`; +may be set to either value, or to `nil`, in the running program. -When +true+, enables Ruby warnings. +When `true`, enables Ruby warnings. -When +nil+, disables warnings, including those from Kernel#warn. +When `nil`, disables warnings, including those from Kernel#warn. Aliased as `$-v` and `$-w`. @@ -347,7 +347,7 @@ Whether command-line option `-a` was given; read-only. ### `$-i` Contains the extension given with command-line option `-i`, -or +nil+ if none. +or `nil` if none. An alias of ARGF.inplace_mode. From cefd4a233f4c6504ff7b02ea9b3c11a4385b754b Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 12 Aug 2025 20:37:50 +0900 Subject: [PATCH 11/22] [DOC] Use backticks instead of `` except for nested markups --- doc/globals.md | 148 ++++++++++++++++++++++++------------------------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/doc/globals.md b/doc/globals.md index 99429e293ded7a..4f7dafea2ca94f 100644 --- a/doc/globals.md +++ b/doc/globals.md @@ -14,70 +14,70 @@ require 'English' ### Exceptions -| Variable | English | Contains | -|-------------|--------------------------|----------------------------------------------------| -| $! | $ERROR_INFO | Exception object; set by Kernel#raise. | -| $@ | $ERROR_POSITION | Array of backtrace positions; set by Kernel#raise. | +| Variable | English | Contains | +|-------------|-------------------|----------------------------------------------------| +| `$!` | `$ERROR_INFO` | Exception object; set by Kernel#raise. | +| `$@` | `$ERROR_POSITION` | Array of backtrace positions; set by Kernel#raise. | ### Pattern Matching -| Variable | English | Contains | -|-------------|----------------------------|--------------------------------------------------| -| $~ | $LAST_MATCH_INFO | MatchData object; set by matcher method. | -| $& | $MATCH | Matched substring; set by matcher method. | -| $` | $PRE_MATCH | Substring left of match; set by matcher method. | -| $' | $POST_MATCH | Substring right of match; set by matcher method. | -| $+ | $LAST_PAREN_MATCH | Last group matched; set by matcher method. | -| $1 | | First group matched; set by matcher method. | -| $2 | | Second group matched; set by matcher method. | -| $n | | nth group matched; set by matcher method. | +| Variable | English | Contains | +|---------------|---------------------|--------------------------------------------------| +| `$~` | `$LAST_MATCH_INFO` | MatchData object; set by matcher method. | +| `$&` | `$MATCH` | Matched substring; set by matcher method. | +| `` $` `` | `$PRE_MATCH` | Substring left of match; set by matcher method. | +| `$'` | `$POST_MATCH` | Substring right of match; set by matcher method. | +| `$+` | `$LAST_PAREN_MATCH` | Last group matched; set by matcher method. | +| `$1` | | First group matched; set by matcher method. | +| `$2` | | Second group matched; set by matcher method. | +| $_n_ | | nth group matched; set by matcher method. | ### Separators -| Variable | English | Contains | -|----------------------|-----------------------------------|--------------------------------------------------| -| $/ | $INPUT_RECORD_SEPARATOR | Input record separator; initially newline. | -| $\\\\\\\\ | $OUTPUT_RECORD_SEPARATOR | Output record separator; initially nil. | +| Variable | English | Contains | +|----------|----------------------------|--------------------------------------------| +| `$/` | `$INPUT_RECORD_SEPARATOR` | Input record separator; initially newline. | +| `$\` | `$OUTPUT_RECORD_SEPARATOR` | Output record separator; initially `nil`. | ### Streams -| Variable | English | Contains | -|------------------|-------------------------------------------|-----------------------------------------------------------| -| $stdin | | Standard input stream; initially STDIN. | -| $stdout | | Standard input stream; initially STDIOUT. | -| $stderr | | Standard input stream; initially STDERR. | -| $< | $DEFAULT_INPUT | Default standard input; ARGF or $stdin. | -| $> | $DEFAULT_OUTPUT | Default standard output; initially $stdout. | -| $. | $INPUT_LINE_NUMBER, $NR | Input position of most recently read stream. | -| $_ | $LAST_READ_LINE | String from most recently read stream. | +| Variable | English | Contains | +|-----------|-----------------------------|-----------------------------------------------| +| `$stdin` | | Standard input stream; initially `STDIN`. | +| `$stdout` | | Standard input stream; initially `STDIOUT`. | +| `$stderr` | | Standard input stream; initially `STDERR`. | +| `$<` | `$DEFAULT_INPUT` | Default standard input; `ARGF` or `$stdin`. | +| `$>` | `$DEFAULT_OUTPUT` | Default standard output; initially `$stdout`. | +| `$.` | `$INPUT_LINE_NUMBER`, `$NR` | Input position of most recently read stream. | +| `$_` | `$LAST_READ_LINE` | String from most recently read stream. | ### Processes -| Variable | English | Contains | -|------------------------------------------------|-------------------------------------|--------------------------------------------------------| -| $0 | | Initially, the name of the executing program. | -| $* | $ARGV | Points to the ARGV array. | -| $$ | $PROCESS_ID, $PID | Process ID of the current process. | -| $? | $CHILD_STATUS | Process::Status of most recently exited child process. | -| $LOAD_PATH, $:, $-I | | Array of paths to be searched. | -| $LOADED_FEATURES, $" | | Array of paths to loaded files. | +| Variable | English | Contains | +|---------------------------|-----------------------|--------------------------------------------------------| +| `$0` | | Initially, the name of the executing program. | +| `$*` | `$ARGV` | Points to the `ARGV` array. | +| `$$` | `$PROCESS_ID`, `$PID` | Process ID of the current process. | +| `$?` | `$CHILD_STATUS` | Process::Status of most recently exited child process. | +| `$LOAD_PATH`, `$:`, `$-I` | | Array of paths to be searched. | +| `$LOADED_FEATURES`, `$"` | | Array of paths to loaded files. | ### Debugging -| Variable | English | Contains | -|--------------------|---------|----------------------------------------------------------------------| -| $FILENAME | | The value returned by method ARGF.filename. | -| $DEBUG | | Initially, whether option -d or --debug was given. | -| $VERBOSE | | Initially, whether option -V or -W was given. | +| Variable | English | Contains | +|-------------|---------|--------------------------------------------------------| +| `$FILENAME` | | The value returned by method ARGF.filename. | +| `$DEBUG` | | Initially, whether option `-d` or `--debug` was given. | +| `$VERBOSE` | | Initially, whether option `-V` or `-W` was given. | ### Other Variables -| Variable | English | Contains | -|--------------|---------|-------------------------------------------------------| -| $-a | | Whether option -a was given. | -| $-i | | Extension given with command-line option -i. | -| $-l | | Whether option -l was given. | -| $-p | | Whether option -p was given. | +| Variable | English | Contains | +|----------|---------|------------------------------------------------| +| `$-a` | | Whether option `-a` was given. | +| `$-i` | | Extension given with command-line option `-i`. | +| `$-l` | | Whether option `-l` was given. | +| `$-p` | | Whether option `-p` was given. | ## Exceptions @@ -165,7 +165,7 @@ English - `$LAST_PAREN_MATCH`. ### `$1`, `$2`, \Etc. (Matched Group) -For `$_n_` the _nth_ group of the match. +For $_n_ the nth group of the match. No \English. @@ -179,7 +179,7 @@ English - `$INPUT_RECORD_SEPARATOR`, `$RS`. Aliased as `$-0`. -### `$\\` (Output Record Separator) +### `$\` (Output Record Separator) An output record separator, initially `nil`. @@ -270,9 +270,9 @@ by Kernel#load and Kernel#require. Singleton method `$LOAD_PATH.resolve_feature_path(feature)` returns: -- `[:rb, _path_]`, where `path` is the path to the Ruby file - to be loaded for the given `feature`. -- `[:so, _path_]`, where `path` is the path to the shared object file +- [:rb, _path_], where `path` is the path to the Ruby file to be + loaded for the given `feature`. +- [:so, _path_], where `path` is the path to the shared object file to be loaded for the given `feature`. - `nil` if there is no such `feature` and `path`. @@ -373,35 +373,35 @@ Whether command-line option `-p` was given; read-only. ### Streams -| Constant | Contains | -|-----------------|-------------------------| -| STDIN | Standard input stream. | -| STDOUT | Standard output stream. | -| STDERR | Standard error stream. | +| Constant | Contains | +|----------|-------------------------| +| `STDIN` | Standard input stream. | +| `STDOUT` | Standard output stream. | +| `STDERR` | Standard error stream. | ### Environment -| Constant | Contains | -|------------------------------|--------------------------------------------------------------------------------------| -| ENV | Hash of current environment variable names and values. | -| ARGF | String concatenation of files given on the command line, or $stdin if none. | -| ARGV | Array of the given command-line arguments. | -| TOPLEVEL_BINDING | Binding of the top level scope. | -| RUBY_VERSION | String Ruby version. | -| RUBY_RELEASE_DATE | String Ruby release date. | -| RUBY_PLATFORM | String Ruby platform. | -| RUBY_PATCH_LEVEL | String Ruby patch level. | -| RUBY_REVISION | String Ruby revision. | -| RUBY_COPYRIGHT | String Ruby copyright. | -| RUBY_ENGINE | String Ruby engine. | -| RUBY_ENGINE_VERSION | String Ruby engine version. | -| RUBY_DESCRIPTION | String Ruby description. | +| Constant | Contains | +|-----------------------|-------------------------------------------------------------------------------| +| `ENV` | Hash of current environment variable names and values. | +| `ARGF` | String concatenation of files given on the command line, or `$stdin` if none. | +| `ARGV` | Array of the given command-line arguments. | +| `TOPLEVEL_BINDING` | Binding of the top level scope. | +| `RUBY_VERSION` | String Ruby version. | +| `RUBY_RELEASE_DATE` | String Ruby release date. | +| `RUBY_PLATFORM` | String Ruby platform. | +| `RUBY_PATCH_LEVEL` | String Ruby patch level. | +| `RUBY_REVISION` | String Ruby revision. | +| `RUBY_COPYRIGHT` | String Ruby copyright. | +| `RUBY_ENGINE` | String Ruby engine. | +| `RUBY_ENGINE_VERSION` | String Ruby engine version. | +| `RUBY_DESCRIPTION` | String Ruby description. | ### Embedded Data -| Constant | Contains | -|---------------|---------------------------------------------------------------------------| -| DATA | File containing embedded data (lines following __END__, if any). | +| Constant | Contains | +|----------|--------------------------------------------------------------------| +| `DATA` | File containing embedded data (lines following `__END__`, if any). | ## Streams From c5c894c6e41dff1e3b053518922b60866c1ab214 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 12 Aug 2025 20:39:08 +0900 Subject: [PATCH 12/22] [DOC] Markup example code as ruby --- doc/globals.md | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/doc/globals.md b/doc/globals.md index 4f7dafea2ca94f..b9315f5ff975e4 100644 --- a/doc/globals.md +++ b/doc/globals.md @@ -6,7 +6,7 @@ For each of those, the \English synonym is given. To use the module: -``` +```ruby require 'English' ``` @@ -85,7 +85,7 @@ require 'English' Contains the Exception object set by Kernel#raise: -``` +```ruby begin raise RuntimeError.new('Boo!') rescue RuntimeError @@ -106,7 +106,7 @@ English - `$ERROR_INFO` Same as `$!.backtrace`; returns an array of backtrace positions: -``` +```ruby begin raise RuntimeError.new('Boo!') rescue RuntimeError @@ -191,7 +191,7 @@ English - `$OUTPUT_RECORD_SEPARATOR`, `$ORS`. The current standard input stream; initially: -``` +```ruby $stdin # => #> ``` @@ -199,7 +199,7 @@ $stdin # => #> The current standard output stream; initially: -``` +```ruby $stdout # => #> ``` @@ -207,7 +207,7 @@ $stdout # => #> The current standard error stream; initially: -``` +```ruby $stderr # => #> ``` @@ -278,7 +278,7 @@ returns: Examples: -``` +```ruby $LOAD_PATH.resolve_feature_path('timeout') # => [:rb, "/snap/ruby/317/lib/ruby/3.2.0/timeout.rb"] $LOAD_PATH.resolve_feature_path('date_core') @@ -293,7 +293,7 @@ Aliased as `$:` and `$-I`. Contains an array of the paths to the loaded files: -``` +```ruby $LOADED_FEATURES.take(10) # => ["enumerator.so", @@ -409,7 +409,7 @@ Whether command-line option `-p` was given; read-only. The standard input stream (the default value for `$stdin`): -``` +```ruby STDIN # => #> ``` @@ -417,7 +417,7 @@ STDIN # => #> The standard output stream (the default value for `$stdout`): -``` +```ruby STDOUT # => #> ``` @@ -425,7 +425,7 @@ STDOUT # => #> The standard error stream (the default value for `$stderr`): -``` +```ruby STDERR # => #> ``` @@ -435,7 +435,7 @@ STDERR # => #> A hash of the contains current environment variables names and values: -``` +```ruby ENV.take(5) # => [["COLORTERM", "truecolor"], @@ -459,7 +459,7 @@ An array of the given command-line arguments. The Binding of the top level scope: -``` +```ruby TOPLEVEL_BINDING # => # ``` @@ -467,7 +467,7 @@ TOPLEVEL_BINDING # => # The Ruby version: -``` +```ruby RUBY_VERSION # => "3.2.2" ``` @@ -475,7 +475,7 @@ RUBY_VERSION # => "3.2.2" The release date string: -``` +```ruby RUBY_RELEASE_DATE # => "2023-03-30" ``` @@ -483,7 +483,7 @@ RUBY_RELEASE_DATE # => "2023-03-30" The platform identifier: -``` +```ruby RUBY_PLATFORM # => "x86_64-linux" ``` @@ -491,7 +491,7 @@ RUBY_PLATFORM # => "x86_64-linux" The integer patch level for this Ruby: -``` +```ruby RUBY_PATCHLEVEL # => 53 ``` @@ -501,7 +501,7 @@ For a development build the patch level will be -1. The git commit hash for this Ruby: -``` +```ruby RUBY_REVISION # => "e51014f9c05aa65cbf203442d37fef7c12390015" ``` @@ -509,7 +509,7 @@ RUBY_REVISION # => "e51014f9c05aa65cbf203442d37fef7c12390015" The copyright string: -``` +```ruby RUBY_COPYRIGHT # => "ruby - Copyright (C) 1993-2023 Yukihiro Matsumoto" ``` @@ -518,7 +518,7 @@ RUBY_COPYRIGHT The name of the Ruby implementation: -``` +```ruby RUBY_ENGINE # => "ruby" ``` @@ -526,7 +526,7 @@ RUBY_ENGINE # => "ruby" The version of the Ruby implementation: -``` +```ruby RUBY_ENGINE_VERSION # => "3.2.2" ``` @@ -534,7 +534,7 @@ RUBY_ENGINE_VERSION # => "3.2.2" The description of the Ruby implementation: -``` +```ruby RUBY_DESCRIPTION # => "ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]" ``` @@ -545,7 +545,7 @@ RUBY_DESCRIPTION Defined if and only if the program has this line: -``` +```ruby __END__ ``` @@ -553,7 +553,7 @@ When defined, `DATA` is a File object containing the lines following the `__END__`, positioned at the first of those lines: -``` +```ruby p DATA DATA.each_line { |line| p line } __END__ From e26ab5dbf24c1a37a18721e29671e7efd4bea803 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Tue, 12 Aug 2025 09:54:50 -0700 Subject: [PATCH 13/22] ZJIT: Avoid splitting add_into/sub_into for x86_64 (#14177) * ZJIT: Avoid splitting add_into/sub_into * Require add_into/sub_into to take a Reg --- zjit/src/backend/lir.rs | 11 +++++----- zjit/src/backend/x86_64/mod.rs | 40 +++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/zjit/src/backend/lir.rs b/zjit/src/backend/lir.rs index 86bea62fcd34f0..7d3afab7a951c1 100644 --- a/zjit/src/backend/lir.rs +++ b/zjit/src/backend/lir.rs @@ -1889,9 +1889,9 @@ impl Assembler { out } - pub fn add_into(&mut self, left: Opnd, right: Opnd) -> Opnd { + pub fn add_into(&mut self, left: Opnd, right: Opnd) { + assert!(matches!(left, Opnd::Reg(_)), "Destination of add_into must be Opnd::Reg, but got: {left:?}"); self.push_insn(Insn::Add { left, right, out: left }); - left } #[must_use] @@ -2233,10 +2233,9 @@ impl Assembler { out } - pub fn sub_into(&mut self, left: Opnd, right: Opnd) -> Opnd { - let out = self.sub(left, right); - self.mov(left, out); - out + pub fn sub_into(&mut self, left: Opnd, right: Opnd) { + assert!(matches!(left, Opnd::Reg(_)), "Destination of sub_into must be Opnd::Reg, but got: {left:?}"); + self.push_insn(Insn::Sub { left, right, out: left }); } #[must_use] diff --git a/zjit/src/backend/x86_64/mod.rs b/zjit/src/backend/x86_64/mod.rs index 8027c74b182e66..718f76837b4069 100644 --- a/zjit/src/backend/x86_64/mod.rs +++ b/zjit/src/backend/x86_64/mod.rs @@ -197,9 +197,15 @@ impl Assembler } }, // We have to load memory operands to avoid corrupting them - (Opnd::Mem(_) | Opnd::Reg(_), _) => { + (Opnd::Mem(_), _) => { *left = asm.load(*left); }, + // We have to load register operands to avoid corrupting them + (Opnd::Reg(_), _) => { + if *left != *out { + *left = asm.load(*left); + } + }, // The first operand can't be an immediate value (Opnd::UImm(_), _) => { *left = asm.load(*left); @@ -1164,7 +1170,21 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4983c540"); + assert_disasm!(cb, "4983c540", {" + 0x0: add r13, 0x40 + "}); + } + + #[test] + fn test_add_into() { + let (mut asm, mut cb) = setup_asm(); + + asm.add_into(CFP, Opnd::UImm(0x40)); + asm.compile_with_num_regs(&mut cb, 1); + + assert_disasm!(cb, "4983c540", {" + 0x0: add r13, 0x40 + "}); } #[test] @@ -1175,7 +1195,21 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4983ed40"); + assert_disasm!(cb, "4983ed40", {" + 0x0: sub r13, 0x40 + "}); + } + + #[test] + fn test_sub_into() { + let (mut asm, mut cb) = setup_asm(); + + asm.sub_into(CFP, Opnd::UImm(0x40)); + asm.compile_with_num_regs(&mut cb, 1); + + assert_disasm!(cb, "4983ed40", {" + 0x0: sub r13, 0x40 + "}); } #[test] From 998be6b3a4b078cfd09aa5b4a4a628c31c395451 Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Tue, 12 Aug 2025 10:00:22 -0700 Subject: [PATCH 14/22] ZJIT: Add flag to disable the HIR optimizer (#14181) Also add a check in the bisect script that can assign blame to the HIR optimizer. --- tool/zjit_bisect.rb | 5 +++++ zjit/src/codegen.rs | 4 +++- zjit/src/options.rs | 6 ++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tool/zjit_bisect.rb b/tool/zjit_bisect.rb index a4280a4ec2b8ab..47d6071d3b92f3 100755 --- a/tool/zjit_bisect.rb +++ b/tool/zjit_bisect.rb @@ -118,6 +118,11 @@ def run_with_jit_list(ruby, options, jit_list) jit_list = File.readlines(temp_file.path).map(&:strip).reject(&:empty?) end LOGGER.info("Starting with JIT list of #{jit_list.length} items.") +# Try running without the optimizer +_, stderr, exitcode = run_with_jit_list(RUBY, ["--zjit-disable-hir-opt", *OPTIONS], jit_list) +if exitcode == 0 + LOGGER.warn "*** Command suceeded with HIR optimizer disabled. HIR optimizer is probably at fault. ***" +end # Now narrow it down command = lambda do |items| _, _, exitcode = run_with_jit_list(RUBY, OPTIONS, items) diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index b1b43abbe6dc03..9fc3b643b7bb5f 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -1275,7 +1275,9 @@ fn compile_iseq(iseq: IseqPtr) -> Option { return None; } }; - function.optimize(); + if !get_option!(disable_hir_opt) { + function.optimize(); + } if let Err(err) = function.validate() { debug!("ZJIT: compile_iseq: {err:?}"); return None; diff --git a/zjit/src/options.rs b/zjit/src/options.rs index 07584c9b99d380..94a6988a4fddc5 100644 --- a/zjit/src/options.rs +++ b/zjit/src/options.rs @@ -35,6 +35,9 @@ pub struct Options { /// Enable debug logging pub debug: bool, + /// Turn off the HIR optimizer + pub disable_hir_opt: bool, + /// Dump initial High-level IR before optimization pub dump_hir_init: Option, @@ -66,6 +69,7 @@ impl Default for Options { num_profiles: 1, stats: false, debug: false, + disable_hir_opt: false, dump_hir_init: None, dump_hir_opt: None, dump_hir_graphviz: false, @@ -210,6 +214,8 @@ fn parse_option(str_ptr: *const std::os::raw::c_char) -> Option<()> { ("debug", "") => options.debug = true, + ("disable-hir-opt", "") => options.disable_hir_opt = true, + // --zjit-dump-hir dumps the actual input to the codegen, which is currently the same as --zjit-dump-hir-opt. ("dump-hir" | "dump-hir-opt", "") => options.dump_hir_opt = Some(DumpHIR::WithoutSnapshot), ("dump-hir" | "dump-hir-opt", "all") => options.dump_hir_opt = Some(DumpHIR::All), From 3e1e2bda49724c619cbb82935b2a11254e810b6c Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Tue, 12 Aug 2025 10:14:57 -0400 Subject: [PATCH 15/22] Make Enumerator::Chain write-barrier protected --- enumerator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/enumerator.c b/enumerator.c index 8d02c836e960e0..3855f79084b4f9 100644 --- a/enumerator.c +++ b/enumerator.c @@ -3073,7 +3073,7 @@ static const rb_data_type_t enum_chain_data_type = { enum_chain_memsize, enum_chain_mark_and_move, }, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED }; static struct enum_chain * @@ -3123,7 +3123,7 @@ enum_chain_initialize(VALUE obj, VALUE enums) if (!ptr) rb_raise(rb_eArgError, "unallocated chain"); - ptr->enums = rb_ary_freeze(enums); + RB_OBJ_WRITE(obj, &ptr->enums, rb_ary_freeze(enums)); ptr->pos = -1; return obj; @@ -3157,7 +3157,7 @@ enum_chain_init_copy(VALUE obj, VALUE orig) if (!ptr1) rb_raise(rb_eArgError, "unallocated chain"); - ptr1->enums = ptr0->enums; + RB_OBJ_WRITE(obj, &ptr1->enums, ptr0->enums); ptr1->pos = ptr0->pos; return obj; From a9230e76ee19716c7d2e035be7bd1be9bdca2b59 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Tue, 12 Aug 2025 10:16:55 -0400 Subject: [PATCH 16/22] Make Enumerator::Product write-barrier protected --- enumerator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/enumerator.c b/enumerator.c index 3855f79084b4f9..0d54058215f088 100644 --- a/enumerator.c +++ b/enumerator.c @@ -3388,7 +3388,7 @@ static const rb_data_type_t enum_product_data_type = { enum_product_memsize, enum_product_mark_and_move, }, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED }; static struct enum_product * @@ -3444,7 +3444,7 @@ enum_product_initialize(int argc, VALUE *argv, VALUE obj) if (!ptr) rb_raise(rb_eArgError, "unallocated product"); - ptr->enums = rb_ary_freeze(enums); + RB_OBJ_WRITE(obj, &ptr->enums, rb_ary_freeze(enums)); return obj; } @@ -3462,7 +3462,7 @@ enum_product_init_copy(VALUE obj, VALUE orig) if (!ptr1) rb_raise(rb_eArgError, "unallocated product"); - ptr1->enums = ptr0->enums; + RB_OBJ_WRITE(obj, &ptr1->enums, ptr0->enums); return obj; } From 2f95eb4e803f3107c157d8eccf6ba62f0487e9ad Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Fri, 18 Jul 2025 23:03:46 -0700 Subject: [PATCH 17/22] Rename rbimpl_atomic.*_set to _store "store" is the terminology the C11 standard uses, which allows us to use this as a fallback. This only changes the private rbimpl_ version of the method, RUBY_ATOMIC_SET et al. keep the same name. --- include/ruby/atomic.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/ruby/atomic.h b/include/ruby/atomic.h index b778276f62d887..2f5da85b45fbf9 100644 --- a/include/ruby/atomic.h +++ b/include/ruby/atomic.h @@ -160,7 +160,7 @@ typedef unsigned int rb_atomic_t; * @return void * @post `var` holds `val`. */ -#define RUBY_ATOMIC_SET(var, val) rbimpl_atomic_set(&(var), (val)) +#define RUBY_ATOMIC_SET(var, val) rbimpl_atomic_store(&(var), (val)) /** * Identical to #RUBY_ATOMIC_FETCH_ADD, except for the return type. @@ -327,7 +327,7 @@ typedef unsigned int rb_atomic_t; * @post `var` holds `val`. */ #define RUBY_ATOMIC_PTR_SET(var, val) \ - rbimpl_atomic_ptr_set((volatile void **)&(var), (val)) + rbimpl_atomic_ptr_store((volatile void **)&(var), (val)) /** * Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `void*`. @@ -354,7 +354,7 @@ typedef unsigned int rb_atomic_t; * @post `var` holds `val`. */ #define RUBY_ATOMIC_VALUE_SET(var, val) \ - rbimpl_atomic_value_set(&(var), (val)) + rbimpl_atomic_value_store(&(var), (val)) /** * Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are @@ -859,7 +859,7 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_size_set(volatile size_t *ptr, size_t val) +rbimpl_atomic_size_store(volatile size_t *ptr, size_t val) { #if 0 @@ -904,13 +904,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_ptr_set(volatile void **ptr, void *val) +rbimpl_atomic_ptr_store(volatile void **ptr, void *val) { RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t)); const size_t sval = RBIMPL_CAST((size_t)val); volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr); - rbimpl_atomic_size_set(sptr, sval); + rbimpl_atomic_size_store(sptr, sval); } RBIMPL_ATTR_ARTIFICIAL() @@ -931,13 +931,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_value_set(volatile VALUE *ptr, VALUE val) +rbimpl_atomic_value_store(volatile VALUE *ptr, VALUE val) { RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t)); const size_t sval = RBIMPL_CAST((size_t)val); volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr); - rbimpl_atomic_size_set(sptr, sval); + rbimpl_atomic_size_store(sptr, sval); } RBIMPL_ATTR_ARTIFICIAL() @@ -959,7 +959,7 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_set(volatile rb_atomic_t *ptr, rb_atomic_t val) +rbimpl_atomic_store(volatile rb_atomic_t *ptr, rb_atomic_t val) { #if 0 From 1d9f76096e8072bf4fa4e2eb22d02079e1cbe429 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 28 Jul 2025 16:13:37 -0700 Subject: [PATCH 18/22] Update rbimpl_atomic_* to all take a memory order --- include/ruby/atomic.h | 249 +++++++++++++++++++++++++----------------- 1 file changed, 148 insertions(+), 101 deletions(-) diff --git a/include/ruby/atomic.h b/include/ruby/atomic.h index 2f5da85b45fbf9..89e1111e4caebb 100644 --- a/include/ruby/atomic.h +++ b/include/ruby/atomic.h @@ -84,6 +84,28 @@ typedef unsigned int rb_atomic_t; # error No atomic operation found #endif +/* Memory ordering constants */ +#if defined(HAVE_GCC_ATOMIC_BUILTINS) +# define RBIMPL_ATOMIC_RELAXED __ATOMIC_RELAXED +# define RBIMPL_ATOMIC_ACQUIRE __ATOMIC_ACQUIRE +# define RBIMPL_ATOMIC_RELEASE __ATOMIC_RELEASE +# define RBIMPL_ATOMIC_ACQ_REL __ATOMIC_ACQ_REL +# define RBIMPL_ATOMIC_SEQ_CST __ATOMIC_SEQ_CST +#elif defined(HAVE_STDATOMIC_H) +# define RBIMPL_ATOMIC_RELAXED memory_order_relaxed +# define RBIMPL_ATOMIC_ACQUIRE memory_order_acquire +# define RBIMPL_ATOMIC_RELEASE memory_order_release +# define RBIMPL_ATOMIC_ACQ_REL memory_order_acq_rel +# define RBIMPL_ATOMIC_SEQ_CST memory_order_seq_cst +#else +/* Dummy values for unsupported platforms */ +# define RBIMPL_ATOMIC_RELAXED 0 +# define RBIMPL_ATOMIC_ACQUIRE 1 +# define RBIMPL_ATOMIC_RELEASE 2 +# define RBIMPL_ATOMIC_ACQ_REL 3 +# define RBIMPL_ATOMIC_SEQ_CST 4 +#endif + /** * Atomically replaces the value pointed by `var` with the result of addition * of `val` to the old value of `var`. @@ -93,7 +115,7 @@ typedef unsigned int rb_atomic_t; * @return What was stored in `var` before the addition. * @post `var` holds `var + val`. */ -#define RUBY_ATOMIC_FETCH_ADD(var, val) rbimpl_atomic_fetch_add(&(var), (val)) +#define RUBY_ATOMIC_FETCH_ADD(var, val) rbimpl_atomic_fetch_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Atomically replaces the value pointed by `var` with the result of @@ -104,7 +126,7 @@ typedef unsigned int rb_atomic_t; * @return What was stored in `var` before the subtraction. * @post `var` holds `var - val`. */ -#define RUBY_ATOMIC_FETCH_SUB(var, val) rbimpl_atomic_fetch_sub(&(var), (val)) +#define RUBY_ATOMIC_FETCH_SUB(var, val) rbimpl_atomic_fetch_sub(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Atomically replaces the value pointed by `var` with the result of @@ -116,7 +138,7 @@ typedef unsigned int rb_atomic_t; * @post `var` holds `var | val`. * @note For portability, this macro can return void. */ -#define RUBY_ATOMIC_OR(var, val) rbimpl_atomic_or(&(var), (val)) +#define RUBY_ATOMIC_OR(var, val) rbimpl_atomic_or(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Atomically replaces the value pointed by `var` with `val`. This is just an @@ -127,7 +149,7 @@ typedef unsigned int rb_atomic_t; * @return What was stored in `var` before the assignment. * @post `var` holds `val`. */ -#define RUBY_ATOMIC_EXCHANGE(var, val) rbimpl_atomic_exchange(&(var), (val)) +#define RUBY_ATOMIC_EXCHANGE(var, val) rbimpl_atomic_exchange(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Atomic compare-and-swap. This stores `val` to `var` if and only if the @@ -141,7 +163,7 @@ typedef unsigned int rb_atomic_t; * @retval otherwise Something else is at `var`; not updated. */ #define RUBY_ATOMIC_CAS(var, oldval, newval) \ - rbimpl_atomic_cas(&(var), (oldval), (newval)) + rbimpl_atomic_cas(&(var), (oldval), (newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST) /** * Atomic load. This loads `var` with an atomic intrinsic and returns @@ -150,7 +172,7 @@ typedef unsigned int rb_atomic_t; * @param var A variable of ::rb_atomic_t * @return What was stored in `var`j */ -#define RUBY_ATOMIC_LOAD(var) rbimpl_atomic_load(&(var)) +#define RUBY_ATOMIC_LOAD(var) rbimpl_atomic_load(&(var), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_EXCHANGE, except for the return type. @@ -160,7 +182,7 @@ typedef unsigned int rb_atomic_t; * @return void * @post `var` holds `val`. */ -#define RUBY_ATOMIC_SET(var, val) rbimpl_atomic_store(&(var), (val)) +#define RUBY_ATOMIC_SET(var, val) rbimpl_atomic_store(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_FETCH_ADD, except for the return type. @@ -170,7 +192,7 @@ typedef unsigned int rb_atomic_t; * @return void * @post `var` holds `var + val`. */ -#define RUBY_ATOMIC_ADD(var, val) rbimpl_atomic_add(&(var), (val)) +#define RUBY_ATOMIC_ADD(var, val) rbimpl_atomic_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_FETCH_SUB, except for the return type. @@ -180,7 +202,7 @@ typedef unsigned int rb_atomic_t; * @return void * @post `var` holds `var - val`. */ -#define RUBY_ATOMIC_SUB(var, val) rbimpl_atomic_sub(&(var), (val)) +#define RUBY_ATOMIC_SUB(var, val) rbimpl_atomic_sub(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Atomically increments the value pointed by `var`. @@ -189,7 +211,7 @@ typedef unsigned int rb_atomic_t; * @return void * @post `var` holds `var + 1`. */ -#define RUBY_ATOMIC_INC(var) rbimpl_atomic_inc(&(var)) +#define RUBY_ATOMIC_INC(var) rbimpl_atomic_inc(&(var), RBIMPL_ATOMIC_SEQ_CST) /** * Atomically decrements the value pointed by `var`. @@ -198,7 +220,7 @@ typedef unsigned int rb_atomic_t; * @return void * @post `var` holds `var - 1`. */ -#define RUBY_ATOMIC_DEC(var) rbimpl_atomic_dec(&(var)) +#define RUBY_ATOMIC_DEC(var) rbimpl_atomic_dec(&(var), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_FETCH_ADD, except it expects its arguments to be `size_t`. @@ -210,7 +232,7 @@ typedef unsigned int rb_atomic_t; * @return What was stored in `var` before the addition. * @post `var` holds `var + val`. */ -#define RUBY_ATOMIC_SIZE_FETCH_ADD(var, val) rbimpl_atomic_size_fetch_add(&(var), (val)) +#define RUBY_ATOMIC_SIZE_FETCH_ADD(var, val) rbimpl_atomic_size_fetch_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_INC, except it expects its argument is `size_t`. @@ -221,7 +243,7 @@ typedef unsigned int rb_atomic_t; * @return void * @post `var` holds `var + 1`. */ -#define RUBY_ATOMIC_SIZE_INC(var) rbimpl_atomic_size_inc(&(var)) +#define RUBY_ATOMIC_SIZE_INC(var) rbimpl_atomic_size_inc(&(var), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_DEC, except it expects its argument is `size_t`. @@ -232,7 +254,7 @@ typedef unsigned int rb_atomic_t; * @return void * @post `var` holds `var - 1`. */ -#define RUBY_ATOMIC_SIZE_DEC(var) rbimpl_atomic_size_dec(&(var)) +#define RUBY_ATOMIC_SIZE_DEC(var) rbimpl_atomic_size_dec(&(var), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are @@ -246,7 +268,7 @@ typedef unsigned int rb_atomic_t; * @post `var` holds `val`. */ #define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) \ - rbimpl_atomic_size_exchange(&(var), (val)) + rbimpl_atomic_size_exchange(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `size_t`. @@ -260,7 +282,7 @@ typedef unsigned int rb_atomic_t; * @retval otherwise Something else is at `var`; not updated. */ #define RUBY_ATOMIC_SIZE_CAS(var, oldval, newval) \ - rbimpl_atomic_size_cas(&(var), (oldval), (newval)) + rbimpl_atomic_size_cas(&(var), (oldval), (newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_ADD, except it expects its arguments are `size_t`. @@ -272,7 +294,7 @@ typedef unsigned int rb_atomic_t; * @return void * @post `var` holds `var + val`. */ -#define RUBY_ATOMIC_SIZE_ADD(var, val) rbimpl_atomic_size_add(&(var), (val)) +#define RUBY_ATOMIC_SIZE_ADD(var, val) rbimpl_atomic_size_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_SUB, except it expects its arguments are `size_t`. @@ -284,7 +306,7 @@ typedef unsigned int rb_atomic_t; * @return void * @post `var` holds `var - val`. */ -#define RUBY_ATOMIC_SIZE_SUB(var, val) rbimpl_atomic_size_sub(&(var), (val)) +#define RUBY_ATOMIC_SIZE_SUB(var, val) rbimpl_atomic_size_sub(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are @@ -303,7 +325,7 @@ typedef unsigned int rb_atomic_t; * some pointers, most notably function pointers. */ #define RUBY_ATOMIC_PTR_EXCHANGE(var, val) \ - RBIMPL_CAST(rbimpl_atomic_ptr_exchange((void **)&(var), (void *)val)) + RBIMPL_CAST(rbimpl_atomic_ptr_exchange((void **)&(var), (void *)val, RBIMPL_ATOMIC_SEQ_CST)) /** * Identical to #RUBY_ATOMIC_LOAD, except it expects its arguments are `void*`. @@ -314,7 +336,7 @@ typedef unsigned int rb_atomic_t; * @return The value of `var` (without tearing) */ #define RUBY_ATOMIC_PTR_LOAD(var) \ - RBIMPL_CAST(rbimpl_atomic_ptr_load((void **)&var)) + RBIMPL_CAST(rbimpl_atomic_ptr_load((void **)&var, RBIMPL_ATOMIC_SEQ_CST)) /** * Identical to #RUBY_ATOMIC_SET, except it expects its arguments are @@ -327,7 +349,7 @@ typedef unsigned int rb_atomic_t; * @post `var` holds `val`. */ #define RUBY_ATOMIC_PTR_SET(var, val) \ - rbimpl_atomic_ptr_store((volatile void **)&(var), (val)) + rbimpl_atomic_ptr_store((volatile void **)&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `void*`. @@ -341,7 +363,7 @@ typedef unsigned int rb_atomic_t; * @retval otherwise Something else is at `var`; not updated. */ #define RUBY_ATOMIC_PTR_CAS(var, oldval, newval) \ - RBIMPL_CAST(rbimpl_atomic_ptr_cas((void **)&(var), (void *)(oldval), (void *)(newval))) + RBIMPL_CAST(rbimpl_atomic_ptr_cas((void **)&(var), (void *)(oldval), (void *)(newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST)) /** * Identical to #RUBY_ATOMIC_SET, except it expects its arguments are @@ -354,7 +376,7 @@ typedef unsigned int rb_atomic_t; * @post `var` holds `val`. */ #define RUBY_ATOMIC_VALUE_SET(var, val) \ - rbimpl_atomic_value_store(&(var), (val)) + rbimpl_atomic_value_store(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are @@ -368,7 +390,7 @@ typedef unsigned int rb_atomic_t; * @post `var` holds `val`. */ #define RUBY_ATOMIC_VALUE_EXCHANGE(var, val) \ - rbimpl_atomic_value_exchange(&(var), (val)) + rbimpl_atomic_value_exchange(&(var), (val), RBIMPL_ATOMIC_SEQ_CST) /** * Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are ::VALUE. @@ -382,19 +404,20 @@ typedef unsigned int rb_atomic_t; * @retval otherwise Something else is at `var`; not updated. */ #define RUBY_ATOMIC_VALUE_CAS(var, oldval, newval) \ - rbimpl_atomic_value_cas(&(var), (oldval), (newval)) + rbimpl_atomic_value_cas(&(var), (oldval), (newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST) /** @cond INTERNAL_MACRO */ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline rb_atomic_t -rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val) +rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - return __atomic_fetch_add(ptr, val, __ATOMIC_SEQ_CST); + return __atomic_fetch_add(ptr, val, memory_order); #elif defined(HAVE_GCC_SYNC_BUILTINS) return __sync_fetch_and_add(ptr, val); @@ -412,7 +435,7 @@ rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val) return atomic_add_int_nv(ptr, val) - val; #elif defined(HAVE_STDATOMIC_H) - return atomic_fetch_add((_Atomic volatile rb_atomic_t *)ptr, val); + return atomic_fetch_add_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order); #else # error Unsupported platform. @@ -424,12 +447,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline size_t -rbimpl_atomic_size_fetch_add(volatile size_t *ptr, size_t val) +rbimpl_atomic_size_fetch_add(volatile size_t *ptr, size_t val, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - return __atomic_fetch_add(ptr, val, __ATOMIC_SEQ_CST); + return __atomic_fetch_add(ptr, val, memory_order); #elif defined(HAVE_GCC_SYNC_BUILTINS) return __sync_fetch_and_add(ptr, val); @@ -446,10 +470,10 @@ rbimpl_atomic_size_fetch_add(volatile size_t *ptr, size_t val) RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t)); volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr); - rbimpl_atomic_fetch_add(tmp, val); + rbimpl_atomic_fetch_add(tmp, val, memory_order); #elif defined(HAVE_STDATOMIC_H) - return atomic_fetch_add((_Atomic volatile size_t *)ptr, val); + return atomic_fetch_add_explicit((_Atomic volatile size_t *)ptr, val, memory_order); #else # error Unsupported platform. @@ -460,8 +484,9 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val) +rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) @@ -470,7 +495,7 @@ rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val) * return value is not used, then compiles it into single `LOCK ADD` * instruction. */ - __atomic_add_fetch(ptr, val, __ATOMIC_SEQ_CST); + __atomic_add_fetch(ptr, val, memory_order); #elif defined(HAVE_GCC_SYNC_BUILTINS) __sync_add_and_fetch(ptr, val); @@ -500,12 +525,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_size_add(volatile size_t *ptr, size_t val) +rbimpl_atomic_size_add(volatile size_t *ptr, size_t val, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - __atomic_add_fetch(ptr, val, __ATOMIC_SEQ_CST); + __atomic_add_fetch(ptr, val, memory_order); #elif defined(HAVE_GCC_SYNC_BUILTINS) __sync_add_and_fetch(ptr, val); @@ -523,7 +549,7 @@ rbimpl_atomic_size_add(volatile size_t *ptr, size_t val) RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t)); volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr); - rbimpl_atomic_add(tmp, val); + rbimpl_atomic_add(tmp, val, memory_order); #elif defined(HAVE_STDATOMIC_H) *(_Atomic volatile size_t *)ptr += val; @@ -537,12 +563,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_inc(volatile rb_atomic_t *ptr) +rbimpl_atomic_inc(volatile rb_atomic_t *ptr, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS) - rbimpl_atomic_add(ptr, 1); + rbimpl_atomic_add(ptr, 1, memory_order); #elif defined(_WIN32) InterlockedIncrement(ptr); @@ -551,7 +578,7 @@ rbimpl_atomic_inc(volatile rb_atomic_t *ptr) atomic_inc_uint(ptr); #elif defined(HAVE_STDATOMIC_H) - rbimpl_atomic_add(ptr, 1); + rbimpl_atomic_add(ptr, 1, memory_order); #else # error Unsupported platform. @@ -562,12 +589,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_size_inc(volatile size_t *ptr) +rbimpl_atomic_size_inc(volatile size_t *ptr, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS) - rbimpl_atomic_size_add(ptr, 1); + rbimpl_atomic_size_add(ptr, 1, memory_order); #elif defined(_WIN64) InterlockedIncrement64(ptr); @@ -578,10 +606,10 @@ rbimpl_atomic_size_inc(volatile size_t *ptr) #elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H)) RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t)); - rbimpl_atomic_size_add(ptr, 1); + rbimpl_atomic_size_add(ptr, 1, memory_order); #elif defined(HAVE_STDATOMIC_H) - rbimpl_atomic_size_add(ptr, 1); + rbimpl_atomic_size_add(ptr, 1, memory_order); #else # error Unsupported platform. @@ -592,12 +620,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline rb_atomic_t -rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val) +rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - return __atomic_fetch_sub(ptr, val, __ATOMIC_SEQ_CST); + return __atomic_fetch_sub(ptr, val, memory_order); #elif defined(HAVE_GCC_SYNC_BUILTINS) return __sync_fetch_and_sub(ptr, val); @@ -613,7 +642,7 @@ rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val) return atomic_add_int_nv(ptr, neg * val) + val; #elif defined(HAVE_STDATOMIC_H) - return atomic_fetch_sub((_Atomic volatile rb_atomic_t *)ptr, val); + return atomic_fetch_sub_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order); #else # error Unsupported platform. @@ -624,12 +653,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val) +rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - __atomic_sub_fetch(ptr, val, __ATOMIC_SEQ_CST); + __atomic_sub_fetch(ptr, val, memory_order); #elif defined(HAVE_GCC_SYNC_BUILTINS) __sync_sub_and_fetch(ptr, val); @@ -654,12 +684,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val) +rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - __atomic_sub_fetch(ptr, val, __ATOMIC_SEQ_CST); + __atomic_sub_fetch(ptr, val, memory_order); #elif defined(HAVE_GCC_SYNC_BUILTINS) __sync_sub_and_fetch(ptr, val); @@ -677,7 +708,7 @@ rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val) RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t)); volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr); - rbimpl_atomic_sub(tmp, val); + rbimpl_atomic_sub(tmp, val, memory_order); #elif defined(HAVE_STDATOMIC_H) *(_Atomic volatile size_t *)ptr -= val; @@ -691,12 +722,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_dec(volatile rb_atomic_t *ptr) +rbimpl_atomic_dec(volatile rb_atomic_t *ptr, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS) - rbimpl_atomic_sub(ptr, 1); + rbimpl_atomic_sub(ptr, 1, memory_order); #elif defined(_WIN32) InterlockedDecrement(ptr); @@ -705,7 +737,7 @@ rbimpl_atomic_dec(volatile rb_atomic_t *ptr) atomic_dec_uint(ptr); #elif defined(HAVE_STDATOMIC_H) - rbimpl_atomic_sub(ptr, 1); + rbimpl_atomic_sub(ptr, 1, memory_order); #else # error Unsupported platform. @@ -716,12 +748,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_size_dec(volatile size_t *ptr) +rbimpl_atomic_size_dec(volatile size_t *ptr, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS) - rbimpl_atomic_size_sub(ptr, 1); + rbimpl_atomic_size_sub(ptr, 1, memory_order); #elif defined(_WIN64) InterlockedDecrement64(ptr); @@ -732,10 +765,10 @@ rbimpl_atomic_size_dec(volatile size_t *ptr) #elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H)) RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t)); - rbimpl_atomic_size_sub(ptr, 1); + rbimpl_atomic_size_sub(ptr, 1, memory_order); #elif defined(HAVE_STDATOMIC_H) - rbimpl_atomic_size_sub(ptr, 1); + rbimpl_atomic_size_sub(ptr, 1, memory_order); #else # error Unsupported platform. @@ -746,12 +779,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val) +rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - __atomic_or_fetch(ptr, val, __ATOMIC_SEQ_CST); + __atomic_or_fetch(ptr, val, memory_order); #elif defined(HAVE_GCC_SYNC_BUILTINS) __sync_or_and_fetch(ptr, val); @@ -796,12 +830,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline rb_atomic_t -rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val) +rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - return __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST); + return __atomic_exchange_n(ptr, val, memory_order); #elif defined(HAVE_GCC_SYNC_BUILTINS) return __sync_lock_test_and_set(ptr, val); @@ -813,7 +848,7 @@ rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val) return atomic_swap_uint(ptr, val); #elif defined(HAVE_STDATOMIC_H) - return atomic_exchange((_Atomic volatile rb_atomic_t *)ptr, val); + return atomic_exchange_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order); #else # error Unsupported platform. @@ -824,12 +859,13 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline size_t -rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val) +rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - return __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST); + return __atomic_exchange_n(ptr, val, memory_order); #elif defined(HAVE_GCC_SYNC_BUILTINS) return __sync_lock_test_and_set(ptr, val); @@ -844,11 +880,11 @@ rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val) RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t)); volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr); - const rb_atomic_t ret = rbimpl_atomic_exchange(tmp, val); + const rb_atomic_t ret = rbimpl_atomic_exchange(tmp, val, memory_order); return RBIMPL_CAST((size_t)ret); #elif defined(HAVE_STDATOMIC_H) - return atomic_exchange((_Atomic volatile size_t *)ptr, val); + return atomic_exchange_explicit((_Atomic volatile size_t *)ptr, val, memory_order); #else # error Unsupported platform. @@ -859,15 +895,16 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_size_store(volatile size_t *ptr, size_t val) +rbimpl_atomic_size_store(volatile size_t *ptr, size_t val, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - __atomic_store_n(ptr, val, __ATOMIC_SEQ_CST); + __atomic_store_n(ptr, val, memory_order); #else - rbimpl_atomic_size_exchange(ptr, val); + rbimpl_atomic_size_exchange(ptr, val, memory_order); #endif } @@ -876,8 +913,9 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void * -rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val) +rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val, int memory_order) { + (void)memory_order; #if 0 #elif defined(InterlockedExchangePointer) @@ -894,7 +932,7 @@ rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val) const size_t sval = RBIMPL_CAST((size_t)val); volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr); - const size_t sret = rbimpl_atomic_size_exchange(sptr, sval); + const size_t sret = rbimpl_atomic_size_exchange(sptr, sval, memory_order); return RBIMPL_CAST((void *)sret); #endif @@ -904,26 +942,26 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_ptr_store(volatile void **ptr, void *val) +rbimpl_atomic_ptr_store(volatile void **ptr, void *val, int memory_order) { RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t)); const size_t sval = RBIMPL_CAST((size_t)val); volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr); - rbimpl_atomic_size_store(sptr, sval); + rbimpl_atomic_size_store(sptr, sval, memory_order); } RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline VALUE -rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val) +rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val, int memory_order) { RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t)); const size_t sval = RBIMPL_CAST((size_t)val); volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr); - const size_t sret = rbimpl_atomic_size_exchange(sptr, sval); + const size_t sret = rbimpl_atomic_size_exchange(sptr, sval, memory_order); return RBIMPL_CAST((VALUE)sret); } @@ -931,27 +969,28 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_value_store(volatile VALUE *ptr, VALUE val) +rbimpl_atomic_value_store(volatile VALUE *ptr, VALUE val, int memory_order) { RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t)); const size_t sval = RBIMPL_CAST((size_t)val); volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr); - rbimpl_atomic_size_store(sptr, sval); + rbimpl_atomic_size_store(sptr, sval, memory_order); } RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline rb_atomic_t -rbimpl_atomic_load(volatile rb_atomic_t *ptr) +rbimpl_atomic_load(volatile rb_atomic_t *ptr, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - return __atomic_load_n(ptr, __ATOMIC_SEQ_CST); + return __atomic_load_n(ptr, memory_order); #else - return rbimpl_atomic_fetch_add(ptr, 0); + return rbimpl_atomic_fetch_add(ptr, 0, memory_order); #endif } @@ -959,16 +998,17 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void -rbimpl_atomic_store(volatile rb_atomic_t *ptr, rb_atomic_t val) +rbimpl_atomic_store(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - __atomic_store_n(ptr, val, __ATOMIC_SEQ_CST); + __atomic_store_n(ptr, val, memory_order); #else /* Maybe std::atomic::store can be faster? */ - rbimpl_atomic_exchange(ptr, val); + rbimpl_atomic_exchange(ptr, val, memory_order); #endif } @@ -977,13 +1017,15 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline rb_atomic_t -rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t newval) +rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t newval, int success_memorder, int failure_memorder) { + (void)success_memorder; + (void)failure_memorder; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) __atomic_compare_exchange_n( - ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + ptr, &oldval, newval, 0, success_memorder, failure_memorder); return oldval; #elif defined(HAVE_GCC_SYNC_BUILTINS) @@ -1003,8 +1045,8 @@ rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t new return atomic_cas_uint(ptr, oldval, newval); #elif defined(HAVE_STDATOMIC_H) - atomic_compare_exchange_strong( - (_Atomic volatile rb_atomic_t *)ptr, &oldval, newval); + atomic_compare_exchange_strong_explicit( + (_Atomic volatile rb_atomic_t *)ptr, &oldval, newval, success_memorder, failure_memorder); return oldval; #else @@ -1025,13 +1067,15 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline size_t -rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval) +rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval, int success_memorder, int failure_memorder) { + (void)success_memorder; + (void)failure_memorder; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) __atomic_compare_exchange_n( - ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + ptr, &oldval, newval, 0, success_memorder, failure_memorder); return oldval; #elif defined(HAVE_GCC_SYNC_BUILTINS) @@ -1047,11 +1091,11 @@ rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval) RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t)); volatile rb_atomic_t *tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr); - return rbimpl_atomic_cas(tmp, oldval, newval); + return rbimpl_atomic_cas(tmp, oldval, newval, success_memorder, failure_memorder); #elif defined(HAVE_STDATOMIC_H) - atomic_compare_exchange_strong( - (_Atomic volatile size_t *)ptr, &oldval, newval); + atomic_compare_exchange_strong_explicit( + (_Atomic volatile size_t *)ptr, &oldval, newval, success_memorder, failure_memorder); return oldval; #else @@ -1063,8 +1107,10 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void * -rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval) +rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval, int success_memorder, int failure_memorder) { + (void)success_memorder; + (void)failure_memorder; #if 0 #elif defined(InterlockedExchangePointer) @@ -1087,7 +1133,7 @@ rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval) const size_t snew = RBIMPL_CAST((size_t)newval); const size_t sold = RBIMPL_CAST((size_t)oldval); volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr); - const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew); + const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew, success_memorder, failure_memorder); return RBIMPL_CAST((void *)sret); #endif @@ -1097,15 +1143,16 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline void * -rbimpl_atomic_ptr_load(void **ptr) +rbimpl_atomic_ptr_load(void **ptr, int memory_order) { + (void)memory_order; #if 0 #elif defined(HAVE_GCC_ATOMIC_BUILTINS) - return __atomic_load_n(ptr, __ATOMIC_SEQ_CST); + return __atomic_load_n(ptr, memory_order); #else void *val = *ptr; - return rbimpl_atomic_ptr_cas(ptr, val, val); + return rbimpl_atomic_ptr_cas(ptr, val, val, memory_order, memory_order); #endif } @@ -1113,14 +1160,14 @@ RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) static inline VALUE -rbimpl_atomic_value_cas(volatile VALUE *ptr, VALUE oldval, VALUE newval) +rbimpl_atomic_value_cas(volatile VALUE *ptr, VALUE oldval, VALUE newval, int success_memorder, int failure_memorder) { RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t)); const size_t snew = RBIMPL_CAST((size_t)newval); const size_t sold = RBIMPL_CAST((size_t)oldval); volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr); - const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew); + const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew, success_memorder, failure_memorder); return RBIMPL_CAST((VALUE)sret); } /** @endcond */ From 77d29ef73cba81e7c18ab9bb95e0756b9f173f38 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 28 Jul 2025 23:22:34 -0700 Subject: [PATCH 19/22] Convert ATOMIC_LOAD_RELAXED to use new rbimpl_* --- ruby_atomic.h | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/ruby_atomic.h b/ruby_atomic.h index 1ccabcbdf6ba6a..29232756362609 100644 --- a/ruby_atomic.h +++ b/ruby_atomic.h @@ -27,16 +27,7 @@ #define ATOMIC_VALUE_CAS(var, oldval, val) RUBY_ATOMIC_VALUE_CAS(var, oldval, val) #define ATOMIC_VALUE_EXCHANGE(var, val) RUBY_ATOMIC_VALUE_EXCHANGE(var, val) -static inline rb_atomic_t -rbimpl_atomic_load_relaxed(volatile rb_atomic_t *ptr) -{ -#if defined(HAVE_GCC_ATOMIC_BUILTINS) - return __atomic_load_n(ptr, __ATOMIC_RELAXED); -#else - return *ptr; -#endif -} -#define ATOMIC_LOAD_RELAXED(var) rbimpl_atomic_load_relaxed(&(var)) +#define ATOMIC_LOAD_RELAXED(var) rbimpl_atomic_load(&(var), RBIMPL_ATOMIC_RELAXED) typedef RBIMPL_ALIGNAS(8) uint64_t rbimpl_atomic_uint64_t; From cb360b0b4b2e53f2335f77f477df54337fc4d87e Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 28 Jul 2025 23:24:11 -0700 Subject: [PATCH 20/22] Implement rbimpl_atomic_value_load This only adds the rbimpl_ version to include/ruby/atomic.h so that it is not a new public interface. We were already using RUBY_ATOMIC_VALUE_LOAD in a few locations. This will allow us to use other memory orders internally when desired. --- include/ruby/atomic.h | 9 +++++++++ ruby_atomic.h | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/ruby/atomic.h b/include/ruby/atomic.h index 89e1111e4caebb..650891ab9cab75 100644 --- a/include/ruby/atomic.h +++ b/include/ruby/atomic.h @@ -1156,6 +1156,15 @@ rbimpl_atomic_ptr_load(void **ptr, int memory_order) #endif } +RBIMPL_ATTR_ARTIFICIAL() +RBIMPL_ATTR_NOALIAS() +RBIMPL_ATTR_NONNULL((1)) +static inline VALUE +rbimpl_atomic_value_load(volatile VALUE *ptr, int memory_order) +{ + return RBIMPL_CAST((VALUE)rbimpl_atomic_ptr_load((void **)ptr, memory_order)); +} + RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) diff --git a/ruby_atomic.h b/ruby_atomic.h index 29232756362609..ad53356f069ce2 100644 --- a/ruby_atomic.h +++ b/ruby_atomic.h @@ -3,7 +3,7 @@ #include "ruby/atomic.h" -#define RUBY_ATOMIC_VALUE_LOAD(x) (VALUE)(RUBY_ATOMIC_PTR_LOAD(x)) +#define RUBY_ATOMIC_VALUE_LOAD(x) rbimpl_atomic_value_load(&(x), RBIMPL_ATOMIC_SEQ_CST) /* shim macros only */ #define ATOMIC_ADD(var, val) RUBY_ATOMIC_ADD(var, val) From 4cf05ea77a82368f77fc50c193934b3b1a027b03 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 29 Jul 2025 00:14:54 -0700 Subject: [PATCH 21/22] Replace stdatomic ops with explicit mem order My previous pass missed these atomic operations using operators. --- include/ruby/atomic.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/ruby/atomic.h b/include/ruby/atomic.h index 650891ab9cab75..c7043b047692a6 100644 --- a/include/ruby/atomic.h +++ b/include/ruby/atomic.h @@ -514,7 +514,7 @@ rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order) atomic_add_int(ptr, val); #elif defined(HAVE_STDATOMIC_H) - *(_Atomic volatile rb_atomic_t *)ptr += val; + atomic_fetch_add_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order); #else # error Unsupported platform. @@ -552,7 +552,7 @@ rbimpl_atomic_size_add(volatile size_t *ptr, size_t val, int memory_order) rbimpl_atomic_add(tmp, val, memory_order); #elif defined(HAVE_STDATOMIC_H) - *(_Atomic volatile size_t *)ptr += val; + atomic_fetch_add_explicit((_Atomic volatile size_t *)ptr, val, memory_order); #else # error Unsupported platform. @@ -673,7 +673,7 @@ rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order) atomic_add_int(ptr, neg * val); #elif defined(HAVE_STDATOMIC_H) - *(_Atomic volatile rb_atomic_t *)ptr -= val; + atomic_fetch_sub_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order); #else # error Unsupported platform. @@ -711,7 +711,7 @@ rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val, int memory_order) rbimpl_atomic_sub(tmp, val, memory_order); #elif defined(HAVE_STDATOMIC_H) - *(_Atomic volatile size_t *)ptr -= val; + atomic_fetch_sub_explicit((_Atomic volatile size_t *)ptr, val, memory_order); #else # error Unsupported platform. @@ -810,7 +810,7 @@ rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order) atomic_or_uint(ptr, val); #elif !defined(_WIN32) && defined(HAVE_STDATOMIC_H) - *(_Atomic volatile rb_atomic_t *)ptr |= val; + atomic_fetch_or_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order); #else # error Unsupported platform. From 507b1e4bde074bdda3083df6b4c2190a385f84bf Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Wed, 13 Aug 2025 02:36:02 +0900 Subject: [PATCH 22/22] [ruby/openssl] pkey: skip tests using invalid keys in the FIPS mode In OpenSSL's master branch, importing/loading a key in the FIPS mode automatically performs a pair-wise consistency check. This breaks tests for OpenSSL::PKey::EC#check_key and DH#params_ok? as they use deliberately invalid keys. These methods would not be useful in the FIPS mode anyway. Fixes https://github.com/ruby/openssl/issues/926 https://github.com/ruby/openssl/commit/25ad8f4bdb --- test/openssl/test_pkey_dh.rb | 2 ++ test/openssl/test_pkey_ec.rb | 2 ++ 2 files changed, 4 insertions(+) diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb index c82f642c016338..f0c42866ea5df7 100644 --- a/test/openssl/test_pkey_dh.rb +++ b/test/openssl/test_pkey_dh.rb @@ -103,6 +103,8 @@ def test_generate_key end if !openssl?(3, 0, 0) def test_params_ok? + omit_on_fips + # Skip the tests in old OpenSSL version 1.1.1c or early versions before # applying the following commits in OpenSSL 1.1.1d to make `DH_check` # function pass the RFC 7919 FFDHE group texts. diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb index 1953b4c2dae6b8..e569397c0a874c 100644 --- a/test/openssl/test_pkey_ec.rb +++ b/test/openssl/test_pkey_ec.rb @@ -72,6 +72,8 @@ def test_marshal end def test_check_key + omit_on_fips + key0 = Fixtures.pkey("p256") assert_equal(true, key0.check_key) assert_equal(true, key0.private?)