Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Application-supplied memory allocators #692

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

YakoYakoYokuYoku
Copy link
Contributor

Because of the usage of the Zend memory manager in the PHP interpreter, gd has a situation with having many options for memory management and no control over it.

This PR brings an API for the management that corresponds to the following methods:

void gdSetMemoryCallocMethod(gdCallocf callocf);
void gdSetMemoryMallocMethod(gdMallocf mallocf);
void gdSetMemoryReallocMethod(gdReallocf reallocf);
void gdSetMemoryFreeMethod(gdFreef freef);
void gdSetMemoryAllocationMethods(gdCallocf callocf, gdMallocf mallocf, gdReallocf reallocf, gdFreef freef);

Each one of these sets an specific allocator for the task and there is a much more general method that sets the allocation functions at once.
The underlying magic is setting static variables for every method.
All of gdMalloc and its friends had to be modified to use the variables.

Marked as draft because discussions may take place first. Fixes #335.

@cmb69
Copy link
Contributor

cmb69 commented Apr 8, 2021

Thank you! Looks generally good to me, but maybe it's better to split the CMake/pthread changes into a separate PR?

@YakoYakoYokuYoku
Copy link
Contributor Author

You welcome.

Pinging @vapier for review.

@YakoYakoYokuYoku
Copy link
Contributor Author

Maybe reallocf is not a good name.

@cmb69
Copy link
Contributor

cmb69 commented Apr 8, 2021

It may make sense to use the same terms: gdSetMemoryCallocMethod vs. gdCallocf. Why not gdCallocMethod? Or gdSetMemoryCallocFunc and gdCallocFunc.

@YakoYakoYokuYoku YakoYakoYokuYoku marked this pull request as ready for review April 15, 2021 21:49
docs/naturaldocs/project/Menu.txt Outdated Show resolved Hide resolved
src/gd.h Outdated Show resolved Hide resolved
src/gd.h Show resolved Hide resolved
tests/gdmem/malloc.c Show resolved Hide resolved
tests/gdmem/malloc.c Outdated Show resolved Hide resolved
tests/gdmem/malloc.c Outdated Show resolved Hide resolved
tests/gdmem/malloc.c Outdated Show resolved Hide resolved
tests/gdmem/malloc.c Show resolved Hide resolved
tests/gdmem/malloc.c Outdated Show resolved Hide resolved
tests/gdmem/malloc.c Show resolved Hide resolved
Copy link
Member

@vapier vapier left a comment

Choose a reason for hiding this comment

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

lot of boilerplate, but not sure we can do better :/. splattering a lot of defines feels like it might be fewer LOC, but harder to understand.

@YakoYakoYokuYoku
Copy link
Contributor Author

Running the test with CMake works just fine but not with Autotools 🤔 .

@pierrejoye
Copy link
Contributor

pierrejoye commented Jul 7, 2021

Very good PR , thank you! :)

It could be a tat bit better using:

common struct to store the f

  • function ptr data in a global struct, surrounded by our lock mechanism, Each getter/setter using the lock/unlock
  • must be only called once per process (not sure we can ensure it but then doc issue, big mess if it changes accross the same process)

What do you think?

@YakoYakoYokuYoku
Copy link
Contributor Author

YakoYakoYokuYoku commented Jul 8, 2021

From what was discussed in the issue we can go either ways with the static struct or the vars, but I'll stick with the latter for the moment.
Speaking about locking I find it kinda pointless, the methods are obviously not thread safe and will cause disastrous alterations with the memory managers if handled incorrectly.
Maybe doing checks on another global variable is an option. Or maybe we could not check anything and document that calling twice is invalid usage (kinda like the vkBeginCommandBuffer docs).

@pierrejoye
Copy link
Contributor

I think it would make sense to have a struct, it will also helps CPU cache, especially in loaders where quite a few alloc/free may happen. Or in GD3 with the Paths APIs.

Taste thing, I find it cleaner as well :)

What do you think?

@pierrejoye
Copy link
Contributor

Besides that, I am all for it and sounds like a good addition for 2.4.0 :) Well done!!

