Ejemplo n.º 1
0
  private ByteList doReceive(ThreadContext context, int length) {
    Ruby runtime = context.runtime;
    ByteBuffer buf = ByteBuffer.allocate(length);

    try {
      context.getThread().beforeBlockingCall();

      int read = openFile.getMainStreamSafe().getDescriptor().read(buf);

      if (read == 0) return null;

      return new ByteList(buf.array(), 0, buf.position());

    } catch (BadDescriptorException e) {
      throw runtime.newIOError("bad descriptor");

    } catch (IOException e) {
      // All errors to sysread should be SystemCallErrors, but on a closed stream
      // Ruby returns an IOError.  Java throws same exception for all errors so
      // we resort to this hack...
      if ("Socket not open".equals(e.getMessage())) {
        throw runtime.newIOError(e.getMessage());
      }

      throw runtime.newSystemCallError(e.getMessage());

    } finally {
      context.getThread().afterBlockingCall();
    }
  }
Ejemplo n.º 2
0
 @JRubyMethod
 public IRubyObject lock(ThreadContext context) {
   try {
     context.getThread().enterSleep();
     try {
       checkRelocking(context);
       context.getThread().lockInterruptibly(lock);
     } catch (InterruptedException ex) {
       context.pollThreadEvents();
       throw context.getRuntime().newConcurrencyError(ex.getLocalizedMessage());
     }
   } finally {
     context.getThread().exitSleep();
   }
   return this;
 }
Ejemplo n.º 3
0
 @JRubyMethod
 public RubyBoolean try_lock(ThreadContext context) {
   if (lock.isHeldByCurrentThread()) {
     return context.runtime.getFalse();
   }
   return context.runtime.newBoolean(context.getThread().tryLock(lock));
 }
Ejemplo n.º 4
0
  @JRubyMethod(module = true)
  public static IRubyObject timeout(
      final ThreadContext context,
      IRubyObject timeout,
      IRubyObject seconds,
      IRubyObject exceptionType,
      Block block) {
    // No seconds, just yield
    if (seconds.isNil() || Helpers.invoke(context, seconds, "zero?").isTrue()) {
      return block.yieldSpecific(context);
    }

    final Ruby runtime = context.runtime;

    // No timeout in critical section
    if (runtime.getThreadService().getCritical()) {
      return raiseBecauseCritical(context);
    }

    final RubyThread currentThread = context.getThread();
    final AtomicBoolean latch = new AtomicBoolean(false);

    IRubyObject id = new RubyObject(runtime, runtime.getObject());
    RubyClass anonException = (RubyClass) runtime.getClassFromPath("Timeout::AnonymousException");
    Runnable timeoutRunnable =
        exceptionType.isNil()
            ? prepareRunnable(currentThread, runtime, latch, id)
            : prepareRunnableWithException(currentThread, exceptionType, runtime, latch);
    Future timeoutFuture = null;

    try {
      try {
        timeoutFuture =
            timeoutExecutor.schedule(
                timeoutRunnable,
                (long) (seconds.convertToFloat().getDoubleValue() * 1000000),
                TimeUnit.MICROSECONDS);

        return block.yield(context, seconds);
      } finally {
        killTimeoutThread(context, timeoutFuture, latch);
      }
    } catch (RaiseException re) {
      // if it's the exception we're expecting
      if (re.getException().getMetaClass() == anonException) {
        // and we were not given a specific exception
        if (exceptionType.isNil()) {
          // and it's the exception intended for us
          if (re.getException().getInternalVariable("__identifier__") == id) {
            return raiseTimeoutError(context, re);
          }
        }
      }

      // otherwise, rethrow
      throw re;
    }
  }
Ejemplo n.º 5
0
 private void addToCorrectThreadGroup(ThreadContext context) {
   // JRUBY-3568, inherit threadgroup or use default
   IRubyObject group = context.getThread().group();
   if (!group.isNil()) {
     ((RubyThreadGroup) group).addDirectly(this);
   } else {
     context.runtime.getDefaultThreadGroup().addDirectly(this);
   }
 }
