Skip to content

Commit 049e761

Browse files
committed
fix: race conditions when using the same grammar concurrently
1 parent 075d8b6 commit 049e761

2 files changed

Lines changed: 40 additions & 5 deletions

File tree

  • org.eclipse.tm4e.core/src

org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/grammar/Grammar.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ public ITokenizeLineResult<int[]> tokenizeLine2(final String lineText, final @Nu
267267
}
268268

269269
@SuppressWarnings("unchecked")
270-
private <T> T _tokenize(
270+
private synchronized <T> T _tokenize(
271271
String lineText,
272272
@Nullable StateStack prevState,
273273
final boolean emitBinaryTokens,

org.eclipse.tm4e.core/src/test/java/org/eclipse/tm4e/core/grammar/GrammarTest.java

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,21 @@
1515
import static org.junit.jupiter.api.Assertions.*;
1616

1717
import java.io.IOException;
18+
import java.nio.file.Files;
19+
import java.nio.file.Paths;
1820
import java.time.Duration;
21+
import java.util.ArrayList;
1922
import java.util.Arrays;
2023
import java.util.List;
24+
import java.util.concurrent.Executors;
25+
import java.util.concurrent.Future;
26+
import java.util.concurrent.TimeUnit;
2127
import java.util.stream.Collectors;
2228

2329
import org.eclipse.tm4e.core.Data;
2430
import org.eclipse.tm4e.core.internal.utils.ResourceUtils;
2531
import org.eclipse.tm4e.core.registry.IGrammarSource;
2632
import org.eclipse.tm4e.core.registry.Registry;
27-
import org.junit.jupiter.api.Assertions;
2833
import org.junit.jupiter.api.Disabled;
2934
import org.junit.jupiter.api.MethodOrderer;
3035
import org.junit.jupiter.api.Test;
@@ -71,6 +76,36 @@ class GrammarTest {
7176
"Token from 11 to 14 with scopes [source.js, meta.function.js, meta.decl.block.js]",
7277
"Token from 14 to 15 with scopes [source.js, meta.function.js, meta.decl.block.js, meta.brace.curly.js]" };
7378

79+
@Test
80+
void testTokenizeConcurrent() throws Exception {
81+
final var registry = new Registry();
82+
final var grammar = registry.addGrammar(fromFile(Paths.get("../org.eclipse.tm4e.language_pack/syntaxes/xml/xml.tmLanguage.json")));
83+
final String content = Files.readString(Paths.get("../org.eclipse.tm4e.language_pack/syntaxes/xml/xml.example.xml"));
84+
85+
final int numThreads = 4;
86+
final int numIterations = 10;
87+
88+
final var executor = Executors.newFixedThreadPool(numThreads);
89+
final Runnable tokenizationTask = () -> {
90+
for (int i = 0; i < numIterations; i++) {
91+
final var r = TokenizationUtils.tokenizeText(content, grammar);
92+
assertTrue(r.count() > 10);
93+
}
94+
};
95+
96+
final List<Future<?>> futures = new ArrayList<>();
97+
for (int i = 0; i < numThreads; i++) {
98+
futures.add(executor.submit(tokenizationTask));
99+
}
100+
101+
for (final Future<?> future : futures) {
102+
future.get();
103+
}
104+
105+
executor.shutdown();
106+
executor.awaitTermination(1, TimeUnit.MINUTES);
107+
}
108+
74109
@Test
75110
void testTokenizeSingleLineExpression() throws Exception {
76111
final var registry = new Registry();
@@ -80,7 +115,7 @@ void testTokenizeSingleLineExpression() throws Exception {
80115
for (int i = 0; i < lineTokens.getTokens().length; i++) {
81116
final IToken token = lineTokens.getTokens()[i];
82117
final String s = "Token from " + token.getStartIndex() + " to " + token.getEndIndex() + " with scopes " + token.getScopes();
83-
Assertions.assertEquals(EXPECTED_SINGLE_LINE_TOKENS[i], s);
118+
assertEquals(EXPECTED_SINGLE_LINE_TOKENS[i], s);
84119
}
85120
}
86121

@@ -100,7 +135,7 @@ void testTokenizeMultilineExpression() throws Exception {
100135
for (i = 0; i < lineTokens.getTokens().length; i++) {
101136
final IToken token = lineTokens.getTokens()[i];
102137
final String s = "Token from " + token.getStartIndex() + " to " + token.getEndIndex() + " with scopes " + token.getScopes();
103-
Assertions.assertEquals(EXPECTED_MULTI_LINE_TOKENS[i + j], s);
138+
assertEquals(EXPECTED_MULTI_LINE_TOKENS[i + j], s);
104139
}
105140
j = i;
106141
}
@@ -220,7 +255,7 @@ void testTokenizeTypeScriptFile() throws Exception {
220255
for (int i = 0; i < lineTokens.getTokens().length; i++) {
221256
tokenIndex++;
222257
final var token = lineTokens.getTokens()[i];
223-
Assertions.assertEquals(
258+
assertEquals(
224259
expectedTokens.get(tokenIndex),
225260
"Token from " + token.getStartIndex() + " to " + token.getEndIndex() + " with scopes " + token.getScopes());
226261
}

0 commit comments

Comments
 (0)