Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

implement open GC registry #1924

Merged
merged 10 commits into from
Feb 15, 2019
Merged

Conversation

MartinNowak
Copy link
Member

  • allows to add new GCs at link time

@dlang-bot
Copy link
Contributor

dlang-bot commented Sep 29, 2017

Thanks for your pull request, @MartinNowak!

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub fetch digger
dub run digger -- build "master + druntime#1924"

@MartinNowak MartinNowak force-pushed the open_gc_registry branch 3 times, most recently from 781ab8e to 377a33b Compare September 30, 2017 13:01
src/gc/config.d Outdated
@@ -40,6 +42,8 @@ struct Config
{
import core.internal.traits : externDFunc;

__gshared linkDummy = &_dummy_ref_to_link_gc_register_constructor;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be simpler to just call _d_register_conservative_gc() and _d_register_manual_gc() explicitely. You can still override these symbols in the executable if you don't want to register them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The C object file wouldn't be referenced and doesn't get linked into the application.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What C object file? Just call _d_register_conservative_gc() and _d_register_manual_gc() right here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed yesterday that you can also reimplement gc_init in the executable registering the desired or new GCs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That wouldn't allow configuring by application users. Think of how Java GC's are often selected/optimized according to specific loads.
Wouldn't work with druntime as DLL or with hidden symbols in shared libraries.
Also many programmers hardly have an idea how linkers work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, replacing gc_init is a bit blunt and doesn't allow adding to existing GCs. It's currently the only way to remove a GC from the binary.

The current of _dummy_ref_to_link_gc_register_constructor seems gratuitious, though. Just registering the GCs here should be fine.

@@ -332,6 +323,7 @@ class ConservativeGC : GC
cstdlib.free(gcx);
gcx = null;
}
cstdlib.free(cast(void*) this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Freeing this in a public method is a bit dangerous because an invariant might crash. One possible solution might be to pass the finalize function to the registry, too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, not so nice.

In fact just using a static buffer instead of the C heap might work as well.

Think the best alternative is to convert Dtor to a real destructor which doesn't have the invariant problem.

class ManualGC : GC
{
__gshared Array!Root roots;
__gshared Array!Range ranges;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it's been this way before, but it doesn't really make sense to make these members __gshared.

__attribute__((constructor)) static void xxx_ctor()
{
register_mygc();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration still needs a solution on Windows (though something similar is possible). I'd prefer if we would not have to rely on C, though.

Some time ago, I tried implementing pragma(dataSeg, "segment-name"), would be pretty helpful for this, too. I think it's badly needed in a system programming language.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping for the _STI/_STD mechanism to work (to be recognized by the linker), but must have misremembered that it works.
There is https://issues.dlang.org/show_bug.cgi?id=16300 and we've recently worked on constructor/destructor functions dlang/dmd#6956 that could be added as pragma(constructor) and pragma(destructor). Not sure what gdc or ldc are doing with regards to that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have https://github.com/ldc-developers/druntime/blob/ldc/src/ldc/attributes.d#L229 in LDC, with the addition of pragma(crt_constructor) and friends, perhaps we should add that?

@rainers
Copy link
Member

rainers commented Sep 30, 2017

The nits aside, this approach is much better for registering and selecting the GC than the current one.

@MartinNowak
Copy link
Member Author

MartinNowak commented Oct 1, 2017

Think it would make sense to work on pragma(crt_constructor[, priority]) first, rather than spending time on a Windows solution here.

https://issues.dlang.org/show_bug.cgi?id=17868

@MartinNowak
Copy link
Member Author

The registered factory should also be nothrow @nogc but that's fairly invasive up to core.thread, should be done first anyhow.

@@ -0,0 +1,87 @@
/**
* Contains a registry for GC factories.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm slightly confused by the terminology here: I would have expected the "registry" to be the "factory" and a GC is registered by adding a "factory method" to the factory.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, yes it's a registry for factory methods.

@dlang-bot dlang-bot added Needs Rebase needs a `git rebase` performed Needs Work labels Jan 1, 2018
@andralex
Copy link
Member

@MartinNowak I wonder if we should explore dropping the notion of GC as a class, which allows replacing it during runtime (not really used or useful). This will cause some breakage but it would be a design improvement. What do you think?

@MartinNowak
Copy link
Member Author

@MartinNowak I wonder if we should explore dropping the notion of GC as a class, which allows replacing it during runtime (not really used or useful). This will cause some breakage but it would be a design improvement. What do you think?

The opposite, let's allow to implement GCs as dub packages (#1924). There is still are still a lot of improvement potentials in the GC domain, but we (as core team) will hardly invest in this area in the next 1 or 2 years.
You might be interested in https://forum.dlang.org/post/[email protected].
Opening this area for innovation outside of our busy core team could realistically get us a low-latency GC in the meantime.

@MartinNowak
Copy link
Member Author

@MartinNowak I wonder if we should explore dropping the notion of GC as a class, which allows replacing it during runtime (not really used or useful).

Also I'd like this to be the last work on the GC for a while, people still get confused that our community keeps talking about GC improvements.

@rainers rainers added the GC garbage collector label Dec 24, 2018
@dlang-bot dlang-bot removed Needs Work Needs Rebase needs a `git rebase` performed labels Dec 24, 2018
@rainers
Copy link
Member

rainers commented Dec 24, 2018

Rebased and replaced the C registration with pragma(crt_constructor). Might need dlang/dmd#9132

@thewilsonator
Copy link
Contributor

src/custom_gc.d(22): Error: class `custom_gc.MallocGC` interface function `ProfileStats profileStats() nothrow` is not implemented

posix.mak Outdated
@@ -229,6 +229,10 @@ $(ROOT)/threadasm.o : src/core/threadasm.S
@mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) $< -o$@

$(ROOT)/gc/%.o : src/gc/%.c
@mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) $< -o$@
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this? (I don't see any C files that have been added)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has remained from the initial version that used C files instead of pragma(crt_constructor). I'll remove it.

@wilzbach
Copy link
Member

FYI the master -> stable branch-off will happen in ~ 3 days. So it would be nice to have this as part of 2.085. Anything blocking this?

@rainers
Copy link
Member

rainers commented Feb 12, 2019

Anything blocking this?

Good to go AFAICT. I guess a changelog entry and an update to the documentation are recommended.


GC createMyGC()
{
__gshared ubyte[__traits(classInstanceSize, MyGC)] buf;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably good to add an alignment here see e.g. #2411

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, classInstanceAlignment doesn't seem good enough (and isn't yet available), so I opted for aligning to pointer size.
I also used core.lifetime.emplace now.

@rainers
Copy link
Member

rainers commented Feb 12, 2019

I've added a changelog entry, but noticed one gotcha: when writing a new GC you will have to import modules from the gc package, but that isn't available in the standard import folders.

You always needed to add the src folder to the import paths somehow, not sure we should bother now.

@rainers rainers force-pushed the open_gc_registry branch 2 times, most recently from 98403a8 to 4f3d2ac Compare February 12, 2019 08:30
Copy link
Member

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhm, looks like we need to move the user-exposed bits to core.gc?

---
extern (C) pragma(crt_constructor) void registerMyGC()
{
registerGCFactory("mygc", &createMyGC);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this need an import?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does (import gc.registry, gc.gcinterface;), but they are not easily accessible right now

@rainers
Copy link
Member

rainers commented Feb 12, 2019

Uhm, looks like we need to move the user-exposed bits to core.gc?

I'd rather add the necessary modules to the import folder as is.

@wilzbach
Copy link
Member

Uhm, looks like we need to move the user-exposed bits to core.gc?

I'd rather add the necessary modules to the import folder as is.

Wouldn't that be a potentially breaking change as we add a new top-level module?
Also, IIRC a few tools (rdmd, dmd -i, etc.) have hard-coded the list of top-level modules from the standard library, so it's probably not a good idea to introduce one lightly.

@rainers
Copy link
Member

rainers commented Feb 12, 2019

Wouldn't that be a potentially breaking change as we add a new top-level module?

It is already there, just hidden. If you create a module with the same module name, you will get symbol conflicts at link time.

Also, IIRC a few tools (rdmd, dmd -i, etc.) have hard-coded the list of top-level modules from the standard library, so it's probably not a good idea to introduce one lightly.

Might be an issue, but most of the time it should be ok to just recompile the module again, the linker just picks one.

I'm also ok with not making them public. If you work on replacing the GC, adding an import path should not scare you. Maybe the changelog text is already too detailed, most of it might be better in the documentation.

@rainers
Copy link
Member

rainers commented Feb 15, 2019

I moved most of the changelog text to the documentation dlang/dlang.org#2577

Copy link
Member

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should still expose the methods to the user, s.t. dub packages have an easy way to provide a nice out-of-the-box experience for their custom GCs, but this can happen in another PR.

@wilzbach
Copy link
Member

I'd rather add the necessary modules to the import folder as is.

Hmm, currently all the user-exposed GC-related methods are in core.memory:

https://dlang.org/phobos/core_memory.html#.GC

How about moving the public interfaces to this module or as a core.memory.gc submodule?

@dlang-bot dlang-bot merged commit 1dcbd74 into dlang:master Feb 15, 2019
@MartinNowak MartinNowak deleted the open_gc_registry branch August 30, 2022 06:10
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
GC garbage collector
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants