
| Current Path : /usr/include/gap/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : //usr/include/gap/gasman.h |
/****************************************************************************
**
*W gasman.h GAP source Martin Schönert
**
**
*Y Copyright (C) 1996, Lehrstuhl D für Mathematik, RWTH Aachen, Germany
*Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland
*Y Copyright (C) 2002 The GAP Group
**
** 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 "system.h"
/****************************************************************************
**
*T Bag . . . . . . . . . . . . . . . . . . . type of the identifier of a bag
**
** '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 "system.h"
**
typedef UInt * * Bag;
*/
/****************************************************************************
**
**
*/
typedef struct {
uint8_t type : 8;
uint8_t flags : 8;
#if SIZEOF_VOID_P == 8
uint64_t size : 48;
#elif SIZEOF_VOID_P == 4
uint16_t reserved : 16;
uint32_t size : 32;
#endif
#ifdef USE_GASMAN
Bag link;
#endif
#if defined(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
**
** 'BAG_HEADER' returns the header of the bag with the identifier <bag>.
*/
static 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.
*/
static inline UInt TNUM_BAG(Bag bag) {
return 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)) ...
**
** Similary, 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 a 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).
*/
static inline uint8_t TEST_BAG_FLAG(Bag bag, uint8_t flag)
{
return BAG_HEADER(bag)->flags & flag;
}
static inline void SET_BAG_FLAG(Bag bag, uint8_t flag)
{
BAG_HEADER(bag)->flags |= flag;
}
static inline void CLEAR_BAG_FLAG(Bag bag, uint8_t flag)
{
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'.
*/
static inline Int IS_BAG_REF(Obj bag)
{
return bag && !((Int)bag & 0x03);
}
/****************************************************************************
**
*F SIZE_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . . . size of a bag
**
** 'SIZE_BAG( <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").
*/
static inline UInt SIZE_BAG(Bag bag) {
return 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.
*/
static inline UInt SIZE_BAG_CONTENTS(const void *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
**
** 'PTR_BAG( <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").
*/
static inline Bag *PTR_BAG(Bag bag)
{
GAP_ASSERT(bag != 0);
return *(Bag**)bag;
}
static inline const Bag *CONST_PTR_BAG(Bag bag)
{
GAP_ASSERT(bag != 0);
return *(const Bag**)bag;
}
static inline void SET_PTR_BAG(Bag bag, Bag *val)
{
GAP_ASSERT(bag != 0);
*(Bag**)bag = val;
}
/****************************************************************************
**
*F CHANGED_BAG(<bag>) . . . . . . . . notify Gasman that a bag has changed
**
** 'CHANGED_BAG( <bag> )'
**
** '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").
*/
#if defined(USE_BOEHM_GC)
static inline void CHANGED_BAG(Bag bag)
{
}
#elif defined(USE_JULIA_GC)
void CHANGED_BAG(Bag bag);
int IsGapObj(void *);
#elif defined(MEMORY_CANARY)
/****************************************************************************
**
** 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 MEMORY_CANARY will make an executable where
** valgrind will detect memory issues.
**
** At the moment the detection is limited to only writing off the last allocated
** block.
*/
extern void CHANGED_BAG(Bag b);
#elif defined(USE_GASMAN)
extern Bag * YoungBags;
extern Bag ChangedBags;
static inline void CHANGED_BAG(Bag bag)
{
if (CONST_PTR_BAG(bag) <= YoungBags && LINK_BAG(bag) == bag) {
LINK_BAG(bag) = ChangedBags;
ChangedBags = bag;
}
}
#else
#error unknown garbage collector
#endif
/****************************************************************************
**
*F NewBag(<type>,<size>) . . . . . . . . . . . . . . . . allocate a new bag
**
** 'NewBag( <type>, <size> )'
**
** '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
** accidently 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").
*/
extern Bag NewBag (
UInt type,
UInt size );
// NewWordSizedBag is the same as NewBag, except it rounds 'size' up to
// the next multiple of sizeof(UInt)
static 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
**
** 'RetypeBag( <bag>, <new> )'
**
** '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>.
*/
extern void RetypeBag (
Bag bag,
UInt new_type );
#ifdef HPCGAP
extern void RetypeBagIfWritable (
Bag bag,
UInt new_type );
#else
#define RetypeBagIfWritable(x,y) RetypeBag(x,y)
#endif
/****************************************************************************
**
*F ResizeBag(<bag>,<new>) . . . . . . . . . . . . change the size of a bag
**
** 'ResizeBag( <bag>, <new> )'
**
** '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").
*/
extern 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)
static 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( <size>, <full> )'
**
** '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").
*/
extern UInt CollectBags (
UInt size,
UInt full );
/****************************************************************************
**
*F SwapMasterPoint( <bag1>, <bag2> ) . . . swap pointer of <bag1> and <bag2>
*/
extern void SwapMasterPoint (
Bag bag1,
Bag bag2 );
/****************************************************************************
**
*V NrAllBags . . . . . . . . . . . . . . . . . number of all bags allocated
*V SizeAllBags . . . . . . . . . . . . . . total size of all bags allocated
*V NrLiveBags . . . . . . . . . . number of bags that survived the last gc
*V SizeLiveBags . . . . . . . total size of bags that survived the last gc
*V NrDeadBags . . . . . . . number of bags that died since the last full gc
*V SizeDeadBags . . . . total size of bags that died since the last full gc
**
** 'NrAllBags'
**
** 'NrAllBags' is the number of bags allocated since Gasman was initialized.
** It is incremented for each 'NewBag' call.
**
** 'SizeAllBags'
**
** 'SizeAllBags' is the total size of bags allocated since Gasman was
** initialized. It is incremented for each 'NewBag' call.
**
** 'NrLiveBags'
**
** 'NrLiveBags' is the number of bags that were live after the last garbage
** collection. So after a full garbage collection it is simply the number
** of bags that have been found to be still live by this garbage collection.
** After a partial garbage collection it is the sum of the previous value of
** 'NrLiveBags', which is the number of live old bags, and the number of
** bags that have been found to be still live by this garbage collection,
** which is the number of live young bags. This value is used in the
** information messages, and to find out how many free identifiers are
** available.
**
** 'SizeLiveBags'
**
** 'SizeLiveBags' is the total size of bags that were live after the last
** garbage collection. So after a full garbage collection it is simply the
** total size of bags that have been found to be still live by this garbage
** collection. After a partial garbage collection it is the sum of the
** previous value of 'SizeLiveBags', which is the total size of live old
** bags, and the total size of bags that have been found to be still live by
** this garbage collection, which is the total size of live young bags.
** This value is used in the information messages.
**
** 'NrDeadBags'
**
** 'NrDeadBags' is the number of bags that died since the last full garbage
** collection. So after a full garbage collection this is zero. After a
** partial garbage collection it is the sum of the previous value of
** 'NrDeadBags' and the number of bags that have been found to be dead by
** this garbage collection. This value is used in the information messages.
**
** 'SizeDeadBags'
**
** 'SizeDeadBags' is the total size of bags that died since the last full
** garbage collection. So after a full garbage collection this is zero.
** After a partial garbage collection it is the sum of the previous value of
** 'SizeDeadBags' and the total size of bags that have been found to be dead
** by this garbage collection. This value is used in the information
** message.
**
** 'NrHalfDeadBags'
**
** 'NrHalfDeadBags' is the number of bags that have been found to be
** reachable only by way of weak pointers since the last garbage collection.
** The bodies of these bags are deleted, but their identifiers are marked so
** that weak pointer objects can recognize this situation.
*/
extern UInt NrAllBags;
extern UInt8 SizeAllBags;
extern UInt NrLiveBags;
extern UInt SizeLiveBags;
extern UInt NrDeadBags;
extern UInt8 SizeDeadBags;
extern UInt NrHalfDeadBags;
/****************************************************************************
**
*V InfoBags[<type>] . . . . . . . . . . . . . . . . . information for bags
**
** 'InfoBags[<type>]'
**
** 'InfoBags[<type>]' is a structure containing information for bags of the
** type <type>.
**
** 'InfoBags[<type>].name' is the name of the type <type>. Note that it is
** the responsibility of the application using {\Gasman} to enter this
** name.
**
** '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.
*/
typedef struct {
const Char * name;
#ifdef COUNT_BAGS
UInt nrLive;
UInt nrAll;
UInt sizeLive;
UInt sizeAll;
#endif
} TNumInfoBags;
extern TNumInfoBags InfoBags [ 256 ];
#ifdef HPCGAP
void MakeBagTypePublic(int type);
Bag MakeBagPublic(Bag bag);
Bag MakeBagReadOnly(Bag bag);
#endif
/****************************************************************************
**
*F InitMsgsFuncBags(<msgs-func>) . . . . . . . . . install message function
**
** 'InitMsgsFuncBags( <msgs-func> )'
**
** 'InitMsgsFuncBags' installs the function <msgs-func> as function used by
** {\Gasman} to print messages during garbage collections. <msgs-func> must
** be a function of three 'unsigned long' arguments <full>, <phase>, and
** <nr>. <msgs-func> should format this information and display it in an
** appropriate way. In fact you will usually want to ignore the messages
** for partial garbage collections, since there are so many of those. If
** you do not install a messages function with 'InitMsgsFuncBags', then
** 'CollectBags' will be silent.
**
** If <full> is 1, the current garbage collection is a full one. If <phase>
** is 0, the garbage collection has just started and <nr> should be ignored
** in this case. If <phase> is 1 respectively 2, the garbage collection has
** completed the mark phase and <nr> is the total number respectively the
** total size of live bags. If <phase> is 3 respectively 4, the garbage
** collection has completed the sweep phase, and <nr> is the number
** respectively the total size of bags that died since the last full garbage
** collection. If <phase> is 5 respectively 6, the garbage collection has
** completed the check phase and <nr> is the size of the free storage
** respectively the size of the workspace. All sizes are measured in KByte.
**
** If <full> is 0, the current garbage collection is a partial one. If
** <phase> is 0, the garbage collection has just started and <nr> should be
** ignored in this case. If <phase> is 1 respectively 2, the garbage
** collection has completed the mark phase and <nr> is the number
** respectively the total size of bags allocated since the last garbage
** collection that are still live. If <phase> is 3 respectively 4, the
** garbage collection has completed the sweep phase and <nr> is the number
** respectively the total size of bags allocated since the last garbage
** collection that are already dead (thus the sum of the values from phase 1
** and 3 is the total number of bags allocated since the last garbage
** collection). If <phase> is 5 respectively 6, the garbage collection has
** completed the check phase and <nr> is the size of the free storage
** respectively the size of the workspace. All sizes are measured in KByte.
**
** The message function should display the information for each phase
** immediatly, i.e., by calling 'flush' if the output device is a file, so
** that the user has some indication how much time each phase used.
**
** For example {\GAP} displays messages for full garbage collections in the
** following form{\:}
**
** #G FULL 47601/ 2341KB live 70111/ 5361KB dead 1376/ 4096KB free
**
** where 47601 is the total number of bags surviving the garbage collection,
** using 2341 KByte, 70111 is the total number of bags that died since the
** last full garbage collection, using 5361 KByte, 1376 KByte are free and
** the total size of the workspace is 4096 KByte.
**
** And partial garbage collections are displayed in {\GAP} in the following
** form{\:}
**
** #G PART 34/ 41KB+live 3016/ 978KB+dead 1281/ 4096KB free
**
** where 34 is the number of young bags that were live after this garbage
** collection, all the old bags survived it anyhow, using 41 KByte, 3016 is
** the number of young bags that died since the last garbage collection, so
** 34+3016 is the number of bags allocated between the last two garbage
** collections, using 978 KByte and the other two numbers are as above.
*/
#ifdef USE_GASMAN
typedef void (* TNumMsgsFuncBags) (
UInt full,
UInt phase,
Int nr );
extern void InitMsgsFuncBags (
TNumMsgsFuncBags msgs_func );
#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 single argument of type
** 'Bag' 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).
**
** 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.
*/
typedef void (* TNumMarkFuncBags )( Bag bag );
extern 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.
*/
extern void MarkNoSubBags( Bag bag );
/****************************************************************************
**
*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.
*/
extern void MarkOneSubBags( Bag bag );
extern void MarkTwoSubBags( Bag bag );
extern void MarkThreeSubBags( Bag bag );
extern void MarkFourSubBags( Bag bag );
/****************************************************************************
**
*F MarkAllSubBags(<bag>) . . . . . . marking function that marks everything
**
** 'MarkAllSubBags( <bag> )'
**
** '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.
*/
extern void MarkAllSubBags( Bag bag );
extern void MarkAllSubBagsDefault ( Bag );
extern void MarkAllButFirstSubBags( Bag bag );
/****************************************************************************
**
*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.
*/
extern void MarkBag( Bag bag );
/****************************************************************************
**
** MARK_BAG is provided for backwards compatibility with existing code. New
** code should use MarkBag directly instead.
**
*/
#define MARK_BAG(bag) MarkBag(bag)
/****************************************************************************
**
*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.
*/
extern void MarkArrayOfBags(const Bag array[], UInt count);
/****************************************************************************
**
*F InitGlobalBag(<addr>) . . . . . inform Gasman about global bag identifier
**
** 'InitGlobalBag( <addr>, <cookie> )'
**
** '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
*/
extern void InitGlobalBag (
Bag * addr,
const Char * cookie );
/****************************************************************************
**
*F InitFreeFuncBag(<type>,<free-func>) . . . . . . install freeing function
**
** 'InitFreeFuncBag( <type>, <free-func> )'
**
** '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 it 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>.
*/
typedef void (* TNumFreeFuncBags ) (
Bag bag );
extern void InitFreeFuncBag (
UInt type,
TNumFreeFuncBags free_func );
/****************************************************************************
**
*F InitCollectFuncBags(<bfr-func>,<aft-func>) . install collection functions
**
** 'InitCollectFuncBags( <before-func>, <after-func> )'
**
** 'InitCollectFuncBags' installs the functions <before-func> and
** <after-func> as collection functions.
**
** The <before-func> will be called before each garbage collection, the
** <after-func> will be called after each garbage collection. One use of
** the <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 the <after-func> 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.
*/
#ifdef USE_GASMAN
typedef void (* TNumCollectFuncBags) ( void );
extern void InitCollectFuncBags (
TNumCollectFuncBags before_func,
TNumCollectFuncBags after_func );
extern void SetStackBottomBags(void * StackBottom);
#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).
typedef void (*TNumExtraMarkFuncBags)(void);
extern void SetExtraMarkFuncBags(TNumExtraMarkFuncBags func);
/****************************************************************************
**
*F InitBags(...) . . . . . . . . . . . . . . . . . . . . . initialize Gasman
**
** InitBags( <initialSize>, <stackStart>, <stackAlign> )
**
** 'InitBags' initializes {\Gasman}. It must be called from a 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'.
**
** <stackAlign> must be the alignment of items of type 'Bag' on the stack.
** It must be a divisor of 'sizeof(Bag)'. The addresses of all identifiers
** on the stack must be a multiple of <stackAlign>. If it is 1, identifiers
** may be anywhere on the stack, and if it is 'sizeof(Bag)', identifiers may
** only be at addresses that are a multiple of 'sizeof(Bag)'. This value
** depends on the machine, the operating system, and the compiler.
*/
extern void InitBags(UInt initialSize, Bag * stackStart, UInt stackAlign);
/****************************************************************************
**
*F FinishBags() end GASMAN and free memory
*/
extern void FinishBags( void );
#if !defined(USE_GASMAN)
void *AllocateMemoryBlock(UInt size);
#endif
#ifdef GAP_MEM_CHECK
Int enableMemCheck(Char ** argv, void * dummy);
#endif
#endif // GAP_GASMAN_H