@YakoYakoYokuYoku
Copy link
Contributor Author

Only thing about this PR is that testing gdmem with Autotools and shared libgd leads to the functions not being used in the test. Although it works with an static archive. From there idek what's happening.

@cmb69
Copy link
Contributor

cmb69 commented Sep 13, 2021

I think it would make sense to have a struct, it will also helps CPU cache, especially in loaders where quite a few alloc/free may happen. Or in GD3 with the Paths APIs.

I don't have a strong opinion on this, but sounds reasonable.

Most important for me is that we ship custom allocator support ASAP. I wouldn't want to unbundle libgd from php-src before this isn't available.

Only thing about this PR is that testing gdmem with Autotools and shared libgd leads to the functions not being used in the test. Although it works with an static archive.

Thanks for reporting. I think this needs closer investigation.

Anyhow, if you have some time, could you please resolve the merge conflicts?

@YakoYakoYokuYoku
Copy link
Contributor Author

No further comments @pierrejoye, @cmb69, @vapier?

@pierrejoye
Copy link
Contributor

@YakoYakoYokuYoku in principle I am good with it. I was waiting @remicollet feedback on the API.

While I still like to provide the atomicity handling on our side tho'. That can be done post merge.

@remicollet
Copy link
Contributor

I was waiting @remicollet feedback on the API.

I don't really care about the API ;) (as soon as it is there)

BTW, a single setter may be enough (I don't think changing only some make sense, and a single call with 4 pointers will avoid forgetting one).

Perhaps a safety bell checking those allocators have not be used yet before allowing the switch...

@YakoYakoYokuYoku
Copy link
Contributor Author

YakoYakoYokuYoku commented Mar 15, 2023

@cmb69, @pierre, @remicollet, @vapier I'm deeply sorry for being late with this PR, was occupied with things IRL and I didn't know how to fix this PR up until now.

So if anyone of you can merge this I'd be glad for it. 🙏

@YakoYakoYokuYoku
Copy link
Contributor Author

@vapier, since you've approved this can you take another look?

@cmb69
Copy link
Contributor

cmb69 commented Oct 25, 2024

Thank you @YakoYakoYokuYoku for all the work you've put into this! However, a related issue came up recently regarding PHP and libgmp, see php/php-src#16507 (comment). So unless the functions would be stored in TLS (thread-local storage), PHP probably can't use the feature. Note that I'm not talking about true thread-safety (that might not be necessary), but rather that each thread should have its own custom allocators.

Another issue is, that is should somehow forbidden to change/clear the allocators after any memory already been allocated. It might be sufficient to track whether any allocation has happend, and in this case let the calls to change/clear the allocators fail or silently do nothing.

@YakoYakoYokuYoku
Copy link
Contributor Author

In theory adding thread local storage specifiers should suffice though tell me if I'm wrong. On the other hand, the allocators guard could be implemented using atomic booleans and use gd_error to print messages, but I think that a warning in the documentation is enough, unless there's something elso to take into account.

@cmb69
Copy link
Contributor

cmb69 commented Oct 27, 2024

In theory adding thread local storage specifiers should suffice though tell me if I'm wrong.

I think that is sufficient, if supported on all supported platforms. A bit hard to verify, since most of CI is failing anyway.

On the other hand, the allocators guard could be implemented using atomic booleans and use gd_error to print messages, but I think that a warning in the documentation is enough, unless there's something elso to take into account.

Thinking about that (see also php/php-src#16609 (review)), there actually should be locks when setting/retrieving the custom allocators, since you never know when a thread switch happens. If we only support a single change of the custom allocators (i.e. set them all at once), that lock could be completely implemented in libgd; if we support individual setters, we likely need to provide some API which needs to be called by the client who wants to change the custom allocators.

And to avoid havoc even when using a single-threaded process, we need to make it very clear in the documentation, that clients need to restore the old allocators when done with their own. And even that would not be sufficient, if libgd allows to install callbacks.

It is most unfortunate, that a simple and highly desireable feature may cause so many issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Application-supplied memory allocators
5 participants