Ejemplo n.º 6
0
 protected IRubyObject resumeOrTransfer(ThreadContext context, IRubyObject arg, boolean transfer) {
   CoroutineFiber current = (CoroutineFiber) context.getFiber();
   slot = arg;
   try {
     switch (state) {
       case SUSPENDED_YIELD:
         if (transfer) {
           current.state = CoroutineFiberState.SUSPENDED_TRANSFER;
         } else {
           current.state = CoroutineFiberState.SUSPENDED_RESUME;
           lastFiber = (CoroutineFiber) context.getFiber();
         }
         state = CoroutineFiberState.RUNNING;
         context.getRuntime().getThreadService().setCurrentContext(context);
         context.setThread(context.getThread());
         Coroutine.yieldTo(coro);
         break;
       case SUSPENDED_TRANSFER:
         if (!transfer) {
           throw context.getRuntime().newFiberError("double resume");
         }
         current.state = CoroutineFiberState.SUSPENDED_TRANSFER;
         state = CoroutineFiberState.RUNNING;
         context.getRuntime().getThreadService().setCurrentContext(context);
         context.setThread(context.getThread());
         Coroutine.yieldTo(coro);
         break;
       case FINISHED:
         throw context.getRuntime().newFiberError("dead fiber called");
       default:
         throw context.getRuntime().newFiberError("fiber in an invalid state: " + state);
     }
   } catch (OutOfMemoryError oome) {
     if (oome.getMessage().equals("unable to create new native thread")) {
       throw context.runtime.newThreadError("too many threads, can't create a new Fiber");
     }
     throw oome;
   }
   // back from fiber, poll events and proceed out of resume
   context.pollThreadEvents();
   return slot;
 }
Ejemplo n.º 7
0
 @JRubyMethod(compat = CompatVersion.RUBY1_9)
 public IRubyObject sleep(ThreadContext context, IRubyObject timeout) {
   long beg = System.currentTimeMillis();
   try {
     unlock(context);
     context.getThread().sleep((long) (timeout.convertToFloat().getDoubleValue() * 1000));
   } catch (InterruptedException ex) {
     // ignore interrupted
   } finally {
     lock(context);
   }
   return context.runtime.newFixnum((System.currentTimeMillis() - beg) / 1000);
 }
Ejemplo n.º 8
0
  @JRubyMethod
  public synchronized IRubyObject unlock(ThreadContext context) {
    Ruby runtime = context.getRuntime();
    if (!lock.isLocked()) {
      throw runtime.newThreadError("Mutex is not locked");
    }
    if (!lock.isHeldByCurrentThread()) {
      throw runtime.newThreadError("Mutex is not owned by calling thread");
    }

    boolean hasQueued = lock.hasQueuedThreads();
    context.getThread().unlock(lock);
    return hasQueued ? context.nil : this;
  }
Ejemplo n.º 9
0
  protected void initFiber(ThreadContext context) {
    final Ruby runtime = context.runtime;

    this.slot = runtime.getNil();
    this.context = root ? context : ThreadContext.newContext(runtime);
    this.context.setFiber(this);
    this.context.setThread(context.getThread());

    this.state = CoroutineFiberState.SUSPENDED_YIELD;
    if (coro == null) {
      coro =
          new Coroutine() {

            @Override
            protected void run() {
              try {
                // first resume, dive into the block
                slot = block.yieldArray(CoroutineFiber.this.context, slot, null, null);
              } catch (JumpException.RetryJump rtry) {
                // FIXME: technically this should happen before the block is executed
                parent.raise(
                    new IRubyObject[] {runtime.newSyntaxError("Invalid retry").getException()},
                    Block.NULL_BLOCK);
              } catch (JumpException.BreakJump brk) {
                parent.raise(
                    new IRubyObject[] {
                      runtime
                          .newLocalJumpError(
                              Reason.BREAK, runtime.getNil(), "break from proc-closure")
                          .getException()
                    },
                    Block.NULL_BLOCK);
              } catch (JumpException.ReturnJump ret) {
                parent.raise(
                    new IRubyObject[] {
                      runtime
                          .newLocalJumpError(Reason.RETURN, runtime.getNil(), "unexpected return")
                          .getException()
                    },
                    Block.NULL_BLOCK);
              } catch (RaiseException re) {
                // re-raise exception in parent thread
                parent.raise(new IRubyObject[] {re.getException()}, Block.NULL_BLOCK);
              } finally {
                state = CoroutineFiberState.FINISHED;
              }
            }
          };
    }
  }
