[jruby-joni] 170/279: Make interrupt check actually reset the interrupt state so the thread can work for more than one regexp. Add some unit tests
Hideki Yamane
henrich at moszumanska.debian.org
Mon Nov 16 11:27:24 UTC 2015
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 <tom.enebo at gmail.com>
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
More information about the pkg-java-commits
mailing list