Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rubinius/rubinius
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1c6b39f4f54a
Choose a base ref
...
head repository: rubinius/rubinius
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: cf0480f6095c
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Jan 28, 2015

  1. to swap in new IO we need it to happen early enough in the load order…

    … before STDIN/etc are used
    chuckremes committed Jan 28, 2015
    Copy the full SHA
    8fe4536 View commit details
  2. Copy the full SHA
    6a54342 View commit details
  3. Copy the full SHA
    cf0480f View commit details
Showing with 679 additions and 505 deletions.
  1. +0 −375 kernel/bootstrap/io.rb
  2. +649 −118 kernel/common/io.rb
  3. +29 −11 kernel/delta/io.rb
  4. +1 −1 kernel/delta/load_order.txt
375 changes: 0 additions & 375 deletions kernel/bootstrap/io.rb
Original file line number Diff line number Diff line change
@@ -1,284 +1,4 @@
class IO
#@@max_descriptors = 2 #Rubinius::AtomicReference.new(2)

# Import platform constants

SEEK_SET = Rubinius::Config['rbx.platform.io.SEEK_SET']
SEEK_CUR = Rubinius::Config['rbx.platform.io.SEEK_CUR']
SEEK_END = Rubinius::Config['rbx.platform.io.SEEK_END']

F_GETFL = Rubinius::Config['rbx.platform.fcntl.F_GETFL']
F_SETFL = Rubinius::Config['rbx.platform.fcntl.F_SETFL']

# O_ACCMODE is /undocumented/ for fcntl() on some platforms
ACCMODE = Rubinius::Config['rbx.platform.fcntl.O_ACCMODE']

F_GETFD = Rubinius::Config['rbx.platform.fcntl.F_GETFD']
F_SETFD = Rubinius::Config['rbx.platform.fcntl.F_SETFD']
FD_CLOEXEC = Rubinius::Config['rbx.platform.fcntl.FD_CLOEXEC']
O_CLOEXEC = Rubinius::Config['rbx.platform.file.O_CLOEXEC']


attr_accessor :descriptor
attr_accessor :mode

def initialize(fd)
@descriptor = fd
acc_mode = FFI::Platform::POSIX.fcntl(@descriptor, F_GETFL, 0)

if acc_mode < 0
# Assume it's closed.
if Errno.eql?(Errno::EBADF)
@descriptor = -1
end

@mode = nil
else
@mode = acc_mode
end

#io->ibuffer(state, IOBuffer::create(state));
@ibuffer = InternalBuffer.new
@sync = true
@lineno = 0

# Discover final size of file so we can set EOF properly
@total_size = sysseek(0, SEEK_END)
@offset = sysseek(0)
@eof = @offset == @total_size
@unget_buffer = []

# Don't bother to add finalization for stdio
if @descriptor >= 3
# finalize
end
end

def self.initialize_pipe
obj = allocate
obj.instance_variable_set :@descriptor, nil
obj.instance_variable_set :@mode, nil
obj.instance_variable_set :@eof, false
obj.instance_variable_set :@lineno, 0
obj.instance_variable_set :@offset, 0
obj.instance_variable_set :@unget_buffer, []

# setup finalization for pipes

obj
end

def self.pagesize
@pagesize ||= FFI::Platform::POSIX.getpagesize
end

def self.open_with_mode(path, mode, perm)
fd = -1
fd = open_with_cloexec(path, mode, perm)

if fd < 0
Errno.handle("failed to open file")
end

fd
end

def self.open_with_cloexec(path, mode, perm)
if O_CLOEXEC
fd = FFI::Platform::POSIX.open(path, mode | O_CLOEXEC, perm)
update_max_fd(fd)
else
fd = FFI::Platform::POSIX.open(path, mode, perm)
new_open_fd(fd)
end

return fd
end

def self.new_open_fd(new_fd)
if new_fd > 2
flags = FFI::Platform::POSIX.fcntl(new_fd, F_GETFD)
Errno.handle("fcntl(2) failed") if flags == -1
flags = FFI::Platform::POSIX.fcntl(new_fd, F_SETFD, FFI::Platform::POSIX.fcntl(new_fd, F_GETFL) | O_CLOEXEC)
Errno.handle("fcntl(2) failed") if flags == -1
end

update_max_fd(new_fd)
end

def self.update_max_fd(new_fd)
#@@max_descriptors.get_and_set(new_fd)
#@@max_descriptors = @@max_descriptors > fd ? @@max_descriptors : fd
end

def reopen(other_fd)
current_fd = @descriptor

if FFI::Platform::POSIX.dup2(otherfd, current_fd) == -1
Errno.handle("reopen")
return nil
end

set_mode

return true
end

def self.reopen_path(path, mode)
current_fd = @descriptor

other_fd = -1
other_fd = open_with_cloexec(path, mode, 0666)

Exception::errno_error("could not reopen path", Errno.errno, "reopen_path") if other_fd < 0

if FFI::Platform::POSIX.dup2(other_fd, current_fd) == -1
if Errno.eql?(Errno::EBADF)
# means current_fd is closed, so set ourselves to use the new fd and continue
self.descriptor = other_fd
else
FFI::Platform::POSIX.close(other_fd) if other_fd > 0
Exception::errno_error("could not reopen path", Errno.errno, "reopen_path")
end
else
FFI::Platform::POSIX.close(other_fd)
end

set_mode
return true
end

