Khimenko Victor wrote:
The relevant hooks are GetMemPtr etc., declared in the GPC unit. You need them if you want to switch between different allocators.
Hmm. It'll require locks in multithreaded program and will be not very convenient.
I see. BTW, are the normal malloc()/free() routines and Boehm's GC thread-safe, do they do their own locking? I can't guarantee that GPC's heap handling routines are thread-safe as I haven't used threads. At first sight, I'd say they are as long as you don't use Mark/Release, but if you want to check them (or other RTS routines) more throughly, you have the source...
Perhaps we can hide it over clever #define ? Let's try:
-- cut -- uses gpc; #define gc_alloc(x) (begin var res:^x; save_ptr:GetMemType; save_ptr:=GetMemPtr; GetMemPtr:=GC_alloc; res:=new(x); GetMemPtr:=save_ptr; end)
Since the variables are declared within a statement part, you'd need a second `var' before save_ptr. Also, Pascal's `New' is syntactically different from C's malloc(). `New' is only meant for typed pointers (simple types, schemata, objects), while `GetMem' takes a memory size, but will not initialize any fields of the structure. The correspondence is `p = malloc (n)' -> `GetMem (p, n)'.
Oops. Is it possible to use compound statement as expression in GPC somehow ?
Not AFAIK. Only as an inline function. The following should work, but as I said, it will not initialize any fields, so it won't work for strings, schemata, files and other types that require initialization (but you could write a second routine specialized for strings, as shown).
inline function GCAlloc (x : SizeType) = Res : Pointer; var save_ptr : GetMemType; begin save_ptr := GetMemPtr; GetMemPtr := @GC_alloc; GetMem (Res, x); GetMemPtr := save_ptr end;
function GCAllocString (const s : String) = Res : PString; var save_ptr : GetMemType; begin save_ptr := GetMemPtr; GetMemPtr := @GC_alloc; New (Res, Length (s)); Res^ := s; GetMemPtr := save_ptr end;
var i : ^Integer; s : PString;
begin i := GCAlloc (SizeOf (Integer)); s := GCAllocString ('foo'); Writeln (s^); end.
Of course, you could then hide then `SizeOf' in a macro with something like:
{$define gc_alloc(x) GCAlloc (SizeOf (x))}
And BTW how I can continue #define on next line (C's \ in the end of line does not work).
{$define ...} can span multiple lines without any `'.
Peter Gerwinski wrote:
Khimenko Victor wrote:
Hmm. It'll require locks in multithreaded program and will be not very convenient. Perhaps we can hide it over clever #define ? Let's try: [...] You need to EXPLICITLY change new strategy every time :-(( Especially annoying since you want to use GC_malloc_atomic for plain strings... [...]
What about introducing a second `New' that allows the user to pass an additional parameter to the allocator?
Might be a solution. (Not that the syntax of `New' isn't already complicated enough... :-/)
Frank
9-Mar-00 18:26 you wrote:
Khimenko Victor wrote:
The relevant hooks are GetMemPtr etc., declared in the GPC unit. You need them if you want to switch between different allocators.
Hmm. It'll require locks in multithreaded program and will be not very convenient.
I see. BTW, are the normal malloc()/free() routines and Boehm's GC thread-safe, do they do their own locking?
Yes for both. Boehm's GC is used in libgcj (GNU Compiler for Java library) after all ... AFAIK "standard" glibc's malloc()/free() are not thread-safe but libpthread has it's own thread-safe replacemnts so you can just specify -lpthread and use malloc()/free() safely.
I can't guarantee that GPC's heap handling routines are thread-safe as I haven't used threads.
It's one thing to gurantee HERE AND NOW and other thing to have this as design goal: if there are some race conditions and such this CAN be fixed, if there are bad design (errno for example) it's MUCH harder to fix...
At first sight, I'd say they are as long as you don't use Mark/Release, but if you want to check them (or other RTS routines) more throughly, you have the source...
Exactly. I repeat: I do not need threads right now. I just want to use them sometime in the future. I can fix problem in implementation but it's MUCH harder to fix problem in API. Sample: errno stuff was solved with ugly #define but end result is MUCH uglier then "Linux's solution": just return not -1 in case of error but -ERROR_CODE. But since errno-based API is "set in stone" now we are using ugly hacks and errno, not clean and mean Linux's solution...
Perhaps we can hide it over clever #define ? Let's try:
-- cut -- uses gpc; #define gc_alloc(x) (begin var res:^x; save_ptr:GetMemType; save_ptr:=GetMemPtr; GetMemPtr:=GC_alloc; res:=new(x); GetMemPtr:=save_ptr; end)
Since the variables are declared within a statement part, you'd need a second `var' before save_ptr. Also, Pascal's `New' is syntactically different from C's malloc(). `New' is only meant for typed pointers (simple types, schemata, objects), while `GetMem' takes a memory size, but will not initialize any fields of the structure. The correspondence is `p = malloc (n)' -> `GetMem (p, n)'.
Oops. But I DO NOT want malloc replacement. I want EXACTLY new replacement. So I can use p:=gc_alloc(integer); ! BTW I'm NOT newbie in Pascal :-) I'm newbie in GPC but I'm used quite a few other implementations (not just Borland Pascal).
Oops. Is it possible to use compound statement as expression in GPC somehow ?
Not AFAIK. Only as an inline function. The following should work, but as I said, it will not initialize any fields, so it won't work for strings, schemata, files and other types that require initialization (but you could write a second routine specialized for strings, as shown).
Hmm. How it's different to direct GC's GC_alloc() call then ???
inline function GCAlloc (x : SizeType) = Res : Pointer; var save_ptr : GetMemType; begin save_ptr := GetMemPtr; GetMemPtr := @GC_alloc; GetMem (Res, x); GetMemPtr := save_ptr end;
function GCAllocString (const s : String) = Res : PString; var save_ptr : GetMemType; begin save_ptr := GetMemPtr; GetMemPtr := @GC_alloc; New (Res, Length (s)); Res^ := s; GetMemPtr := save_ptr end;
var i : ^Integer; s : PString;
begin i := GCAlloc (SizeOf (Integer)); s := GCAllocString ('foo'); Writeln (s^); end.
Of course, you could then hide then `SizeOf' in a macro with something like:
{$define gc_alloc(x) GCAlloc (SizeOf (x))}
And BTW how I can continue #define on next line (C's \ in the end of line does not work).
{$define ...} can span multiple lines without any `'.
Oops. Sorry. As I said I'm new to GPC ...
Peter Gerwinski wrote:
Khimenko Victor wrote:
Hmm. It'll require locks in multithreaded program and will be not very convenient. Perhaps we can hide it over clever #define ? Let's try: [...] You need to EXPLICITLY change new strategy every time :-(( Especially annoying since you want to use GC_malloc_atomic for plain strings... [...]
What about introducing a second `New' that allows the user to pass an additional parameter to the allocator?
Might be a solution. (Not that the syntax of `New' isn't already complicated enough... :-/)
Hmm. IMO something like p:=new[shm_alloc,pool1](string,100); should be recognizeable enough and should not disturb existing mess there much. Even if it's look more like LaTeX then C++ :-)
Khimenko Victor wrote:
What about introducing a second `New' that allows the user to pass an additional parameter to the allocator?
Might be a solution. (Not that the syntax of `New' isn't already complicated enough... :-/)
Hmm. IMO something like p:=new[shm_alloc,pool1](string,100); should be recognizeable enough and should not disturb existing mess there much. Even if it's look more like LaTeX then C++ :-)
I do not like this syntax too much. (For Pascal. It's okay for LaTeX.;-) In principle, it should not be too hard to implement
New (allocator_function, other_parameters)
but with the current implementation of `New' it would need some nontrivial work in the parser.
A clean solution would be a re-write of the parser to accept about any command-line for `New' and then do the analysis afterwards.
The only real problem with this approach would be the implicit `with' in `New' when a constructor of an object is called.
Peter
Hello again,
I wrote:
[...] In principle, it should not be too hard to implement
New (allocator_function, other_parameters)
but with the current implementation of `New' it would need some nontrivial work in the parser.
The following would be much easier to implement (including the implicit `with':-):
New (other_parameters : optional_allocator_function);
What we are still looking for is a syntax to allow for additional parameters (such as a memory pool) to the allocator function. Perhaps like this?
New (other_parameters : optional_allocator_function : parameter, parameter, parameter);
An alternative like this
New (other_parameters : optional_allocator_function (parameter, parameter, parameter));
would look nicer for me, but it would be very difficult to parse.
Suggestions welcome,
Peter
10-Mar-00 02:38 you wrote:
Hello again,
I wrote:
[...] In principle, it should not be too hard to implement
New (allocator_function, other_parameters)
but with the current implementation of `New' it would need some nontrivial work in the parser.
The following would be much easier to implement (including the implicit `with':-):
New (other_parameters : optional_allocator_function);
What we are still looking for is a syntax to allow for additional parameters (such as a memory pool) to the allocator function. Perhaps like this?
New (other_parameters : optional_allocator_function : parameter, parameter, parameter);
An alternative like this
New (other_parameters : optional_allocator_function (parameter, parameter, parameter));
would look nicer for me, but it would be very difficult to parse.
Hmm. I can not understood why it's so difficult to parse (there are already exist something like new(TMyObject, Init(1,2,3)); -- why it's easy to parse but in case of allocator it's not so?). Just wonder. I'm not sure which syntax is better. Think about mentioned shm_alloc: call will be pstr:=new(string,100:shm_alloc(pool1)); or pstr:=new(string,100:shm_alloc:pool1); but what's definition of shm_alloc ? It's function shm_alloc(size:size_t;var pool:PPool):pointer; TWO arguments, not one! We can invite allocator function (akin to constructor function) but IMHO it'll be overkill. So second version is not only easier to implement but less error-prone as well (this is NOT straight call of ahm_alloc, it's special construct so even shm_call has two paramenters it's Ok to have only one in special construct).
P.S. IMO any syntax will look ugly at first but after few months of active usage will look like most natural thing to do :-) This is how human's mind is done.
Khimenko Victor wrote:
[...] pstr:=new(string,100:shm_alloc(pool1)); or pstr:=new(string,100:shm_alloc:pool1); but what's definition of shm_alloc ? It's function shm_alloc(size:size_t;var pool:PPool):pointer; TWO arguments, not one! We can invite allocator function (akin to constructor function) but IMHO it'll be overkill. So second version is not only easier to implement but less error-prone as well (this is NOT straight call of ahm_alloc, it's special construct so even shm_call has two paramenters it's Ok to have only one in special construct).
So the second alternative seems to be the best suggestion up to now.
D'accord everybody?
P.S. IMO any syntax will look ugly at first but after few months of active usage will look like most natural thing to do :-) This is how human's mind is done.
;-)
Peter
9-Mar-00 23:52 you wrote:
Khimenko Victor wrote:
What about introducing a second `New' that allows the user to pass an additional parameter to the allocator?
Might be a solution. (Not that the syntax of `New' isn't already complicated enough... :-/)
Hmm. IMO something like p:=new[shm_alloc,pool1](string,100); should be recognizeable enough and should not disturb existing mess there much. Even if it's look more like LaTeX then C++ :-)
I do not like this syntax too much. (For Pascal. It's okay for LaTeX.;-) In principle, it should not be too hard to implement
New (allocator_function, other_parameters)
but with the current implementation of `New' it would need some nontrivial work in the parser.
Oh, no. Non-trivial work in parser is Ok. Non-trivial work in human reader's mind is NOT Ok. We have enough write-only languages like perl or C++ already...
A clean solution would be a re-write of the parser to accept about any command-line for `New' and then do the analysis afterwards.
The only real problem with this approach would be the implicit `with' in `New' when a constructor of an object is called.
Much more (to me at least) problem here is that to understood such code you must know what's this shm_alloc mean (is it type or pointer to function or wahtever?). Compiler will know this for sure, human reader not always...
Khimenko Victor wrote:
Oh, no. Non-trivial work in parser is Ok. Non-trivial work in human reader's mind is NOT Ok.
What I meant was non-trivial work for _me_ to implement it in the parser. (If someone wants to help, he/she is welcome of course.)
We have enough write-only languages like perl or C++ already...
;-)
Peter