Skip to content

Application-supplied memory allocators#692

Open
YakoYakoYokuYoku wants to merge 1 commit into
libgd:masterfrom
YakoYakoYokuYoku:custom-mem-allocs
Open

Application-supplied memory allocators#692
YakoYakoYokuYoku wants to merge 1 commit into
libgd:masterfrom
YakoYakoYokuYoku:custom-mem-allocs

Conversation

@YakoYakoYokuYoku

Copy link
Copy Markdown
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

cmb69 commented Apr 8, 2021

Copy link
Copy Markdown
Member

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
Copy Markdown
Contributor Author

You welcome.

Pinging @vapier for review.

@YakoYakoYokuYoku

Copy link
Copy Markdown
Contributor Author

Maybe reallocf is not a good name.

@cmb69

cmb69 commented Apr 8, 2021

Copy link
Copy Markdown
Member

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
Comment thread docs/naturaldocs/project/Menu.txt Outdated
Comment thread src/gd.h Outdated
Comment thread src/gd.h
Comment thread tests/gdmem/malloc.c
Comment thread tests/gdmem/malloc.c Outdated
Comment thread tests/gdmem/malloc.c Outdated
Comment thread tests/gdmem/malloc.c Outdated
Comment thread tests/gdmem/malloc.c
Comment thread tests/gdmem/malloc.c Outdated
Comment thread tests/gdmem/malloc.c

@vapier vapier left a comment

Copy link
Copy Markdown
Member

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
Copy Markdown
Contributor Author

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

@pierrejoye

pierrejoye commented Jul 7, 2021

Copy link
Copy Markdown
Contributor

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

YakoYakoYokuYoku commented Jul 8, 2021

Copy link
Copy Markdown
Contributor Author

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
Copy Markdown
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
Copy Markdown
Contributor

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

@pierrejoye pierrejoye added this to the GD 2.4 milestone Aug 24, 2021
@YakoYakoYokuYoku

Copy link
Copy Markdown
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

cmb69 commented Sep 13, 2021

Copy link
Copy Markdown
Member

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
Copy Markdown
Contributor Author

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

@pierrejoye

Copy link
Copy Markdown
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
Copy Markdown
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

YakoYakoYokuYoku commented Mar 15, 2023

Copy link
Copy Markdown
Contributor Author

@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
Copy Markdown
Contributor Author

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

@cmb69

cmb69 commented Oct 25, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
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

cmb69 commented Oct 27, 2024

Copy link
Copy Markdown
Member

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