Skip to content

Commit

Permalink
provide initial but broken C++ to Ruby conversion for IO.select
Browse files Browse the repository at this point in the history
chuckremes committed Mar 30, 2015

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent d64fe7f commit 7ccd64d
Showing 5 changed files with 185 additions and 15 deletions.
117 changes: 104 additions & 13 deletions kernel/common/io.rb
Original file line number Diff line number Diff line change
@@ -605,23 +605,102 @@ def sysseek(offset, whence=SEEK_SET)
raise Errno::ESPIPE
end
end # class FIFOFileDescriptor

def new_pipe(fd, external, internal, options, mode, do_encoding=false)
@fd = FIFOFileDescriptor.new(fd, nil, mode)
@lineno = 0
@pipe = true

# Why do we only set encoding for the "left hand side" pipe? Why not both?
if do_encoding
set_encoding((external || Encoding.default_external), (internal || Encoding.default_internal), options)

# Encapsulates all of the logic necessary for handling #select.
class Select
class FDSet
def self.new
Rubinius.primitive :fdset_allocate
raise PrimitiveFailure, "FDSet.allocate failed"
end

def zero
Rubinius.primitive :fdset_zero
raise PrimitiveFailure, "FDSet.zero failed"
end

def set(descriptor)
Rubinius.primitive :fdset_set
raise PrimitiveFailure, "FDSet.set failed"
end

def set?(descriptor)
Rubinius.primitive :fdset_is_set
raise PrimitiveFailure, "FDSet.set? failed"
end

def to_set
Rubinius.primitive :fdset_to_set
raise PrimitiveFailure, "FDSet.to_set failed"
end
end
end
private :new_pipe

MAX_FD = 1024

def self.fd_set_from_array(array)
highest = -1
fd_set = FDSet.new
fd_set.zero

array.each do |io|
descriptor = io.descriptor

if descriptor >= MAX_FD
raise IOError
elsif descriptor >= 0
fd_set.set(descriptor)
end
end

return [fd_set, highest]
end

def self.collect_set_fds(array, fd_set)
array.select { |io| fd_set.set?(io.descriptor) || io.descriptor < 0 }
end

def self.make_timeout(time)

end

def self.reset_timeout(limit, now)

end

def self.select(readables, writables, errorables, timeout)
read_set, highest_read_fd = fd_set_from_array(readables)
write_set, highest_write_fd = fd_set_from_array(writables)
error_set, highest_err_fd = fd_set_from_array(errorables)
max_fd = [highest_read_fd, highest_write_fd, highest_err_fd].max

time_limit, now = make_timeval_timeout(timeout)

loop do
if FFI.called_failed?(events = FFI::Platform::POSIX.select(max_fd, read_set, write_set, error_set, time_limit))

if Errno::EAGAIN::Errno == Errno.errno || Errno::EINTR::Errno == Errno.errno
# return nil if async_interruption?
time_limit, now = reset_timeval_timeout(time_limit, now)
continue
end

Errno.handle("select(2) failed")
end
end

return nil if events.zero?

output_fds = []
output_fds << collect_set_fds(readables, read_set)
output_fds << collect_set_fds(writables, write_set)
output_fds << collect_set_fds(errorables, error_set)
return output_fds
end
end # class Select

attr_accessor :external
attr_accessor :internal

def self.binread(file, length=nil, offset=0)
raise ArgumentError, "Negative length #{length} given" if !length.nil? && length < 0

@@ -1285,7 +1364,7 @@ def self.select(readables=nil, writables=nil, errorables=nil, timeout=nil)
end
end

IO.select_primitive(readables, writables, errorables, timeout)
IO::Select.select(readables, writables, errorables, timeout)
end

##
@@ -1409,6 +1488,18 @@ def initialize_copy(original_io) # :nodoc:
end
private :initialize_copy

def new_pipe(fd, external, internal, options, mode, do_encoding=false)
@fd = FIFOFileDescriptor.new(fd, nil, mode)
@lineno = 0
@pipe = true

