# Hanging in ijl\_gc\_collect() when using adopted threads

**URL:** <https://discourse.julialang.org/t/hanging-in-ijl-gc-collect-when-using-adopted-threads/99221>\
**Category:** General Usage\
**Created:** [May 22, 2023, 1:48pm UTC](https://discourse.julialang.org/t/hanging-in-ijl-gc-collect-when-using-adopted-threads/99221 "2023-05-22T13:48:34Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![peremato](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/peremato/32/29128_2.png) [@peremato](https://discourse.julialang.org/u/peremato)\
**Post date:** [May 22, 2023, 1:48pm UTC](https://discourse.julialang.org/t/hanging-in-ijl-gc-collect-when-using-adopted-threads/99221/1 "2023-05-22T13:48:34Z")

</div>

When using the MT mode of [Geant4.jl](https://github.com/JuliaHEP/Geant4.jl) the main thread hangs in an infinite loop in `ijl_gc_collect()`. I am using latest 1.9 version of Julia on MacOS.  
The way it works is as follows:

- The main thread (Julia REPL) calls C++ code that creates a number of worker threads. These are calling back Julia and they are all adopted into the Julia pool (I call explicitly `jl_adopt_thread()` but probably not necessary since the callback is done thought `cfunction`). So far, so good. Work is performed as expected.
- After the run is completed, the adopted worker threads are put on wait (`std::cv::wait(...)`) and control is returned to the main thread (REPL). I do call `jl_yield()` at the end of the run and before entering the wait. The threads are waiting for a new run to eventually be started again.
- At this moment, in a unpredictable manner, typically when generating some output, the REPL hangs in an infinite loop in `ijl\_gc\_collect() between addresses +256 and +264. My guess is that is looping around:

```julia
jl_gc_wait_for_the_world(gc_all_tls_states, gc_n_threads);
JL_PROBE_GC_STOP_THE_WORLD();

```

Is anything I can do you avoid this hanging? Many thanks in advance.

---

<div class="post-metadata">

**Author:** ![peremato](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/peremato/32/29128_2.png) [@peremato](https://discourse.julialang.org/u/peremato)\
**Post date:** [May 30, 2023, 12:11pm UTC](https://discourse.julialang.org/t/hanging-in-ijl-gc-collect-when-using-adopted-threads/99221/2 "2023-05-30T12:11:04Z")

</div>

@maleadt do you think this problem I am having could be related/fixed by [https://github.com/JuliaLang/julia/pull/49934](https://github.com/JuliaLang/julia/pull/49934)? I am not really fit to understand the internals of Julia threading and GC.

---

<div class="post-metadata">

**Author:** ![maleadt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maleadt/32/10097_2.png) [@maleadt](https://discourse.julialang.org/u/maleadt)\
**Post date:** [May 30, 2023, 6:16pm UTC](https://discourse.julialang.org/t/hanging-in-ijl-gc-collect-when-using-adopted-threads/99221/3 "2023-05-30T18:16:14Z")

</div>

No, that would manifest as a segfault when adopting. What might be happening here (as per my limited understanding of that part of Julia) is that when a thread starts GC, it waits for all other Julia threads to reach a safepoint. Your newly adopted threads however are not at a safepoint, yet they are blocked in `std::cv::wait`, causing other threads to hang when attempting to enter GC. You probably want to enter a GC safe region during that wait (by calling `jl_gc_safe_enter`), so that GC can run during it.

---

<div class="post-metadata">

**Author:** ![peremato](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/peremato/32/29128_2.png) [@peremato](https://discourse.julialang.org/u/peremato)\
**Post date:** [May 31, 2023, 7:04am UTC](https://discourse.julialang.org/t/hanging-in-ijl-gc-collect-when-using-adopted-threads/99221/4 "2023-05-31T07:04:11Z")

</div>

Thanks very much for your hint. I added `jl_gc_safe_enter` and it did work (didn’t get an infinite loop). Then, I remove it to cross-check that indeed this was the solution, but now I have no infinite loops anymore. Something must have changed in the way I build the C++ wrapper that it now works. Very strange.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [May 31, 2023, 1:58pm UTC](https://discourse.julialang.org/t/hanging-in-ijl-gc-collect-when-using-adopted-threads/99221/5 "2023-05-31T13:58:42Z")

</div>

Is the current status of this “magically solved” (which could just mean repro is hard)?

---

<div class="post-metadata">

**Author:** ![peremato](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/peremato/32/29128_2.png) [@peremato](https://discourse.julialang.org/u/peremato)\
**Post date:** [May 31, 2023, 3:57pm UTC](https://discourse.julialang.org/t/hanging-in-ijl-gc-collect-when-using-adopted-threads/99221/6 "2023-05-31T15:57:14Z")

</div>

Yes. Doing more tests I encountered again the problem. It has to do with the unpredictability of when a GC occurs. To minimize the chances of blockage, when a GC happens, all the waiting adopted threads must have called `jl_gc_safe_enter` just before entering the wait state. In addition, I am also disabling GC when the adopted threads are doing heavy work. With all this, seems to be quite robust.

---

<div class="post-metadata">

**Author:** ![vchuravy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vchuravy/32/8_2.png) [@vchuravy](https://discourse.julialang.org/u/vchuravy)\
**Post date:** [May 31, 2023, 8:19pm UTC](https://discourse.julialang.org/t/hanging-in-ijl-gc-collect-when-using-adopted-threads/99221/7 "2023-05-31T20:19:34Z")

</div>

> [@peremato](#):
>
> In addition, I am also disabling GC when the adopted threads are doing heavy work. With all this, seems to be quite robust.

If you have a reproducer for why you have to do that I would be interested in seeing it.

Generally speaking when your foreign threads do something blocking like `std::cv::wait` or heavy C++ operations, you want to transition the threads into a “GC safe region”, by using `jl_gc_safe_enter` and `jl_gc_safe_leave`. You don’t want to disable GC entirely.

---

<div class="post-metadata">

**Author:** ![peremato](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/peremato/32/29128_2.png) [@peremato](https://discourse.julialang.org/u/peremato)\
**Post date:** [June 1, 2023, 7:08am UTC](https://discourse.julialang.org/t/hanging-in-ijl-gc-collect-when-using-adopted-threads/99221/8 "2023-06-01T07:08:02Z")

</div>

Thanks for the advise. Unfortunately is not easy to have a simple reproducer. The C++ package Geant4 is large, complex and its threading model is far from simple. If I manage I will let you know.
