quack_concurrency 0.5.3 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c6822c50d1a8483a8009ad94e2725691bf28a71d3e9441d67b092c6b96314db
4
- data.tar.gz: 47a4c773d831b66fe2b40db8ca23f7cb3c44962023ff1e7fc7cc4a4832bc41b9
3
+ metadata.gz: d110c1994e7796f45c3cade0f82f7bae2ce8daa0fa775e32fe92cb5a5d1bb3e7
4
+ data.tar.gz: 1253c01f31d051a5cdccd599c3d1ce597bc580c9e06311727b132aa4e1f2e172
5
5
  SHA512:
6
- metadata.gz: 7aebe4c95df5578c5a68d4331965dd6d68763ffd51e2683cc9aa345be9148b77f060914af76a728c3c394a9bb56ceb8f142a59855a22e6c833a9253f957235ba
7
- data.tar.gz: 1f406ab37a50d2d58f2a4952e1ed7f6152d050fa2d723c9477e8ab6cc9cd540dc31fa72b805027bc98c09d0fa73ae641f3d9e85f523cf91facb0f463be19df6c
6
+ metadata.gz: c44997c7c973429240bbf600ea68818eedb548012ccc0248028a4fc5a18509e9050b44baa92c563190512c1cb34a0999d8624288827915eb4dcdbc05997961ad
7
+ data.tar.gz: 99f22237f7a44ea60ac10c0a25c8ac6627fa17cf13de2f55e4797a749607f676dd02ffbfd47ade2f93a983e5ca83dab89e8374480ab930326154e47c14d69c36
@@ -61,18 +61,30 @@ module QuackConcurrency
61
61
  end
62
62
  @mutex.synchronize { @waiting_threads.push(caller) }
63
63
  if mutex
64
+ # ideally we would would check if this Thread can sleep (not the last Thread alive)
65
+ # before we unlock the mutex, however I am not sure is that can be implemented
64
66
  if mutex.respond_to?(:unlock!)
65
67
  mutex.unlock! { sleep(timeout) }
66
68
  else
67
69
  mutex.unlock
68
- sleep(timeout)
69
- mutex.lock
70
+ begin
71
+ sleep(timeout)
72
+ ensure # rescue a fatal error (eg. only Thread stopped)
73
+ if mutex.locked?
74
+ # another Thread locked this before it died
75
+ # this is not a correct state to be in but I don't know how to fix it
76
+ # given that there are no other alive Threads then than the ramifications should be minimal
77
+ else
78
+ mutex.lock
79
+ end
80
+ end
70
81
  end
71
82
  else
72
83
  sleep(timeout)
73
84
  end
74
- @mutex.synchronize { @waiting_threads.delete(caller) }
75
85
  self
86
+ ensure
87
+ @mutex.synchronize { @waiting_threads.delete(caller) }
76
88
  end
77
89
 
78
90
  # Returns the number of `Thread`s currently waiting.
@@ -35,18 +35,30 @@ module QuackConcurrency
35
35
  sleeper = UninterruptibleSleeper.for_current
36
36
  @mutex.synchronize { @waiting_threads_sleepers.push(sleeper) }
37
37
  if mutex
38
+ # ideally we would would check if this Thread can sleep (not the last Thread alive)
39
+ # before we unlock the mutex, however I am not sure is that can be implemented
38
40
  if mutex.respond_to?(:unlock!)
39
41
  mutex.unlock! { sleep(sleeper, timeout) }
40
42
  else
41
43
  mutex.unlock
42
- sleep(sleeper, timeout)
43
- mutex.lock
44
+ begin
45
+ sleep(sleeper, timeout)
46
+ ensure # rescue a fatal error (eg. only Thread stopped)
47
+ if mutex.locked?
48
+ # another Thread locked this before it died
49
+ # this is not a correct state to be in but I don't know how to fix it
50
+ # given that there are no other alive Threads then than the ramifications should be minimal
51
+ else
52
+ mutex.lock
53
+ end
54
+ end
44
55
  end
45
56
  else
46
57
  sleep(sleeper, timeout)
47
58
  end
48
- @mutex.synchronize { @waiting_threads_sleepers.delete(sleeper) }
49
59
  self
60
+ ensure
61
+ @mutex.synchronize { @waiting_threads_sleepers.delete(sleeper) }
50
62
  end
51
63
 
52
64
  def waiting_threads_count
@@ -54,7 +66,7 @@ module QuackConcurrency
54
66
  end
55
67
 
56
68
  private
57
-
69
+
58
70
  # @api private
59
71
  def signal_next
60
72
  next_waiting_thread_sleeper = @waiting_threads_sleepers.shift
@@ -4,6 +4,8 @@ module QuackConcurrency
4
4
  # Unlike simply calling `Thread#sleep`, {#stop_thread} will ensure that only
5
5
  # calling {#run_thread} on this {UninterruptibleSleeper} will wake the `Thread`.
6
6
  # Any call to `Thread#run` directly, will be ignored.
7
+ # `Thread`s can still be resumed if `Thread#raise` is called.
8
+ # A `ThreadError` will be raised if a the last running `Thread` is stopped.
7
9
  class UninterruptibleSleeper
8
10
 
9
11
  def self.for_current
@@ -52,13 +54,14 @@ module QuackConcurrency
52
54
  time_left = target_end_time - Time.now
53
55
  Kernel.sleep(time_left) if time_left > 0
54
56
  else
55
- Thread.stop
57
+ Thread.stop # may raise ThreadError if this is last running Thread
56
58
  end
57
59
  break if @state == :running || Time.now >= target_time
58
60
  end
61
+ ensure
59
62
  @state = :running
60
63
 
61
- # we relock the mutex ensure #run_thread has finshed before #stop_thread
64
+ # we relock the mutex to ensure #run_thread has finshed before #stop_thread
62
65
  # if Thread#run is called by another part of the code at the same time as
63
66
  # #run_thread is being called, we dont want the call to #run_thread
64
67
  # to call Thread#run on a Thread has already resumed and stopped again
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quack_concurrency
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Fors