Skip to content

Commit

Permalink
Move SelectContext shared state to a class
Browse files Browse the repository at this point in the history
  • Loading branch information
bcardiff committed Nov 11, 2019
1 parent 3dd97bf commit 3c8f69a
Showing 1 changed file with 19 additions and 7 deletions.
26 changes: 19 additions & 7 deletions src/channel.cr
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ class Channel(T)
abstract def lock
abstract def unlock

def create_context_and_wait(state_ptr)
context = SelectContext.new(state_ptr, self)
def create_context_and_wait(shared_state)
context = SelectContext.new(shared_state, self)
self.wait(context)
context
end
Expand Down Expand Up @@ -69,8 +69,20 @@ class Channel(T)
Done = 2
end

private class SelectContextSharedState
@state : Atomic(SelectState)

def initialize(value : SelectState)
@state = Atomic(SelectState).new(value)
end

def compare_and_set(cmp : SelectState, new : SelectState) : {SelectState, Bool}
@state.compare_and_set(SelectState::Active, SelectState::Done)
end
end

private class SelectContext(S)
@state : Pointer(Atomic(SelectState))
@state : SelectContextSharedState
property action : SelectAction(S)
@activated = false

Expand All @@ -82,7 +94,7 @@ class Channel(T)
end

def try_trigger : Bool
_, succeed = @state.value.compare_and_set(SelectState::Active, SelectState::Done)
_, succeed = @state.compare_and_set(SelectState::Active, SelectState::Done)
if succeed
@activated = true
end
Expand Down Expand Up @@ -416,11 +428,11 @@ class Channel(T)
return ops.size, NotReady.new
end

# Because channel#close may clean up a long list, `select_context.try_trigger` may
# Because `channel#close` may clean up a long list, `select_context.try_trigger` may
# be called after the select return. In order to prevent invalid address access,
# the state is allocated in the heap.
state_ptr = Pointer.malloc(1, Atomic(SelectState).new(SelectState::Active))
contexts = ops.map &.create_context_and_wait(state_ptr)
shared_state = SelectContextSharedState.new(SelectState::Active)
contexts = ops.map &.create_context_and_wait(shared_state)

ops_locks.each &.unlock
Crystal::Scheduler.reschedule
Expand Down

0 comments on commit 3c8f69a

Please sign in to comment.