Ejemplo n.º 10
0
 @JRubyMethod(rest = true)
 public IRubyObject recv(ThreadContext context, IRubyObject[] args) {
   OpenFile openFile = getOpenFileChecked();
   try {
     context.getThread().beforeBlockingCall();
     return RubyString.newString(
         context.getRuntime(), openFile.getMainStream().read(RubyNumeric.fix2int(args[0])));
   } catch (BadDescriptorException e) {
     throw context.getRuntime().newErrnoEBADFError();
   } catch (EOFException e) {
     // recv returns nil on EOF
     return context.getRuntime().getNil();
   } catch (IOException e) {
     // All errors to sysread should be SystemCallErrors, but on a closed stream
     // Ruby returns an IOError.  Java throws same exception for all errors so
     // we resort to this hack...
     if ("Socket not open".equals(e.getMessage())) {
       throw context.getRuntime().newIOError(e.getMessage());
     }
     throw context.getRuntime().newSystemCallError(e.getMessage());
   } finally {
     context.getThread().afterBlockingCall();
   }
 }
Ejemplo n.º 11
0
    /* Run the selector */
    private int doSelect(Ruby runtime, ThreadContext context, IRubyObject timeout) {
      int result;

      cancelKeys();
      try {
        context.getThread().beforeBlockingCall();
        if (timeout.isNil()) {
          result = this.selector.select();
        } else {
          double t = RubyNumeric.num2dbl(timeout);
          if (t == 0) {
            result = this.selector.selectNow();
          } else if (t < 0) {
            throw runtime.newArgumentError("time interval must be positive");
          } else {
            result = this.selector.select((long) (t * 1000));
          }
        }
        context.getThread().afterBlockingCall();
        return result;
      } catch (IOException ie) {
        throw runtime.newIOError(ie.getLocalizedMessage());
      }
    }
Ejemplo n.º 12
0
  @JRubyMethod(name = "accept_nonblock")
  public IRubyObject accept_nonblock(ThreadContext context) {
    Ruby runtime = context.runtime;
    RubyTCPSocket socket = new RubyTCPSocket(runtime, runtime.getClass("TCPSocket"));
    Selector selector = null;

    synchronized (ssc.blockingLock()) {
      boolean oldBlocking = ssc.isBlocking();

      try {
        ssc.configureBlocking(false);
        selector = SelectorFactory.openWithRetryFrom(runtime, SelectorProvider.provider());

        boolean ready = context.getThread().select(this, SelectionKey.OP_ACCEPT, 0);

        if (!ready) {
          // no connection immediately accepted, let them try again
          throw runtime.newErrnoEAGAINError("Resource temporarily unavailable");

        } else {
          // otherwise one key has been selected (ours) so we get the channel and hand it off
          socket.initSocket(
              context.runtime,
              new ChannelDescriptor(ssc.accept(), newModeFlags(runtime, ModeFlags.RDWR)));

          return socket;
        }

      } catch (IOException e) {
        throw SocketUtils.sockerr(context.runtime, "problem when accepting");

      } finally {
        try {
          if (selector != null) selector.close();
        } catch (Exception e) {
        }
        try {
          ssc.configureBlocking(oldBlocking);
        } catch (IOException ioe) {
        }
      }
    }
  }
Ejemplo n.º 13
0
  @JRubyMethod(module = true)
  public static IRubyObject timeout(
      final ThreadContext context, IRubyObject timeout, IRubyObject seconds, Block block) {
    // No seconds, just yield
    if (seconds.isNil() || Helpers.invoke(context, seconds, "zero?").isTrue()) {
      return block.yieldSpecific(context);
    }

    final Ruby runtime = context.runtime;

    // No timeout in critical section
    if (runtime.getThreadService().getCritical()) {
      return raiseBecauseCritical(context);
    }

    final RubyThread currentThread = context.getThread();
    final AtomicBoolean latch = new AtomicBoolean(false);

    IRubyObject id = new RubyObject(runtime, runtime.getObject());
    Runnable timeoutRunnable = prepareRunnable(currentThread, runtime, latch, id);
    Future timeoutFuture = null;

    try {
      try {
        timeoutFuture =
            timeoutExecutor.schedule(
                timeoutRunnable,
                (long) (seconds.convertToFloat().getDoubleValue() * 1000000),
                TimeUnit.MICROSECONDS);

        return block.yield(context, seconds);
      } finally {
        killTimeoutThread(context, timeoutFuture, latch);
      }
    } catch (RaiseException re) {
      if (re.getException().getInternalVariable("__identifier__") == id) {
        return raiseTimeoutError(context, re);
      } else {
        throw re;
      }
    }
  }
