diff --git a/build/build/src/engine/context.rs b/build/build/src/engine/context.rs index ce0ee683d58b..84a1f684b8f7 100644 --- a/build/build/src/engine/context.rs +++ b/build/build/src/engine/context.rs @@ -661,12 +661,10 @@ pub async fn runner_sanity_test( .args(["--run", repo_root.test.join("Base_Tests").as_str()]) .set_env_opt(ENSO_JAVA, enso_java)? .set_env(ENSO_DATA_DIRECTORY, engine_package)? - .run_stdout() - .await?; - ensure!( - test_base.contains("0 tests failed."), - "All tests shall succeed. Output:\n{test_base}", - ); + .run_ok() + .await; + test_base + } else { + Ok(()) } - Ok(()) } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/ResourceManager.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/ResourceManager.java index d78746647ba5..5a9bbaad6274 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/ResourceManager.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/ResourceManager.java @@ -177,29 +177,34 @@ private final class ProcessItems extends ThreadLocalAction implements Runnable { */ @Override protected void perform(ThreadLocalAction.Access access) { + var isMyThreadChoosen = false; for (; ; ) { Item[] toProcess; synchronized (pendingItems) { - request.cancel(false); + if (!isMyThreadChoosen) { + if (request == null || request.isCancelled()) { + // some thread is already handing the request + return; + } else { + // I am choosen and I will loop and process pendingItems + // until they are available + isMyThreadChoosen = true; + // signal others this request has choosen thread + request.cancel(false); + } + } if (pendingItems.isEmpty()) { - // nothing to process, - // signal request is finished + // nothing to process anymore, + // signal request is finished and new one shall be scheduled request = null; return; } toProcess = pendingItems.toArray(Item[]::new); - // mark as being processed - pendingItems.set(0, null); + pendingItems.clear(); } - try { - for (var it : toProcess) { - it.finalizeNow(context); - removeFromItems(it); - } - } finally { - synchronized (pendingItems) { - pendingItems.subList(0, toProcess.length).clear(); - } + for (var it : toProcess) { + it.finalizeNow(context); + removeFromItems(it); } } } diff --git a/test/Base_Tests/src/Runtime/GC_Example.enso b/test/Base_Tests/src/Runtime/GC_Example.enso index 72507f7cb933..8df17ab0fdec 100644 --- a/test/Base_Tests/src/Runtime/GC_Example.enso +++ b/test/Base_Tests/src/Runtime/GC_Example.enso @@ -1,4 +1,5 @@ from Standard.Base import all +import Standard.Base.Errors.Illegal_State.Illegal_State import Standard.Base.Runtime.Managed_Resource.Managed_Resource import Standard.Base.Runtime.Ref.Ref @@ -15,27 +16,42 @@ type My_Resource close_resource resource = resource.close -repeat_cleanup_until_done counter = - go i = - if counter.get == 0 then Nothing else - if i % 100 == 0 then - IO.println "Still "+counter.get.to_text+" resources to clean up..." - Runtime.gc - @Tail_Call go i+1 - go 1 +repeat_cleanup_until_done counter println = + deadline = Date_Time.now + (Duration.new minutes=5) + while_counter_not_zero i = if counter.get != 0 then + if i % 10 == 0 then + println "Still "+counter.get.to_text+" resources to clean up..." -perform_test n:Integer println = + Runtime.gc + + deadline_not_reached at = if at < deadline then True else + message = "Timeout has been reached, but there are "+counter.get.to_text+" resources remaining that were not cleaned up." + println message + False + + if deadline_not_reached Date_Time.now then + @Tail_Call while_counter_not_zero i+1 + + while_counter_not_zero 1 +perform_test n:Integer println = + resource_holder = Ref.new Nothing counter = Ref.new 0 - println "Allocating "+n.to_text+" resources..." - 0.up_to n . each _-> - My_Resource.allocate counter - println "Cleaning up..." - repeat_cleanup_until_done counter - println "All cleaned up! Remaining: "+counter.get.to_text + println "Allocating "+n.to_text+" resources..." + allocate_resources ref = + all = 0.up_to n . map _-> + My_Resource.allocate counter + ref.put all + allocate_resources resource_holder + + println "Cleaning up "+resource_holder.get.length.to_text+" resources" + # We replace the vector with Nothing to make the resources inaccessible and schedule them for GC + resource_holder.put Nothing + + repeat_cleanup_until_done counter println + println "Cleaning finished! Remaining: "+counter.get.to_text counter.get main n=1000000 = perform_test n IO.println - diff --git a/test/Base_Tests/src/Runtime/Managed_Resource_Spec.enso b/test/Base_Tests/src/Runtime/Managed_Resource_Spec.enso index 748a311f3e67..14f3cd6730cc 100644 --- a/test/Base_Tests/src/Runtime/Managed_Resource_Spec.enso +++ b/test/Base_Tests/src/Runtime/Managed_Resource_Spec.enso @@ -58,9 +58,15 @@ add_specs suite_builder = suite_builder.group "Managed_Resource" group_builder-> r_3 = Panic.recover Any <| Managed_Resource.bracket 42 (_-> Nothing) (_-> Panic.throw "action") r_3.catch . should_equal "action" - group_builder.specify "allocate lots of resources at once" pending=(if Environment.get "CI" . is_nothing . not then "GC Example is marked as pending as it was causing problems on the CI.") <| - remaining = GC_Example.perform_test 100000 (_->Nothing) - remaining . should_equal 0 + group_builder.specify "allocate lots of resources at once" <| + messages = Vector.build builder-> + builder.append '\n' + remaining = GC_Example.perform_test 100000 builder.append + if remaining == 0 then + builder.append "OK" + + if messages.last != "OK" then + Test.fail (messages.join '\n') main filter=Nothing = suite = Test.build suite_builder->