-
-
Notifications
You must be signed in to change notification settings - Fork 925
Commit
- 9.4.12.0
- 9.4.11.0
- 9.4.10.0
- 9.4.9.0
- 9.4.8.0
- 9.4.7.0
- 9.4.6.0
- 9.4.5.0
- 9.4.4.0
- 9.4.3.0
- 9.4.2.0
- 9.4.1.0
- 9.4.0.0
- 9.3.15.0
- 9.3.14.0
- 9.3.13.0
- 9.3.12.0
- 9.3.11.0
- 9.3.10.0
- 9.3.9.0
- 9.3.8.0
- 9.3.7.0
- 9.3.6.0
- 9.3.5.0
- 9.3.4.0
- 9.3.3.0
- 9.3.2.0
- 9.3.1.0
- 9.3.0.0
- 9.2.21.0
- 9.2.20.1
- 9.2.20.0
- 9.2.19.0
- 9.2.18.0
- 9.2.17.0
- 9.2.16.0
- 9.2.15.0
- 9.2.14.0
- 9.2.13.0
- 9.2.12.0
- 9.2.11.1
- 9.2.11.0
- 9.2.10.0
- 9.2.9.0
- 9.2.8.0
- 9.2.7.0
- 9.2.6.0
- 9.2.5.0
- 9.2.4.1
- 9.2.4.0
- 9.2.3.0
- 9.2.2.0
- 9.2.1.0
- 9.2.0.0
- 9.1.17.0
- 9.1.16.0
- 9.1.15.0
- 9.1.14.0
- 9.1.13.0
- 9.1.12.0
- 9.1.11.0
- 9.1.10.0
- 9.1.9.0
- 9.1.8.0
- 9.1.7.0
- 9.1.6.0
- 9.1.5.0
- 9.1.4.0
- 9.1.3.0
- 9.1.2.0
- 9.1.1.0
- 9.1.0.0
- 9.0.5.0
- 9.0.4.0
- 9.0.3.0
- 9.0.1.0
- 9.0.0.0
- 9.0.0.0.rc2
- 9.0.0.0.rc1
- 9.0.0.0.pre2
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* | ||
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This | ||
* code is released under a tri EPL/GPL/LGPL license. You can use it, | ||
* redistribute it and/or modify it under the terms of the: | ||
* | ||
* Eclipse Public License version 1.0 | ||
* GNU General Public License version 2 | ||
* GNU Lesser General Public License version 2.1 | ||
*/ | ||
package org.jruby.truffle.runtime.subsystems; | ||
|
||
import com.sun.net.httpserver.HttpExchange; | ||
import com.sun.net.httpserver.HttpHandler; | ||
import com.sun.net.httpserver.HttpServer; | ||
|
||
import org.jruby.truffle.runtime.RubyCallStack; | ||
import org.jruby.truffle.runtime.RubyContext; | ||
import org.jruby.truffle.runtime.backtrace.Backtrace; | ||
import org.jruby.truffle.runtime.core.RubyThread; | ||
import org.jruby.truffle.runtime.util.Consumer; | ||
|
||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.net.InetSocketAddress; | ||
|
||
@SuppressWarnings("restriction") | ||
public class InstrumentationServerManager { | ||
|
||
private final RubyContext context; | ||
private final int port; | ||
|
||
public InstrumentationServerManager(RubyContext context, int port) { | ||
this.context = context; | ||
this.port = port; | ||
} | ||
|
||
public void start() { | ||
final HttpServer server; | ||
|
||
try { | ||
server = HttpServer.create(new InetSocketAddress(port), 0); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
return; | ||
} | ||
|
||
server.createContext("/stacks", new HttpHandler() { | ||
|
||
@Override | ||
public void handle(HttpExchange httpExchange) { | ||
try { | ||
final StringBuilder builder = new StringBuilder(); | ||
|
||
context.getSafepointManager().pauseAllThreadsAndExecuteFromNonRubyThread(new Consumer<RubyThread>() { | ||
|
||
@Override | ||
public void accept(RubyThread thread) { | ||
try { | ||
Backtrace backtrace = RubyCallStack.getBacktrace(null); | ||
|
||
synchronized (this) { | ||
// Not thread-safe so keep the formatting synchronized for now. | ||
String[] lines = Backtrace.DISPLAY_FORMATTER.format(context, null, backtrace); | ||
|
||
builder.append(Thread.currentThread().getName()); | ||
builder.append("\n"); | ||
for (String line : lines) { | ||
builder.append(line); | ||
builder.append("\n"); | ||
} | ||
builder.append("\n"); | ||
} | ||
} catch (Throwable e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
}); | ||
|
||
final byte[] bytes = builder.toString().getBytes("UTF-8"); | ||
|
||
httpExchange.getResponseHeaders().set("Content-Type", "text/plain"); | ||
httpExchange.sendResponseHeaders(200, bytes.length); | ||
|
||
final OutputStream stream = httpExchange.getResponseBody(); | ||
stream.write(bytes); | ||
stream.close(); | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
}); | ||
|
||
server.start(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,7 +30,7 @@ public class SafepointManager { | |
|
||
private final RubyContext context; | ||
|
||
private final Set<Thread> runningThreads = Collections.newSetFromMap(new ConcurrentHashMap<Thread, Boolean>()); | ||
private final Set<RunningThread> runningThreads = Collections.newSetFromMap(new ConcurrentHashMap<RunningThread, Boolean>()); | ||
|
||
@CompilerDirectives.CompilationFinal private Assumption assumption = Truffle.getRuntime().createAssumption(); | ||
private final ReentrantLock lock = new ReentrantLock(); | ||
|
@@ -44,12 +44,16 @@ public SafepointManager(RubyContext context) { | |
} | ||
|
||
public void enterThread() { | ||
enterThread(true); | ||
} | ||
|
||
public void enterThread(boolean interruptible) { | ||
CompilerAsserts.neverPartOfCompilation(); | ||
|
||
lock.lock(); | ||
try { | ||
phaser.register(); | ||
runningThreads.add(Thread.currentThread()); | ||
runningThreads.add(new RunningThread(Thread.currentThread(), interruptible)); | ||
} finally { | ||
lock.unlock(); | ||
} | ||
|
@@ -116,15 +120,15 @@ public void pauseAllThreadsAndExecute(Consumer<RubyThread> action) { | |
} | ||
|
||
public void pauseAllThreadsAndExecuteFromNonRubyThread(Consumer<RubyThread> action) { | ||
enterThread(); | ||
enterThread(false); | ||
try { | ||
pauseAllThreadsAndExecute(false, action); | ||
} finally { | ||
leaveThread(); | ||
} | ||
} | ||
|
||
private void pauseAllThreadsAndExecute(boolean holdsGlobalLock, Consumer<RubyThread> action) { | ||
public void pauseAllThreadsAndExecute(boolean holdsGlobalLock, Consumer<RubyThread> action) { | ||
CompilerDirectives.transferToInterpreter(); | ||
|
||
if (lock.isHeldByCurrentThread()) { | ||
|
@@ -157,9 +161,48 @@ private void pauseAllThreadsAndExecute(boolean holdsGlobalLock, Consumer<RubyThr | |
} | ||
|
||
private void interruptAllThreads() { | ||
for (Thread thread : runningThreads) { | ||
thread.interrupt(); | ||
for (RunningThread thread : runningThreads) { | ||
if (thread.isInterruptible()) { | ||
thread.getThread().interrupt(); | ||
} | ||
} | ||
} | ||
|
||
private class RunningThread { | ||
|
||
private final Thread thread; | ||
private final boolean interruptible; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
eregon
Member
|
||
|
||
public RunningThread(Thread thread, boolean interruptible) { | ||
this.thread = thread; | ||
this.interruptible = interruptible; | ||
} | ||
|
||
public Thread getThread() { | ||
return thread; | ||
} | ||
|
||
public boolean isInterruptible() { | ||
return interruptible; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (o == null || getClass() != o.getClass()) return false; | ||
|
||
RunningThread that = (RunningThread) o; | ||
|
||
if (!thread.equals(that.thread)) return false; | ||
|
||
return true; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return thread.hashCode(); | ||
} | ||
|
||
} | ||
|
||
} |
This file was deleted.
@eregon not all threads can be interrupted without problem - for example the stack server HTTP server can't be interrupted as it closes the connection. I've added an option to register threads as not to be interrupted.