-
Notifications
You must be signed in to change notification settings - Fork 42
Expand file tree
/
Copy pathma.c
More file actions
3824 lines (3262 loc) · 112 KB
/
ma.c
File metadata and controls
3824 lines (3262 loc) · 112 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#if HAVE_CONFIG_H
# include "config.h"
#endif
/*
* Portable dynamic memory allocator.
*/
#if HAVE_STDIO_H
# include <stdio.h>
#endif
#if HAVE_STDLIB_H
# include <stdlib.h>
#endif
#if HAVE_STRING_H
# include <string.h>
#endif
#if HAVE_MALLOC_H
# include <malloc.h>
#endif
#include "error.h"
#include "farg.h"
#include "ma.h"
#include "memcpy.h"
#include "scope.h"
#include "table.h"
// this was only ever disabled for Blue Gene, which has been removed.
#define ENABLE_ARMCI_MEM_OPTION 1
#if defined(ENABLE_CUDA_MEM)
extern int cudaMallocManaged(void** devPtr, size_t size, unsigned int flags);
#elif defined(ENABLE_ARMCI_MEM_OPTION)
extern void* ARMCI_Malloc_local(long bytes);
#endif
/*
* Memory layout:
*
* segment = heap_region stack_region
* region = block block block ...
* block = AD gap1 guard1 client_space guard2 gap2
*
* A segment of memory is obtained from the OS upon initialization.
* The low end of the segment is managed as a heap; the heap region
* grows from low addresses to high addresses. The high end of the
* segment is managed as a stack; the stack region grows from high
* addresses to low addresses.
*
* Each region consists of a series of contiguous blocks, one per
* allocation request, and possibly some unused space. Blocks in
* the heap region are either in use by the client (allocated and
* not yet deallocated) or not in use by the client (allocated and
* already deallocated). A block on the rightmost end of the heap
* region becomes part of the unused space upon deallocation.
* Blocks in the stack region are always in use by the client,
* because when a stack block is deallocated, it becomes part of
* the unused space.
*
* A block consists of the client space, i.e., the range of memory
* available for use by the application; guard words adjacent to
* each end of the client space to help detect improper memory access
* by the client; bookkeeping info (in an "allocation descriptor,"
* AD); and two gaps, each zero or more bytes long, to satisfy
* alignment constraints (specifically, to ensure that AD and
* client_space are aligned properly).
*/
/**
** constants
**/
/* return value for returns that should never execute */
#define DONTCARE (Integer)0
/* default total # of bytes */
#define DEFAULT_TOTAL_HEAP 524288 /* 2^19 */
#define DEFAULT_TOTAL_STACK 524288 /* 2^19 */
/* estimate of max # of outstanding allocation requests */
#define DEFAULT_REQUESTS_HEAP 1
#define DEFAULT_REQUESTS_STACK 1
/* bytes per address */
#define BPA 1
/* per-allocation storage overhead, excluding alignment gaps */
#define BLOCK_OVERHEAD_FIXED (sizeof(AD) + (2 * sizeof(Guard)))
/* block lengths are integral multiples of this */
/*
* Note that for machines on which sizeof(pointer)
* and sizeof(long) are different than sizeof(int), alignment issues
* can be tricky. For example, the fields of a struct (e.g.,
* client_space of AD) can be improperly aligned if the struct is
* dynamically placed (by MA) in such a way that the first field is
* properly aligned but sizes of subsequent fields accumulate to cause
* a later field to be misaligned. By defining the unit of alignment
* to be the biggest of the integer and pointer types, part of the
* problem is solved, but the sum of sizes of preceding fields can
* still potentially cause difficulty.
*/
#define ALIGNMENT sizeof(size_t)
/* min size of block split and placed on free list */
#define MINBLOCKSIZE mai_round((size_t)(ALIGNMENT + BLOCK_OVERHEAD_FIXED), \
(ulongi)ALIGNMENT)
/* signatures for guard words */
#define GUARD1 (Guard)0xaaaaaaaa /* start signature */
#define GUARD2 (Guard)0x55555555 /* stop signature */
/**
** types
**/
typedef unsigned int Guard; /* for detection of memory trashing */
typedef size_t ulongi; /* for brevity */
/* allocation request for a block */
typedef struct _AR
{
Integer datatype; /* of elements */
Integer nelem; /* # of elements */
} AR;
/* allocation descriptor for a block */
typedef struct _AD
{
Integer datatype; /* of elements */
Integer nelem; /* # of elements */
char name[MA_NAMESIZE]; /* given by client */
Pointer client_space; /* start of client space */
ulongi nbytes; /* total # of bytes */
struct _AD *next; /* AD in linked list */
ulongi checksum; /* of AD */
} AD;
/* block location for mh2ad */
typedef enum
{
BL_HeapOrStack,
BL_Heap,
BL_Stack,
BL_StackTop
} BlockLocation;
/**
** function types
**/
private Boolean ad_big_enough(AD *ad, Pointer ar);
private Boolean ad_eq(AD *ad, Pointer ad_target);
private Boolean ad_gt(AD *ad, Pointer ad_target);
private Boolean ad_le(AD *ad, Pointer ad_target);
private Boolean ad_lt(AD *ad, Pointer ad_target);
private void ad_print(AD *ad, char *block_type);
private void balloc_after(AR *ar, Pointer address, Pointer *client_space, ulongi *nbytes);
private void balloc_before(AR *ar, Pointer address, Pointer *client_space, ulongi *nbytes);
private void block_free_heap(AD *ad);
private AD *block_split(AD *ad, ulongi bytes_needed, Boolean insert_free);
private ulongi checksum(AD *ad);
#ifdef DEBUG
private void debug_ad_print(AD *ad);
#endif /* DEBUG */
private Boolean guard_check(AD *ad);
private void guard_set(AD *ad);
private void list_coalesce(AD *list);
private AD *list_delete(AD *ad, AD **list);
private int list_delete_many(AD **list, Boolean (*pred)(), Pointer closure, void (*action)());
private AD *list_delete_one(AD **list, Boolean (*pred)(), Pointer closure);
private void list_insert(AD *ad, AD **list);
private void list_insert_ordered(AD *ad, AD **list, Boolean (*pred)());
private Boolean list_member(AD *ad, AD *list);
private int list_print(AD *list, char *block_type, int index_base);
private void list_verify(AD *list, char *block_type, char *preamble, int *blocks, int *bad_blocks, int *bad_checksums, int *bad_lguards, int *bad_rguards);
private Integer ma_max_heap_frag_nelem(Integer datatype, Integer min_nelem);
private Integer ma_nelem(Pointer address, ulongi length, Integer datatype);
private void ma_preinitialize(char *caller);
private Boolean mh2ad(Integer memhandle, AD **adout, BlockLocation location, char *caller);
private void mh_free(AD *ad);
private size_t mai_round(size_t value, ulongi unit);
private void str_ncopy(char *to, char *from, int maxchars);
/* foreign routines */
extern Integer ma_set_sizes_(); /* from the MA FORTRAN interface */
/**
** variables
**/
/* base addresses of the datatypes */
private Pointer ma_base[] =
{
(Pointer)ma_cb_char, /* MT_C_CHAR */
(Pointer)ma_cb_int, /* MT_C_INT */
(Pointer)ma_cb_long, /* MT_C_LONGINT */
(Pointer)ma_cb_float, /* MT_C_FLOAT */
(Pointer)ma_cb_dbl, /* MT_C_DBL */
(Pointer)ma_cb_ldbl, /* MT_C_LDBL */
(Pointer)ma_cb_scpl, /* MT_C_SCPL */
(Pointer)ma_cb_dcpl, /* MT_C_DCPL */
(Pointer)ma_cb_ldcpl, /* MT_C_LDCPL */
0, /* MT_F_BYTE */
0, /* MT_F_INT */
0, /* MT_F_LOG */
0, /* MT_F_REAL */
0, /* MT_F_DBL */
0, /* MT_F_SCPL */
0, /* MT_F_DCPL */
(Pointer)ma_cb_longlong /* MT_C_LONGLONG */
};
/* names of the datatypes */
private char *ma_datatype[] =
{
"char",
"int",
"long int",
"float",
"double",
"long double",
"single precision complex",
"double precision complex",
"long double precision complex",
"byte",
"integer",
"logical",
"real",
"double precision",
"single precision complex",
"double precision complex",
"long long"
};
/* numbers of bytes in the datatypes */
private int ma_sizeof[] =
{
sizeof(char), /* MT_C_CHAR */
sizeof(int), /* MT_C_INT */
sizeof(long int), /* MT_C_LONGINT */
sizeof(float), /* MT_C_FLOAT */
sizeof(double), /* MT_C_DBL */
sizeof(MA_LongDouble), /* MT_C_LDBL */
sizeof(MA_SingleComplex), /* MT_C_SCPL */
sizeof(MA_DoubleComplex), /* MT_C_DCPL */
sizeof(MA_LongDoubleComplex), /* MT_C_LDCPL */
0, /* MT_F_BYTE */
0, /* MT_F_INT */
0, /* MT_F_LOG */
0, /* MT_F_REAL */
0, /* MT_F_DBL */
0, /* MT_F_SCPL */
0, /* MT_F_DCPL */
sizeof(long long) /* MT_C_LONGLONG */
};
/*
* Initially, ma_hp points to the start of the segment, and ma_sp
* points to the first address past the end of the segment. The
* start of the segment is always pointed to by ma_segment, and
* the first address past the end of the segment is always pointed
* to by ma_eos. The (unenforced) boundary between the heap region
* and the stack region, defined at initialization, is always pointed
* to by ma_partition.
*
* ................................................
* ^ ^ ^
* ma_segment, ma_hp ma_partition ma_eos, ma_sp
*
* Later, ma_hp points to the first address past the end of the
* rightmost heap block, and ma_sp points to the leftmost stack block.
*
* hhhhhhhhhhhhhhhh.....................sssssssssss
* ^ ^ ^ ^ ^
* ma_segment ma_hp ma_partition ma_sp ma_eos
*/
private Pointer ma_segment; /* memory from OS */
private Pointer ma_partition; /* boundary between heap and stack */
private Pointer ma_eos; /* end of segment */
private Pointer ma_hp; /* heap pointer */
private Pointer ma_sp; /* stack pointer */
private AD *ma_hfree; /* free list for heap */
private AD *ma_hused; /* used list for heap */
private AD *ma_sused; /* used list for stack */
/* toggled when ma_preinitialize succeeds */
private Boolean ma_preinitialized = MA_FALSE;
/* toggled when MA_init succeeds */
private Boolean ma_initialized = MA_FALSE;
/* invoke MA_verify_allocator_stuff in each public routine? */
private Boolean ma_auto_verify = MA_FALSE;
/* print push/pop/alloc/free? */
private Boolean ma_trace = MA_FALSE;
/* base arrays for the C datatypes */
public char ma_cb_char[2]; /* MT_C_CHAR */
public int ma_cb_int[2]; /* MT_C_INT */
public long ma_cb_long[2]; /* MT_C_LONGINT */
public long long ma_cb_longlong[2];/* MT_C_LONGLONG */
public float ma_cb_float[2]; /* MT_C_FLOAT */
public double ma_cb_dbl[2]; /* MT_C_DBL */
public MA_LongDouble ma_cb_ldbl[2]; /* MT_C_LDBL */
public MA_SingleComplex ma_cb_scpl[2]; /* MT_C_SCPL */
public MA_DoubleComplex ma_cb_dcpl[2]; /* MT_C_DCPL */
public MA_LongDoubleComplex ma_cb_ldcpl[2]; /* MT_C_LDCPL */
#if NOFORT
public Integer ma_fb_byte[2];
public Integer ma_fb_integer[2];
public Logical ma_fb_logical[2];
public Real ma_fb_real[2];
public DoublePrecision ma_fb_dbl[2];
public SingleComplex ma_fb_scpl[2];
public DoubleComplex ma_fb_dcpl[2];
#endif
/* requested power-of-two alignment */
private Integer ma_numalign = 0;
/**
** macros
**/
/* minimum of two values */
#ifdef min
#undef min
#endif
#define min(a, b) (((b) < (a)) ? (b) : (a))
/* maximum of two values */
#ifdef max
#undef max
#endif
#define max(a, b) (((b) > (a)) ? (b) : (a))
/* proper word ending corresponding to n */
#define plural(n) (((n) == 1) ? "" : "s")
/* convert between internal and external datatype values */
#define mt_import(d) ((d) - MT_BASE)
#define mt_export(d) ((d) + MT_BASE)
/* return nonzero if d is a valid (external) datatype */
#define mt_valid(d) (((d) >= MT_FIRST) && ((d) <= MT_LAST))
/* convert between pointer (address) and equivalent byte address */
#define p2b(p) ((ulongi)(p) * BPA)
#define b2p(b) ((Pointer)((b) / BPA))
/* return nonzero if a is a potentially valid address */
#define reasonable_address(a) (((a) >= ma_segment) && ((a) < ma_eos))
/* worst case bytes of overhead for any block of elements of datatype d */
#define max_block_overhead(d) \
(BLOCK_OVERHEAD_FIXED + (ma_sizeof[d] - 1) + (ALIGNMENT - 1))
/* compute 0-based index for client_space from AD */
#define client_space_index(ad) \
((MA_AccessIndex)((size_t)((ad)->client_space - ma_base[(ad)->datatype]) / \
ma_sizeof[(ad)->datatype]))
/* compute address of guard from AD */
#define guard1(ad) ((Pointer)((ad)->client_space - sizeof(Guard)))
#define guard2(ad) ((Pointer)((ad)->client_space \
+ ((ad)->nelem * ma_sizeof[(ad)->datatype])))
/*
* When reading or writing guard values, it is necessary to do an
* explicit byte copy to avoid bus errors caused by guards that
* are not suitably aligned.
*/
/* copy from guard to value */
#define guard_read(guard, value) bytecopy((guard), (value), sizeof(Guard))
/* copy from value to guard */
#define guard_write(guard, value) bytecopy((value), (guard), sizeof(Guard))
/**
** statistics stuff
**/
#ifdef STATS
/* the number of routines for which calls are counted */
#define NUMROUTINES ((int)FID_MA_verify_allocator_stuff + 1)
/* function identifiers */
typedef enum
{
FID_MA_alloc_get = 0,
FID_MA_allocate_heap,
FID_MA_chop_stack,
FID_MA_free_heap,
FID_MA_free_heap_piece,
FID_MA_get_index,
FID_MA_get_mbase,
FID_MA_get_next_memhandle,
FID_MA_get_numalign,
FID_MA_get_pointer,
FID_MA_init,
FID_MA_initialized,
FID_MA_init_memhandle_iterator,
FID_MA_inquire_avail,
FID_MA_inquire_heap,
FID_MA_inquire_heap_check_stack,
FID_MA_inquire_heap_no_partition,
FID_MA_inquire_stack,
FID_MA_inquire_stack_check_heap,
FID_MA_inquire_stack_no_partition,
FID_MA_pop_stack,
FID_MA_print_stats,
FID_MA_push_get,
FID_MA_push_stack,
FID_MA_set_auto_verify,
FID_MA_set_error_print,
FID_MA_set_hard_fail,
FID_MA_set_numalign,
FID_MA_sizeof,
FID_MA_sizeof_overhead,
FID_MA_summarize_allocated_blocks,
FID_MA_trace,
FID_MA_count_heap,
FID_MA_uncount_heap,
FID_MA_verify_allocator_stuff
} FID;
/* MA usage statistics */
typedef struct
{
ulongi hblocks; /* current # of heap blocks */
ulongi hblocks_max; /* max # of heap blocks */
ulongi hbytes; /* current # of heap bytes */
ulongi hbytes_max; /* max # of heap bytes */
ulongi sblocks; /* current # of stack blocks */
ulongi sblocks_max; /* max # of stack blocks */
ulongi sbytes; /* current # of stack bytes */
ulongi sbytes_max; /* max # of stack bytes */
ulongi calls[NUMROUTINES];/* # of calls to each routine */
} Stats;
/* names of the routines */
private char *ma_routines[] =
{
"MA_alloc_get",
"MA_allocate_heap",
"MA_chop_stack",
"MA_free_heap",
"MA_free_heap_piece",
"MA_get_index",
"MA_get_mbase",
"MA_get_next_memhandle",
"MA_get_numalign",
"MA_get_pointer",
"MA_init",
"MA_initialized",
"MA_init_memhandle_iterator",
"MA_inquire_avail",
"MA_inquire_heap",
"MA_inquire_heap_check_stack",
"MA_inquire_heap_no_partition",
"MA_inquire_stack",
"MA_inquire_stack_check_heap",
"MA_inquire_stack_no_partition",
"MA_pop_stack",
"MA_print_stats",
"MA_push_get",
"MA_push_stack",
"MA_set_auto_verify",
"MA_set_error_print",
"MA_set_hard_fail",
"MA_set_numalign",
"MA_sizeof",
"MA_sizeof_overhead",
"MA_summarize_allocated_blocks",
"MA_trace",
"MA_verify_allocator_stuff"
};
/* MA usage statistics */
private Stats ma_stats;
#endif /* STATS */
/**
** private routines
**/
/* ------------------------------------------------------------------------- */
/*
* Return MA_TRUE if ad can satisfy ar, else return MA_FALSE.
* If ad can satisfy ar, set its client_space and nbytes fields
* after performing any splitting.
*/
/* ------------------------------------------------------------------------- */
private Boolean ad_big_enough(ad, ar)
AD *ad; /* the AD to test */
Pointer ar; /* allocation request */
{
Pointer client_space; /* location of client_space */
ulongi nbytes; /* length of block for ar */
/* perform trial allocation to determine size */
balloc_after((AR *)ar, (Pointer)ad, &client_space, &nbytes);
if (nbytes <= ad->nbytes)
{
/* ad is big enough; split block if necessary */
(void)block_split(ad, nbytes, MA_TRUE);
/* set fields appropriately */
ad->client_space = client_space;
/* success */
return MA_TRUE;
}
else
/* ad is not big enough */
return MA_FALSE;
}
/* ------------------------------------------------------------------------- */
/*
* Return MA_TRUE if ad == ad_target, else return MA_FALSE.
*/
/* ------------------------------------------------------------------------- */
private Boolean ad_eq(ad, ad_target)
AD *ad; /* the AD to test */
Pointer ad_target; /* the AD to match */
{
return (ad == (AD *)ad_target) ? MA_TRUE : MA_FALSE;
}
/* ------------------------------------------------------------------------- */
/*
* Return MA_TRUE if ad > ad_target, else return MA_FALSE.
*/
/* ------------------------------------------------------------------------- */
private Boolean ad_gt(ad, ad_target)
AD *ad; /* the AD to test */
Pointer ad_target; /* the AD to match */
{
return (ad > (AD *)ad_target) ? MA_TRUE : MA_FALSE;
}
/* ------------------------------------------------------------------------- */
/*
* Return MA_TRUE if ad <= ad_target, else return MA_FALSE.
*/
/* ------------------------------------------------------------------------- */
private Boolean ad_le(ad, ad_target)
AD *ad; /* the AD to test */
Pointer ad_target; /* the AD to match */
{
return (ad <= (AD *)ad_target) ? MA_TRUE : MA_FALSE;
}
/* ------------------------------------------------------------------------- */
/*
* Return MA_TRUE if ad < ad_target, else return MA_FALSE.
*/
/* ------------------------------------------------------------------------- */
private Boolean ad_lt(ad, ad_target)
AD *ad; /* the AD to test */
Pointer ad_target; /* the AD to match */
{
return (ad < (AD *)ad_target) ? MA_TRUE : MA_FALSE;
}
/* ------------------------------------------------------------------------- */
/*
* Print identifying information about the given AD to stdout.
*/
/* ------------------------------------------------------------------------- */
private void ad_print(ad, block_type)
AD *ad; /* to print */
char *block_type; /* for output */
{
Integer memhandle; /* memhandle for AD */
/* convert AD to memhandle */
memhandle = ma_table_lookup_assoc((TableData)ad);
/* print to stdout */
(void)printf("%s block '%s', handle ",
block_type,
ad->name);
if (memhandle == TABLE_HANDLE_NONE)
(void)printf("unknown");
else
(void)printf("%ld",
(size_t)memhandle);
(void)printf(", address 0x%lx",
(size_t)ad);
}
/* ------------------------------------------------------------------------- */
/*
* Allocate a block suitable for ar starting at address. No fields of
* the new block are modified.
*/
/* ------------------------------------------------------------------------- */
private void balloc_after(ar, address, client_space, nbytes)
AR *ar; /* allocation request */
Pointer address; /* to allocate after */
Pointer *client_space; /* RETURN: location of client_space */
ulongi *nbytes; /* RETURN: length of block */
{
Integer datatype; /* of elements in this block */
ulongi L_client_space; /* length of client_space */
Pointer A_client_space; /* address of client_space */
int L_gap1; /* length of gap1 */
int L_gap2; /* length of gap2 */
ulongi B_address; /* byte equivalent of address */
ulongi B_base; /* byte equivalent of ma_base[datatype] */
ulongi B_client_space; /* byte equivalent of A_client_space */
datatype = ar->datatype;
B_address = p2b(address);
B_base = p2b(ma_base[datatype]);
/*
* To ensure that client_space is properly aligned:
*
* (A(client_space) - ma_base[datatype]) % ma_sizeof[datatype] == 0
*
* where
*
* A(client_space) == address + L(AD) + L(gap1) + L(guard1)
*/
L_client_space = ar->nelem * ma_sizeof[datatype];
L_gap1 = ((size_t)B_base
- (size_t)B_address
- (size_t)sizeof(AD)
- (size_t)sizeof(Guard))
% (size_t)ma_sizeof[datatype];
if (L_gap1 < 0)
L_gap1 += ma_sizeof[datatype];
B_client_space = B_address + sizeof(AD) + L_gap1 + sizeof(Guard);
A_client_space = b2p(B_client_space);
B_client_space = p2b(A_client_space);
/*
* To align client space according to overall alignment of absolute
* address on user requested 2^ma_numalign boundary.
* Note that if the base arrays are not aligned accordingly then
* this alignement request is not satisfiable and will be quietly
* ignored.
*/
if (ma_numalign > 0) {
size_t mask = (1<<ma_numalign)-1;
int diff = ((size_t) B_client_space) & mask;
/* Check that the difference is a multiple of the type size.
* If so, then we can shift the client space which is already
* aligned to satisfy this requirement.
*/
if (diff) {
diff = (1<<ma_numalign) - diff;
if ((diff % ma_sizeof[datatype]) == 0 ) {
/*printf("bafter realigned diff=%d\n",diff);*/
A_client_space = b2p(B_client_space + diff);
B_client_space = p2b(A_client_space);
}
/* else {
printf("did not realign diff=%d typelen=%d mod=%d\n",
diff, ma_sizeof[datatype], (diff % ma_sizeof[datatype]));
}*/
}
}
/*
* To ensure that the AD is properly aligned:
*
* L(block) % ALIGNMENT == 0
*
* where
*
* L(block) == A(client_space) + L(client_space) + L(guard2) + L(gap2)
* - address
*/
L_gap2 = ((size_t)B_address
- (size_t)B_client_space
- (size_t)L_client_space
- (size_t)sizeof(Guard))
% (size_t)ALIGNMENT;
if (L_gap2 < 0)
L_gap2 += ALIGNMENT;
/*
* set the return values
*/
*client_space = A_client_space;
*nbytes = (ulongi)(B_client_space
+ L_client_space
+ sizeof(Guard)
+ L_gap2
- B_address);
}
/* ------------------------------------------------------------------------- */
/*
* Allocate a block suitable for ar ending before address. No fields of
* the new block are modified.
*/
/* ------------------------------------------------------------------------- */
private void balloc_before(ar, address, client_space, nbytes)
AR *ar; /* allocation request */
Pointer address; /* to allocate before */
Pointer *client_space; /* RETURN: location of client_space */
ulongi *nbytes; /* RETURN: length of block */
{
Integer datatype; /* of elements in this block */
ulongi L_client_space; /* length of client_space */
Pointer A_client_space; /* address of client_space */
int L_gap1; /* length of gap1 */
int L_gap2; /* length of gap2 */
ulongi B_address; /* byte equivalent of address */
ulongi B_base; /* byte equivalent of ma_base[datatype] */
ulongi B_client_space; /* byte equivalent of A_client_space */
datatype = ar->datatype;
B_address = p2b(address);
B_base = p2b(ma_base[datatype]);
/*
* To ensure that client_space is properly aligned:
*
* (A(client_space) - ma_base[datatype]) % ma_sizeof[datatype] == 0
*
* where
*
* A(client_space) == address - L(gap2) - L(guard2) - L(client_space)
*/
L_client_space = ar->nelem * ma_sizeof[datatype];
L_gap2 = (B_address
- sizeof(Guard)
- L_client_space
- B_base)
% ma_sizeof[datatype];
if (L_gap2 < 0)
L_gap2 += ma_sizeof[datatype];
B_client_space = B_address - L_gap2 - sizeof(Guard) - L_client_space;
A_client_space = b2p(B_client_space);
B_client_space = p2b(A_client_space);
/*
* To align client space according to overall alignment of absolute
* address on user requested 2^ma_numalign boundary.
* Note that if the base arrays are not aligned accordingly then
* this alignement request is not satisfiable and will be quietly
* ignored.
*/
if (ma_numalign > 0) {
size_t mask = (1<<ma_numalign)-1;
int diff = ((size_t) B_client_space) & mask;
/* Check that the difference is a multiple of the type size.
* If so, then we can shift the client space which is already
* aligned to satisfy this requirement.
*/
if (diff) {
if ((diff % ma_sizeof[datatype]) == 0 ) {
/* printf("bbefore realigned diff=%d\n",diff); */
A_client_space = b2p(B_client_space - diff);
B_client_space = p2b(A_client_space);
}
/* else {
printf("did not realign diff=%d typelen=%d mod=%d\n",
diff, ma_sizeof[datatype], (diff % ma_sizeof[datatype]));
}*/
}
}
/*
* To ensure that the AD is properly aligned:
*
* A(AD) % ALIGNMENT == 0
*
* where
*
* A(AD) == A(client_space) - L(guard1) - L(gap1) - L(AD)
*/
L_gap1 = (B_client_space
- sizeof(Guard)
- sizeof(AD))
% ALIGNMENT;
/*
* set the return values
*/
*client_space = A_client_space;
*nbytes = (ulongi)(B_address
- B_client_space
+ sizeof(Guard)
+ L_gap1
+ sizeof(AD));
}
/* ------------------------------------------------------------------------- */
/*
* Reclaim the given block by updating ma_hp and ma_hfree.
*/
/* ------------------------------------------------------------------------- */
private void block_free_heap(ad)
AD *ad; /* AD to free */
{
AD *ad2; /* traversal pointer */
AD *max_ad; /* rightmost AD */
/* find rightmost heap block */
for (max_ad = (AD *)NULL, ad2 = ma_hused; ad2; ad2 = ad2->next)
{
if (ad2 > max_ad)
max_ad = ad2;
}
if (max_ad)
{
/* at least 1 block is in use */
/* set ma_hp to first address past end of max_ad */
ma_hp = (Pointer)max_ad + max_ad->nbytes;
/* delete any free list blocks that are no longer in heap region */
(void)list_delete_many(
&ma_hfree,
ad_gt,
(Pointer)max_ad,
(void (*)())NULL);
/* if ad is in the heap region, add it to free list */
if (ad < max_ad)
{
list_insert_ordered(ad, &ma_hfree, ad_lt);
list_coalesce(ma_hfree);
}
}
else
{
/* no blocks are in use */
/* set ma_hp to start of segment */
ma_hp = ma_segment;
/* clear the free list */
ma_hfree = (AD *)NULL;
}
}
/* ------------------------------------------------------------------------- */
/*
* If ad is sufficiently bigger than bytes_needed bytes, create a new
* block from the remainder, optionally insert it in the free list,
* and set the lengths of both blocks.
*
* Return a pointer to the new block (NULL if not created).
*/
/* ------------------------------------------------------------------------- */
private AD *block_split(ad, bytes_needed, insert_free)
AD *ad; /* the AD to split */
ulongi bytes_needed; /* from ad */
Boolean insert_free; /* insert in free list? */
{
ulongi bytes_extra; /* in ad */
AD *ad2; /* the new AD */
/* caller ensures that ad->nbytes >= bytes_needed */
bytes_extra = ad->nbytes - bytes_needed;
if (bytes_extra >= ((ulongi)MINBLOCKSIZE))
{
/* create a new block */
ad2 = (AD *)((Pointer)ad + bytes_needed);
/* set the length of ad2 */
ad2->nbytes = bytes_extra;
if (insert_free)
{
/* insert ad2 into free list */
list_insert_ordered(ad2, &ma_hfree, ad_lt);
}
/* set the length of ad */
ad->nbytes = bytes_needed;
return ad2;
}
else
{
/*
* If 0 <= bytes_extra < MINBLOCKSIZE then there are too few
* extra bytes to form a new block. In this case, we simply
* do nothing; ad will retain its original length (which is
* either perfect or slightly too big), and the entire block
* will be reclaimed upon deallocation, preventing any
* memory leakage.
*/
return (AD *)NULL;
}
}
/* ------------------------------------------------------------------------- */
/*
* Compute and return a checksum for ad. Include all fields except name,
* next, and checksum.
*/
/* ------------------------------------------------------------------------- */
private ulongi checksum(ad)
AD *ad; /* the AD to compute checksum for */
{
return (ulongi)(
ad->datatype +
ad->nelem +
(ulongi)ad->client_space +
ad->nbytes);
}
/* ------------------------------------------------------------------------- */
/*
* Print to stderr the addresses of the fields of the given ad.
*/
/* ------------------------------------------------------------------------- */
#ifdef DEBUG
private void debug_ad_print(ad)
AD *ad; /* the AD to print */
{
#define NUMADFIELDS 7
char *fn[NUMADFIELDS]; /* field names */
size_t fa[NUMADFIELDS]; /* field addresses */
int i; /* loop index */
size_t address; /* other addresses */
/* set field names */
fn[0] = "datatype";
fn[1] = "nelem";
fn[2] = "name";
fn[3] = "client_space";
fn[4] = "nbytes";
fn[5] = "next";
fn[6] = "checksum";
/* set field addresses */
fa[0] = (size_t)(&(ad->datatype));
fa[1] = (size_t)(&(ad->nelem));
fa[2] = (size_t)(&(ad->name));
fa[3] = (size_t)(&(ad->client_space));
fa[4] = (size_t)(&(ad->nbytes));
fa[5] = (size_t)(&(ad->next));
fa[6] = (size_t)(&(ad->checksum));
/* print AD fields to stderr */
(void)fprintf(stderr, "debug_ad_print:\n");
for (i = 0; i < NUMADFIELDS; i++)