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
  • Loading branch information
chuckremes committed Mar 30, 2015
1 parent d64fe7f commit 7ccd64d
Show file tree
Hide file tree
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
Expand Up @@ -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

Expand Down Expand Up @@ -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

##
Expand Down Expand Up @@ -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
Expand Down
47 changes: 46 additions & 1 deletion vm/builtin/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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
Expand Up @@ -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 */
Expand Down Expand Up @@ -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),
Expand Down
1 change: 1 addition & 0 deletions vm/ontology.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ namespace rubinius {
Randomizer::init(state);
Encoding::init(state);
FSEvent::init(state);
FDSet::init(state);
Logger::init(state);
JIT::init(state);
}
Expand Down

0 comments on commit 7ccd64d

Please sign in to comment.