Created
February 15, 2012 21:39
-
-
Save headius/1839168 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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