Skip to content

Commit

Permalink
Merge pull request #42030 from HindujaB/http-fix
Browse files Browse the repository at this point in the history
Fix NPE from daemon strand for record value creation
  • Loading branch information
warunalakshitha authored Feb 1, 2024
2 parents a7a0e92 + 1662512 commit fa09ebb
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,6 @@ public void unblockStrand(Strand strand) {
}

private void cleanUp(Strand justCompleted) {
justCompleted.scheduler = null;
justCompleted.frames = null;
justCompleted.waitingContexts = null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,8 @@ public static void runInit(CompileResult compileResult) throws ClassNotFoundExce
directRun(compileResult.getClassLoader().loadClass(configClassName), "$configureInit",
new Class[]{String[].class, Path[].class, String.class}, new Object[]{new String[]{},
configurationDetails.paths, configurationDetails.configContent});
runOnSchedule(initClazz, ASTBuilderUtil.createIdentifier(null, "$moduleInit"), scheduler);
runOnSchedule(initClazz, ASTBuilderUtil.createIdentifier(null, "$moduleStart"), scheduler);
runOnSchedule(initClazz, "$moduleInit", scheduler);
runOnSchedule(initClazz, "$moduleStart", scheduler);
// if (temp) {
// scheduler.immortal = true;
// new Thread(scheduler::start).start();
Expand All @@ -397,6 +397,26 @@ private static void directRun(Class<?> initClazz, String functionName, Class[] p
}
}

public static void runOnSchedule(CompileResult compileResult, String functionName, Scheduler scheduler) {
BIRNode.BIRFunction function = getInvokedFunction(compileResult, functionName);
PackageManifest packageManifest = compileResult.packageManifest();
String funcClassName = JarResolver.getQualifiedClassName(packageManifest.org().toString(),
packageManifest.name().toString(),
packageManifest.version().toString(),
getClassName(function.pos.lineRange().fileName()));
Class<?> funcClass = null;
try {
funcClass = compileResult.getClassLoader().loadClass(funcClassName);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Error while invoking function '" + functionName + "'", e);
}
runOnSchedule(funcClass, functionName, scheduler);
}

private static void runOnSchedule(Class<?> initClazz, String name, Scheduler scheduler) {
runOnSchedule(initClazz, ASTBuilderUtil.createIdentifier(null, name), scheduler);
}

private static void runOnSchedule(Class<?> initClazz, BLangIdentifier name, Scheduler scheduler) {
String funcName = JvmCodeGenUtil.cleanupFunctionName(name.value);
try {
Expand All @@ -418,6 +438,7 @@ private static void runOnSchedule(Class<?> initClazz, BLangIdentifier name, Sche
};
final FutureValue out = scheduler
.schedule(new Object[1], func, null, null, null, PredefinedTypes.TYPE_ANY, null, null);
Scheduler.setDaemonStrand(out.strand);
scheduler.start();
final Throwable t = out.panic;
if (t != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,21 @@
*/
package org.ballerinalang.test.runtime.api;

import io.ballerina.runtime.api.Module;
import io.ballerina.runtime.api.creators.ValueCreator;
import io.ballerina.runtime.api.utils.StringUtils;
import io.ballerina.runtime.api.values.BMap;
import io.ballerina.runtime.api.values.BString;
import io.ballerina.runtime.internal.scheduling.Scheduler;
import org.ballerinalang.test.BCompileUtil;
import org.ballerinalang.test.BRunUtil;
import org.ballerinalang.test.CompileResult;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.concurrent.atomic.AtomicReference;

/**
* Test cases for runtime api.
*
Expand All @@ -49,4 +58,41 @@ public Object[] packageNameProvider() {
"environment"
};
}

@Test
public void testRecordNoStrandDefaultValue() {
CompileResult strandResult = BCompileUtil.compile("test-src/runtime/api/no_strand");
final Scheduler scheduler = new Scheduler(false);
AtomicReference<Throwable> exceptionRef = new AtomicReference<>();
Thread thread1 = new Thread(() -> {
BRunUtil.runOnSchedule(strandResult, "main", scheduler);
});
Thread thread2 = new Thread(() -> {
try {
Thread.sleep(1000);
BMap<BString, Object> recordValue = ValueCreator.createRecordValue(new Module("testorg",
"no_strand", "1"), "MutualSslHandshake");
Assert.assertEquals(recordValue.getType().getName(), "MutualSslHandshake");
Assert.assertEquals(recordValue.get(StringUtils.fromString("status")),
StringUtils.fromString("passed"));
Assert.assertNull(recordValue.get(StringUtils.fromString("base64EncodedCert")));
} catch (Throwable e) {
exceptionRef.set(e);
} finally {
scheduler.poison();
}
});
try {
thread1.start();
thread2.start();
thread1.join();
thread2.join();
Throwable storedException = exceptionRef.get();
if (storedException != null) {
throw new AssertionError("Test failed due to an exception in a thread", storedException);
}
} catch (InterruptedException e) {
throw new RuntimeException("Error while invoking function 'main'", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
org= "testorg"
name="no_strand"
version= "1.0.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
//
// WSO2 Inc. licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import ballerina/lang.runtime;

public class Listener {

private string name = "";

public function init(string name){
self.name = name;
}

public function 'start() returns error? {
}

public function gracefulStop() returns error? {
}

public function immediateStop() returns error? {
}

public function attach(service object {} s, string[]|string? name = ()) returns error? {
}

public function detach(service object {} s) returns error? {
}
}

public function main() {
Listener l = new("TestListener");
runtime:registerListener(l);
}

public type MutualSslHandshake record {|
MutualSslStatus status = PASSED;
string? base64EncodedCert = ();
|};

public type MutualSslStatus PASSED|FAILED|();
public const PASSED = "passed";
public const FAILED = "failed";

0 comments on commit fa09ebb

Please sign in to comment.