File: mutex_semaphore.rb

package info (click to toggle)
ruby-concurrent 1.0.0-3
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 3,872 kB
  • ctags: 3,093
  • sloc: ruby: 26,166; java: 6,028; ansic: 282; makefile: 4
file content (115 lines) | stat: -rw-r--r-- 2,853 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
require 'concurrent/synchronization'

module Concurrent

  # @!macro semaphore
  # @!visibility private
  # @!macro internal_implementation_note
  class MutexSemaphore < Synchronization::LockableObject

    # @!macro semaphore_method_initialize
    def initialize(count)
      unless count.is_a?(Fixnum) && count >= 0
        fail ArgumentError, 'count must be an non-negative integer'
      end
      super()
      synchronize { ns_initialize count }
    end

    # @!macro semaphore_method_acquire
    def acquire(permits = 1)
      unless permits.is_a?(Fixnum) && permits > 0
        fail ArgumentError, 'permits must be an integer greater than zero'
      end
      synchronize do
        try_acquire_timed(permits, nil)
        nil
      end
    end

    # @!macro semaphore_method_available_permits
    def available_permits
      synchronize { @free }
    end

    # @!macro semaphore_method_drain_permits
    #
    #   Acquires and returns all permits that are immediately available.
    #
    #   @return [Integer]
    def drain_permits
      synchronize do
        @free.tap { |_| @free = 0 }
      end
    end

    # @!macro semaphore_method_try_acquire
    def try_acquire(permits = 1, timeout = nil)
      unless permits.is_a?(Fixnum) && permits > 0
        fail ArgumentError, 'permits must be an integer greater than zero'
      end
      synchronize do
        if timeout.nil?
          try_acquire_now(permits)
        else
          try_acquire_timed(permits, timeout)
        end
      end
    end

    # @!macro semaphore_method_release
    def release(permits = 1)
      unless permits.is_a?(Fixnum) && permits > 0
        fail ArgumentError, 'permits must be an integer greater than zero'
      end
      synchronize do
        @free += permits
        permits.times { ns_signal }
      end
      nil
    end

    # Shrinks the number of available permits by the indicated reduction.
    #
    # @param [Fixnum] reduction Number of permits to remove.
    #
    # @raise [ArgumentError] if `reduction` is not an integer or is negative
    #
    # @raise [ArgumentError] if `@free` - `@reduction` is less than zero
    #
    # @return [nil]
    #
    # @!visibility private
    def reduce_permits(reduction)
      unless reduction.is_a?(Fixnum) && reduction >= 0
        fail ArgumentError, 'reduction must be an non-negative integer'
      end
      synchronize { @free -= reduction }
      nil
    end

    protected

    # @!visibility private
    def ns_initialize(count)
      @free = count
    end

    private

    # @!visibility private
    def try_acquire_now(permits)
      if @free >= permits
        @free -= permits
        true
      else
        false
      end
    end

    # @!visibility private
    def try_acquire_timed(permits, timeout)
      ns_wait_until(timeout) { try_acquire_now(permits) }
    end
  end
end