# Why do we only set encoding for the "left hand side" pipe? Why not both?
if do_encoding
set_encoding((external || Encoding.default_external), (internal || Encoding.default_internal), options)
end
end
private :new_pipe

def super_inspect
"<IO:#{object_id}> \n#{@fd.inspect}"
end
47 changes: 46 additions & 1 deletion vm/builtin/io.cpp
Original file line number Diff line number Diff line change
@@ -1510,4 +1510,49 @@ namespace rubinius {
start += used_->to_native();
return start;
}
};

void FDSet::init(STATE) {
// Create a constant for FDSet under the IO::Select namespace, i.e. IO::Select::FDSet
GO(select).set(ontology::new_class_under(state, "Select", G(io)));
GO(fdset).set(ontology::new_class_under(state, "FDSet", G(select)));
G(fdset)->set_object_type(state, FDSetType);
}

FDSet* FDSet::allocate(STATE, Object* self) {
FDSet* fdset = create(state);
fdset->klass(state, as<Class>(self));
return fdset;
}

FDSet* FDSet::create(STATE) {
FDSet* fdset = state->new_object<FDSet>(G(fdset));
fdset->actual_set = (fd_set*)malloc(sizeof(fd_set));
return fdset;
}

Object* FDSet::zero(STATE) {
FD_ZERO(actual_set);
return cTrue;
}

Object* FDSet::set(STATE, Fixnum* descriptor) {
native_int fd = descriptor->to_native();

FD_SET((int_fd_t)fd, actual_set);

return cTrue;
}

Object* FDSet::is_set(STATE, Fixnum* descriptor) {
native_int fd = descriptor->to_native();

if (FD_ISSET(fd, actual_set)) {
return cTrue;
}
else {
return cFalse;
}
}

}; // ends namespace rubinius

31 changes: 31 additions & 0 deletions vm/builtin/io.hpp
Original file line number Diff line number Diff line change
@@ -207,7 +207,38 @@ namespace rubinius {
BASIC_TYPEINFO(TypeInfo)
};
};

class FDSet : public Object {
public:
const static object_type type = FDSetType;

private:
fd_set* actual_set;

public:

static void init(STATE);

static FDSet* create(STATE);

// Rubinius.primitive :fdset_allocate
static FDSet* allocate(STATE, Object* self);

// Rubinius.primitive :fdset_zero
Object* zero(STATE);

// Rubinius.primitive :fdset_is_set
Object* is_set(STATE, Fixnum* descriptor);

// Rubinius.primitive :fdset_set
Object* set(STATE, Fixnum* descriptor);

class Info : public TypeInfo {
public:
BASIC_TYPEINFO(TypeInfo)
};
};

}

#endif
4 changes: 3 additions & 1 deletion vm/globals.hpp
Original file line number Diff line number Diff line change
@@ -55,7 +55,7 @@ namespace rubinius {
TypedRoot<Class*> nil_class, true_class, false_class, fixnum_class, undef_class;
TypedRoot<Class*> floatpoint, nmc, list, list_node;
TypedRoot<Class*> channel, thread, thread_state, constantscope, constant_table, lookuptable;
TypedRoot<Class*> iseq, executable, native_function, iobuffer;
TypedRoot<Class*> iseq, executable, native_function, iobuffer, select, fdset;
TypedRoot<Class*> included_module;

/* the primary symbol table */
@@ -175,6 +175,8 @@ namespace rubinius {
executable(&roots),
native_function(&roots),
iobuffer(&roots),
select(&roots),
fdset(&roots),
included_module(&roots),
sym_method_missing(&roots),
sym_respond_to_missing(&roots),
1 change: 1 addition & 0 deletions vm/ontology.cpp
Original file line number Diff line number Diff line change
@@ -366,6 +366,7 @@ namespace rubinius {
Randomizer::init(state);
Encoding::init(state);
FSEvent::init(state);
FDSet::init(state);
Logger::init(state);
JIT::init(state);
}

0 comments on commit 7ccd64d

Please sign in to comment.