CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

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

Path: gap4r8 / src / gasman.h
Views: 418346
1
/****************************************************************************
2
**
3
*W gasman.h GAP source Martin Schönert
4
**
5
**
6
*Y Copyright (C) 1996, Lehrstuhl D für Mathematik, RWTH Aachen, Germany
7
*Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland
8
*Y Copyright (C) 2002 The GAP Group
9
**
10
** This file declares the functions of Gasman, the GAP storage manager.
11
**
12
** {\Gasman} is a storage manager for applications written in C. That means
13
** that an application requests blocks of storage from {\Gasman}, which are
14
** called bags. After using a bag to store data, the application simply
15
** forgets the bag, and we say that such a block is dead. {\Gasman}
16
** implements an automatic, cooperating, compacting, generational,
17
** conservative storage manager. Automatic means that the application only
18
** allocates bags, but need not explicitly deallocate them. This is
19
** important for large or complex application, where explicit deallocation
20
** is difficult. Cooperating means that the allocation must cooperate with
21
** {\Gasman}, i.e., must follow certain rules. This information provided by
22
** the application makes {\Gasman} use less storage and run faster.
23
** Compacting means that {\Gasman} always compacts live bags such that the
24
** free storage is one large block. Because there is no fragmentation of
25
** the free storage {\Gasman} uses as little storage as possible.
26
** Generational means that {\Gasman} usually assumes that bags that have
27
** been live for some time are still live. This means that it can avoid
28
** most of the tests whether a bag is still live or already dead. Only when
29
** not enough storage can be reclaimed under this assumption does it perform
30
** all the tests. Conservative means that {\Gasman} may keep bags longer
31
** than necessary because the C compiler does not provide sufficient
32
** information to distinguish true references to bags from other values that
33
** happen to look like references.
34
*/
35
36
#ifndef GAP_GASMAN_H
37
#define GAP_GASMAN_H
38
39
/* This definition switches to the bigger bag header, supporting bags up to
40
4GB in length (lists limited to 1GB for other reasons) */
41
42
/* Experimental 16+48 bit type/size word for 64 bit systems */
43
44
/****************************************************************************
45
**
46
*V autoconf . . . . . . . . . . . . . . . . . . . . . . . . use "config.h"
47
*/
48
#include "config.h"
49
50
#include "atomic.h"
51
52
/* on 64 bit systems use only two words for bag header */
53
54
#if SIZEOF_VOID_P == 8
55
#define USE_NEWSHAPE
56
#elif !defined(SIZEOF_VOID_P) && !defined(USE_PRECOMPILED)
57
/* If SIZEOF_VOID_P has not been defined, and we are not currently
58
re-making the dependency list (via cnf/Makefile), then trigger
59
an error. */
60
#error Something is wrong with this GAP installation: SIZEOF_VOID_P not defined
61
#endif
62
63
64
/****************************************************************************
65
**
66
67
*T Bag . . . . . . . . . . . . . . . . . . . type of the identifier of a bag
68
**
69
** 'Bag'
70
**
71
** Each bag is identified by its *bag identifier*. That is each bag has a
72
** bag identifier and no two live bags have the same identifier. 'Bag' is
73
** the type of bag identifiers.
74
**
75
** 0 is a valid value of the type 'Bag', but is guaranteed not to be the
76
** identifier of any bag.
77
**
78
** 'NewBag' returns the identifier of the newly allocated bag and the
79
** application passes this identifier to every {\Gasman} function to tell it
80
** which bag it should operate on (see "NewBag", "TNUM_BAG", "SIZE_BAG",
81
** "PTR_BAG", "CHANGED_BAG", "RetypeBag", and "ResizeBag").
82
**
83
** Note that the identifier of a bag is different from the address of the
84
** data area of the bag. This address may change during a garbage
85
** collection while the identifier of a bag never changes.
86
**
87
** Bags that contain references to other bags must always contain the
88
** identifiers of these other bags, never the addresses of the data areas of
89
** the bags.
90
**
91
** Note that bag identifiers are recycled. That means that after a bag dies
92
** its identifier may be reused for a new bag.
93
**
94
** The following is defined in "system.h"
95
**
96
typedef UInt * * Bag;
97
*/
98
99
100
/****************************************************************************
101
**
102
*F TNUM_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . . . type of a bag
103
**
104
** 'TNUM_BAG( <bag> )'
105
**
106
** 'TNUM_BAG' returns the type of the bag with the identifier <bag>.
107
**
108
** Each bag has a certain type that identifies its structure. The type is a
109
** integer between 0 and 253. The types 254 and 255 are reserved for
110
** {\Gasman}. The application specifies the type of a bag when it allocates
111
** it with 'NewBag' and may later change it with 'RetypeBag' (see "NewBag"
112
** and "RetypeBag").
113
**
114
** {\Gasman} needs to know the type of a bag so that it knows which function
115
** to call to mark all subbags of a given bag (see "InitMarkFuncBags").
116
** Apart from that {\Gasman} does not care at all about types.
117
**
118
** Note that 'TNUM_BAG' is a macro, so do not call it with arguments that
119
** have side effects.
120
*/
121
122
#ifdef USE_NEWSHAPE
123
#define TNUM_BAG(bag) (*(*(bag)-2) & 0xFFFFL)
124
#else
125
#define TNUM_BAG(bag) (*(*(bag)-3))
126
#endif
127
128
/****************************************************************************
129
**
130
*F SIZE_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . . . size of a bag
131
**
132
** 'SIZE_BAG( <bag> )'
133
**
134
** 'SIZE_BAG' returns the size of the bag with the identifier <bag> in
135
** bytes.
136
**
137
** Each bag has a certain size. The size of a bag is measured in bytes.
138
** The size must be a value between 0 and $2^{24}-1$. The application
139
** specifies the size of a bag when it allocates it with 'NewBag' and may
140
** later change it with 'ResizeBag' (see "NewBag" and "ResizeBag").
141
**
142
** Note that 'SIZE_BAG' is a macro, so do not call it with arguments that
143
** have side effects.
144
*/
145
#ifdef USE_NEWSHAPE
146
#define SIZE_BAG(bag) (*(*(bag)-2) >> 16)
147
#else
148
#define SIZE_BAG(bag) (*(*(bag)-2))
149
#endif
150
151
#define LINK_BAG(bag) (*(Bag *)(*(bag)-1))
152
/****************************************************************************
153
**
154
*F PTR_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . pointer to a bag
155
**
156
** 'PTR_BAG( <bag> )'
157
**
158
** 'PTR_BAG' returns the address of the data area of the bag with identifier
159
** <bag>. Using this pointer the application can then read data from the
160
** bag or write data into it. The pointer is of type pointer to bag
161
** identifier, i.e., 'PTR_BAG(<bag>)[0]' is the identifier of the first
162
** subbag of the bag, etc. If the bag contains data in a different format,
163
** the application has to cast the pointer returned by 'PTR_BAG', e.g.,
164
** '(long\*)PTR_BAG(<bag>)'.
165
**
166
** Note that the address of the data area of a bag may change during a
167
** garbage collection. That is the value returned by 'PTR_BAG' may differ
168
** between two calls, if 'NewBag', 'ResizeBag', 'CollectBags', or any of the
169
** application\'s functions or macros that may call those functions, is
170
** called in between (see "NewBag", "ResizeBag", "CollectBags").
171
**
172
** The first rule for using {\Gasman} is{\:} *The application must not keep
173
** any pointers to or into the data area of any bag over calls to functions
174
** that may cause a garbage collection.*
175
**
176
** That means that the following code is incorrect{\:}
177
**
178
** ptr = PTR_BAG( old );
179
** new = NewBag( typeNew, sizeNew );
180
** *ptr = new;
181
**
182
** because the creation of the new bag may move the old bag, causing the
183
** pointer to point no longer to the data area of the bag. It must be
184
** written as follows{\:}
185
**
186
** new = NewBag( typeNew, sizeNew );
187
** ptr = PTR_BAG( old );
188
** *ptr = new;
189
**
190
** Note that even the following is incorrect{\:}
191
**
192
** PTR_BAG(old)[0] = NewBag( typeNew, sizeNew );
193
**
194
** because a C compiler is free to compile it to a sequence of instructions
195
** equivalent to first example. Thus whenever the evaluation of a function
196
** or a macro may cause a garbage collection there must be no call to
197
** 'PTR_BAG' in the same expression, except as argument to this function or
198
** macro.
199
**
200
** Note that after writing a bag identifier, e.g., 'new' in the above
201
** example, into the data area of another bag, 'old' in the above example,
202
** the application must inform {\Gasman} that it has changed the bag, by
203
** calling 'CHANGED_BAG(old)' in the above example (see "CHANGED_BAG").
204
**
205
** Note that 'PTR_BAG' is a macro, so do not call it with arguments that
206
** have side effects.
207
*/
208
#define PTR_BAG(bag) (*(Bag**)(bag))
209
210
211
/****************************************************************************
212
**
213
*F CHANGED_BAG(<bag>) . . . . . . . . notify Gasman that a bag has changed
214
**
215
** 'CHANGED_BAG( <bag> )'
216
**
217
** 'CHANGED_BAG' informs {\Gasman} that the bag with identifier <bag> has
218
** been changed by an assignment of another bag identifier.
219
**
220
** The second rule for using {\Gasman} is{\:} *After each assignment of a
221
** bag identifier into a bag the application must inform {\Gasman} that it
222
** has changed the bag before the next garbage collection can happen.*
223
**
224
** Note that the application need not inform {\Gasman} if it changes a bag
225
** by assigning something that is not an identifier of another bag.
226
**
227
** For example to copy all entries from one list into another the following
228
** code must be used{\:}
229
**
230
** for ( i = 0; i < SIZE-BAG(old)/sizeof(Bag); i++ )
231
** PTR_BAG(new)[i] = PTR_BAG(old)[i];
232
** CHANGED_BAG( new );
233
**
234
** On the other hand when the application allocates a matrix, where the
235
** allocation of each row may cause a garbage collection, the following code
236
** must be used{\:}
237
**
238
** mat = NewBag( T_MAT, n * sizeof(Bag) );
239
** for ( i = 0; i < n; i++ ) {
240
** row = NewBag( T_ROW, n * sizeof(Bag) );
241
** PTR_BAG(mat)[i] = row;
242
** CHANGED_BAG( mat );
243
** }
244
**
245
** Note that writing 'PTR_BAG(mat)[i] = NewBag( T_ROW, n\*\ sizeof(Bag) );'
246
** is incorrect as mentioned in the section for 'PTR_BAG' (see "PTR_BAG").
247
**
248
** Note that 'CHANGED_BAG' is a macro, so do not call it with arguments that
249
** have side effects.
250
*/
251
extern Bag * YoungBags;
252
253
extern Bag ChangedBags;
254
255
/*****
256
** MEMORY_CANARY provides (basic) support for catching out-of-bounds memory
257
** problems in GAP. This is done through the excellent 'valgrind' program.
258
** valgrind is of limited use in GAP normally, because it doesn't understand
259
** GAP's memory manager. Enabling MEMORY_CANARY will make an executable where
260
** valgrind will detect memory issues.
261
**
262
** At the moment the detection is limited to only writing off the last allocated
263
** block.
264
*/
265
266
#ifdef MEMORY_CANARY
267
extern void CHANGED_BAG_IMPL(Bag b);
268
#define CHANGED_BAG(bag) CHANGED_BAG_IMPL(bag);
269
#else
270
#define CHANGED_BAG(bag) \
271
if ( PTR_BAG(bag) <= YoungBags \
272
&& PTR_BAG(bag)[-1] == (bag) ) { \
273
PTR_BAG(bag)[-1] = ChangedBags; ChangedBags = (bag); }
274
275
#endif
276
277
/****************************************************************************
278
**
279
*F NewBag(<type>,<size>) . . . . . . . . . . . . . . . . allocate a new bag
280
**
281
** 'NewBag( <type>, <size> )'
282
**
283
** 'NewBag' allocates a new bag of type <type> and <size> bytes. 'NewBag'
284
** returns the identifier of the new bag, which must be passed as first
285
** argument to all other {\Gasman} functions.
286
**
287
** <type> must be a value between 0 and 253. The types 254 and 255 are
288
** reserved for {\Gasman}. The application can find the type of a bag with
289
** 'TNUM_BAG' and change it with 'RetypeBag' (see "TNUM_BAG" and
290
** "RetypeBag").
291
**
292
** It is probably a good idea to define symbolic constants for all types in
293
** a system wide header file, e.g., 'types.h', if only to avoid to
294
** accidently use the same value for two different types.
295
**
296
** <size> is the size of the new bag in bytes and must be a value between 0
297
** and $2^{24}-1$. The application can find the size of a bag with
298
** 'SIZE_BAG' and change it with 'ResizeBag' (see "SIZE_BAG" and
299
** "ResizeBag").
300
**
301
** If the initialization flag <dirty> is 0, all entries of the new bag will
302
** be initialized to 0; otherwise the entries of the new bag will contain
303
** random values (see "InitBags").
304
**
305
** What happens if {\Gasman} cannot get enough storage to perform an
306
** allocation depends on the behavior of the allocation function
307
** <alloc-func>. If <alloc-func> returns 0 when it cannot do a needed
308
** extension of the workspace, then 'NewBag' may return 0 to indicate
309
** failure, and the application has to check the return value of 'NewBag'
310
** for this. If <alloc-func> aborts when it cannot do a needed extension of
311
** the workspace, then the application will abort if 'NewBag' would not
312
** succeed. So in this case whenever 'NewBag' returns, it succeeded, and
313
** the application need not check the return value of 'NewBag' (see
314
** "InitBags").
315
**
316
** Note that 'NewBag' will perform a garbage collection if no free storage
317
** is available. During the garbage collection the addresses of the data
318
** areas of all bags may change. So you must not keep any pointers to or
319
** into the data areas of bags over calls to 'NewBag' (see "PTR_BAG").
320
*/
321
extern Bag NewBag (
322
UInt type,
323
UInt size );
324
325
326
/****************************************************************************
327
**
328
*F RetypeBag(<bag>,<new>) . . . . . . . . . . . . change the type of a bag
329
**
330
** 'RetypeBag( <bag>, <new> )'
331
**
332
** 'RetypeBag' changes the type of the bag with identifier <bag> to the new
333
** type <new>. The identifier, the size, and also the address of the data
334
** area of the bag do not change.
335
**
336
** 'Retype' is usually used to set or reset flags that are stored in the
337
** type of a bag. For example in {\GAP} there are two types of large
338
** integers, one for positive integers and one for negative integers. To
339
** compute the difference of a positive integer and a negative, {\GAP} uses
340
** 'RetypeBag' to temporarily change the second argument into a positive
341
** integer, and then adds the two operands. For another example when {\GAP}
342
** detects that a list is sorted and contains no duplicates, it changes the
343
** type of the bag with 'RetypeBag', and the new type indicates that this
344
** list has this property, so that this need not be tested again.
345
**
346
** It is, as usual, the responsibility of the application to ensure that the
347
** data stored in the bag makes sense when the bag is interpreted as a bag
348
** of type <type>.
349
*/
350
extern void RetypeBag (
351
Bag bag,
352
UInt new_type );
353
354
#define RetypeBagIfWritable(x,y) RetypeBag(x,y)
355
356
/****************************************************************************
357
**
358
*F ResizeBag(<bag>,<new>) . . . . . . . . . . . . change the size of a bag
359
**
360
** 'ResizeBag( <bag>, <new> )'
361
**
362
** 'ResizeBag' changes the size of the bag with identifier <bag> to the new
363
** size <new>. The identifier of the bag does not change, but the address
364
** of the data area of the bag may change. If the new size <new> is less
365
** than the old size, {\Gasman} throws away any data in the bag beyond the
366
** new size. If the new size <new> is larger than the old size, {\Gasman}
367
** extends the bag.
368
**
369
** If the initialization flag <dirty> is 0, all entries of an extension will
370
** be initialized to 0; otherwise the entries of an extension will contain
371
** random values (see "InitBags").
372
**
373
** What happens if {\Gasman} cannot get enough storage to perform an
374
** extension depends on the behavior of the allocation function
375
** <alloc-func>. If <alloc-func> returns 0 when it cannot do a needed
376
** extension of the workspace, then 'ResizeBag' may return 0 to indicate
377
** failure, and the application has to check the return value of 'ResizeBag'
378
** for this. If <alloc-func> aborts when it cannot do a needed extension of
379
** the workspace, then the application will abort if 'ResizeBag' would not
380
** succeed. So in this case whenever 'ResizeBag' returns, it succeeded, and
381
** the application need not check the return value of 'ResizeBag' (see
382
** "InitBags").
383
**
384
** Note that 'ResizeBag' will perform a garbage collection if no free
385
** storage is available. During the garbage collection the addresses of the
386
** data areas of all bags may change. So you must not keep any pointers to
387
** or into the data areas of bags over calls to 'ResizeBag' (see "PTR_BAG").
388
*/
389
extern UInt ResizeBag (
390
Bag bag,
391
UInt new_size );
392
393
394
/****************************************************************************
395
**
396
*F CollectBags(<size>,<full>) . . . . . . . . . . . . . . collect dead bags
397
**
398
** 'CollectBags( <size>, <full> )'
399
**
400
** 'CollectBags' performs a garbage collection. This means it deallocates
401
** the dead bags and compacts the live bags at the beginning of the
402
** workspace. If <full> is 0, then only the dead young bags are
403
** deallocated, otherwise all dead bags are deallocated.
404
**
405
** If the application calls 'CollectBags', <size> must be 0, and <full> must
406
** be 0 or 1 depending on whether it wants to perform a partial or a full
407
** garbage collection.
408
**
409
** If 'CollectBags' is called from 'NewBag' or 'ResizeBag', <size> is the
410
** size of the bag that is currently allocated, and <full> is zero.
411
**
412
** Note that during the garbage collection the addresses of the data areas
413
** of all bags may change. So you must not keep any pointers to or into the
414
** data areas of bags over calls to 'CollectBags' (see "PTR_BAG").
415
*/
416
extern UInt CollectBags (
417
UInt size,
418
UInt full );
419
420
421
/****************************************************************************
422
**
423
*F SwapMasterPoint( <bag1>, <bag2> ) . . . swap pointer of <bag1> and <bag2>
424
*/
425
extern void SwapMasterPoint (
426
Bag bag1,
427
Bag bag2 );
428
429
430
/****************************************************************************
431
**
432
*V NrAllBags . . . . . . . . . . . . . . . . . number of all bags allocated
433
*V SizeAllBags . . . . . . . . . . . . . . total size of all bags allocated
434
*V NrLiveBags . . . . . . . . . . number of bags that survived the last gc
435
*V SizeLiveBags . . . . . . . total size of bags that survived the last gc
436
*V NrDeadBags . . . . . . . number of bags that died since the last full gc
437
*V SizeDeadBags . . . . total size of bags that died since the last full gc
438
**
439
** 'NrAllBags'
440
**
441
** 'NrAllBags' is the number of bags allocated since Gasman was initialized.
442
** It is incremented for each 'NewBag' call.
443
**
444
** 'SizeAllBags'
445
**
446
** 'SizeAllBags' is the total size of bags allocated since Gasman was
447
** initialized. It is incremented for each 'NewBag' call.
448
**
449
** 'NrLiveBags'
450
**
451
** 'NrLiveBags' is the number of bags that were live after the last garbage
452
** collection. So after a full garbage collection it is simply the number
453
** of bags that have been found to be still live by this garbage collection.
454
** After a partial garbage collection it is the sum of the previous value of
455
** 'NrLiveBags', which is the number of live old bags, and the number of
456
** bags that have been found to be still live by this garbage collection,
457
** which is the number of live young bags. This value is used in the
458
** information messages, and to find out how many free identifiers are
459
** available.
460
**
461
** 'SizeLiveBags'
462
**
463
** 'SizeLiveBags' is the total size of bags that were live after the last
464
** garbage collection. So after a full garbage collection it is simply the
465
** total size of bags that have been found to be still live by this garbage
466
** collection. After a partial garbage collection it is the sum of the
467
** previous value of 'SizeLiveBags', which is the total size of live old
468
** bags, and the total size of bags that have been found to be still live by
469
** this garbage collection, which is the total size of live young bags.
470
** This value is used in the information messages.
471
**
472
** 'NrDeadBags'
473
**
474
** 'NrDeadBags' is the number of bags that died since the last full garbage
475
** collection. So after a full garbage collection this is zero. After a
476
** partial garbage collection it is the sum of the previous value of
477
** 'NrDeadBags' and the number of bags that have been found to be dead by
478
** this garbage collection. This value is used in the information messages.
479
**
480
** 'SizeDeadBags'
481
**
482
** 'SizeDeadBags' is the total size of bags that died since the last full
483
** garbage collection. So after a full garbage collection this is zero.
484
** After a partial garbage collection it is the sum of the previous value of
485
** 'SizeDeadBags' and the total size of bags that have been found to be dead
486
** by this garbage collection. This value is used in the information
487
** message.
488
**
489
** 'NrHalfDeadBags'
490
**
491
** 'NrHalfDeadBags' is the number of bags that have been found to be
492
** reachable only by way of weak pointers since the last garbage collection.
493
** The bodies of these bags are deleted, but their identifiers are marked so
494
** that weak pointer objects can recognize this situation.
495
*/
496
497
extern UInt NrAllBags;
498
extern UInt SizeAllBags;
499
extern UInt NrLiveBags;
500
extern UInt SizeLiveBags;
501
extern UInt NrDeadBags;
502
extern UInt SizeDeadBags;
503
extern UInt NrHalfDeadBags;
504
505
506
/****************************************************************************
507
**
508
*V InfoBags[<type>] . . . . . . . . . . . . . . . . . information for bags
509
**
510
** 'InfoBags[<type>]'
511
**
512
** 'InfoBags[<type>]' is a structure containing information for bags of the
513
** type <type>.
514
**
515
** 'InfoBags[<type>].name' is the name of the type <type>. Note that it is
516
** the responsibility of the application using {\Gasman} to enter this
517
** name.
518
**
519
** 'InfoBags[<type>].nrLive' is the number of bags of type <type> that are
520
** currently live.
521
**
522
** 'InfoBags[<type>].nrAll' is the total number of all bags of <type> that
523
** have been allocated.
524
**
525
** 'InfoBags[<type>].sizeLive' is the sum of the sizes of the bags of type
526
** <type> that are currently live.
527
**
528
** 'InfoBags[<type>].sizeAll' is the sum of the sizes of all bags of type
529
** <type> that have been allocated.
530
**
531
** This information is only kept if {\Gasman} is compiled with the option
532
** '-DCOUNT_BAGS', e.g., with 'make <target> COPTS=-DCOUNT_BAGS'.
533
*/
534
typedef struct {
535
const Char * name;
536
UInt nrLive;
537
UInt nrAll;
538
UInt sizeLive;
539
UInt sizeAll;
540
} TNumInfoBags;
541
542
extern TNumInfoBags InfoBags [ 256 ];
543
544
#define MakeBagTypePublic(type) do { } while(0)
545
#define MakeBagTypeProtected(type) do { } while(0)
546
#define MakeBagPublic(bag) do { } while(0)
547
#define MakeBagReadOnly(bag) do { } while(0)
548
549
/****************************************************************************
550
**
551
*F InitMsgsFuncBags(<msgs-func>) . . . . . . . . . install message function
552
**
553
** 'InitMsgsFuncBags( <msgs-func> )'
554
**
555
** 'InitMsgsFuncBags' installs the function <msgs-func> as function used by
556
** {\Gasman} to print messages during garbage collections. <msgs-func> must
557
** be a function of three 'unsigned long' arguments <full>, <phase>, and
558
** <nr>. <msgs-func> should format this information and display it in an
559
** appropriate way. In fact you will usually want to ignore the messages
560
** for partial garbage collections, since there are so many of those. If
561
** you do not install a messages function with 'InitMsgsFuncBags', then
562
** 'CollectBags' will be silent.
563
**
564
** If <full> is 1, the current garbage collection is a full one. If <phase>
565
** is 0, the garbage collection has just started and <nr> should be ignored
566
** in this case. If <phase> is 1 respectively 2, the garbage collection has
567
** completed the mark phase and <nr> is the total number respectively the
568
** total size of live bags. If <phase> is 3 respectively 4, the garbage
569
** collection has completed the sweep phase, and <nr> is the number
570
** respectively the total size of bags that died since the last full garbage
571
** collection. If <phase> is 5 respectively 6, the garbage collection has
572
** completed the check phase and <nr> is the size of the free storage
573
** respectively the size of the workspace. All sizes are measured in KByte.
574
**
575
** If <full> is 0, the current garbage collection is a partial one. If
576
** <phase> is 0, the garbage collection has just started and <nr> should be
577
** ignored in this case. If <phase> is 1 respectively 2, the garbage
578
** collection has completed the mark phase and <nr> is the number
579
** respectively the total size of bags allocated since the last garbage
580
** collection that are still live. If <phase> is 3 respectively 4, the
581
** garbage collection has completed the sweep phase and <nr> is the number
582
** respectively the total size of bags allocated since the last garbage
583
** collection that are already dead (thus the sum of the values from phase 1
584
** and 3 is the total number of bags allocated since the last garbage
585
** collection). If <phase> is 5 respectively 6, the garbage collection has
586
** completed the check phase and <nr> is the size of the free storage
587
** respectively the size of the workspace. All sizes are measured in KByte.
588
**
589
** The message function should display the information for each phase
590
** immediatly, i.e., by calling 'flush' if the output device is a file, so
591
** that the user has some indication how much time each phase used.
592
**
593
** For example {\GAP} displays messages for full garbage collections in the
594
** following form{\:}
595
**
596
** #G FULL 47601/ 2341KB live 70111/ 5361KB dead 1376/ 4096KB free
597
**
598
** where 47601 is the total number of bags surviving the garbage collection,
599
** using 2341 KByte, 70111 is the total number of bags that died since the
600
** last full garbage collection, using 5361 KByte, 1376 KByte are free and
601
** the total size of the workspace is 4096 KByte.
602
**
603
** And partial garbage collections are displayed in {\GAP} in the following
604
** form{\:}
605
**
606
** #G PART 34/ 41KB+live 3016/ 978KB+dead 1281/ 4096KB free
607
**
608
** where 34 is the number of young bags that were live after this garbage
609
** collection, all the old bags survived it anyhow, using 41 KByte, 3016 is
610
** the number of young bags that died since the last garbage collection, so
611
** 34+3016 is the number of bags allocated between the last two garbage
612
** collections, using 978 KByte and the other two numbers are as above.
613
*/
614
typedef void (* TNumMsgsFuncBags) (
615
UInt full,
616
UInt phase,
617
Int nr );
618
619
extern void InitMsgsFuncBags (
620
TNumMsgsFuncBags msgs_func );
621
622
623
/****************************************************************************
624
**
625
*F InitMarkFuncBags(<type>,<mark-func>) . . . . . install marking function
626
*F MarkNoSubBags(<bag>) . . . . . . . . marking function that marks nothing
627
*F MarkOneSubBags(<bag>) . . . . . . marking function that marks one subbag
628
*F MarkTwoSubBags(<bag>) . . . . . . marking function that marks two subbags
629
*F MarkAllSubBags(<bag>) . . . . . . marking function that marks everything
630
*F MARK_BAG(<bag>) . . . . . . . . . . . . . . . . . . . mark a bag as live
631
**
632
** 'InitMarkFuncBags( <type>, <mark-func> )'
633
**
634
** 'InitMarkFuncBags' installs the function <mark-func> as marking function
635
** for bags of type <type>. The application *must* install a marking
636
** function for a type before it allocates any bag of that type. It is
637
** probably best to install all marking functions before allocating any bag.
638
**
639
** A marking function is a function that takes a single argument of type
640
** 'Bag' and returns nothing, i.e., has return type 'void'. Such a function
641
** must apply the macro 'MARK_BAG' to each bag identifier that appears in
642
** the bag (see below).
643
**
644
** Those functions are applied during the garbage collection to each marked
645
** bag, i.e., bags that are assumed to be still live, to also mark their
646
** subbags. The ability to use the correct marking function is the only use
647
** that {\Gasman} has for types.
648
**
649
** 'MARK_BAG( <bag> )'
650
**
651
** 'MARK_BAG' marks the <bag> as live so that it is not thrown away during
652
** a garbage collection. 'MARK_BAG' should only be called from the marking
653
** functions installed with 'InitMarkFuncBags'.
654
**
655
** 'MARK_BAG' tests if <bag> is a valid identifier of a bag in the young
656
** bags area. If it is not, then 'MARK_BAG' does nothing, so there is no
657
** harm in calling 'MARK_BAG' for something that is not actually a bag
658
** identifier.
659
**
660
** Note that 'MARK_BAG' is a macro, so do not call it with an argument that
661
** has side effects.
662
**
663
** 'MarkBagWeakly( <bag> )'
664
**
665
** 'MarkBagWeakly' is an alternative to MARK_BAG, intended to be used by the
666
** marking functions of weak pointer objects. A bag which is marked both
667
** weakly and strongly is treated as strongly marked. A bag which is only
668
** weakly marked will be recovered by garbage collection, but its identifier
669
** remains, marked in a way which can be detected by
670
** "IS_WEAK_DEAD_BAG". Which should always be checked before copying or
671
** using such an identifier.
672
**
673
**
674
** {\Gasman} already provides the following marking functions.
675
**
676
** 'MarkNoSubBags( <bag> )'
677
**
678
** 'MarkNoSubBags' is a marking function for types whose bags contain no
679
** identifier of other bags. It does nothing, as its name implies, and
680
** simply returns. For example in {\GAP} the bags for large integers
681
** contain only the digits and no identifiers of bags.
682
**
683
** 'MarkOneSubBags( <bag> )'
684
**
685
** 'MarkOneSubBags' is a marking function for types whose bags contain
686
** exactly one identifier of another bag as the first entry. It marks this
687
** subbag and returns. For example in {\GAP} bags for finite field elements
688
** contain exactly one bag identifier for the finite field the element
689
** belongs to.
690
**
691
** 'MarkTwoSubBags( <bag> )'
692
**
693
** 'MarkTwoSubBags' is a marking function for types whose bags contain
694
** exactly two identifiers of other bags as the first and second entry such
695
** as the binary operations bags. It marks those subbags and returns. For
696
** example in {\GAP} bags for rational numbers contain exactly two bag
697
** identifiers for the numerator and the denominator.
698
**
699
** 'MarkAllSubBags( <bag> )'
700
**
701
** 'MarkAllSubBags' is the marking function for types whose bags contain
702
** only identifier of other bags. It marks every entry of such a bag. Note
703
** that 'MarkAllSubBags' assumes that all identifiers are at offsets from
704
** the address of the data area of <bag> that are divisible by
705
** 'sizeof(Bag)'. Note also that since it does not do any harm to mark
706
** something which is not actually a bag identifier one could use
707
** 'MarkAllSubBags' for all types as long as the identifiers in the data
708
** area are properly aligned as explained above. This would however slow
709
** down 'CollectBags'. For example in {\GAP} bags for lists contain only
710
** bag identifiers for the elements of the list or 0 if an entry has no
711
** assigned value.
712
** */
713
714
715
typedef void (* TNumMarkFuncBags ) (
716
Bag bag );
717
718
extern void InitMarkFuncBags (
719
UInt type,
720
TNumMarkFuncBags mark_func );
721
722
extern void MarkNoSubBags (
723
Bag bag );
724
725
extern void MarkOneSubBags (
726
Bag bag );
727
728
extern void MarkTwoSubBags (
729
Bag bag );
730
731
extern void MarkThreeSubBags (
732
Bag bag );
733
734
extern void MarkFourSubBags (
735
Bag bag );
736
737
extern void MarkAllSubBags (
738
Bag bag );
739
740
extern void MarkBagWeakly (
741
Bag bag );
742
743
extern Bag * MptrBags;
744
extern Bag * OldBags;
745
extern Bag * AllocBags;
746
extern Bag MarkedBags;
747
748
#define MARKED_DEAD(x) (x)
749
#define MARKED_ALIVE(x) ((Bag)(((Char *)(x))+1))
750
#define MARKED_HALFDEAD(x) ((Bag)(((Char *)(x))+2))
751
#define IS_MARKED_ALIVE(bag) ((PTR_BAG(bag)[-1]) == MARKED_ALIVE(bag))
752
#define IS_MARKED_DEAD(bag) ((PTR_BAG(bag)[-1]) == MARKED_DEAD(bag))
753
#define IS_MARKED_HALFDEAD(bag) ((PTR_BAG(bag)[-1]) == MARKED_HALFDEAD(bag))
754
#define UNMARKED_DEAD(x) (x)
755
#define UNMARKED_ALIVE(x) ((Bag)(((Char *)(x))-1))
756
#define UNMARKED_HALFDEAD(x) ((Bag)(((Char *)(x))-2))
757
758
759
#define MARK_BAG(bag) \
760
if ( (((UInt)(bag)) & (sizeof(Bag)-1)) == 0 \
761
&& (Bag)MptrBags <= (bag) && (bag) < (Bag)OldBags \
762
&& YoungBags < PTR_BAG(bag) && PTR_BAG(bag) <= AllocBags \
763
&& (IS_MARKED_DEAD(bag) || IS_MARKED_HALFDEAD(bag)) ) \
764
{ \
765
PTR_BAG(bag)[-1] = MarkedBags; MarkedBags = (bag); }
766
767
extern void MarkAllSubBagsDefault ( Bag );
768
769
770
/****************************************************************************
771
**
772
*F
773
*/
774
775
#define IS_WEAK_DEAD_BAG(bag) ( (((UInt)bag & (sizeof(Bag)-1)) == 0) && \
776
(Bag)MptrBags <= (bag) && \
777
(bag) < (Bag)OldBags && \
778
(((UInt)*bag) & (sizeof(Bag)-1)) == 1)
779
780
781
/****************************************************************************
782
**
783
*F InitSweepFuncBags(<type>,<sweep-func>) . . . . install sweeping function
784
**
785
** 'InitSweepFuncBags( <type>, <sweep-func> )'
786
**
787
** 'InitSweepFuncBags' installs the function <sweep-func> as sweeping
788
** function for bags of type <type>.
789
**
790
** A sweeping function is a function that takes two arguments src and dst of
791
** type Bag *, and a third, length of type UInt, and returns nothing. When
792
** it is called, src points to the start of the data area of one bag, and
793
** dst to another. The function should copy the data from the source bag to
794
** the destination, making any appropriate changes.
795
**
796
** Those functions are applied during the garbage collection to each marked
797
** bag, i.e., bags that are assumed to be still live to move them to their
798
** new position. The intended use is for weak pointer bags, which must
799
** remove references to identifiers of any half-dead objects.
800
**
801
** If no function is installed for a TNum, then the data is simply copied
802
** unchanged and this is done particularly quickly
803
*/
804
805
typedef void (* TNumSweepFuncBags ) (
806
Bag * src,
807
Bag * dst,
808
UInt length);
809
810
extern void InitSweepFuncBags (
811
UInt tnum,
812
TNumSweepFuncBags sweep_func );
813
814
815
816
/****************************************************************************
817
**
818
*V GlobalBags . . . . . . . . . . . . . . . . . . . . . list of global bags
819
*/
820
#ifndef NR_GLOBAL_BAGS
821
#define NR_GLOBAL_BAGS 20000L
822
#endif
823
824
825
typedef struct {
826
Bag * addr [NR_GLOBAL_BAGS];
827
const Char * cookie [NR_GLOBAL_BAGS];
828
UInt nr;
829
} TNumGlobalBags;
830
831
extern TNumGlobalBags GlobalBags;
832
833
834
/****************************************************************************
835
**
836
*F InitGlobalBag(<addr>) . . . . . inform Gasman about global bag identifier
837
**
838
** 'InitGlobalBag( <addr>, <cookie> )'
839
**
840
** 'InitGlobalBag' informs {\Gasman} that there is a bag identifier at the
841
** address <addr>, which must be of type '(Bag\*)'. {\Gasman} will look at
842
** this address for a bag identifier during a garbage collection.
843
**
844
** The application *must* call 'InitGlobalBag' for every global variable and
845
** every entry of a global array that may hold a bag identifier. It is no
846
** problem if such a variable does not actually hold a bag identifier,
847
** {\Gasman} will simply ignore it then.
848
**
849
** There is a limit on the number of calls to 'InitGlobalBags', which is 512
850
** by default. If the application has more global variables that may hold
851
** bag identifier, you have to compile {\Gasman} with a higher value of
852
** 'NR_GLOBAL_BAGS', i.e., with 'make COPTS=-DNR_GLOBAL_BAGS=<nr>'.
853
**
854
** <cookie> is a C string, which should uniquely identify this global
855
** bag from all others. It is used in reconstructing the Workspace
856
** after a save and load
857
*/
858
859
extern Int WarnInitGlobalBag;
860
861
extern void InitGlobalBag (
862
Bag * addr,
863
const Char * cookie );
864
865
extern void SortGlobals( UInt byWhat );
866
867
extern Bag * GlobalByCookie(
868
const Char * cookie );
869
870
871
extern void StartRestoringBags( UInt nBags, UInt maxSize);
872
873
874
extern Bag NextBagRestoring( UInt size, UInt type);
875
876
877
extern void FinishedRestoringBags( void );
878
879
880
881
/****************************************************************************
882
**
883
*F InitFreeFuncBag(<type>,<free-func>) . . . . . . install freeing function
884
**
885
** 'InitFreeFuncBag( <type>, <free-func> )'
886
**
887
** 'InitFreeFuncBag' installs the function <free-func> as freeing function
888
** for bags of type <type>.
889
**
890
** A freeing function is a function that takes a single argument of type
891
** 'Bag' and returns nothing, i.e., has return type 'void'. If such a
892
** function is installed for a type <type> then it is called for each bag of
893
** that type that is about to be deallocated.
894
**
895
** A freeing function must *not* call 'NewBag', 'ResizeBag', or 'RetypeBag'.
896
**
897
** When such a function is called for a bag <bag>, its subbags are still
898
** accessible. Note that it it not specified, whether the freeing functions
899
** for the subbags of <bag> (if there are freeing functions for bags of
900
** their types) are called before or after the freeing function for <bag>.
901
*/
902
typedef void (* TNumFreeFuncBags ) (
903
Bag bag );
904
905
extern void InitFreeFuncBag (
906
UInt type,
907
TNumFreeFuncBags free_func );
908
909
910
/****************************************************************************
911
**
912
*F InitCollectFuncBags(<bfr-func>,<aft-func>) . install collection functions
913
**
914
** 'InitCollectFuncBags( <before-func>, <after-func> )'
915
**
916
** 'InitCollectFuncBags' installs the functions <before-func> and
917
** <after-func> as collection functions.
918
**
919
** The <before-func> will be called before each garbage collection, the
920
** <after-func> will be called after each garbage collection. One use of
921
** the <before-func> is to call 'CHANGED_BAG' for bags that change very
922
** often, so you do not have to call 'CHANGED_BAG' for them every time they
923
** change. One use of the <after-func> is to update a pointer for a bag, so
924
** you do not have to update that pointer after every operation that might
925
** cause a garbage collection.
926
*/
927
typedef void (* TNumCollectFuncBags) ( void );
928
929
extern void InitCollectFuncBags (
930
TNumCollectFuncBags before_func,
931
TNumCollectFuncBags after_func );
932
933
934
/****************************************************************************
935
**
936
*F CheckMasterPointers() . . . . . . . . . . . . .do some consistency checks
937
**
938
** 'CheckMasterPointers()' tests for masterpoinetrs which are not one of the
939
** following:
940
**
941
** 0 denoting the end of the free chain
942
** NewWeakDeadBagMarker denoting the relic of a bag that was weakly
943
** OldWeakDeadBagMarker but not strongly linked at the last garbage
944
** collection
945
** a pointer into the masterpointer area a link on the free chain
946
** a pointer into the bags area a real object
947
**
948
*/
949
950
extern void CheckMasterPointers( void );
951
952
/****************************************************************************
953
**
954
*F InitBags(...) . . . . . . . . . . . . . . . . . . . . . initialize Gasman
955
**
956
** InitBags( <alloc-func>, <initial-size>,
957
** <stack-func>, <stack-start>, <stack-align>,
958
** <cache-size>, <dirty>, <abort-func> )
959
**
960
** 'InitBags' initializes {\Gasman}. It must be called from a application
961
** using {\Gasman} before any bags can be allocated.
962
**
963
** <alloc-func> must be the function that {\Gasman} uses to allocate the
964
** initial workspace and to extend the workspace. It must accept two 'long'
965
** arguments <size> and <need>. <size> is the amount of storage that it
966
** must allocate, and <need> indicates whether {\Gasman} really needs the
967
** storage or only wants it to have a reasonable amount of free storage.
968
**
969
** *Currently this function must return immediately adjacent areas on
970
** subsequent calls*. So 'sbrk' will work on most systems, but 'malloc'
971
** will not.
972
**
973
** If <need> is 0, <alloc-func> must either return the address of the
974
** extension to indicate success or return 0 if it cannot or does not want
975
** to extend the workspace. If <need> is 1, <alloc-func> must again return
976
** the address of the extension to indicate success and can either return 0
977
** or abort if it cannot or does not want to extend the workspace. This
978
** choice determines whether 'NewBag' and 'ResizeBag' may fail. If it
979
** returns 0, then 'NewBag' and 'ResizeBag' can fail. If it aborts, then
980
** 'NewBag' and 'ResizeBag' can never fail (see "NewBag" and "ResizeBag").
981
**
982
** <size> may also be negative if {\Gasman} has a large amount of free
983
** space, and wants to return some of it to the operating system. In this
984
** case <need> will always be 0. <alloc-func> can either accept this
985
** reduction of the workspace and return a nonzero value and return the
986
** storage to the operating system, or refuse this reduction and return 0.
987
**
988
** <initial-size> must be the size of the initial workspace that 'InitBags'
989
** should allocate. This value is automatically rounded up to the next
990
** multiple of 1/2 MByte by 'InitBags'.
991
**
992
** <stack-func> must be a function that applies 'MARK_BAG' (see
993
** "InitMarkFuncBags") to each possible bag identifier on the application\'s
994
** stack, i.e., the stack where the applications local variables are saved.
995
** This should be a function of no arguments and return type 'void'. This
996
** function is called from 'CollectBags' to mark all bags that are
997
** accessible from local variables. There is a generic function for this
998
** purpose, which is called when the application passes 0 as <stack-func>,
999
** which will work all right on most machines, but *may* fail on some of the
1000
** more exotic machines.
1001
**
1002
** If the application passes 0 as value for <stack-func>, <stack-start> must
1003
** be the start of the stack. Note that the start of the stack is either
1004
** the bottom or the top of the stack, depending on whether the stack grows
1005
** upward or downward. A value that usually works is the address of the
1006
** argument 'argc' of the 'main' function of the application, i.e.,
1007
** '(Bag\*)\&argc'. If the application provides another <stack-func>,
1008
** <stack-start> is ignored.
1009
**
1010
** If the application passes 0 as value for <stack-func>, <stack-align> must
1011
** be the alignment of items of type 'Bag' on the stack. It must be a
1012
** divisor of 'sizeof(Bag)'. The addresses of all identifiers on the stack
1013
** must be a multiple of <stack-align>. So if it is 1, identifiers may be
1014
** anywhere on the stack, and if it is 'sizeof(Bag)', identifiers may only
1015
** be at addresses that are a multiple of 'sizeof(Bag)'. This value depends
1016
** on the machine, the operating system, and the compiler. If the
1017
** application provides another <stack-func>, <stack-align> is ignored.
1018
**
1019
** <cache-size> informs {\Gasman} whether the processor has a usable data
1020
** cache and how large it is measured in bytes. If the application passes
1021
** 0, {\Gasman} assumes that the processor has no data cache or a data cache
1022
** to small to be useful. In this case the entire free storage is made
1023
** available for allocations after garbage collections. If the application
1024
** passes a nonzero value, {\Gasman} assumes that this is the size of the
1025
** part of the data cache that should be used for the allocation area, and
1026
** tries to keep the allocation area small enough so that it fits. For a
1027
** processor that has separate data and instruction caches, the application
1028
** should pass the size of the data cache minus 65536. For a processor with
1029
** a unified cache, the application should pass the size of the unified
1030
** cache minus 131072. The application probably should not pass a value
1031
** less than 131072.
1032
**
1033
** The initialization flag <dirty> determines whether bags allocated by
1034
** 'NewBag' are initialized to contain only 0 or not. If <dirty> is 0, the
1035
** bags are initialized to contain only 0. If <dirty> is 1, the bags
1036
** initially contain random values. Note that {\Gasman} will be a little
1037
** bit faster if bags need not be initialized.
1038
**
1039
** <abort-func> should be a function that {\Gasman} should call in case that
1040
** something goes wrong, e.g., if it cannot allocation the initial
1041
** workspace. <abort-func> should be a function of one string argument, and
1042
** it might want to display this message before aborting the application.
1043
** This function should never return.
1044
*/
1045
typedef Bag * (* TNumAllocFuncBags) (
1046
Int size,
1047
UInt need );
1048
1049
typedef void (* TNumStackFuncBags) ( void );
1050
1051
typedef void (* TNumAbortFuncBags) (
1052
const Char * msg );
1053
1054
extern void InitBags (
1055
TNumAllocFuncBags alloc_func,
1056
UInt initial_size,
1057
TNumStackFuncBags stack_func,
1058
Bag * stack_bottom,
1059
UInt stack_align,
1060
UInt cache_size,
1061
UInt dirty,
1062
TNumAbortFuncBags abort_func );
1063
1064
/****************************************************************************
1065
**
1066
*F FinishBags() end GASMAN and free memory
1067
*/
1068
1069
extern void FinishBags( void );
1070
1071
/****************************************************************************
1072
**
1073
*F CallbackForAllBags( <func> ) call a C function on all non-zero mptrs
1074
**
1075
** This calls a C function on every bag, including ones that are not
1076
** reachable from the root, and will be deleted at the next garbage
1077
** collection, by simply walking the masterpointer area. Not terribly safe
1078
**
1079
*/
1080
1081
extern void CallbackForAllBags(
1082
void (*func)(Bag) );
1083
1084
1085
#endif // GAP_GASMAN_H
1086
1087
/****************************************************************************
1088
**
1089
1090
*E gasman.c . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
1091
*/
1092
1093