Skip to content

Commit

Permalink
Initial version of rubinius-core-api JRuby support.
Browse files Browse the repository at this point in the history
  • Loading branch information
headius committed Jun 15, 2011
0 parents commit 93d98fc
Show file tree
Hide file tree
Showing 19 changed files with 1,835 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
lib/rubinius-core-api.jar
pkg
*.gem
20 changes: 20 additions & 0 deletions README.txt
@@ -0,0 +1,20 @@
This is an attempt to provide some of Rubinius's additional core classes on
other implementations.

Rubinius has all the normal Ruby classes, but to support implementing them
mostly in Ruby, they have added a number of other support classes. This
library hopes to implement those additional support classes for other Ruby
implementations, so they their utility can be shared across implementations.

Currently, only the following classes are implemented, and only on JRuby:

Rubinius::ByteArray - a fixed-size array of bytes
Rubinius::Channel - a low-level synchronization mechanism
Rubinius::EnvironmentAccess - env variable support
Rubinius::Tuple - a fixed-size array of object references
Rubinius::Type - utilities for type conversions

In addition, some utility methods added to Thread for recursive guards and
Kernel::StringValue are also implemented.

More APIs will be added over time.
36 changes: 36 additions & 0 deletions Rakefile
@@ -0,0 +1,36 @@
task :default => :spec

if defined?(JRUBY_VERSION)
require 'ant'

directory "pkg/classes"

desc "Clean up build artifacts"
task :clean do
rm_rf "pkg/classes"
rm_rf "lib/rubinius-core-api.jar"
end

desc "Compile the extension"
task :compile => "pkg/classes" do |t|
ant.javac :srcdir => "src", :destdir => t.prerequisites.first,
:source => "1.5", :target => "1.5", :debug => true,
:classpath => "${java.class.path}:${sun.boot.class.path}"
end

desc "Build the jar"
task :jar => :compile do
ant.jar :basedir => "pkg/classes", :destfile => "lib/rubinius-core-api.jar", :includes => "**/*.class"
end

task :package => :jar
elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
task :package do
# nop
end
end

desc "Run the specs"
task :spec => :package do
ruby "-S", "rspec", "spec"
end
16 changes: 16 additions & 0 deletions lib/rubinius/core-api.rb
@@ -0,0 +1,16 @@
if defined?(JRUBY_VERSION)
begin
require 'rubinius-core-api.jar'
rescue LoadError
# keep going; might be bundled into classpath already
end

# for access to JRuby runtime
require 'jruby'

org.jruby.ext.rubinius.RubiniusLibrary.new.load(JRuby.runtime, false)
elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
# do nothing for Rubinius
else
raise "Only supported on JRuby and Rubinius"
end
106 changes: 106 additions & 0 deletions lib/rubinius/kernel/bootstrap/channel.rb
@@ -0,0 +1,106 @@
##
# Channel is a FIFO, thread-aware value passing class that can hold any number
# of objects similar to Queue. Use #send to add objects to the channel and
# #receive to remove objects from the channel.
#
# If Channel#receive is called on an empty channel, the VM puts the current
# Thread (t1) to sleep. At some future time, when Channel#send is called on
# that same thread, the VM wakes up t1 and the value passed to #send is
# returned. This allows us to implement all manner of Thread semantics, such
# as Mutex.
#
# Channel is used heavily by Scheduler, to allow ruby code to interact with
# the outside world in a thread aware manner.

module Rubinius
class Channel

##
# Returns nil if nothing is waiting, or a List object which contains all
# Thread objects waiting on this Channel.

attr_reader :waiting

##
# Returns nil if there are no values, otherwise a List object containing all
# values the Channel contains.

attr_reader :value

##
# Creates a new Channel and registers it with the VM.

def self.new
Ruby.primitive :channel_new
raise PrimitiveFailure, "Channel.new primitive failed"
end

# We must be sure a Channel is always created properly, so handle
# this the same as new.
def self.allocate
Ruby.primitive :channel_new
raise PrimitiveFailure, "Channel.new primitive failed"
end

##
# Puts +obj+ in the Channel. If there are waiting threads the first thread
# will be woken up and handed +obj+.

def send(obj)
Ruby.primitive :channel_send
raise PrimitiveFailure, "Channel#send primitive failed"
end

alias_method :<<, :send

##
# Removes and returns the first value from the Channel. If the channel
# is empty, Thread.current is put to sleep until #send is called.

def receive
Ruby.primitive :channel_receive
raise PrimitiveFailure, "Channel#receive primitive failed"
end

def receive_timeout(duration)
Ruby.primitive :channel_receive_timeout
raise PrimitiveFailure, "Channel#receive_timeout primitive failed"
end

def try_receive
Ruby.primitive :channel_try_receive
raise PrimitiveFailure, "Channel#try_receive primitive failed"
end

##
# Converts +obj+ into a Channel using #to_channel.

def self.convert_to_channel(obj)
return obj if Channel === obj
begin
o2 = obj.to_channel
unless Channel === o2
raise ArgumentError, "to_channel on #{obj.inspect} did not return a Channel"
end
return o2
rescue NoMethodError
raise ArgumentError, "Unable to convert #{obj.inspect} into a channel"
end
end

##
# Legacy API. To be removed.

def self.receive(obj) # :nodoc:
return convert_to_channel(obj).receive
end

##
# API compliance, returns self.

def to_channel
self
end

end
end
26 changes: 26 additions & 0 deletions lib/rubinius/kernel/common/bytearray.rb
@@ -0,0 +1,26 @@
##
# An array of bytes, used as a low-level data store for implementing various
# other classes.

class Rubinius::ByteArray
alias_method :[], :get_byte
alias_method :[]=, :set_byte

def each
i = 0
max = size()

while i < max
yield get_byte(i)
i += 1
end
end

def inspect
"#<#{self.class}:0x#{object_id.to_s(16)} #{size} bytes>"
end

def <=>(other)
compare_bytes other, size, other.size
end
end
21 changes: 21 additions & 0 deletions lib/rubinius/kernel/common/channel.rb
@@ -0,0 +1,21 @@
##
# A communication mechanism based on pi-calculus channels used primarily to
# communicate between ruby and the VM about events.

module Rubinius
class Channel
def inspect
"#<Rubinius::Channel>"
end

def as_lock(val=nil)
receive

begin
yield
ensure
self << val
end
end
end
end

0 comments on commit 93d98fc

Please sign in to comment.