Ejemplo n.º 14
0
 private synchronized IRubyObject pop(ThreadContext context, boolean should_block) {
   checkShutdown(context);
   if (!should_block && entries.size() == 0) {
     throw new RaiseException(
         context.runtime, context.runtime.getThreadError(), "queue empty", false);
   }
   numWaiting++;
   try {
     while (java_length() == 0) {
       try {
         context.getThread().wait_timeout(this, null);
       } catch (InterruptedException e) {
       }
       checkShutdown(context);
     }
   } finally {
     numWaiting--;
   }
   return (IRubyObject) entries.removeFirst();
 }
Ejemplo n.º 15
0
  @JRubyMethod(name = "stop", meta = true)
  public static IRubyObject stop(ThreadContext context, IRubyObject receiver) {
    RubyThread rubyThread = context.getThread();

    synchronized (rubyThread) {
      rubyThread.checkMail(context);
      try {
        // attempt to decriticalize all if we're the critical thread
        receiver.getRuntime().getThreadService().setCritical(false);

        rubyThread.status.set(Status.SLEEP);
        rubyThread.wait();
      } catch (InterruptedException ie) {
        rubyThread.checkMail(context);
        rubyThread.status.set(Status.RUN);
      }
    }

    return receiver.getRuntime().getNil();
  }
Ejemplo n.º 16
0
 public IRubyObject yield(ThreadContext context, IRubyObject arg) {
   assert !root;
   if (lastFiber.state != CoroutineFiberState.SUSPENDED_RESUME) {
     if (lastFiber.state == CoroutineFiberState.SUSPENDED_TRANSFER) {
       throw context.getRuntime().newFiberError("a Fiber that was transferred to cannot yield");
     }
     throw context
         .getRuntime()
         .newFiberError("invalid state of last Fiber at yield: " + lastFiber.state);
   }
   slot = arg;
   state = CoroutineFiberState.SUSPENDED_YIELD;
   lastFiber.state = CoroutineFiberState.RUNNING;
   context.getRuntime().getThreadService().setCurrentContext(lastFiber.context);
   Object o = lastFiber.context;
   lastFiber.context.setThread(context.getThread());
   Coroutine.yieldTo(lastFiber.coro);
   // back from fiber, poll events and proceed out of resume
   context.pollThreadEvents();
   return slot;
 }
Ejemplo n.º 17
0
  @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;
  }
Ejemplo n.º 18
0
  @JRubyMethod(name = "accept")
  public IRubyObject accept(ThreadContext context) {
    Ruby runtime = context.runtime;
    RubyTCPSocket socket = new RubyTCPSocket(runtime, runtime.getClass("TCPSocket"));

    try {
      RubyThread thread = context.getThread();

      while (true) {
        boolean ready = thread.select(this, SelectionKey.OP_ACCEPT);

        if (!ready) {
          // we were woken up without being selected...poll for thread events and go back to sleep
          context.pollThreadEvents();

        } else {
          SocketChannel connected = ssc.accept();
          if (connected == null) continue;

          connected.finishConnect();

          // Force the client socket to be blocking
          synchronized (connected.blockingLock()) {
            connected.configureBlocking(false);
            connected.configureBlocking(true);
          }

          // otherwise one key has been selected (ours) so we get the channel and hand it off
          socket.initSocket(
              runtime, new ChannelDescriptor(connected, newModeFlags(runtime, ModeFlags.RDWR)));

          return socket;
        }
      }

    } catch (IOException e) {
      throw SocketUtils.sockerr(runtime, "problem when accepting");
    }
  }
Ejemplo n.º 19
0
  @JRubyMethod(name = "accept")
  public IRubyObject accept(ThreadContext context) {
    RubyTCPSocket socket =
        new RubyTCPSocket(context.getRuntime(), context.getRuntime().fastGetClass("TCPSocket"));

    try {
      while (true) {
        boolean ready = context.getThread().select(this, SelectionKey.OP_ACCEPT);
        if (!ready) {
          // we were woken up without being selected...poll for thread events and go back to sleep
          context.pollThreadEvents();
        } else {
          try {
            SocketChannel connected = ssc.accept();
            connected.finishConnect();

            //
            // Force the client socket to be blocking
            //
            synchronized (connected.blockingLock()) {
              connected.configureBlocking(false);
              connected.configureBlocking(true);
            }

            // otherwise one key has been selected (ours) so we get the channel and hand it off
            socket.initSocket(
                context.getRuntime(),
                new ChannelDescriptor(connected, new ModeFlags(ModeFlags.RDWR)));
          } catch (InvalidValueException ex) {
            throw context.getRuntime().newErrnoEINVALError();
          }
          return socket;
        }
      }
    } catch (IOException e) {
      throw sockerr(context.getRuntime(), "problem when accepting");
    }
  }