def ensure_open
if descriptor.nil?
raise IOError, "uninitialized stream"
elsif descriptor == -1
raise IOError, "closed stream"
elsif descriptor == -2
raise IOError, "shutdown stream"
end
return nil
end

def connect_pipe(lhs, rhs)
fds = [0, 0]

Errno.handle("creating pipe failed") if pipe(fds) == -1

new_open_fd(fds[0])
new_open_fd(fds[1])

lhs.descriptor = fds[0]
rhs.descriptor = fds[1]
lhs.mode = O_RDONLY
rhs.mode = O_WRONLY
return true
end

CLONG_OVERFLOW = 1 << 64

def sysseek(offset, whence=SEEK_SET)
ensure_open

# FIXME: check +amount+ to make sure it isn't too large
raise RangeError if offset > CLONG_OVERFLOW

position = FFI::Platform::POSIX.lseek(descriptor, offset, whence)

Errno.handle("seek failed") if position == -1

#@offset = position
@eof = position == @total_size
return position
end
alias_method :prim_seek, :sysseek

def ftruncate(offset)
ensure_open

# FIXME: fail if +offset+ is too large, see C++ code

status = FFI::Platform::POSIX.ftruncate(descriptor, offset)
Errno.handle("ftruncate(2) failed") if status == -1
return status
end

def truncate(name, offset)
# FIXME: fail if +offset+ is too large, see C++ code

status = FFI::Platform::POSIX.truncate(name, offset)
Errno.handle("truncate(2) failed") if status == -1
return status
end

def close
ensure_open
fd = descriptor
if fd != -1
ret_code = FFI::Platform::POSIX.close(fd)

if ret_code == -1
Errno.handle("close failed")
elsif ret_code == 0
# no op
else
raise IOError, "::close(): Unknown error on fd #{fd}"
end
end

self.descriptor = -1

return nil
end

# /**
# * This is NOT the same as close().
# *
# * @todo Need to build the infrastructure to be able to only
# * remove read or write waiters if a partial shutdown
# * is requested. --rue
# */
def shutdown(how)
ensure_open
fd = descriptor

if how != SHUT_RD && how != SHUT_WR && how != SHUT_RDWR
raise ArgumentError, "::shutdown(): Invalid `how` #{how} for fd #{fd}"
end

ret_code = FFI::Platform::POSIX.shutdown(fd, how)

if ret_code == -1
Errno.handle("shutdown(2) failed")
elsif ret_code == 0
if how == SHUT_RDWR
close
self.descriptor = -2
end
else
Errno.handle("::shutdown(): Unknown error on fd #{fd}")
end

return how
end

def set_mode
if F_GETFL
acc_mode = FFI::Platform::POSIX.fcntl(@descriptor, F_GETFL)
Ernno.handle("failed") if acc_mode < 0
else
acc_mode = 0
end

@mode = acc_mode
end

def force_read_only
@mode = (@mode & ~O_ACCMODE ) | O_RDONLY
end

def force_write_only
@mode = (@mode & ~O_ACCMODE) | O_WRONLY
end

def finalizer(io)
return unless io.descriptor
@@ -335,66 +55,6 @@ def self.fnmatch(pattern, path, flags)
# raise PrimitiveFailure, "IO#ensure_open primitive failed"
# end

def read(length, output_string=nil)
length ||= IO.pagesize

while true
ensure_open

storage = FFI::MemoryPointer.new(length)
raise IOError, "read(2) failed to malloc a buffer for read length #{length}" if storage.null?
bytes_read = read_into_storage(length, storage)

if bytes_read == -1
if Errno.eql?(Errno::EAGAIN) || Errno.eql?(Errno::EINTR)
redo
else
Errno.handle "read(2) failed"
end

return nil
elsif bytes_read == 0
@eof = true if length > 0
return nil
else
break
end
end

if output_string
output_string.replace(storage.read_string(bytes_read))
else
output_string = storage.read_string(bytes_read).force_encoding(Encoding::ASCII_8BIT)
end

@offset += bytes_read
@eof = true if @offset == @total_size

return output_string
end

def read_into_storage(count, storage)
while true
bytes_read = FFI::Platform::POSIX.read(descriptor, storage, count)

if bytes_read == -1
errno = Errno.errno

if errno == Errno::EAGAIN || errno == Errno::EINTR
ensure_open
next
else
Errno.handle "read(2) failed"
end
else
break
end
end

return bytes_read
end
private :read_into_storage

# def read_primitive(number_of_bytes)
# Rubinius.primitive :io_sysread
# raise PrimitiveFailure, "IO::sysread primitive failed"
@@ -405,41 +65,6 @@ def write2(str)
raise PrimitiveFailure, "IO#write primitive failed"
end

def write(str)
buf_size = str.bytesize
left = buf_size

buffer = FFI::MemoryPointer.new(left)
buffer.write_string(str)
error = false

while left > 0
bytes_written = FFI::Platform::POSIX.write(@descriptor, buffer, left)

if bytes_written == -1
errno = Errno.errno
if errno == Errno::EINTR || errno == Errno::EAGAIN
# do a #select and wait for descriptor to become writable
continue
elsif errno == Errno::EPIPE
if @descriptor == 1 || @descriptor == 2
return buf_size
end
else
error = true
break
end
end

break if error

left -= bytes_written
buffer += bytes_written
end

return(buf_size - left)
end

def read_if_available(size)
Rubinius.primitive :io_read_if_available
raise PrimitiveFailure, "IO#read_if_available primitive failed"
Loading