@@ -577,7 +577,7 @@ def chain(*args, &task)
577
577
# @overload a_future.chain_on(executor, *args, &task)
578
578
# @yield [fulfilled?, value, reason, *args] to the task.
579
579
def chain_on ( executor , *args , &task )
580
- ChainPromise . new_blocked ( [ self ] , @DefaultExecutor , executor , args , &task ) . future
580
+ ChainPromise . new_blocked1 ( self , @DefaultExecutor , executor , args , &task ) . future
581
581
end
582
582
583
583
# Short string representation.
@@ -664,7 +664,7 @@ def resolve_with(state, raise_on_reassign = true)
664
664
# @return [Array<AbstractPromise>]
665
665
def blocks
666
666
# TODO (pitr-ch 18-Dec-2016): add macro noting that debug methods may change api without warning
667
- @Callbacks . each_with_object ( [ ] ) do |( method , * args ) , promises |
667
+ @Callbacks . each_with_object ( [ ] ) do |( method , args ) , promises |
668
668
promises . push ( args [ 0 ] ) if method == :callback_notify_blocked
669
669
end
670
670
end
@@ -697,9 +697,9 @@ def waiting_threads
697
697
def add_callback ( method , *args )
698
698
state = internal_state
699
699
if resolved? ( state )
700
- call_callback method , state , * args
700
+ call_callback method , state , args
701
701
else
702
- @Callbacks . push [ method , * args ]
702
+ @Callbacks . push [ method , args ]
703
703
state = internal_state
704
704
# take back if it was resolved in the meanwhile
705
705
call_callbacks state if resolved? ( state )
@@ -729,15 +729,15 @@ def wait_until_resolved(timeout)
729
729
resolved?
730
730
end
731
731
732
- def call_callback ( method , state , * args )
732
+ def call_callback ( method , state , args )
733
733
self . send method , state , *args
734
734
end
735
735
736
736
def call_callbacks ( state )
737
- method , * args = @Callbacks . pop
737
+ method , args = @Callbacks . pop
738
738
while method
739
- call_callback method , state , * args
740
- method , * args = @Callbacks . pop
739
+ call_callback method , state , args
740
+ method , args = @Callbacks . pop
741
741
end
742
742
end
743
743
@@ -774,9 +774,9 @@ class Event < AbstractEventFuture
774
774
# @return [Future, Event]
775
775
def zip ( other )
776
776
if other . is_a? ( Future )
777
- ZipFutureEventPromise . new_blocked ( [ other , self ] , @DefaultExecutor ) . future
777
+ ZipFutureEventPromise . new_blocked2 ( other , self , @DefaultExecutor ) . future
778
778
else
779
- ZipEventEventPromise . new_blocked ( [ self , other ] , @DefaultExecutor ) . event
779
+ ZipEventEventPromise . new_blocked2 ( self , other , @DefaultExecutor ) . event
780
780
end
781
781
end
782
782
@@ -787,7 +787,7 @@ def zip(other)
787
787
#
788
788
# @return [Event]
789
789
def any ( event_or_future )
790
- AnyResolvedEventPromise . new_blocked ( [ self , event_or_future ] , @DefaultExecutor ) . event
790
+ AnyResolvedEventPromise . new_blocked2 ( self , event_or_future , @DefaultExecutor ) . event
791
791
end
792
792
793
793
alias_method :| , :any
@@ -798,7 +798,7 @@ def any(event_or_future)
798
798
# @return [Event]
799
799
def delay
800
800
event = DelayPromise . new ( @DefaultExecutor ) . event
801
- ZipEventEventPromise . new_blocked ( [ self , event ] , @DefaultExecutor ) . event
801
+ ZipEventEventPromise . new_blocked2 ( self , event , @DefaultExecutor ) . event
802
802
end
803
803
804
804
# @!macro [new] promise.method.schedule
@@ -811,7 +811,7 @@ def delay
811
811
def schedule ( intended_time )
812
812
chain do
813
813
event = ScheduledPromise . new ( @DefaultExecutor , intended_time ) . event
814
- ZipEventEventPromise . new_blocked ( [ self , event ] , @DefaultExecutor ) . event
814
+ ZipEventEventPromise . new_blocked2 ( self , event , @DefaultExecutor ) . event
815
815
end . flat_event
816
816
end
817
817
@@ -833,7 +833,7 @@ def to_event
833
833
# @!macro promises.method.with_default_executor
834
834
# @return [Event]
835
835
def with_default_executor ( executor )
836
- EventWrapperPromise . new_blocked ( [ self ] , executor ) . event
836
+ EventWrapperPromise . new_blocked1 ( self , executor ) . event
837
837
end
838
838
839
839
private
@@ -946,7 +946,7 @@ def then(*args, &task)
946
946
# @return [Future]
947
947
# @yield [value, *args] to the task.
948
948
def then_on ( executor , *args , &task )
949
- ThenPromise . new_blocked ( [ self ] , @DefaultExecutor , executor , args , &task ) . future
949
+ ThenPromise . new_blocked1 ( self , @DefaultExecutor , executor , args , &task ) . future
950
950
end
951
951
952
952
# @!macro promises.shortcut.on
@@ -964,16 +964,16 @@ def rescue(*args, &task)
964
964
# @return [Future]
965
965
# @yield [reason, *args] to the task.
966
966
def rescue_on ( executor , *args , &task )
967
- RescuePromise . new_blocked ( [ self ] , @DefaultExecutor , executor , args , &task ) . future
967
+ RescuePromise . new_blocked1 ( self , @DefaultExecutor , executor , args , &task ) . future
968
968
end
969
969
970
970
# @!macro promises.method.zip
971
971
# @return [Future]
972
972
def zip ( other )
973
973
if other . is_a? ( Future )
974
- ZipFuturesPromise . new_blocked ( [ self , other ] , @DefaultExecutor ) . future
974
+ ZipFuturesPromise . new_blocked2 ( self , other , @DefaultExecutor ) . future
975
975
else
976
- ZipFutureEventPromise . new_blocked ( [ self , other ] , @DefaultExecutor ) . future
976
+ ZipFutureEventPromise . new_blocked2 ( self , other , @DefaultExecutor ) . future
977
977
end
978
978
end
979
979
@@ -985,7 +985,7 @@ def zip(other)
985
985
#
986
986
# @return [Future]
987
987
def any ( event_or_future )
988
- AnyResolvedFuturePromise . new_blocked ( [ self , event_or_future ] , @DefaultExecutor ) . future
988
+ AnyResolvedFuturePromise . new_blocked2 ( self , event_or_future , @DefaultExecutor ) . future
989
989
end
990
990
991
991
alias_method :| , :any
@@ -996,22 +996,22 @@ def any(event_or_future)
996
996
# @return [Future]
997
997
def delay
998
998
event = DelayPromise . new ( @DefaultExecutor ) . event
999
- ZipFutureEventPromise . new_blocked ( [ self , event ] , @DefaultExecutor ) . future
999
+ ZipFutureEventPromise . new_blocked2 ( self , event , @DefaultExecutor ) . future
1000
1000
end
1001
1001
1002
1002
# @!macro promise.method.schedule
1003
1003
# @return [Future]
1004
1004
def schedule ( intended_time )
1005
1005
chain do
1006
1006
event = ScheduledPromise . new ( @DefaultExecutor , intended_time ) . event
1007
- ZipFutureEventPromise . new_blocked ( [ self , event ] , @DefaultExecutor ) . future
1007
+ ZipFutureEventPromise . new_blocked2 ( self , event , @DefaultExecutor ) . future
1008
1008
end . flat
1009
1009
end
1010
1010
1011
1011
# @!macro promises.method.with_default_executor
1012
1012
# @return [Future]
1013
1013
def with_default_executor ( executor )
1014
- FutureWrapperPromise . new_blocked ( [ self ] , executor ) . future
1014
+ FutureWrapperPromise . new_blocked1 ( self , executor ) . future
1015
1015
end
1016
1016
1017
1017
# Creates new future which will have result of the future returned by receiver. If receiver
@@ -1020,7 +1020,7 @@ def with_default_executor(executor)
1020
1020
# @param [Integer] level how many levels of futures should flatten
1021
1021
# @return [Future]
1022
1022
def flat_future ( level = 1 )
1023
- FlatFuturePromise . new_blocked ( [ self ] , level , @DefaultExecutor ) . future
1023
+ FlatFuturePromise . new_blocked1 ( self , level , @DefaultExecutor ) . future
1024
1024
end
1025
1025
1026
1026
alias_method :flat , :flat_future
@@ -1030,7 +1030,7 @@ def flat_future(level = 1)
1030
1030
#
1031
1031
# @return [Event]
1032
1032
def flat_event
1033
- FlatEventPromise . new_blocked ( [ self ] , @DefaultExecutor ) . event
1033
+ FlatEventPromise . new_blocked1 ( self , @DefaultExecutor ) . event
1034
1034
end
1035
1035
1036
1036
# @!macro promises.shortcut.using
@@ -1104,7 +1104,7 @@ def on_rejection_using(executor, *args, &callback)
1104
1104
# end
1105
1105
# future(0, &body).run.value! # => 5
1106
1106
def run
1107
- RunFuturePromise . new_blocked ( [ self ] , @DefaultExecutor ) . future
1107
+ RunFuturePromise . new_blocked1 ( self , @DefaultExecutor ) . future
1108
1108
end
1109
1109
1110
1110
# @!visibility private
@@ -1199,7 +1199,7 @@ def resolve(raise_on_reassign = true)
1199
1199
#
1200
1200
# @return [Event]
1201
1201
def with_hidden_resolvable
1202
- @with_hidden_resolvable ||= EventWrapperPromise . new_blocked ( [ self ] , @DefaultExecutor ) . event
1202
+ @with_hidden_resolvable ||= EventWrapperPromise . new_blocked1 ( self , @DefaultExecutor ) . event
1203
1203
end
1204
1204
end
1205
1205
@@ -1255,7 +1255,7 @@ def evaluate_to!(*args, &block)
1255
1255
#
1256
1256
# @return [Future]
1257
1257
def with_hidden_resolvable
1258
- @with_hidden_resolvable ||= FutureWrapperPromise . new_blocked ( [ self ] , @DefaultExecutor ) . future
1258
+ @with_hidden_resolvable ||= FutureWrapperPromise . new_blocked1 ( self , @DefaultExecutor ) . future
1259
1259
end
1260
1260
end
1261
1261
@@ -1354,16 +1354,49 @@ class BlockedPromise < InnerPromise
1354
1354
1355
1355
private_class_method :new
1356
1356
1357
+ def self . new_blocked1 ( blocker , *args , &block )
1358
+ blocker_delayed = blocker . promise . delayed
1359
+ delayed = blocker_delayed ? LockFreeStack . new . push ( blocker_delayed ) : nil
1360
+ promise = new ( delayed , 1 , *args , &block )
1361
+ ensure
1362
+ blocker . add_callback :callback_notify_blocked , promise , 0
1363
+ end
1364
+
1365
+ def self . new_blocked2 ( blocker1 , blocker2 , *args , &block )
1366
+ blocker_delayed1 = blocker1 . promise . delayed
1367
+ blocker_delayed2 = blocker2 . promise . delayed
1368
+ delayed = if blocker_delayed1
1369
+ if blocker_delayed2
1370
+ LockFreeStack . new2 ( blocker_delayed1 , blocker_delayed2 )
1371
+ else
1372
+ LockFreeStack . new1 ( blocker_delayed1 )
1373
+ end
1374
+ else
1375
+ blocker_delayed2 ? LockFreeStack . new1 ( blocker_delayed2 ) : nil
1376
+ end
1377
+ promise = new ( delayed , 2 , *args , &block )
1378
+ ensure
1379
+ blocker1 . add_callback :callback_notify_blocked , promise , 0
1380
+ blocker2 . add_callback :callback_notify_blocked , promise , 1
1381
+ end
1382
+
1357
1383
def self . new_blocked ( blockers , *args , &block )
1358
- delayed = blockers . each_with_object ( LockFreeStack . new , &method ( :add_delayed ) )
1384
+ delayed = blockers . reduce ( nil , &method ( :add_delayed ) )
1359
1385
promise = new ( delayed , blockers . size , *args , &block )
1360
1386
ensure
1361
1387
blockers . each_with_index { |f , i | f . add_callback :callback_notify_blocked , promise , i }
1362
1388
end
1363
1389
1364
- def self . add_delayed ( blocker , delayed )
1365
- d = blocker . promise . delayed
1366
- delayed . push ( d ) if d
1390
+ def self . add_delayed ( delayed , blocker )
1391
+ blocker_delayed = blocker . promise . delayed
1392
+ if blocker_delayed
1393
+ delayed = unless delayed
1394
+ LockFreeStack . new1 ( blocker_delayed )
1395
+ else
1396
+ delayed . push ( blocker_delayed )
1397
+ end
1398
+ end
1399
+ delayed
1367
1400
end
1368
1401
1369
1402
def initialize ( delayed , blockers_count , future )
@@ -1390,7 +1423,7 @@ def touch
1390
1423
end
1391
1424
1392
1425
def clear_propagate_touch
1393
- @Delayed . clear_each { |o | propagate_touch o }
1426
+ @Delayed . clear_each { |o | propagate_touch o } if @Delayed
1394
1427
end
1395
1428
1396
1429
# @!visibility private
@@ -1535,7 +1568,7 @@ def add_delayed_of(future)
1535
1568
if touched?
1536
1569
propagate_touch future . promise . delayed
1537
1570
else
1538
- BlockedPromise . add_delayed future , @Delayed
1571
+ BlockedPromise . add_delayed @Delayed , future
1539
1572
clear_propagate_touch if touched?
1540
1573
end
1541
1574
end
@@ -1581,7 +1614,9 @@ class FlatFuturePromise < AbstractFlatPromise
1581
1614
1582
1615
def initialize ( delayed , blockers_count , levels , default_executor )
1583
1616
raise ArgumentError , 'levels has to be higher than 0' if levels < 1
1584
- super delayed , 1 + levels , Future . new ( self , default_executor )
1617
+ # flat promise may result to a future having delayed futures, therefore we have to have empty stack
1618
+ # to be able to add new delayed futures
1619
+ super delayed || LockFreeStack . new , 1 + levels , Future . new ( self , default_executor )
1585
1620
end
1586
1621
1587
1622
def process_on_blocker_resolution ( future , index )
@@ -1915,7 +1950,7 @@ class Future < AbstractEventFuture
1915
1950
# @return [Future]
1916
1951
def then_select ( *channels )
1917
1952
future = Concurrent ::Promises . select ( *channels )
1918
- ZipFuturesPromise . new_blocked ( [ self , future ] , @DefaultExecutor ) . future
1953
+ ZipFuturesPromise . new_blocked2 ( self , future , @DefaultExecutor ) . future
1919
1954
end
1920
1955
1921
1956
# @note may block
0 commit comments