Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
Project: cocalc-sagemath-dev-slelievre
Views: 418346/****************************************************************************1**2*W gasman.h GAP source Martin Schönert3**4**5*Y Copyright (C) 1996, Lehrstuhl D für Mathematik, RWTH Aachen, Germany6*Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland7*Y Copyright (C) 2002 The GAP Group8**9** This file declares the functions of Gasman, the GAP storage manager.10**11** {\Gasman} is a storage manager for applications written in C. That means12** that an application requests blocks of storage from {\Gasman}, which are13** called bags. After using a bag to store data, the application simply14** forgets the bag, and we say that such a block is dead. {\Gasman}15** implements an automatic, cooperating, compacting, generational,16** conservative storage manager. Automatic means that the application only17** allocates bags, but need not explicitly deallocate them. This is18** important for large or complex application, where explicit deallocation19** is difficult. Cooperating means that the allocation must cooperate with20** {\Gasman}, i.e., must follow certain rules. This information provided by21** the application makes {\Gasman} use less storage and run faster.22** Compacting means that {\Gasman} always compacts live bags such that the23** free storage is one large block. Because there is no fragmentation of24** the free storage {\Gasman} uses as little storage as possible.25** Generational means that {\Gasman} usually assumes that bags that have26** been live for some time are still live. This means that it can avoid27** most of the tests whether a bag is still live or already dead. Only when28** not enough storage can be reclaimed under this assumption does it perform29** all the tests. Conservative means that {\Gasman} may keep bags longer30** than necessary because the C compiler does not provide sufficient31** information to distinguish true references to bags from other values that32** happen to look like references.33*/3435#ifndef GAP_GASMAN_H36#define GAP_GASMAN_H3738/* This definition switches to the bigger bag header, supporting bags up to394GB in length (lists limited to 1GB for other reasons) */4041/* Experimental 16+48 bit type/size word for 64 bit systems */4243/****************************************************************************44**45*V autoconf . . . . . . . . . . . . . . . . . . . . . . . . use "config.h"46*/47#include "config.h"4849#include "atomic.h"5051/* on 64 bit systems use only two words for bag header */5253#if SIZEOF_VOID_P == 854#define USE_NEWSHAPE55#elif !defined(SIZEOF_VOID_P) && !defined(USE_PRECOMPILED)56/* If SIZEOF_VOID_P has not been defined, and we are not currently57re-making the dependency list (via cnf/Makefile), then trigger58an error. */59#error Something is wrong with this GAP installation: SIZEOF_VOID_P not defined60#endif616263/****************************************************************************64**6566*T Bag . . . . . . . . . . . . . . . . . . . type of the identifier of a bag67**68** 'Bag'69**70** Each bag is identified by its *bag identifier*. That is each bag has a71** bag identifier and no two live bags have the same identifier. 'Bag' is72** the type of bag identifiers.73**74** 0 is a valid value of the type 'Bag', but is guaranteed not to be the75** identifier of any bag.76**77** 'NewBag' returns the identifier of the newly allocated bag and the78** application passes this identifier to every {\Gasman} function to tell it79** which bag it should operate on (see "NewBag", "TNUM_BAG", "SIZE_BAG",80** "PTR_BAG", "CHANGED_BAG", "RetypeBag", and "ResizeBag").81**82** Note that the identifier of a bag is different from the address of the83** data area of the bag. This address may change during a garbage84** collection while the identifier of a bag never changes.85**86** Bags that contain references to other bags must always contain the87** identifiers of these other bags, never the addresses of the data areas of88** the bags.89**90** Note that bag identifiers are recycled. That means that after a bag dies91** its identifier may be reused for a new bag.92**93** The following is defined in "system.h"94**95typedef UInt * * Bag;96*/979899/****************************************************************************100**101*F TNUM_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . . . type of a bag102**103** 'TNUM_BAG( <bag> )'104**105** 'TNUM_BAG' returns the type of the bag with the identifier <bag>.106**107** Each bag has a certain type that identifies its structure. The type is a108** integer between 0 and 253. The types 254 and 255 are reserved for109** {\Gasman}. The application specifies the type of a bag when it allocates110** it with 'NewBag' and may later change it with 'RetypeBag' (see "NewBag"111** and "RetypeBag").112**113** {\Gasman} needs to know the type of a bag so that it knows which function114** to call to mark all subbags of a given bag (see "InitMarkFuncBags").115** Apart from that {\Gasman} does not care at all about types.116**117** Note that 'TNUM_BAG' is a macro, so do not call it with arguments that118** have side effects.119*/120121#ifdef USE_NEWSHAPE122#define TNUM_BAG(bag) (*(*(bag)-2) & 0xFFFFL)123#else124#define TNUM_BAG(bag) (*(*(bag)-3))125#endif126127/****************************************************************************128**129*F SIZE_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . . . size of a bag130**131** 'SIZE_BAG( <bag> )'132**133** 'SIZE_BAG' returns the size of the bag with the identifier <bag> in134** bytes.135**136** Each bag has a certain size. The size of a bag is measured in bytes.137** The size must be a value between 0 and $2^{24}-1$. The application138** specifies the size of a bag when it allocates it with 'NewBag' and may139** later change it with 'ResizeBag' (see "NewBag" and "ResizeBag").140**141** Note that 'SIZE_BAG' is a macro, so do not call it with arguments that142** have side effects.143*/144#ifdef USE_NEWSHAPE145#define SIZE_BAG(bag) (*(*(bag)-2) >> 16)146#else147#define SIZE_BAG(bag) (*(*(bag)-2))148#endif149150#define LINK_BAG(bag) (*(Bag *)(*(bag)-1))151/****************************************************************************152**153*F PTR_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . pointer to a bag154**155** 'PTR_BAG( <bag> )'156**157** 'PTR_BAG' returns the address of the data area of the bag with identifier158** <bag>. Using this pointer the application can then read data from the159** bag or write data into it. The pointer is of type pointer to bag160** identifier, i.e., 'PTR_BAG(<bag>)[0]' is the identifier of the first161** subbag of the bag, etc. If the bag contains data in a different format,162** the application has to cast the pointer returned by 'PTR_BAG', e.g.,163** '(long\*)PTR_BAG(<bag>)'.164**165** Note that the address of the data area of a bag may change during a166** garbage collection. That is the value returned by 'PTR_BAG' may differ167** between two calls, if 'NewBag', 'ResizeBag', 'CollectBags', or any of the168** application\'s functions or macros that may call those functions, is169** called in between (see "NewBag", "ResizeBag", "CollectBags").170**171** The first rule for using {\Gasman} is{\:} *The application must not keep172** any pointers to or into the data area of any bag over calls to functions173** that may cause a garbage collection.*174**175** That means that the following code is incorrect{\:}176**177** ptr = PTR_BAG( old );178** new = NewBag( typeNew, sizeNew );179** *ptr = new;180**181** because the creation of the new bag may move the old bag, causing the182** pointer to point no longer to the data area of the bag. It must be183** written as follows{\:}184**185** new = NewBag( typeNew, sizeNew );186** ptr = PTR_BAG( old );187** *ptr = new;188**189** Note that even the following is incorrect{\:}190**191** PTR_BAG(old)[0] = NewBag( typeNew, sizeNew );192**193** because a C compiler is free to compile it to a sequence of instructions194** equivalent to first example. Thus whenever the evaluation of a function195** or a macro may cause a garbage collection there must be no call to196** 'PTR_BAG' in the same expression, except as argument to this function or197** macro.198**199** Note that after writing a bag identifier, e.g., 'new' in the above200** example, into the data area of another bag, 'old' in the above example,201** the application must inform {\Gasman} that it has changed the bag, by202** calling 'CHANGED_BAG(old)' in the above example (see "CHANGED_BAG").203**204** Note that 'PTR_BAG' is a macro, so do not call it with arguments that205** have side effects.206*/207#define PTR_BAG(bag) (*(Bag**)(bag))208209210/****************************************************************************211**212*F CHANGED_BAG(<bag>) . . . . . . . . notify Gasman that a bag has changed213**214** 'CHANGED_BAG( <bag> )'215**216** 'CHANGED_BAG' informs {\Gasman} that the bag with identifier <bag> has217** been changed by an assignment of another bag identifier.218**219** The second rule for using {\Gasman} is{\:} *After each assignment of a220** bag identifier into a bag the application must inform {\Gasman} that it221** has changed the bag before the next garbage collection can happen.*222**223** Note that the application need not inform {\Gasman} if it changes a bag224** by assigning something that is not an identifier of another bag.225**226** For example to copy all entries from one list into another the following227** code must be used{\:}228**229** for ( i = 0; i < SIZE-BAG(old)/sizeof(Bag); i++ )230** PTR_BAG(new)[i] = PTR_BAG(old)[i];231** CHANGED_BAG( new );232**233** On the other hand when the application allocates a matrix, where the234** allocation of each row may cause a garbage collection, the following code235** must be used{\:}236**237** mat = NewBag( T_MAT, n * sizeof(Bag) );238** for ( i = 0; i < n; i++ ) {239** row = NewBag( T_ROW, n * sizeof(Bag) );240** PTR_BAG(mat)[i] = row;241** CHANGED_BAG( mat );242** }243**244** Note that writing 'PTR_BAG(mat)[i] = NewBag( T_ROW, n\*\ sizeof(Bag) );'245** is incorrect as mentioned in the section for 'PTR_BAG' (see "PTR_BAG").246**247** Note that 'CHANGED_BAG' is a macro, so do not call it with arguments that248** have side effects.249*/250extern Bag * YoungBags;251252extern Bag ChangedBags;253254/*****255** MEMORY_CANARY provides (basic) support for catching out-of-bounds memory256** problems in GAP. This is done through the excellent 'valgrind' program.257** valgrind is of limited use in GAP normally, because it doesn't understand258** GAP's memory manager. Enabling MEMORY_CANARY will make an executable where259** valgrind will detect memory issues.260**261** At the moment the detection is limited to only writing off the last allocated262** block.263*/264265#ifdef MEMORY_CANARY266extern void CHANGED_BAG_IMPL(Bag b);267#define CHANGED_BAG(bag) CHANGED_BAG_IMPL(bag);268#else269#define CHANGED_BAG(bag) \270if ( PTR_BAG(bag) <= YoungBags \271&& PTR_BAG(bag)[-1] == (bag) ) { \272PTR_BAG(bag)[-1] = ChangedBags; ChangedBags = (bag); }273274#endif275276/****************************************************************************277**278*F NewBag(<type>,<size>) . . . . . . . . . . . . . . . . allocate a new bag279**280** 'NewBag( <type>, <size> )'281**282** 'NewBag' allocates a new bag of type <type> and <size> bytes. 'NewBag'283** returns the identifier of the new bag, which must be passed as first284** argument to all other {\Gasman} functions.285**286** <type> must be a value between 0 and 253. The types 254 and 255 are287** reserved for {\Gasman}. The application can find the type of a bag with288** 'TNUM_BAG' and change it with 'RetypeBag' (see "TNUM_BAG" and289** "RetypeBag").290**291** It is probably a good idea to define symbolic constants for all types in292** a system wide header file, e.g., 'types.h', if only to avoid to293** accidently use the same value for two different types.294**295** <size> is the size of the new bag in bytes and must be a value between 0296** and $2^{24}-1$. The application can find the size of a bag with297** 'SIZE_BAG' and change it with 'ResizeBag' (see "SIZE_BAG" and298** "ResizeBag").299**300** If the initialization flag <dirty> is 0, all entries of the new bag will301** be initialized to 0; otherwise the entries of the new bag will contain302** random values (see "InitBags").303**304** What happens if {\Gasman} cannot get enough storage to perform an305** allocation depends on the behavior of the allocation function306** <alloc-func>. If <alloc-func> returns 0 when it cannot do a needed307** extension of the workspace, then 'NewBag' may return 0 to indicate308** failure, and the application has to check the return value of 'NewBag'309** for this. If <alloc-func> aborts when it cannot do a needed extension of310** the workspace, then the application will abort if 'NewBag' would not311** succeed. So in this case whenever 'NewBag' returns, it succeeded, and312** the application need not check the return value of 'NewBag' (see313** "InitBags").314**315** Note that 'NewBag' will perform a garbage collection if no free storage316** is available. During the garbage collection the addresses of the data317** areas of all bags may change. So you must not keep any pointers to or318** into the data areas of bags over calls to 'NewBag' (see "PTR_BAG").319*/320extern Bag NewBag (321UInt type,322UInt size );323324325/****************************************************************************326**327*F RetypeBag(<bag>,<new>) . . . . . . . . . . . . change the type of a bag328**329** 'RetypeBag( <bag>, <new> )'330**331** 'RetypeBag' changes the type of the bag with identifier <bag> to the new332** type <new>. The identifier, the size, and also the address of the data333** area of the bag do not change.334**335** 'Retype' is usually used to set or reset flags that are stored in the336** type of a bag. For example in {\GAP} there are two types of large337** integers, one for positive integers and one for negative integers. To338** compute the difference of a positive integer and a negative, {\GAP} uses339** 'RetypeBag' to temporarily change the second argument into a positive340** integer, and then adds the two operands. For another example when {\GAP}341** detects that a list is sorted and contains no duplicates, it changes the342** type of the bag with 'RetypeBag', and the new type indicates that this343** list has this property, so that this need not be tested again.344**345** It is, as usual, the responsibility of the application to ensure that the346** data stored in the bag makes sense when the bag is interpreted as a bag347** of type <type>.348*/349extern void RetypeBag (350Bag bag,351UInt new_type );352353#define RetypeBagIfWritable(x,y) RetypeBag(x,y)354355/****************************************************************************356**357*F ResizeBag(<bag>,<new>) . . . . . . . . . . . . change the size of a bag358**359** 'ResizeBag( <bag>, <new> )'360**361** 'ResizeBag' changes the size of the bag with identifier <bag> to the new362** size <new>. The identifier of the bag does not change, but the address363** of the data area of the bag may change. If the new size <new> is less364** than the old size, {\Gasman} throws away any data in the bag beyond the365** new size. If the new size <new> is larger than the old size, {\Gasman}366** extends the bag.367**368** If the initialization flag <dirty> is 0, all entries of an extension will369** be initialized to 0; otherwise the entries of an extension will contain370** random values (see "InitBags").371**372** What happens if {\Gasman} cannot get enough storage to perform an373** extension depends on the behavior of the allocation function374** <alloc-func>. If <alloc-func> returns 0 when it cannot do a needed375** extension of the workspace, then 'ResizeBag' may return 0 to indicate376** failure, and the application has to check the return value of 'ResizeBag'377** for this. If <alloc-func> aborts when it cannot do a needed extension of378** the workspace, then the application will abort if 'ResizeBag' would not379** succeed. So in this case whenever 'ResizeBag' returns, it succeeded, and380** the application need not check the return value of 'ResizeBag' (see381** "InitBags").382**383** Note that 'ResizeBag' will perform a garbage collection if no free384** storage is available. During the garbage collection the addresses of the385** data areas of all bags may change. So you must not keep any pointers to386** or into the data areas of bags over calls to 'ResizeBag' (see "PTR_BAG").387*/388extern UInt ResizeBag (389Bag bag,390UInt new_size );391392393/****************************************************************************394**395*F CollectBags(<size>,<full>) . . . . . . . . . . . . . . collect dead bags396**397** 'CollectBags( <size>, <full> )'398**399** 'CollectBags' performs a garbage collection. This means it deallocates400** the dead bags and compacts the live bags at the beginning of the401** workspace. If <full> is 0, then only the dead young bags are402** deallocated, otherwise all dead bags are deallocated.403**404** If the application calls 'CollectBags', <size> must be 0, and <full> must405** be 0 or 1 depending on whether it wants to perform a partial or a full406** garbage collection.407**408** If 'CollectBags' is called from 'NewBag' or 'ResizeBag', <size> is the409** size of the bag that is currently allocated, and <full> is zero.410**411** Note that during the garbage collection the addresses of the data areas412** of all bags may change. So you must not keep any pointers to or into the413** data areas of bags over calls to 'CollectBags' (see "PTR_BAG").414*/415extern UInt CollectBags (416UInt size,417UInt full );418419420/****************************************************************************421**422*F SwapMasterPoint( <bag1>, <bag2> ) . . . swap pointer of <bag1> and <bag2>423*/424extern void SwapMasterPoint (425Bag bag1,426Bag bag2 );427428429/****************************************************************************430**431*V NrAllBags . . . . . . . . . . . . . . . . . number of all bags allocated432*V SizeAllBags . . . . . . . . . . . . . . total size of all bags allocated433*V NrLiveBags . . . . . . . . . . number of bags that survived the last gc434*V SizeLiveBags . . . . . . . total size of bags that survived the last gc435*V NrDeadBags . . . . . . . number of bags that died since the last full gc436*V SizeDeadBags . . . . total size of bags that died since the last full gc437**438** 'NrAllBags'439**440** 'NrAllBags' is the number of bags allocated since Gasman was initialized.441** It is incremented for each 'NewBag' call.442**443** 'SizeAllBags'444**445** 'SizeAllBags' is the total size of bags allocated since Gasman was446** initialized. It is incremented for each 'NewBag' call.447**448** 'NrLiveBags'449**450** 'NrLiveBags' is the number of bags that were live after the last garbage451** collection. So after a full garbage collection it is simply the number452** of bags that have been found to be still live by this garbage collection.453** After a partial garbage collection it is the sum of the previous value of454** 'NrLiveBags', which is the number of live old bags, and the number of455** bags that have been found to be still live by this garbage collection,456** which is the number of live young bags. This value is used in the457** information messages, and to find out how many free identifiers are458** available.459**460** 'SizeLiveBags'461**462** 'SizeLiveBags' is the total size of bags that were live after the last463** garbage collection. So after a full garbage collection it is simply the464** total size of bags that have been found to be still live by this garbage465** collection. After a partial garbage collection it is the sum of the466** previous value of 'SizeLiveBags', which is the total size of live old467** bags, and the total size of bags that have been found to be still live by468** this garbage collection, which is the total size of live young bags.469** This value is used in the information messages.470**471** 'NrDeadBags'472**473** 'NrDeadBags' is the number of bags that died since the last full garbage474** collection. So after a full garbage collection this is zero. After a475** partial garbage collection it is the sum of the previous value of476** 'NrDeadBags' and the number of bags that have been found to be dead by477** this garbage collection. This value is used in the information messages.478**479** 'SizeDeadBags'480**481** 'SizeDeadBags' is the total size of bags that died since the last full482** garbage collection. So after a full garbage collection this is zero.483** After a partial garbage collection it is the sum of the previous value of484** 'SizeDeadBags' and the total size of bags that have been found to be dead485** by this garbage collection. This value is used in the information486** message.487**488** 'NrHalfDeadBags'489**490** 'NrHalfDeadBags' is the number of bags that have been found to be491** reachable only by way of weak pointers since the last garbage collection.492** The bodies of these bags are deleted, but their identifiers are marked so493** that weak pointer objects can recognize this situation.494*/495496extern UInt NrAllBags;497extern UInt SizeAllBags;498extern UInt NrLiveBags;499extern UInt SizeLiveBags;500extern UInt NrDeadBags;501extern UInt SizeDeadBags;502extern UInt NrHalfDeadBags;503504505/****************************************************************************506**507*V InfoBags[<type>] . . . . . . . . . . . . . . . . . information for bags508**509** 'InfoBags[<type>]'510**511** 'InfoBags[<type>]' is a structure containing information for bags of the512** type <type>.513**514** 'InfoBags[<type>].name' is the name of the type <type>. Note that it is515** the responsibility of the application using {\Gasman} to enter this516** name.517**518** 'InfoBags[<type>].nrLive' is the number of bags of type <type> that are519** currently live.520**521** 'InfoBags[<type>].nrAll' is the total number of all bags of <type> that522** have been allocated.523**524** 'InfoBags[<type>].sizeLive' is the sum of the sizes of the bags of type525** <type> that are currently live.526**527** 'InfoBags[<type>].sizeAll' is the sum of the sizes of all bags of type528** <type> that have been allocated.529**530** This information is only kept if {\Gasman} is compiled with the option531** '-DCOUNT_BAGS', e.g., with 'make <target> COPTS=-DCOUNT_BAGS'.532*/533typedef struct {534const Char * name;535UInt nrLive;536UInt nrAll;537UInt sizeLive;538UInt sizeAll;539} TNumInfoBags;540541extern TNumInfoBags InfoBags [ 256 ];542543#define MakeBagTypePublic(type) do { } while(0)544#define MakeBagTypeProtected(type) do { } while(0)545#define MakeBagPublic(bag) do { } while(0)546#define MakeBagReadOnly(bag) do { } while(0)547548/****************************************************************************549**550*F InitMsgsFuncBags(<msgs-func>) . . . . . . . . . install message function551**552** 'InitMsgsFuncBags( <msgs-func> )'553**554** 'InitMsgsFuncBags' installs the function <msgs-func> as function used by555** {\Gasman} to print messages during garbage collections. <msgs-func> must556** be a function of three 'unsigned long' arguments <full>, <phase>, and557** <nr>. <msgs-func> should format this information and display it in an558** appropriate way. In fact you will usually want to ignore the messages559** for partial garbage collections, since there are so many of those. If560** you do not install a messages function with 'InitMsgsFuncBags', then561** 'CollectBags' will be silent.562**563** If <full> is 1, the current garbage collection is a full one. If <phase>564** is 0, the garbage collection has just started and <nr> should be ignored565** in this case. If <phase> is 1 respectively 2, the garbage collection has566** completed the mark phase and <nr> is the total number respectively the567** total size of live bags. If <phase> is 3 respectively 4, the garbage568** collection has completed the sweep phase, and <nr> is the number569** respectively the total size of bags that died since the last full garbage570** collection. If <phase> is 5 respectively 6, the garbage collection has571** completed the check phase and <nr> is the size of the free storage572** respectively the size of the workspace. All sizes are measured in KByte.573**574** If <full> is 0, the current garbage collection is a partial one. If575** <phase> is 0, the garbage collection has just started and <nr> should be576** ignored in this case. If <phase> is 1 respectively 2, the garbage577** collection has completed the mark phase and <nr> is the number578** respectively the total size of bags allocated since the last garbage579** collection that are still live. If <phase> is 3 respectively 4, the580** garbage collection has completed the sweep phase and <nr> is the number581** respectively the total size of bags allocated since the last garbage582** collection that are already dead (thus the sum of the values from phase 1583** and 3 is the total number of bags allocated since the last garbage584** collection). If <phase> is 5 respectively 6, the garbage collection has585** completed the check phase and <nr> is the size of the free storage586** respectively the size of the workspace. All sizes are measured in KByte.587**588** The message function should display the information for each phase589** immediatly, i.e., by calling 'flush' if the output device is a file, so590** that the user has some indication how much time each phase used.591**592** For example {\GAP} displays messages for full garbage collections in the593** following form{\:}594**595** #G FULL 47601/ 2341KB live 70111/ 5361KB dead 1376/ 4096KB free596**597** where 47601 is the total number of bags surviving the garbage collection,598** using 2341 KByte, 70111 is the total number of bags that died since the599** last full garbage collection, using 5361 KByte, 1376 KByte are free and600** the total size of the workspace is 4096 KByte.601**602** And partial garbage collections are displayed in {\GAP} in the following603** form{\:}604**605** #G PART 34/ 41KB+live 3016/ 978KB+dead 1281/ 4096KB free606**607** where 34 is the number of young bags that were live after this garbage608** collection, all the old bags survived it anyhow, using 41 KByte, 3016 is609** the number of young bags that died since the last garbage collection, so610** 34+3016 is the number of bags allocated between the last two garbage611** collections, using 978 KByte and the other two numbers are as above.612*/613typedef void (* TNumMsgsFuncBags) (614UInt full,615UInt phase,616Int nr );617618extern void InitMsgsFuncBags (619TNumMsgsFuncBags msgs_func );620621622/****************************************************************************623**624*F InitMarkFuncBags(<type>,<mark-func>) . . . . . install marking function625*F MarkNoSubBags(<bag>) . . . . . . . . marking function that marks nothing626*F MarkOneSubBags(<bag>) . . . . . . marking function that marks one subbag627*F MarkTwoSubBags(<bag>) . . . . . . marking function that marks two subbags628*F MarkAllSubBags(<bag>) . . . . . . marking function that marks everything629*F MARK_BAG(<bag>) . . . . . . . . . . . . . . . . . . . mark a bag as live630**631** 'InitMarkFuncBags( <type>, <mark-func> )'632**633** 'InitMarkFuncBags' installs the function <mark-func> as marking function634** for bags of type <type>. The application *must* install a marking635** function for a type before it allocates any bag of that type. It is636** probably best to install all marking functions before allocating any bag.637**638** A marking function is a function that takes a single argument of type639** 'Bag' and returns nothing, i.e., has return type 'void'. Such a function640** must apply the macro 'MARK_BAG' to each bag identifier that appears in641** the bag (see below).642**643** Those functions are applied during the garbage collection to each marked644** bag, i.e., bags that are assumed to be still live, to also mark their645** subbags. The ability to use the correct marking function is the only use646** that {\Gasman} has for types.647**648** 'MARK_BAG( <bag> )'649**650** 'MARK_BAG' marks the <bag> as live so that it is not thrown away during651** a garbage collection. 'MARK_BAG' should only be called from the marking652** functions installed with 'InitMarkFuncBags'.653**654** 'MARK_BAG' tests if <bag> is a valid identifier of a bag in the young655** bags area. If it is not, then 'MARK_BAG' does nothing, so there is no656** harm in calling 'MARK_BAG' for something that is not actually a bag657** identifier.658**659** Note that 'MARK_BAG' is a macro, so do not call it with an argument that660** has side effects.661**662** 'MarkBagWeakly( <bag> )'663**664** 'MarkBagWeakly' is an alternative to MARK_BAG, intended to be used by the665** marking functions of weak pointer objects. A bag which is marked both666** weakly and strongly is treated as strongly marked. A bag which is only667** weakly marked will be recovered by garbage collection, but its identifier668** remains, marked in a way which can be detected by669** "IS_WEAK_DEAD_BAG". Which should always be checked before copying or670** using such an identifier.671**672**673** {\Gasman} already provides the following marking functions.674**675** 'MarkNoSubBags( <bag> )'676**677** 'MarkNoSubBags' is a marking function for types whose bags contain no678** identifier of other bags. It does nothing, as its name implies, and679** simply returns. For example in {\GAP} the bags for large integers680** contain only the digits and no identifiers of bags.681**682** 'MarkOneSubBags( <bag> )'683**684** 'MarkOneSubBags' is a marking function for types whose bags contain685** exactly one identifier of another bag as the first entry. It marks this686** subbag and returns. For example in {\GAP} bags for finite field elements687** contain exactly one bag identifier for the finite field the element688** belongs to.689**690** 'MarkTwoSubBags( <bag> )'691**692** 'MarkTwoSubBags' is a marking function for types whose bags contain693** exactly two identifiers of other bags as the first and second entry such694** as the binary operations bags. It marks those subbags and returns. For695** example in {\GAP} bags for rational numbers contain exactly two bag696** identifiers for the numerator and the denominator.697**698** 'MarkAllSubBags( <bag> )'699**700** 'MarkAllSubBags' is the marking function for types whose bags contain701** only identifier of other bags. It marks every entry of such a bag. Note702** that 'MarkAllSubBags' assumes that all identifiers are at offsets from703** the address of the data area of <bag> that are divisible by704** 'sizeof(Bag)'. Note also that since it does not do any harm to mark705** something which is not actually a bag identifier one could use706** 'MarkAllSubBags' for all types as long as the identifiers in the data707** area are properly aligned as explained above. This would however slow708** down 'CollectBags'. For example in {\GAP} bags for lists contain only709** bag identifiers for the elements of the list or 0 if an entry has no710** assigned value.711** */712713714typedef void (* TNumMarkFuncBags ) (715Bag bag );716717extern void InitMarkFuncBags (718UInt type,719TNumMarkFuncBags mark_func );720721extern void MarkNoSubBags (722Bag bag );723724extern void MarkOneSubBags (725Bag bag );726727extern void MarkTwoSubBags (728Bag bag );729730extern void MarkThreeSubBags (731Bag bag );732733extern void MarkFourSubBags (734Bag bag );735736extern void MarkAllSubBags (737Bag bag );738739extern void MarkBagWeakly (740Bag bag );741742extern Bag * MptrBags;743extern Bag * OldBags;744extern Bag * AllocBags;745extern Bag MarkedBags;746747#define MARKED_DEAD(x) (x)748#define MARKED_ALIVE(x) ((Bag)(((Char *)(x))+1))749#define MARKED_HALFDEAD(x) ((Bag)(((Char *)(x))+2))750#define IS_MARKED_ALIVE(bag) ((PTR_BAG(bag)[-1]) == MARKED_ALIVE(bag))751#define IS_MARKED_DEAD(bag) ((PTR_BAG(bag)[-1]) == MARKED_DEAD(bag))752#define IS_MARKED_HALFDEAD(bag) ((PTR_BAG(bag)[-1]) == MARKED_HALFDEAD(bag))753#define UNMARKED_DEAD(x) (x)754#define UNMARKED_ALIVE(x) ((Bag)(((Char *)(x))-1))755#define UNMARKED_HALFDEAD(x) ((Bag)(((Char *)(x))-2))756757758#define MARK_BAG(bag) \759if ( (((UInt)(bag)) & (sizeof(Bag)-1)) == 0 \760&& (Bag)MptrBags <= (bag) && (bag) < (Bag)OldBags \761&& YoungBags < PTR_BAG(bag) && PTR_BAG(bag) <= AllocBags \762&& (IS_MARKED_DEAD(bag) || IS_MARKED_HALFDEAD(bag)) ) \763{ \764PTR_BAG(bag)[-1] = MarkedBags; MarkedBags = (bag); }765766extern void MarkAllSubBagsDefault ( Bag );767768769/****************************************************************************770**771*F772*/773774#define IS_WEAK_DEAD_BAG(bag) ( (((UInt)bag & (sizeof(Bag)-1)) == 0) && \775(Bag)MptrBags <= (bag) && \776(bag) < (Bag)OldBags && \777(((UInt)*bag) & (sizeof(Bag)-1)) == 1)778779780/****************************************************************************781**782*F InitSweepFuncBags(<type>,<sweep-func>) . . . . install sweeping function783**784** 'InitSweepFuncBags( <type>, <sweep-func> )'785**786** 'InitSweepFuncBags' installs the function <sweep-func> as sweeping787** function for bags of type <type>.788**789** A sweeping function is a function that takes two arguments src and dst of790** type Bag *, and a third, length of type UInt, and returns nothing. When791** it is called, src points to the start of the data area of one bag, and792** dst to another. The function should copy the data from the source bag to793** the destination, making any appropriate changes.794**795** Those functions are applied during the garbage collection to each marked796** bag, i.e., bags that are assumed to be still live to move them to their797** new position. The intended use is for weak pointer bags, which must798** remove references to identifiers of any half-dead objects.799**800** If no function is installed for a TNum, then the data is simply copied801** unchanged and this is done particularly quickly802*/803804typedef void (* TNumSweepFuncBags ) (805Bag * src,806Bag * dst,807UInt length);808809extern void InitSweepFuncBags (810UInt tnum,811TNumSweepFuncBags sweep_func );812813814815/****************************************************************************816**817*V GlobalBags . . . . . . . . . . . . . . . . . . . . . list of global bags818*/819#ifndef NR_GLOBAL_BAGS820#define NR_GLOBAL_BAGS 20000L821#endif822823824typedef struct {825Bag * addr [NR_GLOBAL_BAGS];826const Char * cookie [NR_GLOBAL_BAGS];827UInt nr;828} TNumGlobalBags;829830extern TNumGlobalBags GlobalBags;831832833/****************************************************************************834**835*F InitGlobalBag(<addr>) . . . . . inform Gasman about global bag identifier836**837** 'InitGlobalBag( <addr>, <cookie> )'838**839** 'InitGlobalBag' informs {\Gasman} that there is a bag identifier at the840** address <addr>, which must be of type '(Bag\*)'. {\Gasman} will look at841** this address for a bag identifier during a garbage collection.842**843** The application *must* call 'InitGlobalBag' for every global variable and844** every entry of a global array that may hold a bag identifier. It is no845** problem if such a variable does not actually hold a bag identifier,846** {\Gasman} will simply ignore it then.847**848** There is a limit on the number of calls to 'InitGlobalBags', which is 512849** by default. If the application has more global variables that may hold850** bag identifier, you have to compile {\Gasman} with a higher value of851** 'NR_GLOBAL_BAGS', i.e., with 'make COPTS=-DNR_GLOBAL_BAGS=<nr>'.852**853** <cookie> is a C string, which should uniquely identify this global854** bag from all others. It is used in reconstructing the Workspace855** after a save and load856*/857858extern Int WarnInitGlobalBag;859860extern void InitGlobalBag (861Bag * addr,862const Char * cookie );863864extern void SortGlobals( UInt byWhat );865866extern Bag * GlobalByCookie(867const Char * cookie );868869870extern void StartRestoringBags( UInt nBags, UInt maxSize);871872873extern Bag NextBagRestoring( UInt size, UInt type);874875876extern void FinishedRestoringBags( void );877878879880/****************************************************************************881**882*F InitFreeFuncBag(<type>,<free-func>) . . . . . . install freeing function883**884** 'InitFreeFuncBag( <type>, <free-func> )'885**886** 'InitFreeFuncBag' installs the function <free-func> as freeing function887** for bags of type <type>.888**889** A freeing function is a function that takes a single argument of type890** 'Bag' and returns nothing, i.e., has return type 'void'. If such a891** function is installed for a type <type> then it is called for each bag of892** that type that is about to be deallocated.893**894** A freeing function must *not* call 'NewBag', 'ResizeBag', or 'RetypeBag'.895**896** When such a function is called for a bag <bag>, its subbags are still897** accessible. Note that it it not specified, whether the freeing functions898** for the subbags of <bag> (if there are freeing functions for bags of899** their types) are called before or after the freeing function for <bag>.900*/901typedef void (* TNumFreeFuncBags ) (902Bag bag );903904extern void InitFreeFuncBag (905UInt type,906TNumFreeFuncBags free_func );907908909/****************************************************************************910**911*F InitCollectFuncBags(<bfr-func>,<aft-func>) . install collection functions912**913** 'InitCollectFuncBags( <before-func>, <after-func> )'914**915** 'InitCollectFuncBags' installs the functions <before-func> and916** <after-func> as collection functions.917**918** The <before-func> will be called before each garbage collection, the919** <after-func> will be called after each garbage collection. One use of920** the <before-func> is to call 'CHANGED_BAG' for bags that change very921** often, so you do not have to call 'CHANGED_BAG' for them every time they922** change. One use of the <after-func> is to update a pointer for a bag, so923** you do not have to update that pointer after every operation that might924** cause a garbage collection.925*/926typedef void (* TNumCollectFuncBags) ( void );927928extern void InitCollectFuncBags (929TNumCollectFuncBags before_func,930TNumCollectFuncBags after_func );931932933/****************************************************************************934**935*F CheckMasterPointers() . . . . . . . . . . . . .do some consistency checks936**937** 'CheckMasterPointers()' tests for masterpoinetrs which are not one of the938** following:939**940** 0 denoting the end of the free chain941** NewWeakDeadBagMarker denoting the relic of a bag that was weakly942** OldWeakDeadBagMarker but not strongly linked at the last garbage943** collection944** a pointer into the masterpointer area a link on the free chain945** a pointer into the bags area a real object946**947*/948949extern void CheckMasterPointers( void );950951/****************************************************************************952**953*F InitBags(...) . . . . . . . . . . . . . . . . . . . . . initialize Gasman954**955** InitBags( <alloc-func>, <initial-size>,956** <stack-func>, <stack-start>, <stack-align>,957** <cache-size>, <dirty>, <abort-func> )958**959** 'InitBags' initializes {\Gasman}. It must be called from a application960** using {\Gasman} before any bags can be allocated.961**962** <alloc-func> must be the function that {\Gasman} uses to allocate the963** initial workspace and to extend the workspace. It must accept two 'long'964** arguments <size> and <need>. <size> is the amount of storage that it965** must allocate, and <need> indicates whether {\Gasman} really needs the966** storage or only wants it to have a reasonable amount of free storage.967**968** *Currently this function must return immediately adjacent areas on969** subsequent calls*. So 'sbrk' will work on most systems, but 'malloc'970** will not.971**972** If <need> is 0, <alloc-func> must either return the address of the973** extension to indicate success or return 0 if it cannot or does not want974** to extend the workspace. If <need> is 1, <alloc-func> must again return975** the address of the extension to indicate success and can either return 0976** or abort if it cannot or does not want to extend the workspace. This977** choice determines whether 'NewBag' and 'ResizeBag' may fail. If it978** returns 0, then 'NewBag' and 'ResizeBag' can fail. If it aborts, then979** 'NewBag' and 'ResizeBag' can never fail (see "NewBag" and "ResizeBag").980**981** <size> may also be negative if {\Gasman} has a large amount of free982** space, and wants to return some of it to the operating system. In this983** case <need> will always be 0. <alloc-func> can either accept this984** reduction of the workspace and return a nonzero value and return the985** storage to the operating system, or refuse this reduction and return 0.986**987** <initial-size> must be the size of the initial workspace that 'InitBags'988** should allocate. This value is automatically rounded up to the next989** multiple of 1/2 MByte by 'InitBags'.990**991** <stack-func> must be a function that applies 'MARK_BAG' (see992** "InitMarkFuncBags") to each possible bag identifier on the application\'s993** stack, i.e., the stack where the applications local variables are saved.994** This should be a function of no arguments and return type 'void'. This995** function is called from 'CollectBags' to mark all bags that are996** accessible from local variables. There is a generic function for this997** purpose, which is called when the application passes 0 as <stack-func>,998** which will work all right on most machines, but *may* fail on some of the999** more exotic machines.1000**1001** If the application passes 0 as value for <stack-func>, <stack-start> must1002** be the start of the stack. Note that the start of the stack is either1003** the bottom or the top of the stack, depending on whether the stack grows1004** upward or downward. A value that usually works is the address of the1005** argument 'argc' of the 'main' function of the application, i.e.,1006** '(Bag\*)\&argc'. If the application provides another <stack-func>,1007** <stack-start> is ignored.1008**1009** If the application passes 0 as value for <stack-func>, <stack-align> must1010** be the alignment of items of type 'Bag' on the stack. It must be a1011** divisor of 'sizeof(Bag)'. The addresses of all identifiers on the stack1012** must be a multiple of <stack-align>. So if it is 1, identifiers may be1013** anywhere on the stack, and if it is 'sizeof(Bag)', identifiers may only1014** be at addresses that are a multiple of 'sizeof(Bag)'. This value depends1015** on the machine, the operating system, and the compiler. If the1016** application provides another <stack-func>, <stack-align> is ignored.1017**1018** <cache-size> informs {\Gasman} whether the processor has a usable data1019** cache and how large it is measured in bytes. If the application passes1020** 0, {\Gasman} assumes that the processor has no data cache or a data cache1021** to small to be useful. In this case the entire free storage is made1022** available for allocations after garbage collections. If the application1023** passes a nonzero value, {\Gasman} assumes that this is the size of the1024** part of the data cache that should be used for the allocation area, and1025** tries to keep the allocation area small enough so that it fits. For a1026** processor that has separate data and instruction caches, the application1027** should pass the size of the data cache minus 65536. For a processor with1028** a unified cache, the application should pass the size of the unified1029** cache minus 131072. The application probably should not pass a value1030** less than 131072.1031**1032** The initialization flag <dirty> determines whether bags allocated by1033** 'NewBag' are initialized to contain only 0 or not. If <dirty> is 0, the1034** bags are initialized to contain only 0. If <dirty> is 1, the bags1035** initially contain random values. Note that {\Gasman} will be a little1036** bit faster if bags need not be initialized.1037**1038** <abort-func> should be a function that {\Gasman} should call in case that1039** something goes wrong, e.g., if it cannot allocation the initial1040** workspace. <abort-func> should be a function of one string argument, and1041** it might want to display this message before aborting the application.1042** This function should never return.1043*/1044typedef Bag * (* TNumAllocFuncBags) (1045Int size,1046UInt need );10471048typedef void (* TNumStackFuncBags) ( void );10491050typedef void (* TNumAbortFuncBags) (1051const Char * msg );10521053extern void InitBags (1054TNumAllocFuncBags alloc_func,1055UInt initial_size,1056TNumStackFuncBags stack_func,1057Bag * stack_bottom,1058UInt stack_align,1059UInt cache_size,1060UInt dirty,1061TNumAbortFuncBags abort_func );10621063/****************************************************************************1064**1065*F FinishBags() end GASMAN and free memory1066*/10671068extern void FinishBags( void );10691070/****************************************************************************1071**1072*F CallbackForAllBags( <func> ) call a C function on all non-zero mptrs1073**1074** This calls a C function on every bag, including ones that are not1075** reachable from the root, and will be deleted at the next garbage1076** collection, by simply walking the masterpointer area. Not terribly safe1077**1078*/10791080extern void CallbackForAllBags(1081void (*func)(Bag) );108210831084#endif // GAP_GASMAN_H10851086/****************************************************************************1087**10881089*E gasman.c . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here1090*/109110921093