This is an automated email from the git hooks/post-receive script. henrich pushed a commit to branch debian/sid in repository jruby-joni.
commit 5ac0601a748dac71e0a7697d085c92f41dad0f7f Author: Thomas E. Enebo <[email protected]> Date: Fri May 10 16:06:03 2013 -0500 Make interrupt check actually reset the interrupt state so the thread can work for more than one regexp. Add some unit tests --- src/org/joni/ByteCodeMachine.java | 8 ++- test/org/joni/test/Test.java | 112 ++++++++++++++++++++++++++++++++-- test/org/joni/test/TestInterrupt.java | 100 ++++++++++++++++++++++++++++++ test/org/joni/test/TestJoni.java | 6 ++ 4 files changed, 221 insertions(+), 5 deletions(-) diff --git a/src/org/joni/ByteCodeMachine.java b/src/org/joni/ByteCodeMachine.java index a9e0e08..d5b318c 100644 --- a/src/org/joni/ByteCodeMachine.java +++ b/src/org/joni/ByteCodeMachine.java @@ -37,6 +37,9 @@ import org.joni.exception.ErrorMessages; import org.joni.exception.InternalException; class ByteCodeMachine extends StackMachine { + private static final int INTERRUPT_CHECK_EVERY = 30000; + int interruptCheckCounter = 0; // we modulos this to occasionally check for interrupts + private int bestLen; // return value private int s = 0; // current char @@ -183,12 +186,15 @@ class ByteCodeMachine extends StackMachine { bestLen = -1; s = sstart; + Thread currentThread = Thread.currentThread(); final int[]code = this.code; while (true) { - if (Thread.interrupted()) { + if (interruptCheckCounter++ % INTERRUPT_CHECK_EVERY == 0 && currentThread.isInterrupted()) { + currentThread.interrupted(); throw new InterruptedException(); } + if (Config.DEBUG_MATCH) debugMatchLoop(); sbegin = s; diff --git a/test/org/joni/test/Test.java b/test/org/joni/test/Test.java index 1010446..0887b60 100644 --- a/test/org/joni/test/Test.java +++ b/test/org/joni/test/Test.java @@ -49,12 +49,89 @@ public abstract class Test { protected int length(byte[]bytes) { return bytes.length; } + + protected void assertTrue(boolean expression, String... failMessage) { + if (expression) { + nsucc++; + } else { + Config.err.println(failMessage); + nfail++; + } + } public void xx(byte[]pattern, byte[]str, int from, int to, int mem, boolean not) { xx(pattern, str, from, to, mem, not, option()); } + + public int xx(byte[]pattern, byte[]str, int from, int to, int mem, boolean not, int option) { + Regex reg; + + try { + reg = new Regex(pattern, 0, length(pattern), option, encoding(), syntax()); + } catch (JOniException je) { + Config.err.println("Pattern: " + repr(pattern) + " Str: " + repr(str)); + je.printStackTrace(Config.err); + Config.err.println("ERROR: " + je.getMessage()); + nerror++; + return Matcher.FAILED; + } catch (Exception e) { + Config.err.println("Pattern: " + repr(pattern) + " Str: " + repr(str)); + e.printStackTrace(Config.err); + Config.err.println("SEVERE ERROR: " + e.getMessage()); + nerror++; + return Matcher.FAILED; + } + + Matcher m = reg.matcher(str, 0, length(str)); + Region region; - public void xx(byte[]pattern, byte[]str, int from, int to, int mem, boolean not, int option) { + int r = 0; + try { + r = m.search(0, length(str), Option.NONE); + region = m.getEagerRegion(); + } catch (JOniException je) { + Config.err.println("Pattern: " + repr(pattern) + " Str: " + repr(str)); + je.printStackTrace(Config.err); + Config.err.println("ERROR: " + je.getMessage()); + nerror++; + return Matcher.FAILED; + } catch (Exception e) { + Config.err.println("Pattern: " + repr(pattern) + " Str: " + repr(str)); + e.printStackTrace(Config.err); + Config.err.println("SEVERE ERROR: " + e.getMessage()); + nerror++; + return Matcher.FAILED; + } + + if (r == -1) { + if (not) { + if (VERBOSE) Config.log.println("OK(N): /" + repr(pattern) + "/ '" + repr(str) + "'"); + nsucc++; + } else { + Config.log.println("FAIL: /" + repr(pattern) + "/ '" + repr(str) + "'"); + nfail++; + } + } else { + if (not) { + Config.log.println("FAIL(N): /" + repr(pattern) + "/ '" + repr(str) + "'"); + nfail++; + } else { + if (region.beg[mem] == from && region.end[mem] == to) { + if (VERBOSE) Config.log.println("OK: /" + repr(pattern) + "/ '" +repr(str) + "'"); + nsucc++; + } else { + Config.log.println("FAIL: /" + repr(pattern) + "/ '" + repr(str) + "' " + + from + "-" + to + " : " + region.beg[mem] + "-" + region.end[mem] + ); + nfail++; + } + } + } + + return r; + } + + public void xxi(byte[]pattern, byte[]str, int from, int to, int mem, boolean not, int option) throws InterruptedException { Regex reg; try { @@ -78,7 +155,7 @@ public abstract class Test { int r = 0; try { - r = m.search(0, length(str), Option.NONE); + r = m.searchInterruptible(0, length(str), Option.NONE); region = m.getEagerRegion(); } catch (JOniException je) { Config.err.println("Pattern: " + repr(pattern) + " Str: " + repr(str)); @@ -86,6 +163,8 @@ public abstract class Test { Config.err.println("ERROR: " + je.getMessage()); nerror++; return; + } catch (InterruptedException e) { + throw e; } catch (Exception e) { Config.err.println("Pattern: " + repr(pattern) + " Str: " + repr(str)); e.printStackTrace(Config.err); @@ -151,18 +230,43 @@ public abstract class Test { uee.printStackTrace(); } } + + public void xxsi(String pattern, String str, int from, int to, int mem, boolean not) throws InterruptedException { + xxsi(pattern, str, from, to, mem, not, option()); + } + + public void xxsi(String pattern, String str, int from, int to, int mem, boolean not, int option) throws InterruptedException { + try{ + xxi(pattern.getBytes(testEncoding()), str.getBytes(testEncoding()), from, to, mem, not, option); + } catch (UnsupportedEncodingException uee) { + uee.printStackTrace(); + } + } public void x2s(String pattern, String str, int from, int to) { x2s(pattern, str, from, to, option()); } - public void x2s(String pattern, String str, int from, int to, int option) { + public int x2s(String pattern, String str, int from, int to, int option) { try{ - xx(pattern.getBytes(testEncoding()), str.getBytes(testEncoding()), from, to, 0, false, option); + return xx(pattern.getBytes(testEncoding()), str.getBytes(testEncoding()), from, to, 0, false, option); } catch (UnsupportedEncodingException uee) { uee.printStackTrace(); + return Matcher.FAILED; } } + + public void x2si(String pattern, String str, int from, int to) throws InterruptedException { + x2si(pattern, str, from, to, option()); + } + + public void x2si(String pattern, String str, int from, int to, int option) throws InterruptedException { + try{ + xxi(pattern.getBytes(testEncoding()), str.getBytes(testEncoding()), from, to, 0, false, option); + } catch (UnsupportedEncodingException uee) { + uee.printStackTrace(); + } + } public void x3s(String pattern, String str, int from, int to, int mem) { x3s(pattern, str, from, to, mem, option()); diff --git a/test/org/joni/test/TestInterrupt.java b/test/org/joni/test/TestInterrupt.java new file mode 100644 index 0000000..fab5b17 --- /dev/null +++ b/test/org/joni/test/TestInterrupt.java @@ -0,0 +1,100 @@ +/* + * The MIT License + * + * Copyright 2013 enebo. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.joni.test; + +import java.util.Timer; +import java.util.TimerTask; +import org.jcodings.Encoding; +import org.jcodings.specific.ASCIIEncoding; +import org.joni.Matcher; +import org.joni.Option; +import org.joni.Syntax; + +/** + * These are fairly long-running tests but we want a large time slice to reduce misfires + * on slow ci boxes. + */ +public class TestInterrupt extends Test { + interface InterruptibleRunnable { + public void run() throws InterruptedException; + } + public void test() throws InterruptedException { + interruptAfter(new InterruptibleRunnable() { + public void run() throws InterruptedException { + x2si("a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, 0); + } + }, 1000, 15000); + + /* + final int status[] = new int[1]; + + interruptAfter(new InterruptibleRunnable() { + public void run() throws InterruptedException { + status[0] = x2s("a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, 0); + } + }, 1000, 15000); + + assertTrue(status[0] == Matcher.INTERRUPTED, "Status was not INTERRUPTED: " + status[0]);*/ + } + + private void interruptAfter(InterruptibleRunnable block, int delayBeforeInterrupt, int acceptableMaximumTime) { + final long start[] = new long[1]; + + final Thread currentThread = Thread.currentThread(); + + new Timer().schedule(new TimerTask() { + @Override public void run() { + start[0] = System.currentTimeMillis(); + System.out.println("INTERRUPTING at " + start[0]); + currentThread.interrupt(); + } + }, delayBeforeInterrupt); + + try { + block.run(); + } catch (InterruptedException e) { + long total = System.currentTimeMillis() - start[0]; + System.out.println("Time taken: " + total); + assertTrue(total < acceptableMaximumTime, "Took too long to interrupt: " + total + " > " + acceptableMaximumTime); + } + } + + public int option() { + return Option.DEFAULT; + } + + public Encoding encoding() { + return ASCIIEncoding.INSTANCE; + } + + public String testEncoding() { + return "iso-8859-2"; + } + + public Syntax syntax() { + return Syntax.DEFAULT; + } +} diff --git a/test/org/joni/test/TestJoni.java b/test/org/joni/test/TestJoni.java index a94ed56..b7d5744 100644 --- a/test/org/joni/test/TestJoni.java +++ b/test/org/joni/test/TestJoni.java @@ -29,6 +29,7 @@ public class TestJoni extends TestCase { private Test testnsu8; private Test testLookBehind; private Test testu8; + private Test testInterrupt; protected void setUp() { testa = new TestA(); @@ -37,6 +38,7 @@ public class TestJoni extends TestCase { testnsu8 = new TestNSU8(); testu8 = new TestU8(); testLookBehind = new TestLookBehind(); + testInterrupt = new TestInterrupt(); } protected void tearDown() { @@ -65,4 +67,8 @@ public class TestJoni extends TestCase { public void testLookBehind() { testJoniTest(testLookBehind); } + + public void testInterrupt() { + testJoniTest(testInterrupt); + } } -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jruby-joni.git _______________________________________________ pkg-java-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-java-commits

