# <!-- rdoc-file=ext/monitor/lib/monitor.rb -->
# Use the Monitor class when you want to have a lock object for blocks with
# mutual exclusion.
#
#     require 'monitor'
#
#     lock = Monitor.new
#     lock.synchronize do
#       # exclusive access
#     end
#
class Monitor
  # <!--
  #   rdoc-file=ext/monitor/monitor.c
  #   - enter()
  # -->
  #
  def enter: () -> nil

  # <!--
  #   rdoc-file=ext/monitor/monitor.c
  #   - exit()
  # -->
  #
  def exit: () -> nil

  # <!--
  #   rdoc-file=ext/monitor/monitor.c
  #   - mon_check_owner()
  # -->
  #
  def mon_check_owner: () -> nil

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - mon_enter()
  # -->
  #
  alias mon_enter enter

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - mon_exit()
  # -->
  #
  alias mon_exit exit

  # <!--
  #   rdoc-file=ext/monitor/monitor.c
  #   - mon_locked?()
  # -->
  #
  def mon_locked?: () -> bool

  # <!--
  #   rdoc-file=ext/monitor/monitor.c
  #   - mon_owned?()
  # -->
  #
  def mon_owned?: () -> bool

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - mon_synchronize()
  # -->
  #
  alias mon_synchronize synchronize

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - mon_try_enter()
  # -->
  #
  alias mon_try_enter try_enter

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - new_cond()
  # -->
  #
  def new_cond: () -> ::MonitorMixin::ConditionVariable

  # <!--
  #   rdoc-file=ext/monitor/monitor.c
  #   - synchronize()
  # -->
  #
  def synchronize: [T] () { () -> T } -> T

  # <!--
  #   rdoc-file=ext/monitor/monitor.c
  #   - try_enter()
  # -->
  #
  def try_enter: () -> bool

  # <!-- rdoc-file=ext/monitor/lib/monitor.rb -->
  # for compatibility
  #
  alias try_mon_enter try_enter

  # <!--
  #   rdoc-file=ext/monitor/monitor.c
  #   - wait_for_cond(p1, p2)
  # -->
  #
  def wait_for_cond: (::MonitorMixin::ConditionVariable, Numeric? timeout) -> untyped
end

# <!-- rdoc-file=ext/monitor/lib/monitor.rb -->
# In concurrent programming, a monitor is an object or module intended to be
# used safely by more than one thread. The defining characteristic of a monitor
# is that its methods are executed with mutual exclusion. That is, at each point
# in time, at most one thread may be executing any of its methods. This mutual
# exclusion greatly simplifies reasoning about the implementation of monitors
# compared to reasoning about parallel code that updates a data structure.
#
# You can read more about the general principles on the Wikipedia page for
# [Monitors](https://en.wikipedia.org/wiki/Monitor_%28synchronization%29).
#
# ## Examples
#
# ### Simple object.extend
#
#     require 'monitor.rb'
#
#     buf = []
#     buf.extend(MonitorMixin)
#     empty_cond = buf.new_cond
#
#     # consumer
#     Thread.start do
#       loop do
#         buf.synchronize do
#           empty_cond.wait_while { buf.empty? }
#           print buf.shift
#         end
#       end
#     end
#
#     # producer
#     while line = ARGF.gets
#       buf.synchronize do
#         buf.push(line)
#         empty_cond.signal
#       end
#     end
#
# The consumer thread waits for the producer thread to push a line to buf while
# `buf.empty?`. The producer thread (main thread) reads a line from ARGF and
# pushes it into buf then calls `empty_cond.signal` to notify the consumer
# thread of new data.
#
# ### Simple Class include
#
#     require 'monitor'
#
#     class SynchronizedArray < Array
#
#       include MonitorMixin
#
#       def initialize(*args)
#         super(*args)
#       end
#
#       alias :old_shift :shift
#       alias :old_unshift :unshift
#
#       def shift(n=1)
#         self.synchronize do
#           self.old_shift(n)
#         end
#       end
#
#       def unshift(item)
#         self.synchronize do
#           self.old_unshift(item)
#         end
#       end
#
#       # other methods ...
#     end
#
# `SynchronizedArray` implements an Array with synchronized access to items.
# This Class is implemented as subclass of Array which includes the MonitorMixin
# module.
#
module MonitorMixin
  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - extend_object(obj)
  # -->
  #
  def self.extend_object: (untyped obj) -> untyped

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - mon_enter()
  # -->
  # Enters exclusive section.
  #
  def mon_enter: () -> nil

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - mon_exit()
  # -->
  # Leaves exclusive section.
  #
  def mon_exit: () -> nil

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - mon_locked?()
  # -->
  # Returns true if this monitor is locked by any thread
  #
  def mon_locked?: () -> bool

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - mon_owned?()
  # -->
  # Returns true if this monitor is locked by current thread.
  #
  def mon_owned?: () -> bool

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - mon_synchronize(&b)
  # -->
  # Enters exclusive section and executes the block.  Leaves the exclusive section
  # automatically when the block exits.  See example under `MonitorMixin`.
  #
  def mon_synchronize: [T] () { () -> T } -> T

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - mon_try_enter()
  # -->
  # Attempts to enter exclusive section.  Returns `false` if lock fails.
  #
  def mon_try_enter: () -> bool

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - new_cond()
  # -->
  # Creates a new MonitorMixin::ConditionVariable associated with the Monitor
  # object.
  #
  def new_cond: () -> ::MonitorMixin::ConditionVariable

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - synchronize(&b)
  # -->
  #
  alias synchronize mon_synchronize

  # <!-- rdoc-file=ext/monitor/lib/monitor.rb -->
  # For backward compatibility
  #
  alias try_mon_enter mon_try_enter

  private

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - new(...)
  # -->
  # Use `extend MonitorMixin` or `include MonitorMixin` instead of this
  # constructor.  Have look at the examples above to understand how to use this
  # module.
  #
  def initialize: (*untyped) { (*untyped) -> untyped } -> void

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - mon_check_owner()
  # -->
  #
  def mon_check_owner: () -> nil

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - mon_initialize()
  # -->
  # Initializes the MonitorMixin after being included in a class or when an object
  # has been extended with the MonitorMixin
  #
  def mon_initialize: () -> untyped
end

# <!-- rdoc-file=ext/monitor/lib/monitor.rb -->
# FIXME: This isn't documented in Nutshell.
#
# Since MonitorMixin.new_cond returns a ConditionVariable, and the example above
# calls while_wait and signal, this class should be documented.
#
class MonitorMixin::ConditionVariable
  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - broadcast()
  # -->
  # Wakes up all threads waiting for this lock.
  #
  def broadcast: () -> Thread::ConditionVariable

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - signal()
  # -->
  # Wakes up the first thread in line waiting for this lock.
  #
  def signal: () -> Thread::ConditionVariable

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - wait(timeout = nil)
  # -->
  # Releases the lock held in the associated monitor and waits; reacquires the
  # lock on wakeup.
  #
  # If `timeout` is given, this method returns after `timeout` seconds passed,
  # even if no other thread doesn't signal.
  #
  def wait: (?Numeric? timeout) -> untyped

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - wait_until()
  # -->
  # Calls wait repeatedly until the given block yields a truthy value.
  #
  def wait_until: () { () -> boolish } -> untyped

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - wait_while()
  # -->
  # Calls wait repeatedly while the given block yields a truthy value.
  #
  def wait_while: () { () -> boolish } -> untyped

  private

  # <!--
  #   rdoc-file=ext/monitor/lib/monitor.rb
  #   - new(monitor)
  # -->
  #
  def initialize: (Monitor monitor) -> void
end
