Improve collection of orphaned coroutines when yielding from debug hook functions.

This commit is contained in:
James Roseborough
2015-03-18 03:16:05 +00:00
parent 31c13af7b4
commit cd9cdc496e
4 changed files with 39 additions and 36 deletions

View File

@@ -977,6 +977,7 @@ Files are no longer hosted at LuaForge.
<li>Fix return value for table.remove() and table.insert() (fixes issue #39)</li> <li>Fix return value for table.remove() and table.insert() (fixes issue #39)</li>
<li>Fix aliasing issue for some multiple assignments from varargs return values (fixes issue #38)</li> <li>Fix aliasing issue for some multiple assignments from varargs return values (fixes issue #38)</li>
<li>Let os.getenv() return System.getenv() values first for JSE, then fall back to properties (fixes issue #25)</li> <li>Let os.getenv() return System.getenv() values first for JSE, then fall back to properties (fixes issue #25)</li>
<li>Improve collection of orphaned coroutines when yielding from debug hook functions.</li>
</ul></td></tr> </ul></td></tr>
</table></td></tr></table> </table></td></tr></table>

View File

@@ -63,10 +63,14 @@ public class LuaThread extends LuaValue {
public static int coroutine_count = 0; public static int coroutine_count = 0;
/** Interval at which to check for lua threads that are no longer referenced. /** Polling interval, in milliseconds, which each thread uses while waiting to
* This can be changed by Java startup code if desired. * return from a yielded state to check if the lua threads is no longer
* referenced and therefore should be garbage collected.
* A short polling interval for many threads will consume server resources.
* Orphaned threads cannot be detected and collected unless garbage
* collection is run. This can be changed by Java startup code if desired.
*/ */
static long thread_orphan_check_interval = 30000; public static long thread_orphan_check_interval = 5000;
public static final int STATUS_INITIAL = 0; public static final int STATUS_INITIAL = 0;
public static final int STATUS_SUSPENDED = 1; public static final int STATUS_SUSPENDED = 1;
@@ -83,12 +87,9 @@ public class LuaThread extends LuaValue {
public final State state; public final State state;
public static final int MAX_CALLSTACK = 256; public static final int MAX_CALLSTACK = 256;
/** Interval to check for LuaThread dereferencing. */
public static int GC_INTERVAL = 30000;
/** Thread-local used by DebugLib to store debugging state. /** Thread-local used by DebugLib to store debugging state.
* This is ano opaque value that should not be modified by applications. */ * This is an opaque value that should not be modified by applications. */
public Object callstack; public Object callstack;
public final Globals globals; public final Globals globals;
@@ -244,6 +245,15 @@ public class LuaThread extends LuaValue {
this.result = LuaValue.NONE; this.result = LuaValue.NONE;
} }
} }
public synchronized void set_inhook(boolean value) {
LuaThread t = (LuaThread) this.lua_thread.get();
if (t == null) {
this.status = STATUS_DEAD;
throw new OrphanedThread();
}
t.inhook = value;
}
} }
} }

View File

@@ -62,8 +62,6 @@ import org.luaj.vm2.Varargs;
*/ */
public class CoroutineLib extends TwoArgFunction { public class CoroutineLib extends TwoArgFunction {
static long thread_orphan_check_interval = 30000;
static int coroutine_count = 0; static int coroutine_count = 0;
Globals globals; Globals globals;

View File

@@ -388,61 +388,55 @@ public class DebugLib extends TwoArgFunction {
} }
public void onCall(LuaFunction f) { public void onCall(LuaFunction f) {
LuaThread t = globals.running; if (globals.running.inhook) return;
if (t.inhook) return;
callstack().onCall(f); callstack().onCall(f);
if (t.hookcall && t.hookfunc != null) callHook(globals.running.hookfunc, CALL, NIL);
callHook(CALL, NIL);
} }
public void onCall(LuaClosure c, Varargs varargs, LuaValue[] stack) { public void onCall(LuaClosure c, Varargs varargs, LuaValue[] stack) {
LuaThread t = globals.running; if (globals.running.inhook) return;
if (t.inhook) return;
callstack().onCall(c, varargs, stack); callstack().onCall(c, varargs, stack);
if (t.hookcall && t.hookfunc != null) callHook(globals.running.hookfunc, CALL, NIL);
callHook(CALL, NIL);
} }
public void onInstruction(int pc, Varargs v, int top) { public void onInstruction(int pc, Varargs v, int top) {
LuaThread t = globals.running; if (globals.running.inhook) return;
if (t.inhook) return;
callstack().onInstruction(pc, v, top); callstack().onInstruction(pc, v, top);
if (t.hookfunc == null) return; if (globals.running.hookfunc == null) return;
if (t.hookcount > 0) if (globals.running.hookcount > 0)
if (++t.bytecodes % t.hookcount == 0) if (++globals.running.bytecodes % globals.running.hookcount == 0)
callHook(COUNT, NIL); callHook(globals.running.hookfunc, COUNT, NIL);
if (t.hookline) { if (globals.running.hookline) {
int newline = callstack().currentline(); int newline = callstack().currentline();
if ( newline != t.lastline ) { if ( newline != globals.running.lastline ) {
t.lastline = newline; globals.running.lastline = newline;
callHook(LINE, LuaValue.valueOf(newline)); callHook(globals.running.hookfunc, LINE, LuaValue.valueOf(newline));
} }
} }
} }
public void onReturn() { public void onReturn() {
LuaThread t = globals.running; if (globals.running.inhook) return;
if (t.inhook) return;
callstack().onReturn(); callstack().onReturn();
if (t.hookcall && t.hookfunc != null) callHook(globals.running.hookfunc, RETURN, NIL);
callHook(RETURN, NIL);
} }
public String traceback(int level) { public String traceback(int level) {
return callstack().traceback(level); return callstack().traceback(level);
} }
void callHook(LuaValue type, LuaValue arg) { void callHook(LuaValue hookfunc, LuaValue type, LuaValue arg) {
LuaThread t = globals.running; if (hookfunc == null) return;
t.inhook = true; LuaThread.State state = globals.running.state;
state.set_inhook(true);
try { try {
t.hookfunc.call(type, arg); hookfunc.call(type, arg);
} catch (LuaError e) { } catch (LuaError e) {
throw e; throw e;
} catch (RuntimeException e) { } catch (RuntimeException e) {
throw new LuaError(e); throw new LuaError(e);
} finally { } finally {
t.inhook = false; state.set_inhook(false);
} }
} }