lib/celluloid/io/common_methods.rb in celluloid-io-0.9.0 vs lib/celluloid/io/common_methods.rb in celluloid-io-0.10.0
- old
+ new
@@ -17,33 +17,71 @@
end
end
# Wait until the current object is writable
def wait_writable
- actor = Thread.current[:actor]
-
if evented?
Celluloid.current_actor.wait_writable(self.to_io)
else
Kernel.select([], [self.to_io])
end
end
+ # Request exclusive control for a particular operation
+ # Type should be one of :r (read) or :w (write)
+ def acquire_ownership(type)
+ return unless Thread.current[:actor]
+
+ case type
+ when :r
+ ivar = :@read_owner
+ when :w
+ ivar = :@write_owner
+ else raise ArgumentError, "invalid ownership type: #{type}"
+ end
+
+ Actor.current.wait(self) while instance_variable_get(ivar)
+ instance_variable_set(ivar, Task.current)
+ end
+
+ # Release ownership for a particular operation
+ # Type should be one of :r (read) or :w (write)
+ def release_ownership(type)
+ return unless Thread.current[:actor]
+
+ case type
+ when :r
+ ivar = :@read_owner
+ when :w
+ ivar = :@write_owner
+ else raise ArgumentError, "invalid ownership type: #{type}"
+ end
+
+ raise "not owner" unless instance_variable_get(ivar) == Task.current
+ instance_variable_set(ivar, nil)
+ Actor.current.signal(self)
+ end
+
def read(length, buffer = nil)
buffer ||= ''
remaining = length
- until remaining.zero?
- begin
- str = readpartial(remaining)
- rescue EOFError
- return if length == remaining
- return buffer
- end
+ acquire_ownership :r
+ begin
+ until remaining.zero?
+ begin
+ str = readpartial(remaining)
+ rescue EOFError
+ return if length == remaining
+ return buffer
+ end
- buffer << str
- remaining -= str.length
+ buffer << str
+ remaining -= str.length
+ end
+ ensure
+ release_ownership :r
end
buffer
end
@@ -63,30 +101,27 @@
def write(string)
length = string.length
total_written = 0
remaining = string
- while total_written < length
- begin
- written = write_nonblock(remaining)
- rescue ::IO::WaitWritable
- wait_writable
- retry
- rescue EOFError
- return total_written
- end
+ acquire_ownership :w
- total_written += written
- if written < remaining.length
- # Avoid mutating string itself, but we can mutate the remaining data
- if remaining == string
- # Copy the remaining data so as to avoid mutating string
- # Note if we have a large amount of data remaining this could be slow
- remaining = string[written..-1]
- else
- remaining.slice!(0, written)
+ begin
+ while total_written < length
+ begin
+ written = write_nonblock(remaining)
+ rescue ::IO::WaitWritable
+ wait_writable
+ retry
+ rescue EOFError
+ return total_written
end
+
+ total_written += written
+ remaining.slice!(0, written) if written < remaining.length
end
+ ensure
+ release_ownership :w
end
total_written
end
alias_method :<<, :write