public static RubyClass createPointerClass(Ruby runtime, RubyModule module) { RubyClass pointerClass = module.defineClassUnder( "Pointer", module.getClass(AbstractMemory.ABSTRACT_MEMORY_RUBY_CLASS), RubyInstanceConfig.REIFY_RUBY_CLASSES ? new ReifyingAllocator(Pointer.class) : PointerAllocator.INSTANCE); pointerClass.defineAnnotatedMethods(Pointer.class); pointerClass.defineAnnotatedConstants(Pointer.class); pointerClass.setReifiedClass(Pointer.class); pointerClass.kindOf = new RubyModule.KindOf() { @Override public boolean isKindOf(IRubyObject obj, RubyModule type) { return obj instanceof Pointer && super.isKindOf(obj, type); } }; module.defineClassUnder( "NullPointerError", runtime.getRuntimeError(), runtime.getRuntimeError().getAllocator()); // Add Pointer::NULL as a constant Pointer nullPointer = new Pointer(runtime, pointerClass, new NullMemoryIO(runtime)); pointerClass.setConstant("NULL", nullPointer); runtime .getNilClass() .addMethod("to_ptr", new NilToPointerMethod(runtime.getNilClass(), nullPointer)); return pointerClass; }
public static RubyClass createThreadClass(Ruby runtime) { // FIXME: In order for Thread to play well with the standard 'new' behavior, // it must provide an allocator that can create empty object instances which // initialize then fills with appropriate data. RubyClass threadClass = runtime.defineClass( "Thread", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR); runtime.setThread(threadClass); threadClass.index = ClassIndex.THREAD; threadClass.setReifiedClass(RubyThread.class); threadClass.defineAnnotatedMethods(RubyThread.class); RubyThread rubyThread = new RubyThread(runtime, threadClass); // TODO: need to isolate the "current" thread from class creation rubyThread.threadImpl = new NativeThread(rubyThread, Thread.currentThread()); runtime.getThreadService().setMainThread(Thread.currentThread(), rubyThread); // set to default thread group runtime.getDefaultThreadGroup().addDirectly(rubyThread); threadClass.setMarshal(ObjectMarshal.NOT_MARSHALABLE_MARSHAL); return threadClass; }
private synchronized IRubyObject status(Ruby runtime) { if (threadImpl.isAlive()) { return RubyString.newStringShared(runtime, status.get().bytes); } else if (exitingException != null) { return runtime.getNil(); } else { return runtime.getFalse(); } }
public static IRubyObject newLocationArray(Ruby runtime, RubyStackTraceElement[] elements) { RubyArray ary = runtime.newArray(elements.length); for (RubyStackTraceElement element : elements) { ary.append(new RubyThread.Location(runtime, runtime.getLocation(), element)); } return ary; }
@JRubyMethod(rest = true, name = "start", meta = true, compat = RUBY1_9) public static RubyThread start19(IRubyObject recv, IRubyObject[] args, Block block) { Ruby runtime = recv.getRuntime(); // The error message may appear incongruous here, due to the difference // between JRuby's Thread model and MRI's. // We mimic MRI's message in the name of compatibility. if (!block.isGiven()) throw runtime.newArgumentError("tried to create Proc object without a block"); return startThread(recv, args, false, block); }
@JRubyMethod(rest = true, visibility = PRIVATE) public IRubyObject initialize(ThreadContext context, IRubyObject[] args, Block block) { Ruby runtime = getRuntime(); if (!block.isGiven()) throw runtime.newThreadError("must be called with a block"); if (threadImpl != null) throw runtime.newThreadError("already initialized thread"); RubyRunnable runnable = new RubyRunnable(this, args, block); return startWith(runnable); }
@JRubyMethod public IRubyObject convpath(ThreadContext context) { Ruby runtime = context.runtime; EncodingService encodingService = runtime.getEncodingService(); // we always pass through UTF-16 IRubyObject utf16Encoding = encodingService.getEncodingList()[UTF16.getIndex()]; return RubyArray.newArray( runtime, RubyArray.newArray(runtime, source_encoding(context), utf16Encoding), RubyArray.newArray(runtime, utf16Encoding, destination_encoding(context))); }
public static RubyClass createConverterClass(Ruby runtime) { RubyClass converterc = runtime.defineClassUnder( "Converter", runtime.getClass("Data"), CONVERTER_ALLOCATOR, runtime.getEncoding()); runtime.setConverter(converterc); converterc.index = ClassIndex.CONVERTER; converterc.setReifiedClass(RubyConverter.class); converterc.kindOf = new RubyModule.JavaClassKindOf(RubyConverter.class); converterc.defineAnnotatedMethods(RubyConverter.class); return converterc; }
@JRubyMethod(visibility = PRIVATE) public IRubyObject initialize( ThreadContext context, IRubyObject src, IRubyObject dest, IRubyObject _opt) { Ruby runtime = context.runtime; EncodingService encodingService = runtime.getEncodingService(); // both may be null Encoding srcEncoding = encodingService.getEncodingFromObjectNoError(src); Encoding destEncoding = encodingService.getEncodingFromObjectNoError(dest); int flags = 0; IRubyObject replace = context.nil; if (srcEncoding == destEncoding && srcEncoding != null) { throw runtime.newConverterNotFoundError( "code converter not found (" + srcEncoding + " to " + destEncoding + ")"); } // Ensure we'll be able to get charsets fo these encodings try { if (srcEncoding != destEncoding) { if (srcEncoding != null) encodingService.charsetForEncoding(srcEncoding); if (destEncoding != null) encodingService.charsetForEncoding(destEncoding); } } catch (RaiseException e) { if (e.getException().getMetaClass().getBaseName().equals("CompatibilityError")) { throw runtime.newConverterNotFoundError( "code converter not found (" + srcEncoding + " to " + destEncoding + ")"); } else { throw e; } } if (!_opt.isNil()) { if (_opt instanceof RubyHash) { RubyHash opt = (RubyHash) _opt; flags |= EncodingUtils.econvPrepareOpts(context, opt, new IRubyObject[] {opt}); IRubyObject value = opt.fastARef(runtime.newSymbol("replace")); if (value != null) { replace = value; } } else { flags = (int) _opt.convertToInteger().getLongValue(); replace = context.nil; } } transcoder = new CharsetTranscoder(context, destEncoding, srcEncoding, flags, replace); return context.runtime.getNil(); }
@JRubyMethod(name = "pass", meta = true) public static IRubyObject pass(IRubyObject recv) { Ruby runtime = recv.getRuntime(); ThreadService ts = runtime.getThreadService(); boolean critical = ts.getCritical(); ts.setCritical(false); Thread.yield(); ts.setCritical(critical); return recv.getRuntime().getNil(); }
public void exceptionRaised(RaiseException exception) { assert isCurrent(); RubyException rubyException = exception.getException(); Ruby runtime = rubyException.getRuntime(); if (runtime.getSystemExit().isInstance(rubyException)) { runtime .getThreadService() .getMainThread() .raise(new IRubyObject[] {rubyException}, Block.NULL_BLOCK); } else if (abortOnException(runtime)) { RubyException systemExit; if (!runtime.is1_9()) { runtime.printError(rubyException); systemExit = RubySystemExit.newInstance(runtime, 1); systemExit.message = rubyException.message; systemExit.set_backtrace(rubyException.backtrace()); } else { systemExit = rubyException; } runtime .getThreadService() .getMainThread() .raise(new IRubyObject[] {systemExit}, Block.NULL_BLOCK); return; } else if (runtime.getDebug().isTrue()) { runtime.printError(exception.getException()); } exitingException = exception; }
private static RubyThread adoptThread(final IRubyObject recv, Thread t, Block block) { final Ruby runtime = recv.getRuntime(); final RubyThread rubyThread = new RubyThread(runtime, (RubyClass) recv); rubyThread.threadImpl = new NativeThread(rubyThread, t); ThreadContext context = runtime.getThreadService().registerNewThread(rubyThread); runtime.getThreadService().associateThread(t, rubyThread); context.preAdoptThread(); // set to default thread group runtime.getDefaultThreadGroup().addDirectly(rubyThread); return rubyThread; }
/** * For handling all non-Ruby exceptions bubbling out of threads * * @param exception */ @SuppressWarnings("deprecation") public void exceptionRaised(Throwable exception) { if (exception instanceof RaiseException) { exceptionRaised((RaiseException) exception); return; } assert isCurrent(); Ruby runtime = getRuntime(); if (abortOnException(runtime) && exception instanceof Error) { // re-propagate on main thread runtime.getThreadService().getMainThread().getNativeThread().stop(exception); } else { // just rethrow on this thread, let system handlers report it UnsafeFactory.getUnsafe().throwException(exception); } }
private IRubyObject symbolFromResult( RubyCoderResult result, Ruby runtime, int flags, ThreadContext context) { if (result != null) { return runtime.newSymbol(result.stringResult); } if ((flags & PARTIAL_INPUT) == 0) { return context.runtime.newSymbol("finished"); } else { return context.runtime.newSymbol("source_buffer_empty"); } }
@JRubyMethod(optional = 3) public IRubyObject raise(IRubyObject[] args, Block block) { Ruby runtime = getRuntime(); ThreadContext context = runtime.getCurrentContext(); if (this == context.getThread()) { return RubyKernel.raise(context, runtime.getKernel(), args, block); } debug(this, "before raising"); RubyThread currentThread = getRuntime().getCurrentContext().getThread(); debug(this, "raising"); IRubyObject exception = prepareRaiseException(runtime, args, block); runtime .getThreadService() .deliverEvent( new ThreadService.Event( currentThread, this, ThreadService.Event.Type.RAISE, exception)); return this; }
@JRubyMethod(compat = RUBY1_9, meta = true) public static IRubyObject asciicompat_encoding( ThreadContext context, IRubyObject self, IRubyObject strOrEnc) { Ruby runtime = context.runtime; EncodingService encodingService = runtime.getEncodingService(); Encoding encoding = encodingService.getEncodingFromObjectNoError(strOrEnc); if (encoding == null) { return context.nil; } if (encoding.isAsciiCompatible()) { return context.nil; } Encoding asciiCompat = NONASCII_TO_ASCII.get(encoding); if (asciiCompat == null) { throw runtime.newConverterNotFoundError("no ASCII compatible encoding found for " + strOrEnc); } return encodingService.convertEncodingToRubyEncoding(asciiCompat); }
@JRubyMethod(compat = RUBY1_9) public IRubyObject primitive_errinfo(ThreadContext context) { Ruby runtime = context.runtime; RubyCoderResult lastResult = transcoder.getLastResult(); // if we have not done anything, produce an empty errinfo if (lastResult == null) { return runtime.newArray( new IRubyObject[] { runtime.newSymbol("source_buffer_empty"), context.nil, context.nil, context.nil, context.nil }); } RubyArray errinfo = RubyArray.newArray(context.runtime); if (!lastResult.isError()) { return runtime.newArray( new IRubyObject[] { runtime.newSymbol(lastResult.stringResult), context.nil, context.nil, context.nil, context.nil }); } else { errinfo.append(runtime.newSymbol(lastResult.stringResult)); // FIXME: gross errinfo.append(RubyString.newString(runtime, lastResult.inEncoding.getName())); errinfo.append(RubyString.newString(runtime, lastResult.outEncoding.getName())); if (lastResult.isError() && lastResult.errorBytes != null) { // FIXME: do this elsewhere and cache it ByteList errorBytes = new ByteList(lastResult.errorBytes, lastResult.inEncoding, true); errinfo.append(RubyString.newString(runtime, errorBytes)); } else { errinfo.append(RubyString.newEmptyString(runtime)); } if (lastResult.readagainBytes != null) { // FIXME: do this elsewhere and cache it ByteList readagainBytes = new ByteList(lastResult.readagainBytes, lastResult.inEncoding, true); errinfo.append(RubyString.newString(runtime, readagainBytes)); } else { errinfo.append(RubyString.newEmptyString(runtime)); } } return errinfo; }
@JRubyMethod(rest = true, visibility = PRIVATE) public IRubyObject initialize(ThreadContext context, IRubyObject[] args, Block block) { Ruby runtime = getRuntime(); if (!block.isGiven()) throw runtime.newThreadError("must be called with a block"); try { RubyRunnable runnable = new RubyRunnable(this, args, context.getFrames(0), block); if (RubyInstanceConfig.POOLING_ENABLED) { FutureThread futureThread = new FutureThread(this, runnable); threadImpl = futureThread; addToCorrectThreadGroup(context); threadImpl.start(); // JRUBY-2380, associate future early so it shows up in Thread.list right away, in case it // doesn't run immediately runtime.getThreadService().associateThread(futureThread.getFuture(), this); } else { Thread thread = new Thread(runnable); thread.setDaemon(true); thread.setName( "Ruby" + thread.getName() + ": " + context.getFile() + ":" + (context.getLine() + 1)); threadImpl = new NativeThread(this, thread); addToCorrectThreadGroup(context); // JRUBY-2380, associate thread early so it shows up in Thread.list right away, in case it // doesn't run immediately runtime.getThreadService().associateThread(thread, this); threadImpl.start(); } // We yield here to hopefully permit the target thread to schedule // MRI immediately schedules it, so this is close but not exact Thread.yield(); return this; } catch (OutOfMemoryError oome) { if (oome.getMessage().equals("unable to create new native thread")) { throw runtime.newThreadError(oome.getMessage()); } throw oome; } catch (SecurityException ex) { throw runtime.newThreadError(ex.getMessage()); } }
private IRubyObject startWith(ThreadedRunnable runnable) throws RaiseException, OutOfMemoryError { Ruby runtime = getRuntime(); ThreadContext context = runtime.getCurrentContext(); try { if (RubyInstanceConfig.POOLING_ENABLED) { FutureThread futureThread = new FutureThread(this, runnable); threadImpl = futureThread; addToCorrectThreadGroup(context); threadImpl.start(); // JRUBY-2380, associate future early so it shows up in Thread.list right away, in case it // doesn't run immediately runtime.getThreadService().associateThread(futureThread.getFuture(), this); } else { Thread thread = new Thread(runnable); thread.setDaemon(true); thread.setName( "Ruby" + thread.getName() + ": " + context.getFile() + ":" + (context.getLine() + 1)); threadImpl = new NativeThread(this, thread); addToCorrectThreadGroup(context); // JRUBY-2380, associate thread early so it shows up in Thread.list right away, in case it // doesn't run immediately runtime.getThreadService().associateThread(thread, this); threadImpl.start(); } // We yield here to hopefully permit the target thread to schedule // MRI immediately schedules it, so this is close but not exact Thread.yield(); return this; } catch (OutOfMemoryError oome) { if (oome.getMessage().equals("unable to create new native thread")) { throw runtime.newThreadError(oome.getMessage()); } throw oome; } catch (SecurityException ex) { throw runtime.newThreadError(ex.getMessage()); } }
private IRubyObject prepareRaiseException(Ruby runtime, IRubyObject[] args, Block block) { if (args.length == 0) { IRubyObject lastException = errorInfo; if (lastException.isNil()) { return new RaiseException(runtime, runtime.getRuntimeError(), "", false).getException(); } return lastException; } IRubyObject exception; ThreadContext context = getRuntime().getCurrentContext(); if (args.length == 1) { if (args[0] instanceof RubyString) { return runtime.getRuntimeError().newInstance(context, args, block); } if (!args[0].respondsTo("exception")) { return runtime.newTypeError("exception class/object expected").getException(); } exception = args[0].callMethod(context, "exception"); } else { if (!args[0].respondsTo("exception")) { return runtime.newTypeError("exception class/object expected").getException(); } exception = args[0].callMethod(context, "exception", args[1]); } if (!runtime.getException().isInstance(exception)) { return runtime.newTypeError("exception object expected").getException(); } if (args.length == 3) { ((RubyException) exception).set_backtrace(args[2]); } return exception; }
public static final Pointer getNull(Ruby runtime) { return runtime.getFFI().nullPointer; }
@JRubyMethod(name = "join", optional = 1) public IRubyObject join(IRubyObject[] args) { Ruby runtime = getRuntime(); long timeoutMillis = Long.MAX_VALUE; if (args.length > 0 && !args[0].isNil()) { if (args.length > 1) { throw getRuntime().newArgumentError(args.length, 1); } // MRI behavior: value given in seconds; converted to Float; less // than or equal to zero returns immediately; returns nil timeoutMillis = (long) (1000.0D * args[0].convertToFloat().getValue()); if (timeoutMillis <= 0) { // TODO: not sure that we should skip calling join() altogether. // Thread.join() has some implications for Java Memory Model, etc. if (threadImpl.isAlive()) { return getRuntime().getNil(); } else { return this; } } } if (isCurrent()) { throw getRuntime().newThreadError("thread " + identityString() + " tried to join itself"); } try { if (runtime.getThreadService().getCritical()) { // If the target thread is sleeping or stopped, wake it synchronized (this) { notify(); } // interrupt the target thread in case it's blocking or waiting // WARNING: We no longer interrupt the target thread, since this usually means // interrupting IO and with NIO that means the channel is no longer usable. // We either need a new way to handle waking a target thread that's waiting // on IO, or we need to accept that we can't wake such threads and must wait // for them to complete their operation. // threadImpl.interrupt(); } RubyThread currentThread = getRuntime().getCurrentContext().getThread(); final long timeToWait = Math.min(timeoutMillis, 200); // We need this loop in order to be able to "unblock" the // join call without actually calling interrupt. long start = System.currentTimeMillis(); while (true) { currentThread.pollThreadEvents(); threadImpl.join(timeToWait); if (!threadImpl.isAlive()) { break; } if (System.currentTimeMillis() - start > timeoutMillis) { break; } } } catch (InterruptedException ie) { ie.printStackTrace(); assert false : ie; } catch (ExecutionException ie) { ie.printStackTrace(); assert false : ie; } if (exitingException != null) { // Set $! in the current thread before exiting getRuntime().getGlobalVariables().set("$!", (IRubyObject) exitingException.getException()); throw exitingException; } if (threadImpl.isAlive()) { return getRuntime().getNil(); } else { return this; } }
public RubyConverter(Ruby runtime) { super(runtime, runtime.getConverter()); }
/** * Returns the status of the global ``abort on exception'' condition. The default is false. When * set to true, will cause all threads to abort (the process will exit(0)) if an exception is * raised in any thread. See also Thread.abort_on_exception= . */ @JRubyMethod(name = "abort_on_exception", meta = true) public static RubyBoolean abort_on_exception_x(IRubyObject recv) { Ruby runtime = recv.getRuntime(); return runtime.isGlobalAbortOnExceptionEnabled() ? runtime.getTrue() : runtime.getFalse(); }
@JRubyMethod(required = 2, optional = 4) public IRubyObject primitive_convert(ThreadContext context, IRubyObject[] args) { Ruby runtime = context.runtime; RubyString input; RubyString output; int outputByteoffset = -1; int outputBytesize = 0; int flags = 0; int hashArg = -1; if (args.length > 2 && !args[2].isNil()) { if (args.length == 3 && args[2] instanceof RubyHash) { hashArg = 2; } else { outputByteoffset = (int) args[2].convertToInteger().getLongValue(); if (outputByteoffset < 0) throw runtime.newArgumentError("negative offset"); } } if (args.length > 3 && !args[3].isNil()) { if (args.length == 4 && args[3] instanceof RubyHash) { hashArg = 3; } else { outputBytesize = (int) args[3].convertToInteger().getLongValue(); if (outputBytesize < 0) throw runtime.newArgumentError("negative bytesize"); } } if (args.length > 4 && !args[4].isNil()) { if (args.length > 5 && !args[5].isNil()) { throw runtime.newArgumentError(args.length, 5); } if (args[4] instanceof RubyHash) { hashArg = 4; } else { flags = (int) args[4].convertToInteger().getLongValue(); } } IRubyObject opt = context.nil; if (hashArg != -1 && !(opt = TypeConverter.checkHashType(runtime, args[hashArg])).isNil()) { IRubyObject v = ((RubyHash) opt).op_aref(context, runtime.newSymbol("partial_input")); if (v.isTrue()) { flags |= EncodingUtils.ECONV_PARTIAL_INPUT; } v = ((RubyHash) opt).op_aref(context, runtime.newSymbol("after_output")); if (v.isTrue()) { flags |= EncodingUtils.ECONV_AFTER_OUTPUT; } } else { flags = 0; } ByteList inBytes; ByteList outBytes; if (args[0].isNil()) { inBytes = new ByteList(); } else { input = args[0].convertToString(); input.modify19(); inBytes = input.getByteList(); } output = args[1].convertToString(); output.modify19(); outBytes = output.getByteList(); if (outputByteoffset == -1) { outputByteoffset = outBytes.getRealSize(); } else if (outputByteoffset > outBytes.getRealSize()) { throw runtime.newArgumentError("offset too big"); } int outputByteEnd = outputByteoffset + outputBytesize; if (outputByteEnd > outBytes.getRealSize()) { outBytes.ensure(outputByteEnd); } RubyCoderResult result = transcoder.primitiveConvert( context, inBytes, output.getByteList(), outputByteoffset, outputBytesize, inBytes.getEncoding(), inBytes.getEncoding().isAsciiCompatible(), flags); outBytes.setEncoding( transcoder.outEncoding != null ? transcoder.outEncoding : inBytes.getEncoding()); return symbolFromResult(result, runtime, flags, context); }
protected RubyThread(Ruby runtime, RubyClass type) { super(runtime, type); finalResult = runtime.getNil(); errorInfo = runtime.getNil(); }
public Pointer(Ruby runtime, RubyClass klazz) { super(runtime, klazz, runtime.getFFI().getNullMemoryIO(), 0); }
public static final RubyClass getPointerClass(Ruby runtime) { return runtime.getFFI().pointerClass; }
private boolean abortOnException(Ruby runtime) { return (runtime.isGlobalAbortOnExceptionEnabled() || abortOnException); }