# frozen_string_literal: true

require "monitor"

module ActiveSupport
  module Concurrency
    # A monitor that will permit dependency loading while blocked waiting for
    # the lock.
    class LoadInterlockAwareMonitor < Monitor
      # Enters an exclusive section, but allows dependency loading while blocked
      def mon_enter
        mon_try_enter ||
          ActiveSupport::Dependencies.interlock.permit_concurrent_loads { super }
      end
    end
  end
end

# frozen_string_literal: true

require "monitor"

module ActiveSupport
  module Concurrency
    # A monitor that will permit dependency loading while blocked waiting for
    # the lock.
    class LoadInterlockAwareMonitor < Monitor
      EXCEPTION_NEVER = { Exception => :never }.freeze
      EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze
      private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE

      # Enters an exclusive section, but allows dependency loading while blocked
      def mon_enter
        mon_try_enter ||
          ActiveSupport::Dependencies.interlock.permit_concurrent_loads { super }
      end

      def synchronize
        Thread.handle_interrupt(EXCEPTION_NEVER) do
          mon_enter

          begin
            Thread.handle_interrupt(EXCEPTION_IMMEDIATE) do
              yield
            end
          ensure
            mon_exit
          end
        end
      end
    end
  end
end

Make `LoadInterlockAwareMonitor` work in Ruby 2.7
Make `LoadInterlockAwareMonitor` work in Ruby 2.7

Currently `LoadInterlockAwareMonitorTest` does not pass with Ruby 2.7 [1].
This is due to the refactoring of the `monitor` done in Ruby 2.7 [2].

With this refactoring, the behavior of the method has changed from the
expected behavior in `LoadInterlockAwareMonitor`.

This patch also overwrites `synchronize` so that
`LoadInterlockAwareMonitor` works as expected.

[1]: https://buildkite.com/rails/rails/builds/65877#eec47af5-7595-47cb-97c0-30c589716176/996-2743
[2]: https://bugs.ruby-lang.org/issues/16255
