/**************************************************************************** ** ** This file is part of GAP, a system for computational discrete algebra. ** ** Copyright of GAP belongs to its developers, whose names are too numerous ** to list here. Please refer to the COPYRIGHT file for details. ** ** SPDX-License-Identifier: GPL-2.0-or-later ** ** This file declares the functions of Gasman, the GAP storage manager. ** ** {\Gasman} is a storage manager for applications written in C. That means ** that an application requests blocks of storage from {\Gasman}, which are ** called bags. After using a bag to store data, the application simply ** forgets the bag, and we say that such a block is dead. {\Gasman} ** implements an automatic, cooperating, compacting, generational, ** conservative storage manager. Automatic means that the application only ** allocates bags, but need not explicitly deallocate them. This is ** important for large or complex application, where explicit deallocation ** is difficult. Cooperating means that the allocation must cooperate with ** {\Gasman}, i.e., must follow certain rules. This information provided by ** the application makes {\Gasman} use less storage and run faster. ** Compacting means that {\Gasman} always compacts live bags such that the ** free storage is one large block. Because there is no fragmentation of ** the free storage {\Gasman} uses as little storage as possible. ** Generational means that {\Gasman} usually assumes that bags that have ** been live for some time are still live. This means that it can avoid ** most of the tests whether a bag is still live or already dead. Only when ** not enough storage can be reclaimed under this assumption does it perform ** all the tests. Conservative means that {\Gasman} may keep bags longer ** than necessary because the C compiler does not provide sufficient ** information to distinguish true references to bags from other values that ** happen to look like references.
*/
#ifndef GAP_GASMAN_H #define GAP_GASMAN_H
#include"common.h"
/**************************************************************************** ** *T Bag . . . . . . . . . . . . . . . . . . . type of the identifier of a bag ** ** Each bag is identified by its *bag identifier*. That is each bag has a ** bag identifier and no two live bags have the same identifier. 'Bag' is ** the type of bag identifiers. ** ** 0 is a valid value of the type 'Bag', but is guaranteed not to be the ** identifier of any bag. ** ** 'NewBag' returns the identifier of the newly allocated bag and the ** application passes this identifier to every {\Gasman} function to tell it ** which bag it should operate on (see "NewBag", "TNUM_BAG", "SIZE_BAG", ** "PTR_BAG", "CHANGED_BAG", "RetypeBag", and "ResizeBag"). ** ** Note that the identifier of a bag is different from the address of the ** data area of the bag. This address may change during a garbage ** collection while the identifier of a bag never changes. ** ** Bags that contain references to other bags must always contain the ** identifiers of these other bags, never the addresses of the data areas of ** the bags. ** ** Note that bag identifiers are recycled. That means that after a bag dies ** its identifier may be reused for a new bag. ** ** The following is defined in "common.h" ** typedef UInt * * Bag;
*/
/**************************************************************************** ** *T BagHeader
*/ typedefstruct {
uint8_t type : 8;
uint8_t flags : 8; // the following unnamed field ensures that on 32 bit systems, // the 'size' field is aligned to a 32 bit boundary
uint16_t : (sizeof(UInt) == 8) ? 0 : 16;
uint64_t size : (sizeof(UInt) == 8) ? 48 : 32; #ifdef USE_GASMAN
Bag link; #endif #ifdefined(GAP_MEMORY_CANARY) // The following variable is marked as not readable or writable // in valgrind, to check for code reading before the start of a Bag.
uint64_t memory_canary_padding[8]; #endif
} BagHeader;
/**************************************************************************** ** ** 'NUM_TYPES' is the maximal number of different types supported, and ** depends on the number of bits in the type member of struct BagHeader. ** It must be a power of two.
*/ enum {
NUM_TYPES = 256,
};
/**************************************************************************** ** *F BAG_HEADER(<bag>) . . . . . . . . . . . . . . . . . . . . header of a bag *F CONST_BAG_HEADER(<bag>) . . . . . . . . . . . . read-only header of a bag ** ** 'BAG_HEADER' returns the header of the bag with the identifier <bag>.
*/
EXPORT_INLINE BagHeader * BAG_HEADER(Bag bag)
{
GAP_ASSERT(bag); return ((*(BagHeader **)bag) - 1);
}
/**************************************************************************** ** *F TNUM_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . . . type of a bag ** ** 'TNUM_BAG' returns the type of the bag with the identifier <bag>. ** ** Each bag has a certain type that identifies its structure. The type is a ** integer between 0 and 253. The types 254 and 255 are reserved for ** {\Gasman}. The application specifies the type of a bag when it allocates ** it with 'NewBag' and may later change it with 'RetypeBag' (see "NewBag" ** and "RetypeBag"). ** ** {\Gasman} needs to know the type of a bag so that it knows which function ** to call to mark all subbags of a given bag (see "InitMarkFuncBags"). ** Apart from that {\Gasman} does not care at all about types.
*/
EXPORT_INLINE UInt TNUM_BAG(Bag bag)
{ return CONST_BAG_HEADER(bag)->type;
}
/**************************************************************************** ** *F TEST_BAG_FLAG(<bag>, <flag>) . . . . . . . . . . . . . . . test bag flag *F SET_BAG_FLAG(<bag>, <flag>) . . . . . . . . . . . . . . . . set bag flag *F CLEAR_BAG_FLAG(<bag>, <flag>) . . . . . . . . . . . . . . clear bag flag ** ** These three macros test, set, and clear bag flags, respectively. ** Bag flags are stored in the bag header. Multiple flags can be ored ** together using '|' to set or clear multiple flags at once. ** ** TEST_BAG_FLAG() will return the ored version of all tested flags. To ** test that one of them is set, check if the result is not equal to zero. ** To test that all of them are set, compare the result to the original ** flags, e.g. ** ** if (TEST_BAG_FLAG(obj, FLAG1 | FLAG2 ) == (FLAG1 | FLAG2)) ... ** ** Similarly, if you wish to test that FLAG1 is set and FLAG2 is not set, ** use: ** ** if (TEST_BAG_FLAG(obj, FLAG1 | FLAG2 ) == FLAG1) ... ** ** Each flag must be an integer with exactly one bit set, e.g. a value ** of the form (1 << i). Currently, 'i' must be in the range from 0 to ** 7 (inclusive).
*/
EXPORT_INLINE uint8_t TEST_BAG_FLAG(Bag bag, uint8_t flag)
{ return CONST_BAG_HEADER(bag)->flags & flag;
}
/**************************************************************************** ** *F IS_BAG_REF(<bag>) . . . . . . verify that <bag> is a valid bag identifier ** ** 'IS_BAG_REF' checks whether <bag> is a valid bag identifier, i.e. that ** it is neither zero, nor an immediate object. ** ** See also 'IS_INTOBJ' and 'IS_FFE'.
*/
EXPORT_INLINE BOOL IS_BAG_REF(Obj bag)
{ return bag && !((Int)bag & 0x03);
}
/**************************************************************************** ** *F SIZE_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . . . size of a bag ** ** 'SIZE_BAG' returns the size of the bag with the identifier <bag> in ** bytes. ** ** Each bag has a certain size. The size of a bag is measured in bytes. ** The size must be a value between 0 and $2^{32}-1$ (on 32 bit systems) ** respectively $2^{48}-1$ (on 64 bit systems). The application specifies ** the size of a bag when it allocates it with 'NewBag' and may later change ** it with 'ResizeBag' (see "NewBag" and "ResizeBag").
*/
EXPORT_INLINE UInt SIZE_BAG(Bag bag)
{ return CONST_BAG_HEADER(bag)->size;
}
/**************************************************************************** ** *F SIZE_BAG_CONTENTS(<ptr>) . . . . . . . . . . . . . . . . . size of a bag ** ** 'SIZE_BAG_CONTENTS' performs the same function as 'SIZE_BAG', but takes ** a pointer to the contents of the bag instead. This is useful for certain ** atomic operations that require a memory barrier in between dereferencing ** the bag pointer and accessing the contents of the bag.
*/
EXPORT_INLINE UInt SIZE_BAG_CONTENTS(constvoid *ptr)
{ return ((const BagHeader *)ptr)[-1].size;
}
/**************************************************************************** ** *F LINK_BAG(<bag>) . . . . . . . . . . . . . . . . . . link pointer of a bag ** ** 'LINK_BAG' returns the link pointer of the bag with the identifier <bag>. ** ** Note that 'LINK_BAG' is a macro, so do not call it with arguments that ** have side effects.
*/ #ifdef USE_GASMAN #define LINK_BAG(bag) (BAG_HEADER(bag)->link) #endif
/**************************************************************************** ** *F PTR_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . . pointer to a bag *F CONST_PTR_BAG(<bag>) . . . . . . . . . . . . . read-only pointer to a bag *F SET_PTR_BAG(<bag>) . . . . . . . . . . . . . . . set the pointer to a bag ** ** 'PTR_BAG' returns the address of the data area of the bag with identifier ** <bag>. Using this pointer the application can then read data from the ** bag or write data into it. The pointer is of type pointer to bag ** identifier, i.e., 'PTR_BAG(<bag>)[0]' is the identifier of the first ** subbag of the bag, etc. If the bag contains data in a different format, ** the application has to cast the pointer returned by 'PTR_BAG', e.g., ** '(long\*)PTR_BAG(<bag>)'. ** ** Note that the address of the data area of a bag may change during a ** garbage collection. That is the value returned by 'PTR_BAG' may differ ** between two calls, if 'NewBag', 'ResizeBag', 'CollectBags', or any of the ** application\'s functions or macros that may call those functions, is ** called in between (see "NewBag", "ResizeBag", "CollectBags"). ** ** The first rule for using {\Gasman} is{\:} *The application must not keep ** any pointers to or into the data area of any bag over calls to functions ** that may cause a garbage collection.* ** ** That means that the following code is incorrect{\:} ** ** ptr = PTR_BAG( old ); ** new = NewBag( typeNew, sizeNew ); ** *ptr = new; ** ** because the creation of the new bag may move the old bag, causing the ** pointer to point no longer to the data area of the bag. It must be ** written as follows{\:} ** ** new = NewBag( typeNew, sizeNew ); ** ptr = PTR_BAG( old ); ** *ptr = new; ** ** Note that even the following is incorrect{\:} ** ** PTR_BAG(old)[0] = NewBag( typeNew, sizeNew ); ** ** because a C compiler is free to compile it to a sequence of instructions ** equivalent to first example. Thus whenever the evaluation of a function ** or a macro may cause a garbage collection there must be no call to ** 'PTR_BAG' in the same expression, except as argument to this function or ** macro. ** ** Note that after writing a bag identifier, e.g., 'new' in the above ** example, into the data area of another bag, 'old' in the above example, ** the application must inform {\Gasman} that it has changed the bag, by ** calling 'CHANGED_BAG(old)' in the above example (see "CHANGED_BAG").
*/
EXPORT_INLINE Bag *PTR_BAG(Bag bag)
{
GAP_ASSERT(bag != 0); return *(Bag**)bag;
}
EXPORT_INLINE const Bag *CONST_PTR_BAG(Bag bag)
{
GAP_ASSERT(bag != 0); return *(const Bag * const *)bag;
}
#ifdefined(USE_BOEHM_GC) void SET_PTR_BAG(Bag bag, Bag *val); #endif
/**************************************************************************** ** *F CHANGED_BAG(<bag>) . . . . . . . . notify Gasman that a bag has changed ** ** 'CHANGED_BAG' informs {\Gasman} that the bag with identifier <bag> has ** been changed by an assignment of another bag identifier. ** ** The second rule for using {\Gasman} is{\:} *After each assignment of a ** bag identifier into a bag the application must inform {\Gasman} that it ** has changed the bag before the next garbage collection can happen.* ** ** Note that the application need not inform {\Gasman} if it changes a bag ** by assigning something that is not an identifier of another bag. ** ** For example to copy all entries from one list into another the following ** code must be used{\:} ** ** for ( i = 0; i < SIZE-BAG(old)/sizeof(Bag); i++ ) ** PTR_BAG(new)[i] = PTR_BAG(old)[i]; ** CHANGED_BAG( new ); ** ** On the other hand when the application allocates a matrix, where the ** allocation of each row may cause a garbage collection, the following code ** must be used{\:} ** ** mat = NewBag( T_MAT, n * sizeof(Bag) ); ** for ( i = 0; i < n; i++ ) { ** row = NewBag( T_ROW, n * sizeof(Bag) ); ** PTR_BAG(mat)[i] = row; ** CHANGED_BAG( mat ); ** } ** ** Note that writing 'PTR_BAG(mat)[i] = NewBag( T_ROW, n\*\ sizeof(Bag) );' ** is incorrect as mentioned in the section for 'PTR_BAG' (see "PTR_BAG").
*/
#ifdefined(USE_BOEHM_GC)
EXPORT_INLINE void CHANGED_BAG(Bag bag)
{
}
#elifdefined(USE_JULIA_GC)
void CHANGED_BAG(Bag bag);
BOOL IsGapObj(void *);
#elifdefined(GAP_MEMORY_CANARY)
/**************************************************************************** ** ** GAP_MEMORY_CANARY provides (basic) support for catching out-of-bounds ** memory problems in GAP. This is done through the excellent 'valgrind' ** program. Valgrind is of limited use in GAP normally, because it doesn't ** understand GAP's memory manager. Enabling GAP_MEMORY_CANARY will make an ** executable where valgrind will detect memory issues. **
*/
/**************************************************************************** ** *F NewBag(<type>,<size>) . . . . . . . . . . . . . . . . allocate a new bag ** ** 'NewBag' allocates a new bag of type <type> and <size> bytes. 'NewBag' ** returns the identifier of the new bag, which must be passed as first ** argument to all other {\Gasman} functions. ** ** <type> must be a value between 0 and 253. The types 254 and 255 are ** reserved for {\Gasman}. The application can find the type of a bag with ** 'TNUM_BAG' and change it with 'RetypeBag' (see "TNUM_BAG" and ** "RetypeBag"). ** ** It is probably a good idea to define symbolic constants for all types in ** a system wide header file, e.g., 'types.h', if only to avoid to ** accidentally use the same value for two different types. ** ** <size> is the size of the new bag in bytes and must be a value between 0 ** and $2^{32}-1$ (on 32 bit systems) resp. $2^{48}-1$ (on 64 bit systems). ** The application can find the size of a bag with 'SIZE_BAG' and change it ** with 'ResizeBag' (see "SIZE_BAG" and "ResizeBag"). ** ** All entries of the new bag will be initialized to 0. ** ** What happens if {\Gasman} cannot get enough storage to perform an ** allocation depends on the behavior of the allocation function ** <alloc-func>. If <alloc-func> returns 0 when it cannot do a needed ** extension of the workspace, then 'NewBag' may return 0 to indicate ** failure, and the application has to check the return value of 'NewBag' ** for this. If <alloc-func> aborts when it cannot do a needed extension of ** the workspace, then the application will abort if 'NewBag' would not ** succeed. So in this case whenever 'NewBag' returns, it succeeded, and ** the application need not check the return value of 'NewBag' (see ** "InitBags"). ** ** Note that 'NewBag' will perform a garbage collection if no free storage ** is available. During the garbage collection the addresses of the data ** areas of all bags may change. So you must not keep any pointers to or ** into the data areas of bags over calls to 'NewBag' (see "PTR_BAG").
*/
Bag NewBag(UInt type, UInt size);
// NewWordSizedBag is the same as NewBag, except it rounds 'size' up to // the next multiple of sizeof(UInt)
EXPORT_INLINE Bag NewWordSizedBag(UInt type, UInt size)
{
UInt padding = 0; if(size % sizeof(UInt) != 0) {
padding = sizeof(UInt) - (size % sizeof(UInt));
} return NewBag(type, size + padding);
}
/**************************************************************************** ** *F RetypeBag(<bag>,<new>) . . . . . . . . . . . . . change the type of a bag *F RetypeBagIntern(<bag>,<new>) . . . . . . . . . . . . . internal interface ** ** 'RetypeBag' changes the type of the bag with identifier <bag> to the new ** type <new>. The identifier, the size, and also the address of the data ** area of the bag do not change. ** ** 'Retype' is usually used to set or reset flags that are stored in the ** type of a bag. For example in {\GAP} there are two types of large ** integers, one for positive integers and one for negative integers. To ** compute the difference of a positive integer and a negative, {\GAP} uses ** 'RetypeBag' to temporarily change the second argument into a positive ** integer, and then adds the two operands. For another example when {\GAP} ** detects that a list is sorted and contains no duplicates, it changes the ** type of the bag with 'RetypeBag', and the new type indicates that this ** list has this property, so that this need not be tested again. ** ** It is, as usual, the responsibility of the application to ensure that the ** data stored in the bag makes sense when the bag is interpreted as a bag ** of type <type>. ** ** 'RetypeBagIntern' is the internal version of 'RetypeBag', implemented by ** the GC backend. It is called by 'RetypeBag'.
*/ void RetypeBagIntern(Bag bag, UInt new_type);
#ifdef GAP_KERNEL_DEBUG // This helper tests whether the type change is "allowed". As such, it rejects // attempts to retype an immutable list or record into a mutable one. void PrecheckRetypeBag(Bag bag, UInt new_type); #endif
/**************************************************************************** ** ** 'RetypeBagSM' works like 'RetypeBag', but ensures that the given bag ** retains the same mutability (SM). ** ** FIXME: for now, this checks the tnums; later, this will be turned ** into a check for an object flag
*/ void RetypeBagSM(Bag bag, UInt new_type); #ifdef HPCGAP void RetypeBagSMIfWritable(Bag bag, UInt new_type); #else #define RetypeBagSMIfWritable(x,y) RetypeBagSM(x,y) #endif
/**************************************************************************** ** *F ResizeBag(<bag>,<new>) . . . . . . . . . . . . change the size of a bag ** ** 'ResizeBag' changes the size of the bag with identifier <bag> to the new ** size <new>. The identifier of the bag does not change, but the address ** of the data area of the bag may change. If the new size <new> is less ** than the old size, {\Gasman} throws away any data in the bag beyond the ** new size. If the new size <new> is larger than the old size, {\Gasman} ** extends the bag. ** ** All entries of an extension will be initialized to 0. ** ** What happens if {\Gasman} cannot get enough storage to perform an ** extension depends on the behavior of the allocation function ** <alloc-func>. If <alloc-func> returns 0 when it cannot do a needed ** extension of the workspace, then 'ResizeBag' may return 0 to indicate ** failure, and the application has to check the return value of 'ResizeBag' ** for this. If <alloc-func> aborts when it cannot do a needed extension of ** the workspace, then the application will abort if 'ResizeBag' would not ** succeed. So in this case whenever 'ResizeBag' returns, it succeeded, and ** the application need not check the return value of 'ResizeBag' (see ** "InitBags"). ** ** Note that 'ResizeBag' will perform a garbage collection if no free ** storage is available. During the garbage collection the addresses of the ** data areas of all bags may change. So you must not keep any pointers to ** or into the data areas of bags over calls to 'ResizeBag' (see "PTR_BAG").
*/
UInt ResizeBag(Bag bag, UInt new_size);
// ResizedWordSizedBag is the same as ResizeBag, except it round 'size' // up to the next multiple of sizeof(UInt)
EXPORT_INLINE UInt ResizeWordSizedBag(Bag bag, UInt size)
{
UInt padding = 0; if(size % sizeof(UInt) != 0) {
padding = sizeof(UInt) - (size % sizeof(UInt));
} return ResizeBag(bag, size + padding);
}
/**************************************************************************** ** *F CollectBags(<size>,<full>) . . . . . . . . . . . . . . collect dead bags ** ** 'CollectBags' performs a garbage collection. This means it deallocates ** the dead bags and compacts the live bags at the beginning of the ** workspace. If <full> is 0, then only the dead young bags are ** deallocated, otherwise all dead bags are deallocated. ** ** If the application calls 'CollectBags', <size> must be 0, and <full> must ** be 0 or 1 depending on whether it wants to perform a partial or a full ** garbage collection. ** ** If 'CollectBags' is called from 'NewBag' or 'ResizeBag', <size> is the ** size of the bag that is currently allocated, and <full> is zero. ** ** Note that during the garbage collection the addresses of the data areas ** of all bags may change. So you must not keep any pointers to or into the ** data areas of bags over calls to 'CollectBags' (see "PTR_BAG").
*/
UInt CollectBags(UInt size, UInt full);
/**************************************************************************** ** *F SwapMasterPoint( <bag1>, <bag2> ) . . . swap pointer of <bag1> and <bag2>
*/ void SwapMasterPoint(Bag bag1, Bag bag2);
/**************************************************************************** ** *V SizeAllBags . . . . . . . . . . . . . . total size of all bags allocated ** ** 'SizeAllBags' is the total size of bags allocated since Gasman was ** initialized. It is incremented for each 'NewBag' call.
*/ extern UInt8 SizeAllBags;
/**************************************************************************** ** *V InfoBags[<type>] . . . . . . . . . . . . . . . . . information for bags ** ** 'InfoBags[<type>]' is a structure containing information for bags of the ** type <type>. ** ** 'InfoBags[<type>].nrLive' is the number of bags of type <type> that are ** currently live. ** ** 'InfoBags[<type>].nrAll' is the total number of all bags of <type> that ** have been allocated. ** ** 'InfoBags[<type>].sizeLive' is the sum of the sizes of the bags of type ** <type> that are currently live. ** ** 'InfoBags[<type>].sizeAll' is the sum of the sizes of all bags of type ** <type> that have been allocated. ** ** This information is only kept if {\Gasman} is compiled with the option ** 'COUNT_BAGS' defined.
*/ #ifdef COUNT_BAGS typedefstruct {
UInt nrLive;
UInt nrAll;
UInt sizeLive;
UInt sizeAll;
} TNumInfoBags;
extern TNumInfoBags InfoBags [ 256 ]; #endif
#ifdef HPCGAP void MakeBagTypePublic(int type);
Bag MakeBagPublic(Bag bag);
Bag MakeBagReadOnly(Bag bag); #endif
/**************************************************************************** ** *F InitMarkFuncBags(<type>,<mark-func>) . . . . . install marking function ** ** 'InitMarkFuncBags' installs the function <mark-func> as marking function ** for bags of type <type>. The application *must* install a marking ** function for a type before it allocates any bag of that type. It is ** probably best to install all marking functions before allocating any bag. ** ** A marking function is a function that takes a two arguments, one of type ** 'Bag' and one of type 'void *' and returns nothing, i.e., has return type ** 'void'. Such a function must apply the function 'MarkBag' to each bag ** identifier that appears in the bag (see below), passing on its 'void *' ** argument unchanged to 'MarkBag' as second argument. ** ** Those functions are applied during the garbage collection to each marked ** bag, i.e., bags that are assumed to be still live, to also mark their ** subbags. The ability to use the correct marking function is the only use ** that {\Gasman} has for types. ** ** {\Gasman} already provides several marking functions, see below.
*/ #define GAP_MARK_FUNC_WITH_REF 1 typedefvoid (* TNumMarkFuncBags )( Bag bag, void * ref ); void InitMarkFuncBags(UInt type, TNumMarkFuncBags mark_func);
/**************************************************************************** ** *F MarkNoSubBags(<bag>) . . . . . . . . marking function that marks nothing ** ** 'MarkNoSubBags' is a marking function for types whose bags contain no ** identifier of other bags. It does nothing, as its name implies, and ** simply returns. For example in {\GAP} the bags for large integers ** contain only the digits and no identifiers of bags.
*/ void MarkNoSubBags(Bag bag, void * ref);
/**************************************************************************** ** *F MarkOneSubBags(<bag>) . . . . . . marking function that marks one subbag *F MarkTwoSubBags(<bag>) . . . . . . marking function that marks two subbags *F MarkThreeSubBags(<bag>) . . . . marking function that marks three subbags *F MarkFourSubBags(<bag>) . . . . . marking function that marks four subbags ** ** These are marking functions for types whose bags contain exactly the ** the indicated number as bag identifiers as their initial entries. ** These functions mark those subbags and return.
*/ void MarkOneSubBags(Bag bag, void * ref); void MarkTwoSubBags(Bag bag, void * ref); void MarkThreeSubBags(Bag bag, void * ref); void MarkFourSubBags(Bag bag, void * ref);
/**************************************************************************** ** *F MarkAllSubBags(<bag>) . . . . . . marking function that marks everything ** ** 'MarkAllSubBags' is the marking function for types whose bags contain ** only identifier of other bags. It marks every entry of such a bag. Note ** that 'MarkAllSubBags' assumes that all identifiers are at offsets from ** the address of the data area of <bag> that are divisible by ** 'sizeof(Bag)'. Note also that since it does not do any harm to mark ** something which is not actually a bag identifier one could use ** 'MarkAllSubBags' for all types as long as the identifiers in the data ** area are properly aligned as explained above. This would however slow ** down 'CollectBags'. For example in {\GAP} bags for lists contain only ** bag identifiers for the elements of the list or 0 if an entry has no ** assigned value.
*/ void MarkAllSubBags(Bag bag, void * ref);
/**************************************************************************** ** *F MarkAllButFirstSubBags(<bag>) . . . . marks all subbags except the first
*/ void MarkAllButFirstSubBags(Bag bag, void * ref);
/**************************************************************************** ** *F MarkBag(<bag>) . . . . . . . . . . . . . . . . . . . mark a bag as live ** ** 'MarkBag' marks the <bag> as live so that it is not thrown away during ** a garbage collection. 'MarkBag' should only be called from the marking ** functions installed with 'InitMarkFuncBags'. ** ** 'MarkBag' tests if <bag> is a valid identifier of a bag in the young ** bags area. If it is not, then 'MarkBag' does nothing, so there is no ** harm in calling 'MarkBag' for something that is not actually a bag ** identifier.
*/ #ifdef USE_BOEHM_GC
EXPORT_INLINE void MarkBag( Bag bag, void * ref )
{
} #else void MarkBag(Bag bag, void * ref); #endif
/**************************************************************************** ** *F MarkArrayOfBags(<array>,<count>) . . . . . . . mark all bags in an array ** ** 'MarkArrayOfBags' iterates over <count> all bags in the given array, ** and marks each bag using MarkBag.
*/ externvoid MarkArrayOfBags(const Bag array[], UInt count, void * ref);
/**************************************************************************** ** *F InitGlobalBag(<addr>,<cookie>) inform Gasman about global bag identifier ** ** 'InitGlobalBag' informs {\Gasman} that there is a bag identifier at the ** address <addr>, which must be of type '(Bag\*)'. {\Gasman} will look at ** this address for a bag identifier during a garbage collection. ** ** The application *must* call 'InitGlobalBag' for every global variable and ** every entry of a global array that may hold a bag identifier. It is no ** problem if such a variable does not actually hold a bag identifier, ** {\Gasman} will simply ignore it then. ** ** There is a limit on the number of calls to 'InitGlobalBag', which is 20000 ** by default. If the application has more global variables that may hold ** bag identifier, you have to compile {\Gasman} with a higher value of ** 'NR_GLOBAL_BAGS'. ** ** <cookie> is a C string, which should uniquely identify this global ** bag from all others. It is used in reconstructing the Workspace ** after a save and load
*/
/**************************************************************************** ** *F InitFreeFuncBag(<type>,<free-func>) . . . . . . install freeing function ** ** 'InitFreeFuncBag' installs the function <free-func> as freeing function ** for bags of type <type>. ** ** A freeing function is a function that takes a single argument of type ** 'Bag' and returns nothing, i.e., has return type 'void'. If such a ** function is installed for a type <type> then it is called for each bag of ** that type that is about to be deallocated. ** ** A freeing function must *not* call 'NewBag', 'ResizeBag', or 'RetypeBag'. ** ** When such a function is called for a bag <bag>, its subbags are still ** accessible. Note that it is not specified whether the freeing functions ** for the subbags of <bag> (if there are freeing functions for bags of ** their types) are called before or after the freeing function for <bag>.
*/ typedefvoid (* TNumFreeFuncBags ) (
Bag bag );
/**************************************************************************** ** *F RegisterBeforeCollectFuncBags(<func>) install before-collection function *F RegisterAfterCollectFuncBags(<func>) . install after-collection function ** ** Register a callback to be called before respectively after each garbage ** collection. ** ** One use of a <before-func> is to call 'CHANGED_BAG' for bags that change ** very often, so you do not have to call 'CHANGED_BAG' for them every time ** they change. ** ** One use of after-collection callbacks is to update a pointer for a bag, ** so you do not have to update that pointer after every operation that ** might cause a garbage collection. ** ** The number of callbacks which can be registered is limited. If the ** callback was successfully registered, 0 is returned, otherwise 1.
*/ #ifdef USE_GASMAN typedefvoid (* TNumCollectFuncBags) ( void );
int RegisterBeforeCollectFuncBags(TNumCollectFuncBags func); int RegisterAfterCollectFuncBags(TNumCollectFuncBags func); #endif
// ExtraMarkFuncBags, if not NULL, is called during garbage collection // This is used for integrating GAP (possibly linked as a shared library) with // other code bases which use their own form of garbage collection. For // example, with Python (for SageMath). typedefvoid (*TNumExtraMarkFuncBags)(void); void SetExtraMarkFuncBags(TNumExtraMarkFuncBags func);
/**************************************************************************** ** *F InitBags(<initialSize>, <stackStart>) . . . . . . . . . initialize Gasman ** ** 'InitBags' initializes {\Gasman}. It must be called from an application ** using {\Gasman} before any bags can be allocated. ** ** <initialSize> must be the size of the initial workspace that 'InitBags' ** should allocate. This value is automatically rounded up to the next ** multiple of 1/2 MByte by 'InitBags'. ** ** <stackStart> must be the start of the stack. Note that the start of the ** stack is either the bottom or the top of the stack, depending on whether ** the stack grows upward or downward. A value that usually works is the ** address of the argument 'argc' of the 'main' function of the application, ** i.e., '(Bag\*)\&argc'.
*/ void InitBags(UInt initialSize, Bag * stackStart);
/**************************************************************************** ** *F FinishBags() end GASMAN and free memory
*/ void FinishBags(void);
/**************************************************************************** ** *F TotalGCTime() . . . . . . . . . . total time spent on garbage collection
*/
UInt TotalGCTime(void);
#endif// GAP_GASMAN_H
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.42Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.