Jonas Hahnfeld via Discussions on LilyPond development <lilypond-devel@gnu.org> writes:
> Am Freitag, den 07.02.2020, 19:26 +0100 schrieb Han-Wen Nienhuys: >> Hey Dan, >> >> I thought you might know this. >> >> To do >> https://codereview.appspot.com/561390043/ >> properly, I have to expand >> the heap when GC notifies us that a collection took place. Unfortunately, >> libgc notifications are done with the garbage collector lock held. So I'll >> need schedule a call to GC_expand_heap on a different thread. >> >> Would you know what is the best way to do this in C++ nowadays? > > If I understand the information correctly, it would be enough to pass > data from the callback to e.g. the main thread, right? > > When a single boolean is sufficient (ie call that function now), I'd > start with std::atomic_flag which is guaranteed to be lock-free. Upon > reading the documentation, the semantics are a bit weird (ie > test_and_set sets the flag to true). So you'd need flag.clear() in the > callback and if (!flag.test_and_set()) GC_expand_heap(...) in the main > code. A thin layer around it may improve readability, ie doing the > inverted logic in a struct / class. Alternatively you can use > std::atomic<bool> which is probably lock-free on all architectures we > care about. > > If you need to transport more than that (ie an integer), the more > generic std::atomic<T> might be a choice. For your concrete case, > declare the following: > static std::atomic_size_t expand_heap = ATOMIC_VAR_INIT(0); > then in the callback: > expand_heap = <<<computed argument>>>; > and in the main thread: > // Benign race condition: Check that there is something to do to avoid > // writes if the variable is already 0. The value is then retrieved > // via exchange() below which is atomic. > if (expand_heap != 0) { > size_t arg = expand_heap.exchange(0); > if (arg != 0) { > GC_expand_hp(arg); > } > } > > Does this already solve your needs? > Jonas It's worth pointing out that almost _all_ of our Scheme-level allocations are routed through the Smob_core class, so doing the heap extension _there_ when one passes there next should be workable. While the code certainly does allocate non-Smob SCM objects a lot as well (by calling things like scm_cons), the smobbed ones should be worked often enough that extending the heap then should not cause too much churn. -- David Kastrup