Skip to content

Instantly share code, notes, and snippets.

@headius
Created February 15, 2012 21:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save headius/1839168 to your computer and use it in GitHub Desktop.
Save headius/1839168 to your computer and use it in GitHub Desktop.
diff --git a/src/org/jruby/Ruby.java b/src/org/jruby/Ruby.java
index 0a17484..e7239da 100644
--- a/src/org/jruby/Ruby.java
+++ b/src/org/jruby/Ruby.java
@@ -3189,100 +3189,104 @@ public final class Ruby {
}
public RaiseException newErrnoENOTDIRError(String message) {
return newRaiseException(getErrno().getClass("ENOTDIR"), message);
}
public RaiseException newErrnoENOTEMPTYError(String message) {
return newRaiseException(getErrno().getClass("ENOTEMPTY"), message);
}
public RaiseException newErrnoENOTSOCKError(String message) {
return newRaiseException(getErrno().getClass("ENOTSOCK"), message);
}
public RaiseException newErrnoENOTCONNError(String message) {
return newRaiseException(getErrno().getClass("ENOTCONN"), message);
}
public RaiseException newErrnoENOTCONNError() {
return newRaiseException(getErrno().getClass("ENOTCONN"), "Socket is not connected");
}
public RaiseException newErrnoENOENTError(String message) {
return newRaiseException(getErrno().getClass("ENOENT"), message);
}
public RaiseException newErrnoESPIPEError(String message) {
return newRaiseException(getErrno().getClass("ESPIPE"), message);
}
public RaiseException newErrnoEEXISTError(String message) {
return newRaiseException(getErrno().getClass("EEXIST"), message);
}
public RaiseException newErrnoEDOMError(String message) {
return newRaiseException(getErrno().getClass("EDOM"), "Domain error - " + message);
}
public RaiseException newErrnoECHILDError() {
return newRaiseException(getErrno().getClass("ECHILD"), "No child processes");
}
public RaiseException newErrnoEADDRNOTAVAILError(String message) {
return newRaiseException(getErrno().getClass("EADDRNOTAVAIL"), message);
}
public RaiseException newErrnoESRCHError() {
return newRaiseException(getErrno().getClass("ESRCH"), null);
}
+ public RaiseException newErrnoEWOULDBLOCKError() {
+ return newRaiseException(getErrno().getClass("EWOULDBLOCK"), null);
+ }
+
public RaiseException newIndexError(String message) {
return newRaiseException(getIndexError(), message);
}
public RaiseException newSecurityError(String message) {
return newRaiseException(getSecurityError(), message);
}
public RaiseException newSystemCallError(String message) {
return newRaiseException(getSystemCallError(), message);
}
public RaiseException newKeyError(String message) {
return newRaiseException(getKeyError(), message);
}
public RaiseException newErrnoFromLastPOSIXErrno() {
return newRaiseException(getErrno(getPosix().errno()), null);
}
public RaiseException newErrnoFromInt(int errno, String message) {
RubyClass errnoClass = getErrno(errno);
if (errnoClass != null) {
return newRaiseException(errnoClass, message);
} else {
return newSystemCallError("Unknown Error (" + errno + ") - " + message);
}
}
public RaiseException newErrnoFromInt(int errno) {
Errno errnoObj = Errno.valueOf(errno);
if (errnoObj == null) {
return newSystemCallError("Unknown Error (" + errno + ")");
}
String message = errnoObj.description();
return newErrnoFromInt(errno, message);
}
private final static Pattern ADDR_NOT_AVAIL_PATTERN = Pattern.compile("assign.*address");
public RaiseException newErrnoEADDRFromBindException(BindException be) {
String msg = be.getMessage();
if (msg == null) {
msg = "bind";
} else {
msg = "bind - " + msg;
}
// This is ugly, but what can we do, Java provides the same BindingException
// for both EADDRNOTAVAIL and EADDRINUSE, so we differentiate the errors
// based on BindException's message.
diff --git a/src/org/jruby/RubyIO.java b/src/org/jruby/RubyIO.java
index 70bc75a..a24355a 100644
--- a/src/org/jruby/RubyIO.java
+++ b/src/org/jruby/RubyIO.java
@@ -1213,101 +1213,106 @@ public class RubyIO extends RubyObject {
OpenFile myOpenFile = getOpenFileChecked();
myOpenFile.checkWritable(runtime);
Stream writeStream = myOpenFile.getWriteStream();
if (myOpenFile.isWriteBuffered()) {
runtime.getWarnings().warn(ID.SYSWRITE_BUFFERED_IO, "syswrite for buffered IO");
}
if (!writeStream.getDescriptor().isWritable()) {
myOpenFile.checkClosed(runtime);
}
context.getThread().beforeBlockingCall();
int read = writeStream.getDescriptor().write(string.getByteList());
if (read == -1) {
// TODO? I think this ends up propagating from normal Java exceptions
// sys_fail(openFile.getPath())
}
return runtime.newFixnum(read);
} catch (InvalidValueException ex) {
throw runtime.newErrnoEINVALError();
} catch (BadDescriptorException e) {
throw runtime.newErrnoEBADFError();
} catch (IOException e) {
throw runtime.newSystemCallError(e.getMessage());
} finally {
context.getThread().afterBlockingCall();
}
}
@JRubyMethod(name = "write_nonblock", required = 1)
public IRubyObject write_nonblock(ThreadContext context, IRubyObject obj) {
// MRI behavior: always check whether the file is writable
// or not, even if we are to write 0 bytes.
OpenFile myOpenFile = getOpenFileChecked();
try {
myOpenFile.checkWritable(context.getRuntime());
RubyString str = obj.asString();
if (str.getByteList().length() == 0) {
return context.getRuntime().newFixnum(0);
}
if (myOpenFile.isWriteBuffered()) {
context.getRuntime().getWarnings().warn(ID.SYSWRITE_BUFFERED_IO, "write_nonblock for buffered IO");
}
- int written = myOpenFile.getWriteStream().getDescriptor().write(str.getByteList());
+
+ ChannelStream stream = (ChannelStream)myOpenFile.getWriteStream();
+
+ int written = stream.writenonblock(str.getByteList());
+ if (written == 0) throw context.runtime.newErrnoEWOULDBLOCKError();
+
return context.getRuntime().newFixnum(written);
} catch (IOException ex) {
throw context.getRuntime().newIOErrorFromException(ex);
} catch (BadDescriptorException ex) {
throw context.getRuntime().newErrnoEBADFError();
} catch (InvalidValueException ex) {
throw context.getRuntime().newErrnoEINVALError();
}
}
/** io_write
*
*/
@JRubyMethod(name = "write", required = 1)
public IRubyObject write(ThreadContext context, IRubyObject obj) {
Ruby runtime = context.getRuntime();
runtime.secure(4);
RubyString str = obj.asString();
// TODO: Ruby reuses this logic for other "write" behavior by checking if it's an IO and calling write again
if (str.getByteList().length() == 0) {
return runtime.newFixnum(0);
}
try {
OpenFile myOpenFile = getOpenFileChecked();
myOpenFile.checkWritable(runtime);
context.getThread().beforeBlockingCall();
int written = fwrite(str.getByteList());
if (written == -1) {
// TODO: sys fail
}
// if not sync, we switch to write buffered mode
if (!myOpenFile.isSync()) {
myOpenFile.setWriteBuffered();
}
return runtime.newFixnum(written);
} catch (IOException ex) {
throw runtime.newIOErrorFromException(ex);
} catch (BadDescriptorException ex) {
throw runtime.newErrnoEBADFError();
} catch (InvalidValueException ex) {
diff --git a/src/org/jruby/util/io/ChannelStream.java b/src/org/jruby/util/io/ChannelStream.java
index 0ab9d90..c673625 100644
--- a/src/org/jruby/util/io/ChannelStream.java
+++ b/src/org/jruby/util/io/ChannelStream.java
@@ -1207,100 +1207,101 @@ public class ChannelStream implements Stream, Finalizable {
public synchronized int fgetc() throws IOException, BadDescriptorException {
if (eof) {
return -1;
}
checkReadable();
int c = read();
if (c == -1) {
eof = true;
return c;
}
return c & 0xff;
}
public synchronized int fwrite(ByteList string) throws IOException, BadDescriptorException {
return bufferedWrite(string);
}
public synchronized int write(ByteBuffer buf) throws IOException, BadDescriptorException {
return bufferedWrite(buf);
}
public synchronized int writenonblock(ByteList buf) throws IOException, BadDescriptorException {
checkWritable();
ensureWrite();
// Ruby ignores empty syswrites
if (buf == null || buf.length() == 0) return 0;
if (buffer.position() != 0 && !flushWrite(false)) return 0;
if (descriptor.getChannel() instanceof SelectableChannel) {
SelectableChannel selectableChannel = (SelectableChannel)descriptor.getChannel();
synchronized (selectableChannel.blockingLock()) {
boolean oldBlocking = selectableChannel.isBlocking();
try {
if (oldBlocking) {
selectableChannel.configureBlocking(false);
}
return descriptor.write(ByteBuffer.wrap(buf.getUnsafeBytes(), buf.begin(), buf.length()));
} finally {
if (oldBlocking) {
selectableChannel.configureBlocking(oldBlocking);
}
}
}
} else {
+ // can't set nonblocking, so go ahead with it...not much else we can do
return descriptor.write(ByteBuffer.wrap(buf.getUnsafeBytes(), buf.begin(), buf.length()));
}
}
public synchronized ByteList fread(int number) throws IOException, BadDescriptorException {
try {
if (number == 0) {
if (eof) {
return null;
} else {
return new ByteList(0);
}
}
return bufferedRead(number);
} catch (EOFException e) {
eof = true;
return null;
}
}
public synchronized ByteList readnonblock(int number) throws IOException, BadDescriptorException, EOFException {
assert number >= 0;
if (number == 0) {
return null;
}
if (descriptor.getChannel() instanceof SelectableChannel) {
SelectableChannel selectableChannel = (SelectableChannel)descriptor.getChannel();
synchronized (selectableChannel.blockingLock()) {
boolean oldBlocking = selectableChannel.isBlocking();
try {
selectableChannel.configureBlocking(false);
return readpartial(number);
} finally {
selectableChannel.configureBlocking(oldBlocking);
}
}
} else if (descriptor.getChannel() instanceof FileChannel) {
return fread(number);
} else {
return null;
}
}
public synchronized ByteList readpartial(int number) throws IOException, BadDescriptorException, EOFException {
assert number >= 0;
if (number == 0) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment