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 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>Improve collection of orphaned coroutines when yielding from debug hook functions.</li>
</ul></td></tr>
</table></td></tr></table>

View File

@@ -63,10 +63,14 @@ public class LuaThread extends LuaValue {
public static int coroutine_count = 0;
/** Interval at which to check for lua threads that are no longer referenced.
* This can be changed by Java startup code if desired.
/** Polling interval, in milliseconds, which each thread uses while waiting to
* 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_SUSPENDED = 1;
@@ -83,12 +87,9 @@ public class LuaThread extends LuaValue {
public final State state;
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.
* 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 final Globals globals;
@@ -244,6 +245,15 @@ public class LuaThread extends LuaValue {
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 {
static long thread_orphan_check_interval = 30000;
static int coroutine_count = 0;
Globals globals;

View File

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