Hi,

Przemyslaw Czerpak wrote:
>> - hb_gc[Un]Lock() is used only by hbregexc.c module. Why this module is so
different?

because I made it safe for asynchronous GC activation.
In other modules I used to avoid any memory allocation between hb_gcAlloc()
and attaching the block to well known item. I've seen that you haven't
respected it in some new code but I decided to not talk about it and
generate some noice for other users planing to change GC API.

Ok, I guess you mean:
  pSink = ( ISink* ) hb_gcAlloc( sizeof( ISink ), hb_sink_destructor );
  pSink->lpVtbl = ( IDispatchVtbl * ) &ISink_Vtbl;
  pSink->pItemHandler = hb_itemNew( pItemBlock );
  hb_retptrGC( pSink );
should be changed to:
  pItemHandler = hb_itemNew( pItemBlock );
  pSink = ( ISink* ) hb_gcAlloc( sizeof( ISink ), hb_sink_destructor );
  pSink->lpVtbl = ( IDispatchVtbl * ) &ISink_Vtbl;
  pSink->pItemHandler = pItemHandler;
  hb_retptrGC( pSink );


PHB_ITEM hb_oleItemPut( PHB_ITEM pItem, IDispatch* pDisp )
{
   IDispatch** ppDisp;
ppDisp = ( IDispatch** ) hb_gcAlloc( sizeof( IDispatch* ), hb_ole_destructor );
   *ppDisp = pDisp;
   return hb_itemPutPtrGC( pItem, ppDisp );
}
changed to:
PHB_ITEM hb_oleItemPut( PHB_ITEM pItem, IDispatch* pDisp )
{
   IDispatch** ppDisp;
   pItem = hb_itemNew( pItem );
ppDisp = ( IDispatch** ) hb_gcAlloc( sizeof( IDispatch* ), hb_ole_destructor );
   *ppDisp = pDisp;
   return hb_itemPutPtrGC( pItem, ppDisp );
}

and

ppDisp = ( IDispatch** ) hb_gcAlloc( sizeof( IDispatch* ), hb_ole_destructor );
   *ppDisp = pVariant->n1.n2.n3.pdispVal;
   pPtrGC = hb_itemPutPtrGC( NULL, ppDisp );
to:
   pPtrGC = hb_itemNew( NULL );
ppDisp = ( IDispatch** ) hb_gcAlloc( sizeof( IDispatch* ), hb_ole_destructor );
   *ppDisp = pVariant->n1.n2.n3.pdispVal;
   hb_itemPutPtrGC( pPtrGC, ppDisp );


typedef struct {
   int               size;
   PHB_GC_FUNC_FREE  free;
   PHB_GC_FUNC_MARK  mark;
} HB_GC_VTBL;
.size should be initialized to sizeof( HB_GC_VTBL ). This will allow to track incompatible gcAlloc() calls in current code (without GPF, because size is first 4 bytes of function), and in the future (.size is a kind of "version number", if we add new methods to GC).

Yes, but I do not think it's such important in open source projects.
I rather do not believe that we will accept runtime overhead to keep
binary compatibility. Probably we force code recompilation, f.e. by
changing function name. We can define hb_gcAlloc as macro to some
real function like hb_gcAlloc_2 (2 functions in HB_GC_VTBL) and then
simply change it.


Yes, I agree. The proposed solution came to my mind, because this solution is often used in Windows API, but there are more ways to force recompile in open source project. Though usage of old DLL sometimes can be a problem.


I guess I understand that you mean. It will add additional grip list insert/delete operations on hb_itemCopy(). I guess it will slow down HVM.

Not exactly. Such list can be used only as extension to current code.
Each GC block will have pointer to cyclic GC block list and each GC
block can be relinked from s_pCurrBlock or s_pLockedBlock to other
GC block and then it will be marked automatically when parent GC block
is marked. In such version GC knows about all references between different
blocks and they are not hidden by user mark function. It's possible that
such knowledge will be usable in the future.

I get the details, but I still not see the whole picture. Should grip block be reassigned to another list after new value is associated to it? OK, forget these questions, I thing it will more easy for you to implement it, and for me to analyse the code, than describe it in words.


I still thinking about why grips are locked. The PROPER unlocking may solve the problem. But we need to include grips into the marking process. Only locked or marked grips should mark their content. hb_gcItemRef() can be split into hb_grip_mark, hb_array_mark, hb_hash_mark, etc. grip becoms one of the common GC blocks.

Of course the unlocked container is necessary for us and we will have
to add function which allocates such container or as I wrote in previous
message document hb_gcUnlock() behavior for grip blocks - it will convert
locked container into unlocked one or in other words remove weak reference.
It's necessary in both versions but it's not enough. We still need
additional mechanism to scan and mark unlocked block which are logically
bound. It can be done by user mark/sweep function (the 1-st version) or
known for GC references chains (the 2-nd version).
Probably the second version gives cleaner final API. F.e. in your example
it will be enough to introduce only one function used to attach to other
container and it will internally automatically remove weak reference (unlock)
the container allocated by hb_itemNew()

It's difficult for me to compare 1-st and 2-nd version, since I do not understand the 2-nd, but I GUESS the 2-nd does not allow to keep GC blocks without grip container. For example, if I want to create a new C object/pointer to store a sorted array, I would not be able to do it in a way similar to current array implementation and store items in HB_ITEM array. I will need to store items in PHB_ITEM array and contain grip for each item. It is a rear case, and it could be optimized to store array item instead of array of HB_ITEM.

I thing we must select the best solution to not slow down HVM, to make implementation cleaner. Backward compatibility is not an issue here.


Regards,
Mindaugas

_______________________________________________
Harbour mailing list
[email protected]
http://lists.harbour-project.org/mailman/listinfo/harbour

Reply via email to