~ubuntu-branches/ubuntu/utopic/nwchem/utopic

« back to all changes in this revision

Viewing changes to src/tools/ga-5-2/ma/ma.c

  • Committer: Package Import Robot
  • Author(s): Michael Banck, Daniel Leidert, Andreas Tille, Michael Banck
  • Date: 2013-07-04 12:14:55 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20130704121455-5tvsx2qabor3nrui
Tags: 6.3-1
* New upstream release.
* Fixes anisotropic properties (Closes: #696361).
* New features include:
  + Multi-reference coupled cluster (MRCC) approaches
  + Hybrid DFT calculations with short-range HF 
  + New density-functionals including Minnesota (M08, M11) and HSE hybrid
    functionals
  + X-ray absorption spectroscopy (XAS) with TDDFT
  + Analytical gradients for the COSMO solvation model
  + Transition densities from TDDFT 
  + DFT+U and Electron-Transfer (ET) methods for plane wave calculations
  + Exploitation of space group symmetry in plane wave geometry optimizations
  + Local density of states (LDOS) collective variable added to Metadynamics
  + Various new XC functionals added for plane wave calculations, including
    hybrid and range-corrected ones
  + Electric field gradients with relativistic corrections 
  + Nudged Elastic Band optimization method
  + Updated basis sets and ECPs 

[ Daniel Leidert ]
* debian/watch: Fixed.

[ Andreas Tille ]
* debian/upstream: References

[ Michael Banck ]
* debian/upstream (Name): New field.
* debian/patches/02_makefile_flags.patch: Refreshed.
* debian/patches/06_statfs_kfreebsd.patch: Likewise.
* debian/patches/07_ga_target_force_linux.patch: Likewise.
* debian/patches/05_avoid_inline_assembler.patch: Removed, no longer needed.
* debian/patches/09_backported_6.1.1_fixes.patch: Likewise.
* debian/control (Build-Depends): Added gfortran-4.7 and gcc-4.7.
* debian/patches/10_force_gcc-4.7.patch: New patch, explicitly sets
  gfortran-4.7 and gcc-4.7, fixes test suite hang with gcc-4.8 (Closes:
  #701328, #713262).
* debian/testsuite: Added tests for COSMO analytical gradients and MRCC.
* debian/rules (MRCC_METHODS): New variable, required to enable MRCC methods.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if HAVE_CONFIG_H
 
2
#   include "config.h"
 
3
#endif
 
4
 
 
5
/*
 
6
 * Portable dynamic memory allocator.
 
7
 */
 
8
 
 
9
#if HAVE_STDIO_H
 
10
#   include <stdio.h>
 
11
#endif
 
12
#if HAVE_STDLIB_H
 
13
#   include <stdlib.h>
 
14
#endif
 
15
#if HAVE_STRING_H
 
16
#   include <string.h>
 
17
#endif
 
18
#if HAVE_MALLOC_H
 
19
#   include <malloc.h>
 
20
#endif
 
21
#include "error.h"
 
22
#include "farg.h"
 
23
#include "ma.h"
 
24
#include "memcpy.h"
 
25
#include "scope.h"
 
26
#include "table.h"
 
27
 
 
28
#ifdef ENABLE_ARMCI_MEM_OPTION
 
29
extern void* ARMCI_Malloc_local(long bytes);
 
30
#endif
 
31
 
 
32
/*
 
33
 * Memory layout:
 
34
 *
 
35
 *    segment = heap_region stack_region
 
36
 *    region = block block block ...
 
37
 *    block = AD gap1 guard1 client_space guard2 gap2
 
38
 *
 
39
 * A segment of memory is obtained from the OS upon initialization.
 
40
 * The low end of the segment is managed as a heap; the heap region
 
41
 * grows from low addresses to high addresses.  The high end of the
 
42
 * segment is managed as a stack; the stack region grows from high
 
43
 * addresses to low addresses.
 
44
 *
 
45
 * Each region consists of a series of contiguous blocks, one per
 
46
 * allocation request, and possibly some unused space.  Blocks in
 
47
 * the heap region are either in use by the client (allocated and
 
48
 * not yet deallocated) or not in use by the client (allocated and
 
49
 * already deallocated).  A block on the rightmost end of the heap
 
50
 * region becomes part of the unused space upon deallocation.
 
51
 * Blocks in the stack region are always in use by the client,
 
52
 * because when a stack block is deallocated, it becomes part of
 
53
 * the unused space.
 
54
 *
 
55
 * A block consists of the client space, i.e., the range of memory
 
56
 * available for use by the application; guard words adjacent to
 
57
 * each end of the client space to help detect improper memory access
 
58
 * by the client; bookkeeping info (in an "allocation descriptor,"
 
59
 * AD); and two gaps, each zero or more bytes long, to satisfy
 
60
 * alignment constraints (specifically, to ensure that AD and
 
61
 * client_space are aligned properly).
 
62
 */
 
63
 
 
64
/**
 
65
 ** constants
 
66
 **/
 
67
 
 
68
/* return value for returns that should never execute */
 
69
#define DONTCARE (Integer)0
 
70
 
 
71
/* default total # of bytes */
 
72
#define DEFAULT_TOTAL_HEAP  524288 /* 2^19 */
 
73
#define DEFAULT_TOTAL_STACK 524288 /* 2^19 */
 
74
 
 
75
/* estimate of max # of outstanding allocation requests */
 
76
#define DEFAULT_REQUESTS_HEAP  1
 
77
#define DEFAULT_REQUESTS_STACK 1
 
78
 
 
79
/* bytes per address */
 
80
#define BPA    1
 
81
 
 
82
/* per-allocation storage overhead, excluding alignment gaps */
 
83
#define BLOCK_OVERHEAD_FIXED (sizeof(AD) + (2 * sizeof(Guard)))
 
84
 
 
85
/* block lengths are integral multiples of this */
 
86
/*
 
87
 * Note that for machines such as the KSR on which sizeof(pointer)
 
88
 * and sizeof(long) are different than sizeof(int), alignment issues
 
89
 * can be tricky.  For example, the fields of a struct (e.g.,
 
90
 * client_space of AD) can be improperly aligned if the struct is
 
91
 * dynamically placed (by MA) in such a way that the first field is
 
92
 * properly aligned but sizes of subsequent fields accumulate to cause
 
93
 * a later field to be misaligned.  By defining the unit of alignment
 
94
 * to be the biggest of the integer and pointer types, part of the
 
95
 * problem is solved, but the sum of sizes of preceding fields can
 
96
 * still potentially cause difficulty.
 
97
 */
 
98
#if defined(BGP) || defined(BGQ)
 
99
#define ALIGNMENT       32
 
100
#else
 
101
#define ALIGNMENT       sizeof(long)
 
102
#endif
 
103
 
 
104
/* min size of block split and placed on free list */
 
105
#define MINBLOCKSIZE mai_round((long)(ALIGNMENT + BLOCK_OVERHEAD_FIXED), \
 
106
        (ulongi)ALIGNMENT)
 
107
 
 
108
/* signatures for guard words */
 
109
#define GUARD1 (Guard)0xaaaaaaaa /* start signature */
 
110
#define GUARD2 (Guard)0x55555555 /* stop signature */
 
111
 
 
112
/**
 
113
 ** types
 
114
 **/
 
115
 
 
116
typedef unsigned int Guard;   /* for detection of memory trashing */
 
117
typedef unsigned long ulongi; /* for brevity */
 
118
 
 
119
/* allocation request for a block */
 
120
typedef struct _AR
 
121
{
 
122
    Integer    datatype; /* of elements */
 
123
    Integer    nelem;    /* # of elements */
 
124
} AR;
 
125
 
 
126
/* allocation descriptor for a block */
 
127
typedef struct _AD
 
128
{
 
129
    Integer     datatype;          /* of elements */
 
130
    Integer     nelem;             /* # of elements */
 
131
    char        name[MA_NAMESIZE]; /* given by client */
 
132
    Pointer     client_space;      /* start of client space */
 
133
    ulongi      nbytes;            /* total # of bytes */
 
134
    struct _AD *next;              /* AD in linked list */
 
135
    ulongi      checksum;          /* of AD */
 
136
} AD;
 
137
 
 
138
/* block location for mh2ad */
 
139
typedef enum
 
140
{
 
141
    BL_HeapOrStack,
 
142
    BL_Heap,
 
143
    BL_Stack,
 
144
    BL_StackTop
 
145
} BlockLocation;
 
146
 
 
147
/**
 
148
 ** function types
 
149
 **/
 
150
 
 
151
private Boolean ad_big_enough(AD *ad, Pointer ar);
 
152
private Boolean ad_eq(AD *ad, Pointer ad_target);
 
153
private Boolean ad_gt(AD *ad, Pointer ad_target);
 
154
private Boolean ad_le(AD *ad, Pointer ad_target);
 
155
private Boolean ad_lt(AD *ad, Pointer ad_target);
 
156
private void ad_print(AD *ad, char *block_type);
 
157
private void balloc_after(AR *ar, Pointer address, Pointer *client_space, ulongi *nbytes);
 
158
private void balloc_before(AR *ar, Pointer address, Pointer *client_space, ulongi *nbytes);
 
159
private void block_free_heap(AD *ad);
 
160
private AD *block_split(AD *ad, ulongi bytes_needed, Boolean insert_free);
 
161
private ulongi checksum(AD *ad);
 
162
 
 
163
#ifdef DEBUG
 
164
private void debug_ad_print(AD *ad);
 
165
#endif /* DEBUG */
 
166
 
 
167
private Boolean guard_check(AD *ad);
 
168
private void guard_set(AD *ad);
 
169
private void list_coalesce(AD *list);
 
170
private AD *list_delete(AD *ad, AD **list);
 
171
private int list_delete_many(AD **list, Boolean (*pred)(), Pointer closure, void (*action)());
 
172
private AD *list_delete_one(AD **list, Boolean (*pred)(), Pointer closure);
 
173
private void list_insert(AD *ad, AD **list);
 
174
private void list_insert_ordered(AD *ad, AD **list, Boolean (*pred)());
 
175
private Boolean list_member(AD *ad, AD *list);
 
176
private int list_print(AD *list, char *block_type, int index_base);
 
177
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);
 
178
private Integer ma_max_heap_frag_nelem(Integer datatype, Integer min_nelem);
 
179
private Integer ma_nelem(Pointer address, ulongi length, Integer datatype);
 
180
private void ma_preinitialize(char *caller);
 
181
private Boolean mh2ad(Integer memhandle, AD **adout, BlockLocation location, char *caller);
 
182
private void mh_free(AD *ad);
 
183
private long mai_round(long value, ulongi unit);
 
184
private void str_ncopy(char *to, char *from, int maxchars);
 
185
 
 
186
/* foreign routines */
 
187
 
 
188
extern Integer ma_set_sizes_();    /* from the MA FORTRAN interface */
 
189
 
 
190
/**
 
191
 ** variables
 
192
 **/
 
193
 
 
194
/* base addresses of the datatypes */
 
195
private Pointer ma_base[] =
 
196
{
 
197
    (Pointer)ma_cb_char,    /* MT_C_CHAR */
 
198
    (Pointer)ma_cb_int,     /* MT_C_INT */
 
199
    (Pointer)ma_cb_long,    /* MT_C_LONGINT */
 
200
    (Pointer)ma_cb_float,   /* MT_C_FLOAT */
 
201
    (Pointer)ma_cb_dbl,     /* MT_C_DBL */
 
202
    (Pointer)ma_cb_ldbl,    /* MT_C_LDBL */
 
203
    (Pointer)ma_cb_scpl,    /* MT_C_SCPL */
 
204
    (Pointer)ma_cb_dcpl,    /* MT_C_DCPL */
 
205
    (Pointer)ma_cb_ldcpl,   /* MT_C_LDCPL */
 
206
    0,                      /* MT_F_BYTE */
 
207
    0,                      /* MT_F_INT */
 
208
    0,                      /* MT_F_LOG */
 
209
    0,                      /* MT_F_REAL */
 
210
    0,                      /* MT_F_DBL */
 
211
    0,                      /* MT_F_SCPL */
 
212
    0,                      /* MT_F_DCPL */
 
213
    (Pointer)ma_cb_longlong /* MT_C_LONGLONG */
 
214
};
 
215
 
 
216
/* names of the datatypes */
 
217
private char *ma_datatype[] =
 
218
{
 
219
    "char",
 
220
    "int",
 
221
    "long int",
 
222
    "float",
 
223
    "double",
 
224
    "long double",
 
225
    "single precision complex",
 
226
    "double precision complex",
 
227
    "long double precision complex",
 
228
    "byte",
 
229
    "integer",
 
230
    "logical",
 
231
    "real",
 
232
    "double precision",
 
233
    "single precision complex",
 
234
    "double precision complex",
 
235
    "long long"
 
236
};
 
237
 
 
238
/* numbers of bytes in the datatypes */
 
239
private int ma_sizeof[] =
 
240
{
 
241
    sizeof(char),                 /* MT_C_CHAR */
 
242
    sizeof(int),                  /* MT_C_INT */
 
243
    sizeof(long int),             /* MT_C_LONGINT */
 
244
    sizeof(float),                /* MT_C_FLOAT */
 
245
    sizeof(double),               /* MT_C_DBL */
 
246
    sizeof(MA_LongDouble),        /* MT_C_LDBL */
 
247
    sizeof(MA_SingleComplex),     /* MT_C_SCPL */
 
248
    sizeof(MA_DoubleComplex),     /* MT_C_DCPL */
 
249
    sizeof(MA_LongDoubleComplex), /* MT_C_LDCPL */
 
250
    0,                            /* MT_F_BYTE */
 
251
    0,                            /* MT_F_INT */
 
252
    0,                            /* MT_F_LOG */
 
253
    0,                            /* MT_F_REAL */
 
254
    0,                            /* MT_F_DBL */
 
255
    0,                            /* MT_F_SCPL */
 
256
    0,                            /* MT_F_DCPL */
 
257
    sizeof(long long)             /* MT_C_LONGLONG */
 
258
};
 
259
 
 
260
/*
 
261
 * Initially, ma_hp points to the start of the segment, and ma_sp
 
262
 * points to the first address past the end of the segment.  The
 
263
 * start of the segment is always pointed to by ma_segment, and
 
264
 * the first address past the end of the segment is always pointed
 
265
 * to by ma_eos.  The (unenforced) boundary between the heap region
 
266
 * and the stack region, defined at initialization, is always pointed
 
267
 * to by ma_partition.
 
268
 *
 
269
 *    ................................................
 
270
 *    ^                      ^                        ^
 
271
 *    ma_segment, ma_hp      ma_partition             ma_eos, ma_sp
 
272
 *
 
273
 * Later, ma_hp points to the first address past the end of the
 
274
 * rightmost heap block, and ma_sp points to the leftmost stack block.
 
275
 *
 
276
 *    hhhhhhhhhhhhhhhh.....................sssssssssss
 
277
 *    ^               ^      ^             ^          ^
 
278
 *    ma_segment      ma_hp  ma_partition  ma_sp      ma_eos
 
279
 */
 
280
 
 
281
private Pointer ma_segment;   /* memory from OS */
 
282
private Pointer ma_partition; /* boundary between heap and stack */
 
283
private Pointer ma_eos;       /* end of segment */
 
284
private Pointer ma_hp;        /* heap pointer */
 
285
private Pointer ma_sp;        /* stack pointer */
 
286
 
 
287
private AD *ma_hfree;         /* free list for heap */
 
288
private AD *ma_hused;         /* used list for heap */
 
289
private AD *ma_sused;         /* used list for stack */
 
290
 
 
291
/* toggled when ma_preinitialize succeeds */
 
292
private Boolean ma_preinitialized = MA_FALSE;
 
293
 
 
294
/* toggled when MA_init succeeds */
 
295
private Boolean ma_initialized = MA_FALSE;
 
296
 
 
297
/* invoke MA_verify_allocator_stuff in each public routine? */
 
298
private Boolean ma_auto_verify = MA_FALSE;
 
299
 
 
300
/* print push/pop/alloc/free? */
 
301
private Boolean ma_trace = MA_FALSE;
 
302
 
 
303
/* base arrays for the C datatypes */
 
304
public char                 ma_cb_char[2];    /* MT_C_CHAR */
 
305
public int                  ma_cb_int[2];     /* MT_C_INT */
 
306
public long                 ma_cb_long[2];    /* MT_C_LONGINT */
 
307
public long long            ma_cb_longlong[2];/* MT_C_LONGLONG */
 
308
public float                ma_cb_float[2];   /* MT_C_FLOAT */
 
309
public double               ma_cb_dbl[2];     /* MT_C_DBL */
 
310
public MA_LongDouble        ma_cb_ldbl[2];    /* MT_C_LDBL */
 
311
public MA_SingleComplex     ma_cb_scpl[2];    /* MT_C_SCPL */
 
312
public MA_DoubleComplex     ma_cb_dcpl[2];    /* MT_C_DCPL */
 
313
public MA_LongDoubleComplex ma_cb_ldcpl[2];   /* MT_C_LDCPL */
 
314
 
 
315
/* requested power-of-two alignment */
 
316
private Integer ma_numalign = 0;
 
317
 
 
318
/**
 
319
 ** macros
 
320
 **/
 
321
 
 
322
/* minimum of two values */
 
323
#ifdef min
 
324
#undef min
 
325
#endif
 
326
#define min(a, b) (((b) < (a)) ? (b) : (a))
 
327
 
 
328
/* maximum of two values */
 
329
#ifdef max
 
330
#undef max
 
331
#endif
 
332
#define max(a, b) (((b) > (a)) ? (b) : (a))
 
333
 
 
334
/* proper word ending corresponding to n */
 
335
#define plural(n) (((n) == 1) ? "" : "s")
 
336
 
 
337
/* convert between internal and external datatype values */
 
338
#define mt_import(d) ((d) - MT_BASE)
 
339
#define mt_export(d) ((d) + MT_BASE)
 
340
 
 
341
/* return nonzero if d is a valid (external) datatype */
 
342
#define mt_valid(d) (((d) >= MT_FIRST) && ((d) <= MT_LAST))
 
343
 
 
344
/* convert between pointer (address) and equivalent byte address */
 
345
#define p2b(p) ((ulongi)(p) * BPA)
 
346
#define b2p(b) ((Pointer)((b) / BPA))
 
347
 
 
348
/* return nonzero if a is a potentially valid address */
 
349
#define reasonable_address(a) (((a) >= ma_segment) && ((a) < ma_eos))
 
350
 
 
351
/* worst case bytes of overhead for any block of elements of datatype d */
 
352
#define max_block_overhead(d) \
 
353
    (BLOCK_OVERHEAD_FIXED + (ma_sizeof[d] - 1) + (ALIGNMENT - 1))
 
354
 
 
355
/* compute 0-based index for client_space from AD */
 
356
#define client_space_index(ad) \
 
357
    ((MA_AccessIndex)((long)((ad)->client_space - ma_base[(ad)->datatype]) / \
 
358
                 ma_sizeof[(ad)->datatype]))
 
359
 
 
360
/* compute address of guard from AD */
 
361
#define guard1(ad) ((Pointer)((ad)->client_space - sizeof(Guard)))
 
362
#define guard2(ad) ((Pointer)((ad)->client_space \
 
363
                + ((ad)->nelem * ma_sizeof[(ad)->datatype])))
 
364
 
 
365
/*
 
366
 * When reading or writing guard values, it is necessary to do an
 
367
 * explicit byte copy to avoid bus errors caused by guards that
 
368
 * are not suitably aligned.
 
369
 */
 
370
 
 
371
/* copy from guard to value */
 
372
#define guard_read(guard, value) bytecopy((guard), (value), sizeof(Guard))
 
373
 
 
374
/* copy from value to guard */
 
375
#define guard_write(guard, value) bytecopy((value), (guard), sizeof(Guard))
 
376
 
 
377
/**
 
378
 ** statistics stuff
 
379
 **/
 
380
 
 
381
#ifdef STATS
 
382
 
 
383
/* the number of routines for which calls are counted */
 
384
#define NUMROUTINES ((int)FID_MA_verify_allocator_stuff + 1)
 
385
 
 
386
/* function identifiers */
 
387
typedef enum
 
388
{
 
389
    FID_MA_alloc_get = 0,
 
390
    FID_MA_allocate_heap,
 
391
    FID_MA_chop_stack,
 
392
    FID_MA_free_heap,
 
393
    FID_MA_free_heap_piece,
 
394
    FID_MA_get_index,
 
395
    FID_MA_get_mbase,
 
396
    FID_MA_get_next_memhandle,
 
397
    FID_MA_get_numalign,
 
398
    FID_MA_get_pointer,
 
399
    FID_MA_init,
 
400
    FID_MA_initialized,
 
401
    FID_MA_init_memhandle_iterator,
 
402
    FID_MA_inquire_avail,
 
403
    FID_MA_inquire_heap,
 
404
    FID_MA_inquire_heap_check_stack,
 
405
    FID_MA_inquire_heap_no_partition,
 
406
    FID_MA_inquire_stack,
 
407
    FID_MA_inquire_stack_check_heap,
 
408
    FID_MA_inquire_stack_no_partition,
 
409
    FID_MA_pop_stack,
 
410
    FID_MA_print_stats,
 
411
    FID_MA_push_get,
 
412
    FID_MA_push_stack,
 
413
    FID_MA_set_auto_verify,
 
414
    FID_MA_set_error_print,
 
415
    FID_MA_set_hard_fail,
 
416
    FID_MA_set_numalign,
 
417
    FID_MA_sizeof,
 
418
    FID_MA_sizeof_overhead,
 
419
    FID_MA_summarize_allocated_blocks,
 
420
    FID_MA_trace,
 
421
    FID_MA_verify_allocator_stuff
 
422
} FID;
 
423
 
 
424
/* MA usage statistics */
 
425
typedef struct
 
426
{
 
427
    ulongi    hblocks;           /* current # of heap blocks */
 
428
    ulongi    hblocks_max;       /* max # of heap blocks */
 
429
    ulongi    hbytes;            /* current # of heap bytes */
 
430
    ulongi    hbytes_max;        /* max # of heap bytes */
 
431
    ulongi    sblocks;           /* current # of stack blocks */
 
432
    ulongi    sblocks_max;       /* max # of stack blocks */
 
433
    ulongi    sbytes;            /* current # of stack bytes */
 
434
    ulongi    sbytes_max;        /* max # of stack bytes */
 
435
    ulongi    calls[NUMROUTINES];/* # of calls to each routine */
 
436
} Stats;
 
437
 
 
438
/* names of the routines */
 
439
private char *ma_routines[] =
 
440
{
 
441
    "MA_alloc_get",
 
442
    "MA_allocate_heap",
 
443
    "MA_chop_stack",
 
444
    "MA_free_heap",
 
445
    "MA_free_heap_piece",
 
446
    "MA_get_index",
 
447
    "MA_get_mbase",
 
448
    "MA_get_next_memhandle",
 
449
    "MA_get_numalign",
 
450
    "MA_get_pointer",
 
451
    "MA_init",
 
452
    "MA_initialized",
 
453
    "MA_init_memhandle_iterator",
 
454
    "MA_inquire_avail",
 
455
    "MA_inquire_heap",
 
456
    "MA_inquire_heap_check_stack",
 
457
    "MA_inquire_heap_no_partition",
 
458
    "MA_inquire_stack",
 
459
    "MA_inquire_stack_check_heap",
 
460
    "MA_inquire_stack_no_partition",
 
461
    "MA_pop_stack",
 
462
    "MA_print_stats",
 
463
    "MA_push_get",
 
464
    "MA_push_stack",
 
465
    "MA_set_auto_verify",
 
466
    "MA_set_error_print",
 
467
    "MA_set_hard_fail",
 
468
    "MA_set_numalign",
 
469
    "MA_sizeof",
 
470
    "MA_sizeof_overhead",
 
471
    "MA_summarize_allocated_blocks",
 
472
    "MA_trace",
 
473
    "MA_verify_allocator_stuff"
 
474
};
 
475
 
 
476
/* MA usage statistics */
 
477
private Stats ma_stats;
 
478
 
 
479
#endif /* STATS */
 
480
 
 
481
/**
 
482
 ** private routines
 
483
 **/
 
484
 
 
485
/* ------------------------------------------------------------------------- */
 
486
/*
 
487
 * Return MA_TRUE if ad can satisfy ar, else return MA_FALSE.
 
488
 * If ad can satisfy ar, set its client_space and nbytes fields
 
489
 * after performing any splitting.
 
490
 */
 
491
/* ------------------------------------------------------------------------- */
 
492
 
 
493
private Boolean ad_big_enough(ad, ar)
 
494
    AD        *ad;        /* the AD to test */
 
495
    Pointer    ar;        /* allocation request */
 
496
{
 
497
    Pointer    client_space;    /* location of client_space */
 
498
    ulongi    nbytes;        /* length of block for ar */
 
499
 
 
500
    /* perform trial allocation to determine size */
 
501
    balloc_after((AR *)ar, (Pointer)ad, &client_space, &nbytes);
 
502
 
 
503
    if (nbytes <= ad->nbytes)
 
504
    {
 
505
        /* ad is big enough; split block if necessary */
 
506
        (void)block_split(ad, nbytes, MA_TRUE);
 
507
 
 
508
        /* set fields appropriately */
 
509
        ad->client_space = client_space;
 
510
 
 
511
        /* success */
 
512
        return MA_TRUE;
 
513
    }
 
514
    else
 
515
        /* ad is not big enough */
 
516
        return MA_FALSE;
 
517
}
 
518
 
 
519
/* ------------------------------------------------------------------------- */
 
520
/*
 
521
 * Return MA_TRUE if ad == ad_target, else return MA_FALSE.
 
522
 */
 
523
/* ------------------------------------------------------------------------- */
 
524
 
 
525
private Boolean ad_eq(ad, ad_target)
 
526
    AD        *ad;        /* the AD to test */
 
527
    Pointer    ad_target;    /* the AD to match */
 
528
{
 
529
    return (ad == (AD *)ad_target) ? MA_TRUE : MA_FALSE;
 
530
}
 
531
 
 
532
/* ------------------------------------------------------------------------- */
 
533
/*
 
534
 * Return MA_TRUE if ad > ad_target, else return MA_FALSE.
 
535
 */
 
536
/* ------------------------------------------------------------------------- */
 
537
 
 
538
private Boolean ad_gt(ad, ad_target)
 
539
    AD        *ad;        /* the AD to test */
 
540
    Pointer    ad_target;    /* the AD to match */
 
541
{
 
542
    return (ad > (AD *)ad_target) ? MA_TRUE : MA_FALSE;
 
543
}
 
544
 
 
545
/* ------------------------------------------------------------------------- */
 
546
/*
 
547
 * Return MA_TRUE if ad <= ad_target, else return MA_FALSE.
 
548
 */
 
549
/* ------------------------------------------------------------------------- */
 
550
 
 
551
private Boolean ad_le(ad, ad_target)
 
552
    AD        *ad;        /* the AD to test */
 
553
    Pointer    ad_target;    /* the AD to match */
 
554
{
 
555
    return (ad <= (AD *)ad_target) ? MA_TRUE : MA_FALSE;
 
556
}
 
557
 
 
558
/* ------------------------------------------------------------------------- */
 
559
/*
 
560
 * Return MA_TRUE if ad < ad_target, else return MA_FALSE.
 
561
 */
 
562
/* ------------------------------------------------------------------------- */
 
563
 
 
564
private Boolean ad_lt(ad, ad_target)
 
565
    AD        *ad;        /* the AD to test */
 
566
    Pointer    ad_target;    /* the AD to match */
 
567
{
 
568
    return (ad < (AD *)ad_target) ? MA_TRUE : MA_FALSE;
 
569
}
 
570
 
 
571
/* ------------------------------------------------------------------------- */
 
572
/*
 
573
 * Print identifying information about the given AD to stdout.
 
574
 */
 
575
/* ------------------------------------------------------------------------- */
 
576
 
 
577
private void ad_print(ad, block_type)
 
578
    AD        *ad;        /* to print */
 
579
    char    *block_type;    /* for output */
 
580
{
 
581
    Integer    memhandle;    /* memhandle for AD */
 
582
 
 
583
    /* convert AD to memhandle */
 
584
    memhandle = ma_table_lookup_assoc((TableData)ad);
 
585
 
 
586
    /* print to stdout */
 
587
    (void)printf("%s block '%s', handle ",
 
588
        block_type,
 
589
        ad->name);
 
590
    if (memhandle == TABLE_HANDLE_NONE)
 
591
        (void)printf("unknown");
 
592
    else
 
593
        (void)printf("%ld",
 
594
            (long)memhandle);
 
595
    (void)printf(", address 0x%lx",
 
596
        (long)ad);
 
597
}
 
598
 
 
599
/* ------------------------------------------------------------------------- */
 
600
/*
 
601
 * Allocate a block suitable for ar starting at address.  No fields of
 
602
 * the new block are modified.
 
603
 */
 
604
/* ------------------------------------------------------------------------- */
 
605
 
 
606
private void balloc_after(ar, address, client_space, nbytes)
 
607
    AR        *ar;        /* allocation request */
 
608
    Pointer    address;    /* to allocate after */
 
609
    Pointer    *client_space;    /* RETURN: location of client_space */
 
610
    ulongi    *nbytes;    /* RETURN: length of block */
 
611
{
 
612
    Integer    datatype;    /* of elements in this block */
 
613
    ulongi    L_client_space;    /* length of client_space */
 
614
    Pointer    A_client_space;    /* address of client_space */
 
615
    int        L_gap1;        /* length of gap1 */
 
616
    int        L_gap2;        /* length of gap2 */
 
617
 
 
618
    ulongi    B_address;    /* byte equivalent of address */
 
619
    ulongi    B_base;        /* byte equivalent of ma_base[datatype] */
 
620
    ulongi    B_client_space;    /* byte equivalent of A_client_space */
 
621
 
 
622
    datatype = ar->datatype;
 
623
 
 
624
    B_address = p2b(address);
 
625
    B_base = p2b(ma_base[datatype]);
 
626
 
 
627
    /*
 
628
     * To ensure that client_space is properly aligned:
 
629
     *
 
630
     *    (A(client_space) - ma_base[datatype]) % ma_sizeof[datatype] == 0
 
631
     *
 
632
     * where
 
633
     *
 
634
     *    A(client_space) == address + L(AD) + L(gap1) + L(guard1)
 
635
     */
 
636
 
 
637
    L_client_space = ar->nelem * ma_sizeof[datatype];
 
638
 
 
639
    L_gap1 = ((long)B_base
 
640
        - (long)B_address
 
641
        - (long)sizeof(AD)
 
642
        - (long)sizeof(Guard))
 
643
        % (long)ma_sizeof[datatype];
 
644
 
 
645
    if (L_gap1 < 0)
 
646
        L_gap1 += ma_sizeof[datatype];
 
647
 
 
648
    B_client_space = B_address + sizeof(AD) + L_gap1 + sizeof(Guard);
 
649
    A_client_space = b2p(B_client_space);
 
650
    B_client_space = p2b(A_client_space);
 
651
 
 
652
    /*
 
653
     * To align client space according to overall alignment of absolute
 
654
     * address on user requested 2^ma_numalign boundary.
 
655
     * Note that if the base arrays are not aligned accordingly then
 
656
     * this alignement request is not satisfiable and will be quietly
 
657
     * ignored.
 
658
     */
 
659
 
 
660
    if (ma_numalign > 0) {
 
661
      unsigned long mask = (1<<ma_numalign)-1;
 
662
      int diff = ((unsigned long) B_client_space) & mask;
 
663
      
 
664
      /* Check that the difference is a multiple of the type size.
 
665
       * If so, then we can shift the client space which is already
 
666
       * aligned to satisfy this requirement.
 
667
       */
 
668
 
 
669
      if (diff) {
 
670
    diff = (1<<ma_numalign) - diff;
 
671
    if ((diff % ma_sizeof[datatype]) == 0 ) {
 
672
      /*printf("bafter realigned diff=%d\n",diff);*/
 
673
      A_client_space = b2p(B_client_space + diff);
 
674
      B_client_space = p2b(A_client_space);
 
675
    }    
 
676
    /*    else {
 
677
      printf("did not realign diff=%d typelen=%d mod=%d\n",
 
678
         diff, ma_sizeof[datatype], (diff % ma_sizeof[datatype]));
 
679
         }*/
 
680
      }
 
681
    }
 
682
 
 
683
    /*
 
684
     * To ensure that the AD is properly aligned:
 
685
     *
 
686
     *    L(block) % ALIGNMENT == 0
 
687
     *
 
688
     * where
 
689
     *
 
690
     *    L(block) == A(client_space) + L(client_space) + L(guard2) + L(gap2)
 
691
     *        - address
 
692
     */
 
693
 
 
694
    L_gap2 = ((long)B_address
 
695
        - (long)B_client_space
 
696
        - (long)L_client_space
 
697
        - (long)sizeof(Guard))
 
698
        % (long)ALIGNMENT;
 
699
 
 
700
    if (L_gap2 < 0)
 
701
        L_gap2 += ALIGNMENT;
 
702
 
 
703
    /*
 
704
     * set the return values
 
705
     */
 
706
 
 
707
    *client_space = A_client_space;
 
708
    *nbytes = (ulongi)(B_client_space
 
709
        + L_client_space
 
710
        + sizeof(Guard)
 
711
        + L_gap2
 
712
        - B_address);
 
713
}
 
714
 
 
715
/* ------------------------------------------------------------------------- */
 
716
/*
 
717
 * Allocate a block suitable for ar ending before address.  No fields of
 
718
 * the new block are modified.
 
719
 */
 
720
/* ------------------------------------------------------------------------- */
 
721
 
 
722
private void balloc_before(ar, address, client_space, nbytes)
 
723
    AR        *ar;        /* allocation request */
 
724
    Pointer    address;    /* to allocate before */
 
725
    Pointer    *client_space;    /* RETURN: location of client_space */
 
726
    ulongi    *nbytes;    /* RETURN: length of block */
 
727
{
 
728
    Integer    datatype;    /* of elements in this block */
 
729
    ulongi    L_client_space;    /* length of client_space */
 
730
    Pointer    A_client_space;    /* address of client_space */
 
731
    int        L_gap1;        /* length of gap1 */
 
732
    int        L_gap2;        /* length of gap2 */
 
733
 
 
734
    ulongi    B_address;    /* byte equivalent of address */
 
735
    ulongi    B_base;        /* byte equivalent of ma_base[datatype] */
 
736
    ulongi    B_client_space;    /* byte equivalent of A_client_space */
 
737
 
 
738
    datatype = ar->datatype;
 
739
 
 
740
    B_address = p2b(address);
 
741
    B_base = p2b(ma_base[datatype]);
 
742
 
 
743
    /*
 
744
     * To ensure that client_space is properly aligned:
 
745
     *
 
746
     *    (A(client_space) - ma_base[datatype]) % ma_sizeof[datatype] == 0
 
747
     *
 
748
     * where
 
749
     *
 
750
     *    A(client_space) == address - L(gap2) - L(guard2) - L(client_space)
 
751
     */
 
752
 
 
753
    L_client_space = ar->nelem * ma_sizeof[datatype];
 
754
 
 
755
    L_gap2 = (B_address
 
756
        - sizeof(Guard)
 
757
        - L_client_space
 
758
        - B_base)
 
759
        % ma_sizeof[datatype];
 
760
 
 
761
    if (L_gap2 < 0)
 
762
        L_gap2 += ma_sizeof[datatype];
 
763
 
 
764
    B_client_space = B_address - L_gap2 - sizeof(Guard) - L_client_space;
 
765
    A_client_space = b2p(B_client_space);
 
766
    B_client_space = p2b(A_client_space);
 
767
 
 
768
    /*
 
769
     * To align client space according to overall alignment of absolute
 
770
     * address on user requested 2^ma_numalign boundary.
 
771
     * Note that if the base arrays are not aligned accordingly then
 
772
     * this alignement request is not satisfiable and will be quietly
 
773
     * ignored.
 
774
     */
 
775
 
 
776
    if (ma_numalign > 0) {
 
777
      unsigned long mask = (1<<ma_numalign)-1;
 
778
      int diff = ((unsigned long) B_client_space) & mask;
 
779
      
 
780
      /* Check that the difference is a multiple of the type size.
 
781
       * If so, then we can shift the client space which is already
 
782
       * aligned to satisfy this requirement.
 
783
       */
 
784
 
 
785
      if (diff) {
 
786
    if ((diff % ma_sizeof[datatype]) == 0 ) {
 
787
      /* printf("bbefore realigned diff=%d\n",diff); */
 
788
      A_client_space = b2p(B_client_space - diff);
 
789
      B_client_space = p2b(A_client_space);
 
790
    }    
 
791
    /*    else {
 
792
      printf("did not realign diff=%d typelen=%d mod=%d\n",
 
793
         diff, ma_sizeof[datatype], (diff % ma_sizeof[datatype]));
 
794
         }*/
 
795
      }
 
796
    }
 
797
 
 
798
    /*
 
799
     * To ensure that the AD is properly aligned:
 
800
     *
 
801
     *    A(AD) % ALIGNMENT == 0
 
802
     *
 
803
     * where
 
804
     *
 
805
     *    A(AD) == A(client_space) - L(guard1) - L(gap1) - L(AD)
 
806
     */
 
807
 
 
808
    L_gap1 = (B_client_space
 
809
        - sizeof(Guard)
 
810
        - sizeof(AD))
 
811
        % ALIGNMENT;
 
812
 
 
813
    /*
 
814
     * set the return values
 
815
     */
 
816
 
 
817
    *client_space = A_client_space;
 
818
    *nbytes = (ulongi)(B_address
 
819
        - B_client_space
 
820
        + sizeof(Guard)
 
821
        + L_gap1
 
822
        + sizeof(AD));
 
823
}
 
824
 
 
825
/* ------------------------------------------------------------------------- */
 
826
/*
 
827
 * Reclaim the given block by updating ma_hp and ma_hfree.
 
828
 */
 
829
/* ------------------------------------------------------------------------- */
 
830
 
 
831
private void block_free_heap(ad)
 
832
    AD        *ad;        /* AD to free */
 
833
{
 
834
    AD        *ad2;        /* traversal pointer */
 
835
    AD        *max_ad;    /* rightmost AD */
 
836
 
 
837
    /* find rightmost heap block */
 
838
    for (max_ad = (AD *)NULL, ad2 = ma_hused; ad2; ad2 = ad2->next)
 
839
    {
 
840
        if (ad2 > max_ad)
 
841
            max_ad = ad2;
 
842
    }
 
843
 
 
844
    if (max_ad)
 
845
    {
 
846
        /* at least 1 block is in use */
 
847
 
 
848
        /* set ma_hp to first address past end of max_ad */
 
849
        ma_hp = (Pointer)max_ad + max_ad->nbytes;
 
850
 
 
851
        /* delete any free list blocks that are no longer in heap region */
 
852
        (void)list_delete_many(
 
853
            &ma_hfree,
 
854
            ad_gt,
 
855
            (Pointer)max_ad,
 
856
            (void (*)())NULL);
 
857
 
 
858
        /* if ad is in the heap region, add it to free list */
 
859
        if (ad < max_ad)
 
860
        {
 
861
            list_insert_ordered(ad, &ma_hfree, ad_lt);
 
862
            list_coalesce(ma_hfree);
 
863
        }
 
864
    }
 
865
    else
 
866
    {
 
867
        /* no blocks are in use */
 
868
 
 
869
        /* set ma_hp to start of segment */
 
870
        ma_hp = ma_segment;
 
871
 
 
872
        /* clear the free list */
 
873
        ma_hfree = (AD *)NULL;
 
874
    }
 
875
}
 
876
 
 
877
/* ------------------------------------------------------------------------- */
 
878
/*
 
879
 * If ad is sufficiently bigger than bytes_needed bytes, create a new
 
880
 * block from the remainder, optionally insert it in the free list,
 
881
 * and set the lengths of both blocks.
 
882
 *
 
883
 * Return a pointer to the new block (NULL if not created).
 
884
 */
 
885
/* ------------------------------------------------------------------------- */
 
886
 
 
887
private AD *block_split(ad, bytes_needed, insert_free)
 
888
    AD        *ad;        /* the AD to split */
 
889
    ulongi    bytes_needed;    /* from ad */
 
890
    Boolean    insert_free;    /* insert in free list? */
 
891
{
 
892
    ulongi    bytes_extra;    /* in ad */
 
893
    AD        *ad2;        /* the new AD */
 
894
 
 
895
    /* caller ensures that ad->nbytes >= bytes_needed */
 
896
    bytes_extra = ad->nbytes - bytes_needed;
 
897
 
 
898
    if (bytes_extra >= ((ulongi)MINBLOCKSIZE))
 
899
    {
 
900
        /* create a new block */
 
901
        ad2 = (AD *)((Pointer)ad + bytes_needed);
 
902
 
 
903
        /* set the length of ad2 */
 
904
        ad2->nbytes = bytes_extra;
 
905
 
 
906
        if (insert_free)
 
907
        {
 
908
            /* insert ad2 into free list */
 
909
            list_insert_ordered(ad2, &ma_hfree, ad_lt);
 
910
        }
 
911
 
 
912
        /* set the length of ad */
 
913
        ad->nbytes = bytes_needed;
 
914
 
 
915
        return ad2;
 
916
    }
 
917
    else
 
918
    {
 
919
        /*
 
920
         * If 0 <= bytes_extra < MINBLOCKSIZE then there are too few
 
921
         * extra bytes to form a new block.  In this case, we simply
 
922
         * do nothing; ad will retain its original length (which is
 
923
         * either perfect or slightly too big), and the entire block
 
924
         * will be reclaimed upon deallocation, preventing any
 
925
         * memory leakage.
 
926
         */
 
927
 
 
928
        return (AD *)NULL;
 
929
    }
 
930
}
 
931
 
 
932
/* ------------------------------------------------------------------------- */
 
933
/*
 
934
 * Compute and return a checksum for ad.  Include all fields except name,
 
935
 * next, and checksum.
 
936
 */
 
937
/* ------------------------------------------------------------------------- */
 
938
 
 
939
private ulongi checksum(ad)
 
940
    AD        *ad;        /* the AD to compute checksum for */
 
941
{
 
942
    return (ulongi)(
 
943
                ad->datatype +
 
944
                ad->nelem +
 
945
        (ulongi)ad->client_space +
 
946
                ad->nbytes);
 
947
}
 
948
 
 
949
/* ------------------------------------------------------------------------- */
 
950
/*
 
951
 * Print to stderr the addresses of the fields of the given ad.
 
952
 */
 
953
/* ------------------------------------------------------------------------- */
 
954
 
 
955
#ifdef DEBUG
 
956
 
 
957
private void debug_ad_print(ad)
 
958
    AD        *ad;        /* the AD to print */
 
959
{
 
960
#define NUMADFIELDS 7
 
961
 
 
962
    char    *fn[NUMADFIELDS];    /* field names */
 
963
    long    fa[NUMADFIELDS];    /* field addresses */
 
964
    int        i;            /* loop index */
 
965
    long    address;        /* other addresses */
 
966
 
 
967
    /* set field names */
 
968
    fn[0] = "datatype";
 
969
    fn[1] = "nelem";
 
970
    fn[2] = "name";
 
971
    fn[3] = "client_space";
 
972
    fn[4] = "nbytes";
 
973
    fn[5] = "next";
 
974
    fn[6] = "checksum";
 
975
 
 
976
    /* set field addresses */
 
977
    fa[0] = (long)(&(ad->datatype));
 
978
    fa[1] = (long)(&(ad->nelem));
 
979
    fa[2] = (long)(&(ad->name));
 
980
    fa[3] = (long)(&(ad->client_space));
 
981
    fa[4] = (long)(&(ad->nbytes));
 
982
    fa[5] = (long)(&(ad->next));
 
983
    fa[6] = (long)(&(ad->checksum));
 
984
 
 
985
    /* print AD fields to stderr */
 
986
    (void)fprintf(stderr, "debug_ad_print:\n");
 
987
    for (i = 0; i < NUMADFIELDS; i++)
 
988
        (void)fprintf(stderr, "\t0x%lx  mod4,8,16=%d,%d,%-2d  ad->%s\n",
 
989
            fa[i],
 
990
            fa[i] % 4,
 
991
            fa[i] % 8,
 
992
            fa[i] % 16,
 
993
            fn[i]);
 
994
 
 
995
    /* print other addresses to stderr */
 
996
    address = (long)guard1(ad);
 
997
    (void)fprintf(stderr, "\t0x%lx  mod4,8,16=%d,%d,%-2d  guard1\n",
 
998
        address,
 
999
        address % 4,
 
1000
        address % 8,
 
1001
        address % 16);
 
1002
    address = (long)ad->client_space;
 
1003
    (void)fprintf(stderr, "\t0x%lx  mod4,8,16=%d,%d,%-2d  client_space\n",
 
1004
        address,
 
1005
        address % 4,
 
1006
        address % 8,
 
1007
        address % 16);
 
1008
    address = (long)guard2(ad);
 
1009
    (void)fprintf(stderr, "\t0x%lx  mod4,8,16=%d,%d,%-2d  guard2\n",
 
1010
        address,
 
1011
        address % 4,
 
1012
        address % 8,
 
1013
        address % 16);
 
1014
 
 
1015
    (void)fflush(stderr);
 
1016
}
 
1017
 
 
1018
#endif /* DEBUG */
 
1019
 
 
1020
/* ------------------------------------------------------------------------- */
 
1021
/*
 
1022
 * Return MA_TRUE if the guards associated with ad contain valid signatures,
 
1023
 * else return MA_FALSE.
 
1024
 */
 
1025
/* ------------------------------------------------------------------------- */
 
1026
 
 
1027
private Boolean guard_check(ad)
 
1028
    AD        *ad;        /* the AD to check guards for */
 
1029
{
 
1030
    Guard    signature;    /* value to be read */
 
1031
    Pointer    guard;        /* address to read from */
 
1032
 
 
1033
    guard = guard1(ad);
 
1034
    guard_read(guard, &signature);
 
1035
    if (signature != GUARD1)
 
1036
        return MA_FALSE;
 
1037
 
 
1038
    guard = guard2(ad);
 
1039
    guard_read(guard, &signature);
 
1040
    if (signature != GUARD2)
 
1041
        return MA_FALSE;
 
1042
 
 
1043
    /* success */
 
1044
    return MA_TRUE;
 
1045
}
 
1046
 
 
1047
/* ------------------------------------------------------------------------- */
 
1048
/*
 
1049
 * Write signatures into the guards associated with ad.
 
1050
 */
 
1051
/* ------------------------------------------------------------------------- */
 
1052
 
 
1053
private void guard_set(ad)
 
1054
    AD        *ad;        /* the AD to set guards for */
 
1055
{
 
1056
    Guard    signature;    /* value to be written */
 
1057
    Pointer    guard;        /* address to write to */
 
1058
 
 
1059
    signature = GUARD1;
 
1060
    guard = guard1(ad);
 
1061
    guard_write(guard, &signature);
 
1062
 
 
1063
    signature = GUARD2;
 
1064
    guard = guard2(ad);
 
1065
    guard_write(guard, &signature);
 
1066
}
 
1067
 
 
1068
/* ------------------------------------------------------------------------- */
 
1069
/*
 
1070
 * Coalesce list by merging any adjacent elements that are contiguous.
 
1071
 * The list is assumed to be ordered by increasing addresses, i.e.,
 
1072
 * addressOf(element i) < addressOf(element i+1).
 
1073
 */
 
1074
/* ------------------------------------------------------------------------- */
 
1075
 
 
1076
private void list_coalesce(list)
 
1077
    AD        *list;        /* the list to coalesce */
 
1078
{
 
1079
    AD        *ad1;        /* lead traversal pointer */
 
1080
    AD        *ad2;        /* trailing traversal pointer */
 
1081
 
 
1082
    for (ad2 = list; ad2;)
 
1083
    {
 
1084
        /* compute first address beyond ad2 */
 
1085
        ad1 = (AD *)((Pointer)ad2 + ad2->nbytes);
 
1086
 
 
1087
        /* are ad2 and ad1 contiguous? */
 
1088
        if (ad1 == ad2->next)
 
1089
        {
 
1090
            /* yes; merge ad1 into ad2 */
 
1091
            ad2->nbytes += ad1->nbytes;
 
1092
            ad2->next = ad1->next;
 
1093
        }
 
1094
        else
 
1095
        {
 
1096
            /* no; advance ad2 */
 
1097
            ad2 = ad2->next;
 
1098
        }
 
1099
    }
 
1100
}
 
1101
 
 
1102
/* ------------------------------------------------------------------------- */
 
1103
/*
 
1104
 * Delete and return the first occurrence of ad from list.  If ad is not
 
1105
 * a member of list, return NULL.
 
1106
 */
 
1107
/* ------------------------------------------------------------------------- */
 
1108
 
 
1109
private AD *list_delete(ad, list)
 
1110
    AD        *ad;        /* the AD to delete */
 
1111
    AD        **list;        /* the list to delete from */
 
1112
{
 
1113
    return list_delete_one(list, ad_eq, (Pointer)ad);
 
1114
}
 
1115
 
 
1116
/* ------------------------------------------------------------------------- */
 
1117
/*
 
1118
 * Apply pred (with closure) to each element of list.  Delete each element
 
1119
 * that satisfies pred, after applying action to the element (if action is
 
1120
 * not NULL).  Return the number of elements deleted.
 
1121
 */
 
1122
/* ------------------------------------------------------------------------- */
 
1123
 
 
1124
private int list_delete_many(list, pred, closure, action)
 
1125
    AD        **list;        /* the list to search */
 
1126
    Boolean    (*pred)();    /* predicate */
 
1127
    Pointer    closure;    /* for pred */
 
1128
    void    (*action)();    /* to apply before deletion */
 
1129
{
 
1130
    AD        *ad1;        /* lead traversal pointer */
 
1131
    AD        *ad2;        /* trailing traversal pointer */
 
1132
    int        ndeleted = 0;    /* # of elements deleted from list */
 
1133
 
 
1134
    for (ad2 = (AD *)NULL, ad1 = *list; ad1; ad1 = ad1->next)
 
1135
    {
 
1136
        /* does ad1 match? */
 
1137
        if ((*pred)(ad1, closure))
 
1138
        {
 
1139
            /* yes; apply action, then delete ad1 from list */
 
1140
            if (action != (void (*)())NULL)
 
1141
                (*action)(ad1);
 
1142
            if (ad2)
 
1143
            {
 
1144
                /* ad1 is second or later element */
 
1145
                ad2->next = ad1->next;
 
1146
            }
 
1147
            else
 
1148
            {
 
1149
                /* ad1 is first element */
 
1150
                *list = ad1->next;
 
1151
            }
 
1152
 
 
1153
            ndeleted++;
 
1154
        }
 
1155
        else
 
1156
        {
 
1157
            /* no; ad1 survives, so scoot ad2 along */
 
1158
            ad2 = ad1;
 
1159
        }
 
1160
    }
 
1161
 
 
1162
    /* return the # of elements deleted from list */
 
1163
    return ndeleted;
 
1164
}
 
1165
 
 
1166
/* ------------------------------------------------------------------------- */
 
1167
/*
 
1168
 * Apply pred (with closure) to each element of list.  Delete and return
 
1169
 * the first element that satisfies pred.  If no element satisfies pred,
 
1170
 * return NULL.
 
1171
 */
 
1172
/* ------------------------------------------------------------------------- */
 
1173
 
 
1174
private AD *list_delete_one(list, pred, closure)
 
1175
    AD        **list;        /* the list to search */
 
1176
    Boolean    (*pred)();    /* predicate */
 
1177
    Pointer    closure;    /* for pred */
 
1178
{
 
1179
    AD        *ad1;        /* lead traversal pointer */
 
1180
    AD        *ad2;        /* trailing traversal pointer */
 
1181
 
 
1182
    for (ad2 = (AD *)NULL, ad1 = *list; ad1; ad2 = ad1, ad1 = ad1->next)
 
1183
    {
 
1184
        /* does ad1 match? */
 
1185
        if ((*pred)(ad1, closure))
 
1186
        {
 
1187
            /* yes; delete ad1 from list */
 
1188
            if (ad2)
 
1189
            {
 
1190
                /* ad1 is second or later element */
 
1191
                ad2->next = ad1->next;
 
1192
            }
 
1193
            else
 
1194
            {
 
1195
                /* ad1 is first element */
 
1196
                *list = ad1->next;
 
1197
            }
 
1198
 
 
1199
            /* success */
 
1200
            return ad1;
 
1201
        }
 
1202
    }
 
1203
 
 
1204
    /* failure */
 
1205
    return (AD *)NULL;
 
1206
}
 
1207
 
 
1208
/* ------------------------------------------------------------------------- */
 
1209
/*
 
1210
 * Insert ad into list.
 
1211
 */
 
1212
/* ------------------------------------------------------------------------- */
 
1213
 
 
1214
private void list_insert(ad, list)
 
1215
    AD        *ad;        /* the AD to insert */
 
1216
    AD        **list;        /* the list to insert into */
 
1217
{
 
1218
    /* push ad onto list */
 
1219
    ad->next = *list;
 
1220
    *list = ad;
 
1221
}
 
1222
 
 
1223
/* ------------------------------------------------------------------------- */
 
1224
/*
 
1225
 * Insert ad into list, immediately before the first element e
 
1226
 * for which pred(ad, e) returns true.  If there is no such element,
 
1227
 * insert ad after the last element of list.
 
1228
 */
 
1229
/* ------------------------------------------------------------------------- */
 
1230
 
 
1231
private void list_insert_ordered(ad, list, pred)
 
1232
    AD        *ad;        /* the AD to insert */
 
1233
    AD        **list;        /* the list to insert into */
 
1234
    Boolean    (*pred)();    /* predicate */
 
1235
{
 
1236
    AD        *ad1;        /* lead traversal pointer */
 
1237
    AD        *ad2;        /* trailing traversal pointer */
 
1238
 
 
1239
    if (*list == (AD *)NULL)
 
1240
    {
 
1241
        /* empty list */
 
1242
        ad->next = (AD *)NULL;
 
1243
        *list = ad;
 
1244
        return;
 
1245
    }
 
1246
 
 
1247
    /* list has at least one element */
 
1248
    for (ad2 = (AD *)NULL, ad1 = *list; ad1; ad2 = ad1, ad1 = ad1->next)
 
1249
    {
 
1250
        /* does ad1 match? */
 
1251
        if ((*pred)(ad, ad1))
 
1252
        {
 
1253
            /* yes; insert ad before ad1 */
 
1254
            if (ad2)
 
1255
            {
 
1256
                /* ad1 is second or later element */
 
1257
                ad2->next = ad;
 
1258
            }
 
1259
            else
 
1260
            {
 
1261
                /* ad1 is first element */
 
1262
                *list = ad;
 
1263
            }
 
1264
            ad->next = ad1;
 
1265
 
 
1266
            /* success */
 
1267
            return;
 
1268
        }
 
1269
    }
 
1270
 
 
1271
    /* append ad to list */
 
1272
    ad2->next = ad;
 
1273
    ad->next = (AD *)NULL;
 
1274
}
 
1275
 
 
1276
/* ------------------------------------------------------------------------- */
 
1277
/*
 
1278
 * Return MA_TRUE if ad is a member of list, else return MA_FALSE.
 
1279
 */
 
1280
/* ------------------------------------------------------------------------- */
 
1281
 
 
1282
private Boolean list_member(ad, list)
 
1283
    AD        *ad;        /* the AD to search for */
 
1284
    AD        *list;        /* the list to search */
 
1285
{
 
1286
    AD        *ad1;        /* traversal pointer */
 
1287
 
 
1288
    for (ad1 = list; ad1; ad1 = ad1->next)
 
1289
        if (ad1 == ad)
 
1290
            /* ad is a member of list */
 
1291
            return MA_TRUE;
 
1292
 
 
1293
    /* ad is not a member of list */
 
1294
    return MA_FALSE;
 
1295
}
 
1296
 
 
1297
/* ------------------------------------------------------------------------- */
 
1298
/*
 
1299
 * Print information to stdout about each block on list.  Return the
 
1300
 * number of blocks on list.
 
1301
 */
 
1302
/* ------------------------------------------------------------------------- */
 
1303
 
 
1304
private int list_print(list, block_type, index_base)
 
1305
    AD        *list;        /* to print */
 
1306
    char    *block_type;    /* for output */
 
1307
    int        index_base;    /* 0 (C) or 1 (FORTRAN) */
 
1308
{
 
1309
    AD        *ad;        /* traversal pointer */
 
1310
    int        nblocks;    /* # of blocks on list */
 
1311
 
 
1312
    /* print each block on list */
 
1313
    for (ad = list, nblocks = 0; ad; ad = ad->next, nblocks++)
 
1314
    {
 
1315
        /* print to stdout */
 
1316
        ad_print(ad, block_type);
 
1317
        (void)printf(":\n");
 
1318
        (void)printf("\ttype of elements:\t\t%s\n",
 
1319
            ma_datatype[ad->datatype]);
 
1320
        (void)printf("\tnumber of elements:\t\t%ld\n",
 
1321
            (long)ad->nelem);
 
1322
        (void)printf("\taddress of client space:\t0x%lx\n",
 
1323
            (long)ad->client_space);
 
1324
        (void)printf("\tindex for client space:\t\t%ld\n",
 
1325
            (long)(client_space_index(ad) + index_base));
 
1326
        (void)printf("\ttotal number of bytes:\t\t%lu\n",
 
1327
            ad->nbytes);
 
1328
    }
 
1329
 
 
1330
    /* return the number of blocks on list */
 
1331
    return nblocks;
 
1332
}
 
1333
 
 
1334
/* ------------------------------------------------------------------------- */
 
1335
/*
 
1336
 * Check each block on list for checksum and guard errors.  For each error
 
1337
 * found, print a message to stdout.  Return counts of the various errors
 
1338
 * in the bad_ parameters.
 
1339
 */
 
1340
/* ------------------------------------------------------------------------- */
 
1341
 
 
1342
private void list_verify(list, block_type, preamble, blocks,
 
1343
                         bad_blocks, bad_checksums, bad_lguards, bad_rguards)
 
1344
    AD        *list;        /* to verify */
 
1345
    char    *block_type;    /* for error messages */
 
1346
    char    *preamble;    /* printed before first error message */
 
1347
    int        *blocks;    /* RETURN: # of blocks */
 
1348
    int        *bad_blocks;    /* RETURN: # of blocks having errors */
 
1349
    int        *bad_checksums;    /* RETURN: # of blocks having bad checksum */
 
1350
    int        *bad_lguards;    /* RETURN: # of blocks having bad guard1 */
 
1351
    int        *bad_rguards;    /* RETURN: # of blocks having bad guard2 */
 
1352
{
 
1353
    AD        *ad;        /* traversal pointer */
 
1354
    Boolean    first_bad_block;/* first bad block found? */
 
1355
    Boolean    bad_block;    /* problem in current block? */
 
1356
    Guard    signature;    /* value to be read */
 
1357
    Pointer    guard;        /* address to read from */
 
1358
 
 
1359
    /* initialize */
 
1360
    *blocks = 0;
 
1361
    *bad_blocks = 0;
 
1362
    *bad_checksums = 0;
 
1363
    *bad_lguards = 0;
 
1364
    *bad_rguards = 0;
 
1365
    first_bad_block = MA_TRUE;
 
1366
 
 
1367
    /* check each block on list */
 
1368
    for (ad = list; ad; ad = ad->next)
 
1369
    {
 
1370
        (*blocks)++;
 
1371
        bad_block = MA_FALSE;
 
1372
 
 
1373
        /* check for checksum error */
 
1374
        if (checksum(ad) != ad->checksum)
 
1375
        {
 
1376
            /* print preamble if necessary */
 
1377
            if (first_bad_block && (preamble != (char *)NULL))
 
1378
            {
 
1379
                (void)printf(preamble);
 
1380
                first_bad_block = MA_FALSE;
 
1381
            }
 
1382
 
 
1383
            /* print error message to stdout */
 
1384
            ad_print(ad, block_type);
 
1385
            (void)printf(":\n\t");
 
1386
            (void)printf("current checksum %lu != stored checksum %lu\n",
 
1387
                checksum(ad),
 
1388
                ad->checksum);
 
1389
 
 
1390
            /* do bookkeeping */
 
1391
            (*bad_checksums)++;
 
1392
            bad_block = MA_TRUE;
 
1393
        }
 
1394
 
 
1395
        /* check for bad guard1 */
 
1396
        guard = guard1(ad);
 
1397
        guard_read(guard, &signature);
 
1398
        if (signature != GUARD1)
 
1399
        {
 
1400
            /* print preamble if necessary */
 
1401
            if (first_bad_block && (preamble != (char *)NULL))
 
1402
            {
 
1403
                (void)printf(preamble);
 
1404
                first_bad_block = MA_FALSE;
 
1405
            }
 
1406
 
 
1407
            /* print error message to stdout */
 
1408
            ad_print(ad, block_type);
 
1409
            (void)printf(":\n\t");
 
1410
            (void)printf(
 
1411
                "current left signature %u != proper left signature %u\n",
 
1412
                signature,
 
1413
                GUARD1);
 
1414
 
 
1415
            /* do bookkeeping */
 
1416
            (*bad_lguards)++;
 
1417
            bad_block = MA_TRUE;
 
1418
        }
 
1419
 
 
1420
        /* check for bad guard2 */
 
1421
        guard = guard2(ad);
 
1422
        guard_read(guard, &signature);
 
1423
        if (signature != GUARD2)
 
1424
        {
 
1425
            /* print preamble if necessary */
 
1426
            if (first_bad_block && (preamble != (char *)NULL))
 
1427
            {
 
1428
                (void)printf(preamble);
 
1429
                first_bad_block = MA_FALSE;
 
1430
            }
 
1431
 
 
1432
            /* print error message to stdout */
 
1433
            ad_print(ad, block_type);
 
1434
            (void)printf(":\n\t");
 
1435
            (void)printf(
 
1436
                "current right signature %u != proper right signature %u\n",
 
1437
                signature,
 
1438
                GUARD2);
 
1439
 
 
1440
            /* do bookkeeping */
 
1441
            (*bad_rguards)++;
 
1442
            bad_block = MA_TRUE;
 
1443
        }
 
1444
 
 
1445
        /* if any errors, bump bad block count */
 
1446
        if (bad_block)
 
1447
            (*bad_blocks)++;
 
1448
    }
 
1449
}
 
1450
 
 
1451
/* ------------------------------------------------------------------------- */
 
1452
/*
 
1453
 * Return the maximum number of datatype elements that can currently be
 
1454
 * accomodated in a heap fragment (a block on the heap free list) entirely
 
1455
 * within the heap region, or 0 if this number is less than min_nelem.
 
1456
 */
 
1457
/* ------------------------------------------------------------------------- */
 
1458
 
 
1459
private Integer ma_max_heap_frag_nelem(datatype, min_nelem)
 
1460
    Integer    datatype;    /* of elements */
 
1461
    Integer    min_nelem;    /* for fragment to be considered */
 
1462
{
 
1463
    ulongi    min_bytes;    /* for fragment to be considered */
 
1464
    AD        *ad;        /* traversal pointer */
 
1465
    ulongi    nbytes;        /* in current fragment */
 
1466
    Integer    nelem;        /* in current fragment */
 
1467
    Integer    max_nelem;    /* result */
 
1468
 
 
1469
    /* set the threshold */
 
1470
    min_bytes = (min_nelem * ma_sizeof[datatype]) + BLOCK_OVERHEAD_FIXED;
 
1471
 
 
1472
    /* search the heap free list */
 
1473
    max_nelem = 0;
 
1474
    for (ad = ma_hfree; ad; ad = ad->next)
 
1475
    {
 
1476
        /*
 
1477
         * There are 3 cases to consider:
 
1478
         *
 
1479
         * (a) fragment is outside heap region
 
1480
         * (b) fragment straddles partition between heap and stack regions
 
1481
         * (c) fragment is inside heap region
 
1482
         */
 
1483
 
 
1484
        if ((Pointer)ad >= ma_partition)
 
1485
        {
 
1486
            /* case (a): reject */
 
1487
            continue;
 
1488
        }
 
1489
        else if (((Pointer)ad + ad->nbytes) >= ma_partition)
 
1490
        {
 
1491
            /* case (b): truncate fragment at partition */
 
1492
            nbytes = (ulongi)(ma_partition - (Pointer)ad);
 
1493
        }
 
1494
        else
 
1495
        {
 
1496
            /* case (c): accept */
 
1497
            nbytes = ad->nbytes;
 
1498
        }
 
1499
 
 
1500
        if (nbytes >= min_bytes)
 
1501
        {
 
1502
            nelem = ma_nelem((Pointer)ad, nbytes, datatype);
 
1503
            max_nelem = max(max_nelem, nelem);
 
1504
        }
 
1505
    }
 
1506
 
 
1507
    /* return the result */
 
1508
    return max_nelem;
 
1509
}
 
1510
 
 
1511
/* ------------------------------------------------------------------------- */
 
1512
/*
 
1513
 * Return the maximum number of datatype elements that can currently
 
1514
 * be accomodated in length bytes starting at address.
 
1515
 */
 
1516
/* ------------------------------------------------------------------------- */
 
1517
 
 
1518
private Integer ma_nelem(address, length, datatype)
 
1519
    Pointer    address;    /* location of hypothetical block */
 
1520
    ulongi    length;        /* length of hypothetical block */
 
1521
    Integer    datatype;    /* of elements in hypothetical block */
 
1522
{
 
1523
    AR        ar;        /* allocation request */
 
1524
    Pointer    client_space;    /* location of client_space */
 
1525
    ulongi    nbytes;        /* length of block for ar */
 
1526
 
 
1527
    if (length <= BLOCK_OVERHEAD_FIXED)
 
1528
        /* no point in computing anything */
 
1529
        return (Integer)0;
 
1530
 
 
1531
    /* compute initial request */
 
1532
    ar.datatype = datatype;
 
1533
    ar.nelem = (length - BLOCK_OVERHEAD_FIXED) / ma_sizeof[datatype];
 
1534
 
 
1535
    /* make requests until one succeeds or we give up */
 
1536
    while (ar.nelem > 0)
 
1537
    {
 
1538
        /* perform trial allocation to determine size */
 
1539
        balloc_after(&ar, address, &client_space, &nbytes);
 
1540
 
 
1541
        if (nbytes > length)
 
1542
            /* not enough space for ar.nelem elements */
 
1543
            ar.nelem--;
 
1544
        else
 
1545
            /* enough space for ar.nelem elements */
 
1546
            break;
 
1547
    }
 
1548
 
 
1549
    /* return the result */
 
1550
    return ar.nelem;
 
1551
}
 
1552
 
 
1553
/* ------------------------------------------------------------------------- */
 
1554
/*
 
1555
 * Perform operations necessary to allow certain functions to be invoked
 
1556
 * before MA_init is called.
 
1557
 */
 
1558
/* ------------------------------------------------------------------------- */
 
1559
 
 
1560
private void ma_preinitialize(caller)
 
1561
    char    *caller;    /* name of calling routine */
 
1562
{
 
1563
    if (ma_preinitialized)
 
1564
        return;
 
1565
 
 
1566
    /* call a FORTRAN routine to set bases and sizes of FORTRAN datatypes */
 
1567
    if (ma_set_sizes_() == 0)
 
1568
    {
 
1569
        (void)sprintf(ma_ebuf,
 
1570
            "unable to set sizes of FORTRAN datatypes");
 
1571
        ma_error(EL_Fatal, ET_Internal, caller, ma_ebuf);
 
1572
        return;
 
1573
    }
 
1574
 
 
1575
    /* success */
 
1576
    ma_preinitialized = MA_TRUE;
 
1577
}
 
1578
 
 
1579
/* ------------------------------------------------------------------------- */
 
1580
/*
 
1581
 * If memhandle is valid according to location, return the corresponding AD
 
1582
 * in adout and return MA_TRUE, else print an error message and return
 
1583
 * MA_FALSE.
 
1584
 */
 
1585
/* ------------------------------------------------------------------------- */
 
1586
 
 
1587
private Boolean mh2ad(memhandle, adout, location, caller)
 
1588
    Integer    memhandle;    /* the handle to verify and convert */
 
1589
    AD        **adout;    /* RETURN: AD corresponding to memhandle */
 
1590
    BlockLocation location;    /* where AD must reside */
 
1591
    char    *caller;    /* name of calling routine */
 
1592
{
 
1593
    AD        *ad;
 
1594
    Boolean    check_checksum = MA_TRUE;
 
1595
    Boolean    check_guards = MA_TRUE;
 
1596
    Boolean    check_heap = MA_FALSE;
 
1597
    Boolean    check_stack = MA_FALSE;
 
1598
    Boolean    check_stacktop = MA_FALSE;
 
1599
    Boolean    check_heapandstack = MA_FALSE;
 
1600
 
 
1601
    switch (location)
 
1602
    {
 
1603
        case BL_HeapOrStack:
 
1604
            check_heapandstack = MA_TRUE;
 
1605
            break;
 
1606
        case BL_Heap:
 
1607
            check_heap = MA_TRUE;
 
1608
            break;
 
1609
        case BL_Stack:
 
1610
            check_stack = MA_TRUE;
 
1611
            break;
 
1612
        case BL_StackTop:
 
1613
            check_stacktop = MA_TRUE;
 
1614
            break;
 
1615
        default:
 
1616
            (void)sprintf(ma_ebuf,
 
1617
                "invalid location: %d",
 
1618
                (int)location);
 
1619
            ma_error(EL_Nonfatal, ET_Internal, "mh2ad", ma_ebuf);
 
1620
            return MA_FALSE;
 
1621
    }
 
1622
 
 
1623
    /* convert memhandle to AD */
 
1624
    if (!ma_table_verify(memhandle, caller))
 
1625
        return MA_FALSE;
 
1626
    else
 
1627
        ad = (AD *)ma_table_lookup(memhandle);
 
1628
 
 
1629
    /* attempt to avoid crashes due to corrupt addresses */
 
1630
    if (!reasonable_address((Pointer)ad))
 
1631
    {
 
1632
        (void)sprintf(ma_ebuf,
 
1633
            "invalid block address (0x%lx) for memhandle %ld",
 
1634
            (long)ad, (long)memhandle);
 
1635
        ma_error(EL_Nonfatal, ET_External, caller, ma_ebuf);
 
1636
        return MA_FALSE;
 
1637
    }
 
1638
 
 
1639
    if (check_checksum)
 
1640
    {
 
1641
        if (checksum(ad) != ad->checksum)
 
1642
        {
 
1643
            (void)sprintf(ma_ebuf,
 
1644
                "invalid checksum for memhandle %ld (name: '%s')",
 
1645
                (long)memhandle, ad->name);
 
1646
            ma_error(EL_Nonfatal, ET_External, caller, ma_ebuf);
 
1647
            return MA_FALSE;
 
1648
        }
 
1649
    }
 
1650
 
 
1651
    if (check_guards)
 
1652
    {
 
1653
        if (!guard_check(ad))
 
1654
        {
 
1655
            (void)sprintf(ma_ebuf,
 
1656
                "invalid guard(s) for memhandle %ld (name: '%s')",
 
1657
                (long)memhandle, ad->name);
 
1658
            ma_error(EL_Nonfatal, ET_External, caller, ma_ebuf);
 
1659
            return MA_FALSE;
 
1660
        }
 
1661
    }
 
1662
 
 
1663
    if (check_heap)
 
1664
    {
 
1665
        if (!list_member(ad, ma_hused))
 
1666
        {
 
1667
            (void)sprintf(ma_ebuf,
 
1668
                "memhandle %ld (name: '%s') not in heap",
 
1669
                (long)memhandle, ad->name);
 
1670
            ma_error(EL_Nonfatal, ET_External, caller, ma_ebuf);
 
1671
            return MA_FALSE;
 
1672
        }
 
1673
    }
 
1674
    else if (check_stack)
 
1675
    {
 
1676
        if (!list_member(ad, ma_sused))
 
1677
        {
 
1678
            (void)sprintf(ma_ebuf,
 
1679
                "memhandle %ld (name: '%s') not in stack",
 
1680
                (long)memhandle, ad->name);
 
1681
            ma_error(EL_Nonfatal, ET_External, caller, ma_ebuf);
 
1682
            return MA_FALSE;
 
1683
        }
 
1684
    }
 
1685
    else if (check_stacktop)
 
1686
    {
 
1687
        /* is it in the stack? */
 
1688
        if (!list_member(ad, ma_sused))
 
1689
        {
 
1690
            (void)sprintf(ma_ebuf,
 
1691
                "memhandle %ld (name: '%s') not in stack",
 
1692
                (long)memhandle, ad->name);
 
1693
            ma_error(EL_Nonfatal, ET_External, caller, ma_ebuf);
 
1694
            return MA_FALSE;
 
1695
        }
 
1696
 
 
1697
        /* is it on top of the stack? */
 
1698
        if ((Pointer)ad != ma_sp)
 
1699
        {
 
1700
            (void)sprintf(ma_ebuf,
 
1701
                "memhandle %ld (name: '%s') not top of stack",
 
1702
                (long)memhandle, ad->name);
 
1703
            ma_error(EL_Nonfatal, ET_External, caller, ma_ebuf);
 
1704
            return MA_FALSE;
 
1705
        }
 
1706
    }
 
1707
    else if (check_heapandstack)
 
1708
    {
 
1709
        if ((!list_member(ad, ma_hused)) && (!list_member(ad, ma_sused)))
 
1710
        {
 
1711
            (void)sprintf(ma_ebuf,
 
1712
                "memhandle %ld (name: '%s') not in heap or stack",
 
1713
                (long)memhandle, ad->name);
 
1714
            ma_error(EL_Nonfatal, ET_External, caller, ma_ebuf);
 
1715
            return MA_FALSE;
 
1716
        }
 
1717
    }
 
1718
 
 
1719
    /* ad is valid */
 
1720
    *adout = ad;
 
1721
    return MA_TRUE;
 
1722
}
 
1723
 
 
1724
/* ------------------------------------------------------------------------- */
 
1725
/*
 
1726
 * Free the memhandle corresponding to the given AD.
 
1727
 */
 
1728
/* ------------------------------------------------------------------------- */
 
1729
 
 
1730
private void mh_free(ad)
 
1731
    AD        *ad;        /* the AD whose memhandle to free */
 
1732
{
 
1733
    Integer    memhandle;    /* memhandle for AD */
 
1734
 
 
1735
    /* convert AD to memhandle */
 
1736
    if ((memhandle = ma_table_lookup_assoc((TableData)ad)) == TABLE_HANDLE_NONE)
 
1737
    {
 
1738
        (void)sprintf(ma_ebuf,
 
1739
            "cannot find memhandle for block address 0x%lx",
 
1740
            (long)ad);
 
1741
        ma_error(EL_Nonfatal, ET_Internal, "mh_free", ma_ebuf);
 
1742
    }
 
1743
    else
 
1744
        /* free memhandle */
 
1745
        ma_table_deallocate(memhandle);
 
1746
}
 
1747
 
 
1748
/* ------------------------------------------------------------------------- */
 
1749
/*
 
1750
 * Return the first multiple of unit which is >= value.
 
1751
 */
 
1752
/* ------------------------------------------------------------------------- */
 
1753
 
 
1754
private long mai_round(value, unit)
 
1755
    long    value;        /* to round */
 
1756
    ulongi    unit;        /* to round to */
 
1757
{
 
1758
    /* voodoo ... */
 
1759
    unit--;
 
1760
    value += unit;
 
1761
    value &= ~(long)unit;
 
1762
    return value;
 
1763
}
 
1764
 
 
1765
/* ------------------------------------------------------------------------- */
 
1766
/*
 
1767
 * Copy at most maxchars-1 non-NUL chars from from to to; NUL-terminate to.
 
1768
 */
 
1769
/* ------------------------------------------------------------------------- */
 
1770
 
 
1771
private void str_ncopy(to, from, maxchars)
 
1772
    char    *to;        /* space to copy to */
 
1773
    char    *from;        /* space to copy from */
 
1774
    int        maxchars;    /* max # of chars (including NUL) copied */
 
1775
{
 
1776
    if (from == (char *)NULL)
 
1777
    {
 
1778
        to[0] = '\0';
 
1779
        return;
 
1780
    }
 
1781
 
 
1782
    /* copy up to maxchars chars */
 
1783
    (void)strncpy(to, from, maxchars);
 
1784
 
 
1785
    /* ensure to is NUL-terminated */
 
1786
    to[maxchars-1] = '\0';
 
1787
}
 
1788
 
 
1789
/**
 
1790
 ** public routines for internal use only
 
1791
 **/
 
1792
 
 
1793
/* ------------------------------------------------------------------------- */
 
1794
/*
 
1795
 * Set the base address and size of the given datatype.
 
1796
 */
 
1797
/* ------------------------------------------------------------------------- */
 
1798
 
 
1799
public Boolean MAi_inform_base(datatype, address1, address2)
 
1800
    Integer    datatype;    /* to set size of */
 
1801
    Pointer    address1;    /* of datatype element base */
 
1802
    Pointer    address2;    /* of an adjacent datatype element */
 
1803
{
 
1804
    /* verify uninitialization */
 
1805
    if (ma_initialized)
 
1806
    {
 
1807
        (void)sprintf(ma_ebuf,
 
1808
            "MA already initialized");
 
1809
        ma_error(EL_Nonfatal, ET_Internal, "MAi_inform_base", ma_ebuf);
 
1810
        return MA_FALSE;
 
1811
    }
 
1812
 
 
1813
    /* verify datatype */
 
1814
    if (!mt_valid(datatype))
 
1815
    {
 
1816
        (void)sprintf(ma_ebuf,
 
1817
            "invalid datatype: %ld",
 
1818
            (long)datatype);
 
1819
        ma_error(EL_Nonfatal, ET_Internal, "MAi_inform_base", ma_ebuf);
 
1820
        return MA_FALSE;
 
1821
    }
 
1822
 
 
1823
    /* convert datatype to internal (index-suitable) value */
 
1824
    datatype = mt_import(datatype);
 
1825
 
 
1826
    /* set the base address of datatype */
 
1827
    ma_base[datatype] = address1;
 
1828
 
 
1829
    /* set the size of datatype */
 
1830
    ma_sizeof[datatype] = (int)(address2 - address1);
 
1831
 
 
1832
    /* success */
 
1833
    return MA_TRUE;
 
1834
}
 
1835
 
 
1836
#if NOFORT
 
1837
Integer ma_set_sizes_()
 
1838
{
 
1839
    MAi_inform_base(MT_F_BYTE, &ma_cb_char[0],  &ma_cb_char[1]);
 
1840
    MAi_inform_base(MT_F_INT,  &ma_cb_int[0],   &ma_cb_int[1]);
 
1841
    MAi_inform_base(MT_F_LOG,  &ma_cb_int[0],   &ma_cb_int[1]);
 
1842
    MAi_inform_base(MT_F_REAL, &ma_cb_float[0], &ma_cb_float[1]);
 
1843
    MAi_inform_base(MT_F_DBL,  &ma_cb_dbl[0],   &ma_cb_dbl[1]);
 
1844
    MAi_inform_base(MT_F_SCPL, &ma_cb_scpl[0],  &ma_cb_scpl[1]);
 
1845
    MAi_inform_base(MT_F_DCPL, &ma_cb_dcpl[0],  &ma_cb_dcpl[1]);
 
1846
    return 1;
 
1847
}
 
1848
#endif
 
1849
 
 
1850
/* ------------------------------------------------------------------------- */
 
1851
/*
 
1852
 * Print debugging information about all blocks currently in use
 
1853
 * on the heap or the stack.
 
1854
 */
 
1855
/* ------------------------------------------------------------------------- */
 
1856
 
 
1857
public void MAi_summarize_allocated_blocks(index_base)
 
1858
    int        index_base;    /* 0 (C) or 1 (FORTRAN) */
 
1859
{
 
1860
    int        heap_blocks;    /* # of blocks on heap used list */
 
1861
    int        stack_blocks;    /* # of blocks on stack used list */
 
1862
 
 
1863
#ifdef STATS
 
1864
    ma_stats.calls[(int)FID_MA_summarize_allocated_blocks]++;
 
1865
#endif /* STATS */
 
1866
 
 
1867
#ifdef VERIFY
 
1868
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
1869
        return;
 
1870
#endif /* VERIFY */
 
1871
 
 
1872
    /* verify index_base */
 
1873
    if ((index_base != 0) && (index_base != 1))
 
1874
    {
 
1875
        (void)sprintf(ma_ebuf,
 
1876
            "invalid index_base: %d",
 
1877
            index_base);
 
1878
        ma_error(EL_Nonfatal, ET_Internal, "MAi_summarize_allocated_blocks", ma_ebuf);
 
1879
        return;
 
1880
    }
 
1881
 
 
1882
    (void)printf("MA_summarize_allocated_blocks: starting scan ...\n");
 
1883
 
 
1884
    /* print blocks on the heap used list */
 
1885
    heap_blocks = list_print(ma_hused, "heap", index_base);
 
1886
 
 
1887
    /* print blocks on the stack used list */
 
1888
    stack_blocks = list_print(ma_sused, "stack", index_base);
 
1889
 
 
1890
    (void)printf("MA_summarize_allocated_blocks: scan completed: ");
 
1891
    (void)printf("%d heap block%s, %d stack block%s\n",
 
1892
        heap_blocks,
 
1893
        plural(heap_blocks),
 
1894
        stack_blocks,
 
1895
        plural(stack_blocks));
 
1896
}
 
1897
 
 
1898
/**
 
1899
 ** public routines
 
1900
 **/
 
1901
 
 
1902
/* ------------------------------------------------------------------------- */
 
1903
/*
 
1904
 * Convenience function that combines MA_allocate_heap and MA_get_index.
 
1905
 */
 
1906
/* ------------------------------------------------------------------------- */
 
1907
 
 
1908
public Boolean MA_alloc_get(
 
1909
    Integer    datatype,    /* of elements in this block */
 
1910
    Integer    nelem,        /* # of elements in this block */
 
1911
    const char    *name,        /* assigned to this block by client */
 
1912
    Integer    *memhandle,    /* RETURN: handle for this block */
 
1913
    MA_AccessIndex    *index  /* RETURN: index for this block */   )
 
1914
{
 
1915
#ifdef STATS
 
1916
    ma_stats.calls[(int)FID_MA_alloc_get]++;
 
1917
#endif /* STATS */
 
1918
 
 
1919
    if (MA_allocate_heap(datatype, nelem, name, memhandle))
 
1920
        /* MA_allocate_heap succeeded; try MA_get_index */
 
1921
        return MA_get_index(*memhandle, index);
 
1922
    else
 
1923
        /* MA_allocate_heap failed */
 
1924
        return MA_FALSE;
 
1925
}
 
1926
 
 
1927
/* ------------------------------------------------------------------------- */
 
1928
/*
 
1929
 * Allocate a heap block big enough to hold nelem elements
 
1930
 * of the given datatype.
 
1931
 *
 
1932
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
1933
 */
 
1934
/* ------------------------------------------------------------------------- */
 
1935
 
 
1936
public Boolean MA_allocate_heap(
 
1937
    Integer    datatype,    /* of elements in this block */
 
1938
    Integer    nelem,        /* # of elements in this block */
 
1939
    const char    *name,        /* assigned to this block by client */
 
1940
    Integer    *memhandle    /* RETURN: handle for this block */ )
 
1941
{
 
1942
    AR        ar;        /* allocation request */
 
1943
    AD        *ad;        /* AD for newly allocated block */
 
1944
    Pointer    client_space;    /* location of client_space */
 
1945
    ulongi    nbytes;        /* length of block for ar */
 
1946
    Pointer    new_hp;        /* new ma_hp */
 
1947
 
 
1948
#ifdef STATS
 
1949
    ma_stats.calls[(int)FID_MA_allocate_heap]++;
 
1950
#endif /* STATS */
 
1951
 
 
1952
#ifdef VERIFY
 
1953
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
1954
        return MA_FALSE;
 
1955
#endif /* VERIFY */
 
1956
 
 
1957
    if (ma_trace) 
 
1958
    (void)printf("MA: allocating '%s' (%d)\n", name, (int)nelem);
 
1959
 
 
1960
    /* verify initialization */
 
1961
    if (!ma_initialized)
 
1962
    {
 
1963
        (void)sprintf(ma_ebuf,
 
1964
            "block '%s', MA not yet initialized",
 
1965
            name);
 
1966
        ma_error(EL_Nonfatal, ET_External, "MA_allocate_heap", ma_ebuf);
 
1967
        return MA_FALSE;
 
1968
    }
 
1969
 
 
1970
    /* verify datatype */
 
1971
    if (!mt_valid(datatype))
 
1972
    {
 
1973
        (void)sprintf(ma_ebuf,
 
1974
            "block '%s', invalid datatype: %ld",
 
1975
            name, (long)datatype);
 
1976
        ma_error(EL_Nonfatal, ET_External, "MA_allocate_heap", ma_ebuf);
 
1977
        return MA_FALSE;
 
1978
    }
 
1979
 
 
1980
    /* verify nelem */
 
1981
    if (nelem < 0)
 
1982
    {
 
1983
        (void)sprintf(ma_ebuf,
 
1984
            "block '%s', invalid nelem: %ld",
 
1985
            name, (long)nelem);
 
1986
        ma_error(EL_Nonfatal, ET_External, "MA_allocate_heap", ma_ebuf);
 
1987
        return MA_FALSE;
 
1988
    }
 
1989
 
 
1990
    /* convert datatype to internal (index-suitable) value */
 
1991
    datatype = mt_import(datatype);
 
1992
 
 
1993
    /*
 
1994
     * attempt to allocate space
 
1995
     */
 
1996
 
 
1997
    ar.datatype = datatype;
 
1998
    ar.nelem = nelem;
 
1999
 
 
2000
    /* search the free list */
 
2001
    ad = list_delete_one(&ma_hfree, ad_big_enough, (Pointer)&ar);
 
2002
 
 
2003
    /* if search of free list failed, try expanding heap region */
 
2004
    if (ad == (AD *)NULL)
 
2005
    {
 
2006
        /* perform trial allocation to determine size */
 
2007
        balloc_after(&ar, ma_hp, &client_space, &nbytes);
 
2008
 
 
2009
        new_hp = ma_hp + nbytes;
 
2010
        if (new_hp > ma_sp)
 
2011
        {
 
2012
            (void)sprintf(ma_ebuf,
 
2013
                "block '%s', not enough space to allocate %lu bytes",
 
2014
                name, nbytes);
 
2015
            ma_error(EL_Nonfatal, ET_External, "MA_allocate_heap", ma_ebuf);
 
2016
            return MA_FALSE;
 
2017
        }
 
2018
        else
 
2019
        {
 
2020
            /* heap region expanded successfully */
 
2021
            ad = (AD *)ma_hp;
 
2022
 
 
2023
            /* set fields appropriately */
 
2024
            ad->client_space = client_space;
 
2025
            ad->nbytes = nbytes;
 
2026
        }
 
2027
    }
 
2028
 
 
2029
    /*
 
2030
     * space has been allocated
 
2031
     */
 
2032
 
 
2033
    /* initialize the AD */
 
2034
    ad->datatype = datatype;
 
2035
    ad->nelem = nelem;
 
2036
    str_ncopy(ad->name, (char*)name, MA_NAMESIZE);
 
2037
    /* ad->client_space is already set */
 
2038
    /* ad->nbytes is already set */
 
2039
    list_insert(ad, &ma_hused);
 
2040
    ad->checksum = checksum(ad);
 
2041
 
 
2042
    /* set the guards */
 
2043
    guard_set(ad);
 
2044
 
 
2045
#ifdef DEBUG
 
2046
    debug_ad_print(ad);
 
2047
#endif /* DEBUG */
 
2048
 
 
2049
    /* update ma_hp if necessary */
 
2050
    new_hp = (Pointer)ad + ad->nbytes;
 
2051
    if (new_hp > ma_hp)
 
2052
    {
 
2053
        ma_hp = new_hp;
 
2054
    }
 
2055
 
 
2056
#ifdef STATS
 
2057
    ma_stats.hblocks++;
 
2058
    ma_stats.hblocks_max = max(ma_stats.hblocks, ma_stats.hblocks_max);
 
2059
    ma_stats.hbytes += ad->nbytes;
 
2060
    ma_stats.hbytes_max = max(ma_stats.hbytes, ma_stats.hbytes_max);
 
2061
#endif /* STATS */
 
2062
 
 
2063
    /* convert AD to memhandle */
 
2064
    if ((*memhandle = ma_table_allocate((TableData)ad)) == TABLE_HANDLE_NONE)
 
2065
        /* failure */
 
2066
        return MA_FALSE;
 
2067
    else
 
2068
        /* success */
 
2069
        return MA_TRUE;
 
2070
}
 
2071
 
 
2072
/* ------------------------------------------------------------------------- */
 
2073
/*
 
2074
 * Deallocate the given stack block and all stack blocks allocated
 
2075
 * after it.
 
2076
 *
 
2077
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
2078
 */
 
2079
/* ------------------------------------------------------------------------- */
 
2080
 
 
2081
public Boolean MA_chop_stack(Integer memhandle)/*the block to deallocate up to*/
 
2082
{
 
2083
    AD        *ad;        /* AD for memhandle */
 
2084
 
 
2085
#ifdef STATS
 
2086
    ma_stats.calls[(int)FID_MA_chop_stack]++;
 
2087
#endif /* STATS */
 
2088
 
 
2089
#ifdef VERIFY
 
2090
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2091
        return MA_FALSE;
 
2092
#endif /* VERIFY */
 
2093
 
 
2094
    /* verify memhandle and convert to AD */
 
2095
    if (!mh2ad(memhandle, &ad, BL_Stack, "MA_chop_stack"))
 
2096
        return MA_FALSE;
 
2097
 
 
2098
    /* delete block and all blocks above it from used list */
 
2099
#ifdef STATS
 
2100
    ma_stats.sblocks -=
 
2101
        list_delete_many(&ma_sused, ad_le, (Pointer)ad, mh_free);
 
2102
#else
 
2103
    (void)list_delete_many(&ma_sused, ad_le, (Pointer)ad, mh_free);
 
2104
#endif /* STATS */
 
2105
 
 
2106
    /* pop block and all blocks above it from stack */
 
2107
#ifdef STATS
 
2108
    ma_stats.sbytes -= (((Pointer)ad + ad->nbytes) - ma_sp);
 
2109
#endif /* STATS */
 
2110
    ma_sp = (Pointer)ad + ad->nbytes;
 
2111
 
 
2112
    /* success */
 
2113
    return MA_TRUE;
 
2114
}
 
2115
 
 
2116
/* ------------------------------------------------------------------------- */
 
2117
/*
 
2118
 * Deallocate the given heap block.
 
2119
 *
 
2120
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
2121
 */
 
2122
/* ------------------------------------------------------------------------- */
 
2123
 
 
2124
public Boolean MA_free_heap(Integer memhandle) /* the block to deallocate */
 
2125
{
 
2126
    AD        *ad;        /* AD for memhandle */
 
2127
 
 
2128
#ifdef STATS
 
2129
    ma_stats.calls[(int)FID_MA_free_heap]++;
 
2130
#endif /* STATS */
 
2131
 
 
2132
#ifdef VERIFY
 
2133
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2134
        return MA_FALSE;
 
2135
#endif /* VERIFY */
 
2136
 
 
2137
    /* verify memhandle and convert to AD */
 
2138
    if (!mh2ad(memhandle, &ad, BL_Heap, "MA_free_heap"))
 
2139
        return MA_FALSE;
 
2140
 
 
2141
    if (ma_trace) 
 
2142
    (void)printf("MA: freeing '%s'\n", ad->name);
 
2143
 
 
2144
    /* delete block from used list */
 
2145
    if (list_delete(ad, &ma_hused) != ad)
 
2146
    {
 
2147
        (void)sprintf(ma_ebuf,
 
2148
            "memhandle %ld (name: '%s') not on heap used list",
 
2149
            (long)memhandle, ad->name);
 
2150
        ma_error(EL_Nonfatal, ET_Internal, "MA_free_heap", ma_ebuf);
 
2151
        return MA_FALSE;
 
2152
    }
 
2153
 
 
2154
#ifdef STATS
 
2155
    ma_stats.hblocks--;
 
2156
    ma_stats.hbytes -= ad->nbytes;
 
2157
#endif /* STATS */
 
2158
 
 
2159
    /* reclaim the deallocated block */
 
2160
    block_free_heap(ad);
 
2161
 
 
2162
    /* free memhandle */
 
2163
    ma_table_deallocate(memhandle);
 
2164
 
 
2165
    /* success */
 
2166
    return MA_TRUE;
 
2167
}
 
2168
 
 
2169
/* ------------------------------------------------------------------------- */
 
2170
/*
 
2171
 * Deallocate nelem elements from the given heap block.
 
2172
 *
 
2173
 * The nelem elements (of the datatype specified when the heap block
 
2174
 * was allocated) to be deallocated are assumed to be at the rightmost
 
2175
 * (i.e., higher addresses) edge of the heap block.
 
2176
 *
 
2177
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
2178
 */
 
2179
/* ------------------------------------------------------------------------- */
 
2180
 
 
2181
public Boolean MA_free_heap_piece(
 
2182
    Integer    memhandle,    /* the block to deallocate a piece of */
 
2183
    Integer    nelem         /* # of elements to deallocate */)
 
2184
{
 
2185
    AD        *ad;        /* AD for memhandle */
 
2186
    AD        *ad_reclaim;    /* AD for data returned */
 
2187
    AR        ar;        /* AR for data kept */
 
2188
    Pointer    client_space;    /* location of client_space */
 
2189
    ulongi    nbytes;        /* length of block for data kept */
 
2190
 
 
2191
#ifdef STATS
 
2192
    ma_stats.calls[(int)FID_MA_free_heap_piece]++;
 
2193
#endif /* STATS */
 
2194
 
 
2195
#ifdef VERIFY
 
2196
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2197
        return MA_FALSE;
 
2198
#endif /* VERIFY */
 
2199
 
 
2200
    /* verify memhandle and convert to AD */
 
2201
    if (!mh2ad(memhandle, &ad, BL_Heap, "MA_free_heap_piece"))
 
2202
        return MA_FALSE;
 
2203
 
 
2204
    /* verify nelem */
 
2205
    if (nelem < 0)
 
2206
    {
 
2207
        (void)sprintf(ma_ebuf,
 
2208
            "block '%s', invalid nelem: %ld",
 
2209
            ad->name, (long)nelem);
 
2210
        ma_error(EL_Nonfatal, ET_External, "MA_free_heap_piece", ma_ebuf);
 
2211
        return MA_FALSE;
 
2212
    }
 
2213
    else if (nelem >= ad->nelem)
 
2214
    {
 
2215
        /* deallocate the whole block */
 
2216
        return MA_free_heap(memhandle);
 
2217
    }
 
2218
 
 
2219
    if (ma_trace) 
 
2220
    (void)printf("MA: freeing %ld elements of '%s'\n",
 
2221
            (long)nelem, ad->name);
 
2222
 
 
2223
    /* set AR for data to keep */
 
2224
    ar.datatype = ad->datatype;
 
2225
    ar.nelem = ad->nelem - nelem;
 
2226
 
 
2227
    /* perform trial allocation to determine size */
 
2228
    balloc_after(&ar, (Pointer)ad, &client_space, &nbytes);
 
2229
 
 
2230
    if (nbytes < ad->nbytes)
 
2231
    {
 
2232
        /* ad has extra space; split block if possible */
 
2233
        ad_reclaim = block_split(ad, nbytes, (Boolean)MA_FALSE);
 
2234
 
 
2235
        if (ad_reclaim)
 
2236
        {
 
2237
#ifdef STATS
 
2238
            ma_stats.hbytes -= ad_reclaim->nbytes;
 
2239
#endif /* STATS */
 
2240
 
 
2241
            /* reclaim the deallocated (new) block */
 
2242
            block_free_heap(ad_reclaim);
 
2243
        }
 
2244
    }
 
2245
 
 
2246
    /* update surviving block */
 
2247
    ad->nelem = ar.nelem;
 
2248
    ad->checksum = checksum(ad);
 
2249
 
 
2250
    /* set the guards */
 
2251
    guard_set(ad);
 
2252
 
 
2253
#ifdef DEBUG
 
2254
    debug_ad_print(ad);
 
2255
#endif /* DEBUG */
 
2256
 
 
2257
    /* success */
 
2258
    return MA_TRUE;
 
2259
}
 
2260
 
 
2261
/* ------------------------------------------------------------------------- */
 
2262
/*
 
2263
 * Get the base index for the given block.
 
2264
 *
 
2265
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
2266
 */
 
2267
/* ------------------------------------------------------------------------- */
 
2268
 
 
2269
public Boolean MA_get_index(
 
2270
    Integer    memhandle,    /* block to get index for */
 
2271
    MA_AccessIndex    *index         /* RETURN: base index */)
 
2272
{
 
2273
    AD        *ad;        /* AD for memhandle */
 
2274
 
 
2275
#ifdef STATS
 
2276
    ma_stats.calls[(int)FID_MA_get_index]++;
 
2277
#endif /* STATS */
 
2278
 
 
2279
#ifdef VERIFY
 
2280
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2281
        return MA_FALSE;
 
2282
#endif /* VERIFY */
 
2283
 
 
2284
    /* verify memhandle and convert to AD */
 
2285
    if (mh2ad(memhandle, &ad, BL_HeapOrStack, "MA_get_index"))
 
2286
    {
 
2287
        /* compute index */
 
2288
        *index = client_space_index(ad);
 
2289
 
 
2290
        /* success */
 
2291
        return MA_TRUE;
 
2292
    }
 
2293
    else
 
2294
    {
 
2295
        /* failure */
 
2296
        return MA_FALSE;
 
2297
    }
 
2298
}
 
2299
 
 
2300
/* ------------------------------------------------------------------------- */
 
2301
/*
 
2302
 * Return the base address of the given datatype.
 
2303
 */
 
2304
/* ------------------------------------------------------------------------- */
 
2305
 
 
2306
public Pointer MA_get_mbase(Integer datatype)    /* to get base address of */
 
2307
{
 
2308
#ifdef STATS
 
2309
    ma_stats.calls[(int)FID_MA_get_mbase]++;
 
2310
#endif /* STATS */
 
2311
 
 
2312
    /* preinitialize if necessary */
 
2313
    ma_preinitialize("MA_get_mbase");
 
2314
 
 
2315
    /* verify datatype */
 
2316
    if (!mt_valid(datatype))
 
2317
    {
 
2318
        (void)sprintf(ma_ebuf,
 
2319
            "invalid datatype: %ld",
 
2320
            (long)datatype);
 
2321
        ma_error(EL_Fatal, ET_External, "MA_get_mbase", ma_ebuf);
 
2322
        return NULL;
 
2323
    }
 
2324
 
 
2325
    /* convert datatype to internal (index-suitable) value */
 
2326
    datatype = mt_import(datatype);
 
2327
 
 
2328
    return ma_base[datatype];
 
2329
}
 
2330
 
 
2331
/* ------------------------------------------------------------------------- */
 
2332
/*
 
2333
 * Get the handle for the next block in the scan of currently allocated
 
2334
 * blocks.
 
2335
 *
 
2336
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
2337
 */
 
2338
/* ------------------------------------------------------------------------- */
 
2339
 
 
2340
public Boolean MA_get_next_memhandle(
 
2341
    Integer    *ithandle,    /* handle for this iterator */
 
2342
    Integer    *memhandle     /* RETURN: handle for the next block */)
 
2343
{
 
2344
#ifdef STATS
 
2345
    ma_stats.calls[(int)FID_MA_get_next_memhandle]++;
 
2346
#endif /* STATS */
 
2347
 
 
2348
#ifdef VERIFY
 
2349
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2350
        return MA_FALSE;
 
2351
#endif /* VERIFY */
 
2352
 
 
2353
    /* not yet implemented */
 
2354
    (void)sprintf(ma_ebuf,
 
2355
        "not yet implemented");
 
2356
    ma_error(EL_Nonfatal, ET_External, "MA_get_next_memhandle", ma_ebuf);
 
2357
    return MA_FALSE;
 
2358
}
 
2359
 
 
2360
/* ------------------------------------------------------------------------- */
 
2361
/*
 
2362
 * Get the requested alignment.
 
2363
 *
 
2364
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
2365
 */
 
2366
/* ------------------------------------------------------------------------- */
 
2367
 
 
2368
public Boolean MA_get_numalign(Integer *value)
 
2369
    /* RETURN: requested alignment */
 
2370
{
 
2371
#ifdef STATS
 
2372
    ma_stats.calls[(int)FID_MA_get_numalign]++;
 
2373
#endif /* STATS */
 
2374
 
 
2375
    *value = ma_numalign;
 
2376
    return MA_TRUE;
 
2377
}
 
2378
 
 
2379
/* ------------------------------------------------------------------------- */
 
2380
/*
 
2381
 * Get the base pointer for the given block.
 
2382
 *
 
2383
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
2384
 */
 
2385
/* ------------------------------------------------------------------------- */
 
2386
 
 
2387
/* JN  converted to void* to avoid calling hassles */
 
2388
public Boolean MA_get_pointer(
 
2389
    Integer    memhandle,    /* block to get pointer for */
 
2390
    void    *pointer     /* RETURN: base pointer */)
 
2391
{
 
2392
    AD        *ad;        /* AD for memhandle */
 
2393
 
 
2394
#ifdef STATS
 
2395
    ma_stats.calls[(int)FID_MA_get_pointer]++;
 
2396
#endif /* STATS */
 
2397
 
 
2398
#ifdef VERIFY
 
2399
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2400
        return MA_FALSE;
 
2401
#endif /* VERIFY */
 
2402
 
 
2403
    /* verify memhandle and convert to AD */
 
2404
    if (mh2ad(memhandle, &ad, BL_HeapOrStack, "MA_get_pointer"))
 
2405
    {
 
2406
        /* compute pointer */
 
2407
#if 0
 
2408
        *pointer = ad->client_space;
 
2409
#endif
 
2410
        *(char**)pointer = ad->client_space;
 
2411
 
 
2412
        /* success */
 
2413
        return MA_TRUE;
 
2414
    }
 
2415
    else
 
2416
    {
 
2417
        /* failure */
 
2418
        return MA_FALSE;
 
2419
    }
 
2420
}
 
2421
 
 
2422
/* ------------------------------------------------------------------------- */
 
2423
/*
 
2424
 * Initialize the memory allocator.
 
2425
 *
 
2426
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
2427
 */
 
2428
/* ------------------------------------------------------------------------- */
 
2429
 
 
2430
public Boolean MA_init(
 
2431
    Integer    datatype,    /* for computing storage requirement */
 
2432
    Integer    nominal_stack,    /* # of datatype elements desired for stack */
 
2433
    Integer    nominal_heap     /* # of datatype elements desired for heap */)
 
2434
{
 
2435
    ulongi    heap_bytes;    /* # of bytes for heap */
 
2436
    ulongi    stack_bytes;    /* # of bytes for stack */
 
2437
    ulongi    total_bytes;    /* total # of bytes */
 
2438
 
 
2439
#ifdef STATS
 
2440
    ma_stats.calls[(int)FID_MA_init]++;
 
2441
#endif /* STATS */
 
2442
 
 
2443
#ifdef VERIFY
 
2444
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2445
        return MA_FALSE;
 
2446
#endif /* VERIFY */
 
2447
 
 
2448
    /* preinitialize if necessary */
 
2449
    ma_preinitialize("MA_init");
 
2450
 
 
2451
    /* verify uninitialization */
 
2452
    if (ma_initialized)
 
2453
    {
 
2454
        (void)sprintf(ma_ebuf,
 
2455
            "MA already initialized");
 
2456
        ma_error(EL_Nonfatal, ET_External, "MA_init", ma_ebuf);
 
2457
        return MA_FALSE;
 
2458
    }
 
2459
 
 
2460
    /* verify datatype */
 
2461
    if (!mt_valid(datatype))
 
2462
    {
 
2463
        (void)sprintf(ma_ebuf,
 
2464
            "invalid datatype: %ld",
 
2465
            (long)datatype);
 
2466
        ma_error(EL_Nonfatal, ET_External, "MA_init", ma_ebuf);
 
2467
        return MA_FALSE;
 
2468
    }
 
2469
 
 
2470
    /* convert datatype to internal (index-suitable) value */
 
2471
    datatype = mt_import(datatype);
 
2472
 
 
2473
    /* compute # of bytes in heap */
 
2474
    if (nominal_heap < 0)
 
2475
    {
 
2476
        heap_bytes = DEFAULT_TOTAL_HEAP;
 
2477
    }
 
2478
    else
 
2479
    {
 
2480
        heap_bytes = (nominal_heap * ma_sizeof[datatype]) +
 
2481
            (DEFAULT_REQUESTS_HEAP * max_block_overhead(datatype));
 
2482
    }
 
2483
    heap_bytes = (unsigned long)mai_round((long)heap_bytes, (ulongi)ALIGNMENT);
 
2484
 
 
2485
    /* compute # of bytes in stack */
 
2486
    if (nominal_stack < 0)
 
2487
    {
 
2488
        stack_bytes = DEFAULT_TOTAL_STACK;
 
2489
    }
 
2490
    else
 
2491
    {
 
2492
        stack_bytes = (nominal_stack * ma_sizeof[datatype]) +
 
2493
            (DEFAULT_REQUESTS_STACK * max_block_overhead(datatype));
 
2494
    }
 
2495
    stack_bytes = (unsigned long)mai_round((long)stack_bytes, (ulongi)ALIGNMENT);
 
2496
 
 
2497
    /* segment consists of heap and stack */
 
2498
    total_bytes = heap_bytes + stack_bytes;
 
2499
#ifdef NOUSE_MMAP
 
2500
    /* disable memory mapped malloc */
 
2501
    mallopt(M_MMAP_MAX, 0);
 
2502
    mallopt(M_TRIM_THRESHOLD, -1);
 
2503
#endif
 
2504
    /* allocate the segment of memory */
 
2505
#ifdef ENABLE_ARMCI_MEM_OPTION
 
2506
    if(getenv("MA_USE_ARMCI_MEM"))
 
2507
    {
 
2508
        ma_segment = (Pointer)ARMCI_Malloc_local(total_bytes);
 
2509
    }
 
2510
    else
 
2511
#endif
 
2512
        ma_segment = (Pointer)bytealloc(total_bytes);
 
2513
    if (ma_segment == (Pointer)NULL)
 
2514
    {
 
2515
        (void)sprintf(ma_ebuf,
 
2516
            "could not allocate %lu bytes",
 
2517
            total_bytes);
 
2518
        ma_error(EL_Nonfatal, ET_External, "MA_init", ma_ebuf);
 
2519
        return MA_FALSE;
 
2520
    }
 
2521
 
 
2522
    /*
 
2523
     * initialize management stuff
 
2524
     */
 
2525
 
 
2526
    /* partition is at (first address past) end of heap */
 
2527
    ma_partition = ma_segment + heap_bytes;
 
2528
    /* compute (first address past) end of segment */
 
2529
    ma_eos = ma_segment + total_bytes;
 
2530
    /* ma_hp initially points at start of segment */
 
2531
    ma_hp = ma_segment;
 
2532
    /* ma_sp initially points at end of segment */
 
2533
    ma_sp = ma_eos;
 
2534
 
 
2535
    /* lists are all initially empty */
 
2536
    ma_hfree = (AD *)NULL;
 
2537
    ma_hused = (AD *)NULL;
 
2538
    ma_sused = (AD *)NULL;
 
2539
 
 
2540
    /* we are now initialized */
 
2541
    ma_initialized = MA_TRUE;
 
2542
 
 
2543
    /* success */
 
2544
    return MA_TRUE;
 
2545
}
 
2546
 
 
2547
/* ------------------------------------------------------------------------- */
 
2548
/*
 
2549
 * Return MA_TRUE if MA_init has been called successfully,
 
2550
 * else return MA_FALSE.
 
2551
 */
 
2552
/* ------------------------------------------------------------------------- */
 
2553
 
 
2554
public Boolean MA_initialized()
 
2555
{
 
2556
#ifdef STATS
 
2557
    ma_stats.calls[(int)FID_MA_initialized]++;
 
2558
#endif /* STATS */
 
2559
 
 
2560
    return ma_initialized;
 
2561
}
 
2562
 
 
2563
/* ------------------------------------------------------------------------- */
 
2564
/*
 
2565
 * Initialize a scan of currently allocated blocks.
 
2566
 *
 
2567
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
2568
 */
 
2569
/* ------------------------------------------------------------------------- */
 
2570
 
 
2571
public Boolean MA_init_memhandle_iterator( Integer *ithandle)
 
2572
{
 
2573
#ifdef STATS
 
2574
    ma_stats.calls[(int)FID_MA_init_memhandle_iterator]++;
 
2575
#endif /* STATS */
 
2576
 
 
2577
#ifdef VERIFY
 
2578
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2579
        return MA_FALSE;
 
2580
#endif /* VERIFY */
 
2581
 
 
2582
    /* not yet implemented */
 
2583
    (void)sprintf(ma_ebuf,
 
2584
        "not yet implemented");
 
2585
    ma_error(EL_Nonfatal, ET_External, "MA_init_memhandle_iterator", ma_ebuf);
 
2586
    return MA_FALSE;
 
2587
}
 
2588
 
 
2589
/* ------------------------------------------------------------------------- */
 
2590
/*
 
2591
 * Return the maximum number of datatype elements that can currently
 
2592
 * be allocated in the space between the heap and the stack, in a single
 
2593
 * allocation request, ignoring the partition defined at initialization.
 
2594
 *
 
2595
 * Note that this might not be the largest piece of memory available;
 
2596
 * the heap may contain deallocated blocks that are larger.
 
2597
 */
 
2598
/* ------------------------------------------------------------------------- */
 
2599
 
 
2600
public Integer MA_inquire_avail(Integer datatype)
 
2601
{
 
2602
    long    gap_length;    /* # of bytes between heap and stack */
 
2603
    Integer    nelem_gap;    /* max elements containable in gap */
 
2604
 
 
2605
#ifdef STATS
 
2606
    ma_stats.calls[(int)FID_MA_inquire_avail]++;
 
2607
#endif /* STATS */
 
2608
 
 
2609
#ifdef VERIFY
 
2610
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2611
        return DONTCARE;
 
2612
#endif /* VERIFY */
 
2613
 
 
2614
    /* verify initialization */
 
2615
    if (!ma_initialized)
 
2616
    {
 
2617
        (void)sprintf(ma_ebuf,
 
2618
            "MA not yet initialized");
 
2619
        ma_error(EL_Nonfatal, ET_External, "MA_inquire_avail", ma_ebuf);
 
2620
        return (Integer)0;
 
2621
    }
 
2622
 
 
2623
    /* verify datatype */
 
2624
    if (!mt_valid(datatype))
 
2625
    {
 
2626
        (void)sprintf(ma_ebuf,
 
2627
            "invalid datatype: %ld",
 
2628
            (long)datatype);
 
2629
        ma_error(EL_Fatal, ET_External, "MA_inquire_avail", ma_ebuf);
 
2630
        return DONTCARE;
 
2631
    }
 
2632
 
 
2633
    /* convert datatype to internal (index-suitable) value */
 
2634
    datatype = mt_import(datatype);
 
2635
 
 
2636
    /*
 
2637
     * compute the # of elements for which space is available
 
2638
     */
 
2639
 
 
2640
    /* try space between heap and stack */
 
2641
    gap_length = (long)(ma_sp - ma_hp);
 
2642
    if (gap_length > 0)
 
2643
        nelem_gap = ma_nelem(ma_hp, (ulongi)gap_length, datatype);
 
2644
    else
 
2645
        nelem_gap = 0;
 
2646
 
 
2647
    /* success */
 
2648
    return nelem_gap;
 
2649
}
 
2650
 
 
2651
/* ------------------------------------------------------------------------- */
 
2652
/*
 
2653
 * Return the maximum number of datatype elements that can currently
 
2654
 * be allocated in the heap, in a single allocation request,
 
2655
 * honoring the partition defined at initialization.
 
2656
 *
 
2657
 * This routine does not check the stack.  Therefore, if the stack
 
2658
 * has overgrown the partition, the answer returned by this routine
 
2659
 * might be incorrect, i.e., there might be less memory available
 
2660
 * than this routine indicates.
 
2661
 */
 
2662
/* ------------------------------------------------------------------------- */
 
2663
 
 
2664
public Integer MA_inquire_heap(Integer datatype)
 
2665
{
 
2666
    long    gap_length;    /* # of bytes between heap and partition */
 
2667
    Integer    nelem_gap;    /* max elements containable in gap */
 
2668
    Integer    nelem_frag;    /* max elements containable in any frag */
 
2669
 
 
2670
#ifdef STATS
 
2671
    ma_stats.calls[(int)FID_MA_inquire_heap]++;
 
2672
#endif /* STATS */
 
2673
 
 
2674
#ifdef VERIFY
 
2675
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2676
        return DONTCARE;
 
2677
#endif /* VERIFY */
 
2678
 
 
2679
    /* verify initialization */
 
2680
    if (!ma_initialized)
 
2681
    {
 
2682
        (void)sprintf(ma_ebuf,
 
2683
            "MA not yet initialized");
 
2684
        ma_error(EL_Nonfatal, ET_External, "MA_inquire_heap", ma_ebuf);
 
2685
        return (Integer)0;
 
2686
    }
 
2687
 
 
2688
    /* verify datatype */
 
2689
    if (!mt_valid(datatype))
 
2690
    {
 
2691
        (void)sprintf(ma_ebuf,
 
2692
            "invalid datatype: %ld",
 
2693
            (long)datatype);
 
2694
        ma_error(EL_Fatal, ET_External, "MA_inquire_heap", ma_ebuf);
 
2695
        return DONTCARE;
 
2696
    }
 
2697
 
 
2698
    /* convert datatype to internal (index-suitable) value */
 
2699
    datatype = mt_import(datatype);
 
2700
 
 
2701
    /*
 
2702
     * compute the # of elements for which space is available
 
2703
     */
 
2704
 
 
2705
    /* try space between heap and partition */
 
2706
    gap_length = (long)(ma_partition - ma_hp);
 
2707
    if (gap_length > 0)
 
2708
        nelem_gap = ma_nelem(ma_hp, (ulongi)gap_length, datatype);
 
2709
    else
 
2710
        nelem_gap = 0;
 
2711
 
 
2712
    /* try heap fragments */
 
2713
    nelem_frag = ma_max_heap_frag_nelem(datatype, nelem_gap);
 
2714
 
 
2715
    /* success */
 
2716
    return max(nelem_gap, nelem_frag);
 
2717
}
 
2718
 
 
2719
/* ------------------------------------------------------------------------- */
 
2720
/*
 
2721
 * Return the maximum number of datatype elements that can currently
 
2722
 * be allocated in the heap, in a single allocation request,
 
2723
 * honoring the partition defined at initialization.
 
2724
 *
 
2725
 * This routine does check the stack.  Therefore, whether or not the stack
 
2726
 * has overgrown the partition, the answer returned by this routine
 
2727
 * will be correct, i.e., there will be at least the memory available
 
2728
 * that this routine indicates.
 
2729
 *
 
2730
 * Note that this might not be the largest piece of memory available;
 
2731
 * the space between the heap and the stack may be larger.
 
2732
 */
 
2733
/* ------------------------------------------------------------------------- */
 
2734
 
 
2735
public Integer MA_inquire_heap_check_stack(Integer datatype)
 
2736
{
 
2737
    long    gap_length;    /* # of bytes between heap and partition */
 
2738
    Integer    nelem_gap;    /* max elements containable in gap */
 
2739
    Integer    nelem_frag;    /* max elements containable in any frag */
 
2740
 
 
2741
#ifdef STATS
 
2742
    ma_stats.calls[(int)FID_MA_inquire_heap_check_stack]++;
 
2743
#endif /* STATS */
 
2744
 
 
2745
#ifdef VERIFY
 
2746
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2747
        return DONTCARE;
 
2748
#endif /* VERIFY */
 
2749
 
 
2750
    /* verify initialization */
 
2751
    if (!ma_initialized)
 
2752
    {
 
2753
        (void)sprintf(ma_ebuf,
 
2754
            "MA not yet initialized");
 
2755
        ma_error(EL_Nonfatal, ET_External, "MA_inquire_heap_check_stack", ma_ebuf);
 
2756
        return (Integer)0;
 
2757
    }
 
2758
 
 
2759
    /* verify datatype */
 
2760
    if (!mt_valid(datatype))
 
2761
    {
 
2762
        (void)sprintf(ma_ebuf,
 
2763
            "invalid datatype: %ld",
 
2764
            (long)datatype);
 
2765
        ma_error(EL_Fatal, ET_External, "MA_inquire_heap_check_stack", ma_ebuf);
 
2766
        return DONTCARE;
 
2767
    }
 
2768
 
 
2769
    /* convert datatype to internal (index-suitable) value */
 
2770
    datatype = mt_import(datatype);
 
2771
 
 
2772
    /*
 
2773
     * compute the # of elements for which space is available
 
2774
     */
 
2775
 
 
2776
    /* try space between heap and partition or heap and stack */
 
2777
    gap_length = min((long)(ma_partition - ma_hp), (long)(ma_sp - ma_hp));
 
2778
    if (gap_length > 0)
 
2779
        nelem_gap = ma_nelem(ma_hp, (ulongi)gap_length, datatype);
 
2780
    else
 
2781
        nelem_gap = 0;
 
2782
 
 
2783
    /* try heap fragments */
 
2784
    nelem_frag = ma_max_heap_frag_nelem(datatype, nelem_gap);
 
2785
 
 
2786
    /* success */
 
2787
    return max(nelem_gap, nelem_frag);
 
2788
}
 
2789
 
 
2790
/* ------------------------------------------------------------------------- */
 
2791
/*
 
2792
 * Return the maximum number of datatype elements that can currently
 
2793
 * be allocated in the heap, in a single allocation request,
 
2794
 * ignoring the partition defined at initialization.
 
2795
 *
 
2796
 * This routine does check the stack.  Therefore, whether or not the stack
 
2797
 * has overgrown the partition, the answer returned by this routine
 
2798
 * will be correct, i.e., there will be at least the memory available
 
2799
 * that this routine indicates.
 
2800
 *
 
2801
 * Note that this will be the largest piece of memory available.
 
2802
 */
 
2803
/* ------------------------------------------------------------------------- */
 
2804
 
 
2805
public Integer MA_inquire_heap_no_partition(Integer datatype)
 
2806
{
 
2807
    long    gap_length;    /* # of bytes between heap and partition */
 
2808
    Integer    nelem_gap;    /* max elements containable in gap */
 
2809
    Integer    nelem_frag;    /* max elements containable in any frag */
 
2810
 
 
2811
#ifdef STATS
 
2812
    ma_stats.calls[(int)FID_MA_inquire_heap_no_partition]++;
 
2813
#endif /* STATS */
 
2814
 
 
2815
#ifdef VERIFY
 
2816
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2817
        return DONTCARE;
 
2818
#endif /* VERIFY */
 
2819
 
 
2820
    /* verify initialization */
 
2821
    if (!ma_initialized)
 
2822
    {
 
2823
        (void)sprintf(ma_ebuf,
 
2824
            "MA not yet initialized");
 
2825
        ma_error(EL_Nonfatal, ET_External, "MA_inquire_heap_no_partition", ma_ebuf);
 
2826
        return (Integer)0;
 
2827
    }
 
2828
 
 
2829
    /* verify datatype */
 
2830
    if (!mt_valid(datatype))
 
2831
    {
 
2832
        (void)sprintf(ma_ebuf,
 
2833
            "invalid datatype: %ld",
 
2834
            (long)datatype);
 
2835
        ma_error(EL_Fatal, ET_External, "MA_inquire_heap_no_partition", ma_ebuf);
 
2836
        return DONTCARE;
 
2837
    }
 
2838
 
 
2839
    /* convert datatype to internal (index-suitable) value */
 
2840
    datatype = mt_import(datatype);
 
2841
 
 
2842
    /*
 
2843
     * compute the # of elements for which space is available
 
2844
     */
 
2845
 
 
2846
    /* try space between heap and stack */
 
2847
    gap_length = (long)(ma_sp - ma_hp);
 
2848
    if (gap_length > 0)
 
2849
        nelem_gap = ma_nelem(ma_hp, (ulongi)gap_length, datatype);
 
2850
    else
 
2851
        nelem_gap = 0;
 
2852
 
 
2853
    /* try heap fragments */
 
2854
    nelem_frag = ma_max_heap_frag_nelem(datatype, nelem_gap);
 
2855
 
 
2856
    /* success */
 
2857
    return max(nelem_gap, nelem_frag);
 
2858
}
 
2859
 
 
2860
/* ------------------------------------------------------------------------- */
 
2861
/*
 
2862
 * Return the maximum number of datatype elements that can currently
 
2863
 * be allocated in the stack, in a single allocation request,
 
2864
 * honoring the partition defined at initialization.
 
2865
 *
 
2866
 * This routine does not check the heap.  Therefore, if the heap
 
2867
 * has overgrown the partition, the answer returned by this routine
 
2868
 * might be incorrect, i.e., there might be less memory available
 
2869
 * than this routine indicates.
 
2870
 */
 
2871
/* ------------------------------------------------------------------------- */
 
2872
 
 
2873
public Integer MA_inquire_stack(Integer datatype)
 
2874
{
 
2875
    long    gap_length;    /* # of bytes between partition and stack */
 
2876
    Integer    nelem_gap;    /* max elements containable in gap */
 
2877
 
 
2878
#ifdef STATS
 
2879
    ma_stats.calls[(int)FID_MA_inquire_stack]++;
 
2880
#endif /* STATS */
 
2881
 
 
2882
#ifdef VERIFY
 
2883
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2884
        return DONTCARE;
 
2885
#endif /* VERIFY */
 
2886
 
 
2887
    /* verify initialization */
 
2888
    if (!ma_initialized)
 
2889
    {
 
2890
        (void)sprintf(ma_ebuf,
 
2891
            "MA not yet initialized");
 
2892
        ma_error(EL_Nonfatal, ET_External, "MA_inquire_stack", ma_ebuf);
 
2893
        return (Integer)0;
 
2894
    }
 
2895
 
 
2896
    /* verify datatype */
 
2897
    if (!mt_valid(datatype))
 
2898
    {
 
2899
        (void)sprintf(ma_ebuf,
 
2900
            "invalid datatype: %ld",
 
2901
            (long)datatype);
 
2902
        ma_error(EL_Fatal, ET_External, "MA_inquire_stack", ma_ebuf);
 
2903
        return DONTCARE;
 
2904
    }
 
2905
 
 
2906
    /* convert datatype to internal (index-suitable) value */
 
2907
    datatype = mt_import(datatype);
 
2908
 
 
2909
    /*
 
2910
     * compute the # of elements for which space is available
 
2911
     */
 
2912
 
 
2913
    /* try space between partition and stack */
 
2914
    gap_length = (long)(ma_sp - ma_partition);
 
2915
    if (gap_length > 0)
 
2916
        nelem_gap = ma_nelem(ma_partition, (ulongi)gap_length, datatype);
 
2917
    else
 
2918
        nelem_gap = 0;
 
2919
 
 
2920
    /* success */
 
2921
    return nelem_gap;
 
2922
}
 
2923
 
 
2924
/* ------------------------------------------------------------------------- */
 
2925
/*
 
2926
 * Return the maximum number of datatype elements that can currently
 
2927
 * be allocated in the stack, in a single allocation request,
 
2928
 * honoring the partition defined at initialization.
 
2929
 *
 
2930
 * This routine does check the heap.  Therefore, whether or not the heap
 
2931
 * has overgrown the partition, the answer returned by this routine
 
2932
 * will be correct, i.e., there will be at least the memory available
 
2933
 * that this routine indicates.
 
2934
 *
 
2935
 * Note that this might not be the largest piece of memory available;
 
2936
 * the space between the heap and the stack may be larger.
 
2937
 */
 
2938
/* ------------------------------------------------------------------------- */
 
2939
 
 
2940
public Integer MA_inquire_stack_check_heap(Integer datatype)
 
2941
{
 
2942
    long    gap_length;    /* # of bytes between partition and stack */
 
2943
    Integer    nelem_gap;    /* max elements containable in gap */
 
2944
 
 
2945
#ifdef STATS
 
2946
    ma_stats.calls[(int)FID_MA_inquire_stack_check_heap]++;
 
2947
#endif /* STATS */
 
2948
 
 
2949
#ifdef VERIFY
 
2950
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
2951
        return DONTCARE;
 
2952
#endif /* VERIFY */
 
2953
 
 
2954
    /* verify initialization */
 
2955
    if (!ma_initialized)
 
2956
    {
 
2957
        (void)sprintf(ma_ebuf,
 
2958
            "MA not yet initialized");
 
2959
        ma_error(EL_Nonfatal, ET_External, "MA_inquire_stack_check_heap", ma_ebuf);
 
2960
        return (Integer)0;
 
2961
    }
 
2962
 
 
2963
    /* verify datatype */
 
2964
    if (!mt_valid(datatype))
 
2965
    {
 
2966
        (void)sprintf(ma_ebuf,
 
2967
            "invalid datatype: %ld",
 
2968
            (long)datatype);
 
2969
        ma_error(EL_Fatal, ET_External, "MA_inquire_stack_check_heap", ma_ebuf);
 
2970
        return DONTCARE;
 
2971
    }
 
2972
 
 
2973
    /* convert datatype to internal (index-suitable) value */
 
2974
    datatype = mt_import(datatype);
 
2975
 
 
2976
    /*
 
2977
     * compute the # of elements for which space is available
 
2978
     */
 
2979
 
 
2980
    /* try space between partition and stack or heap and stack */
 
2981
    gap_length = min((long)(ma_sp - ma_partition), (long)(ma_sp - ma_hp));
 
2982
    if (gap_length > 0)
 
2983
        nelem_gap = ma_nelem(ma_partition, (ulongi)gap_length, datatype);
 
2984
    else
 
2985
        nelem_gap = 0;
 
2986
 
 
2987
    /* success */
 
2988
    return nelem_gap;
 
2989
}
 
2990
 
 
2991
/* ------------------------------------------------------------------------- */
 
2992
/*
 
2993
 * Return the maximum number of datatype elements that can currently
 
2994
 * be allocated in the stack, in a single allocation request,
 
2995
 * ignoring the partition defined at initialization.
 
2996
 *
 
2997
 * This routine does check the heap.  Therefore, whether or not the heap
 
2998
 * has overgrown the partition, the answer returned by this routine
 
2999
 * will be correct, i.e., there will be at least the memory available
 
3000
 * that this routine indicates.
 
3001
 *
 
3002
 * Note that this might not be the largest piece of memory available;
 
3003
 * the heap may contain deallocated blocks that are larger.
 
3004
 *
 
3005
 * This routine is equivalent to MA_inquire_avail.
 
3006
 */
 
3007
/* ------------------------------------------------------------------------- */
 
3008
 
 
3009
public Integer MA_inquire_stack_no_partition(Integer datatype)
 
3010
{
 
3011
    long    gap_length;    /* # of bytes between heap and partition */
 
3012
    Integer    nelem_gap;    /* max elements containable in gap */
 
3013
 
 
3014
#ifdef STATS
 
3015
    ma_stats.calls[(int)FID_MA_inquire_stack_no_partition]++;
 
3016
#endif /* STATS */
 
3017
 
 
3018
#ifdef VERIFY
 
3019
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
3020
        return DONTCARE;
 
3021
#endif /* VERIFY */
 
3022
 
 
3023
    /* verify initialization */
 
3024
    if (!ma_initialized)
 
3025
    {
 
3026
        (void)sprintf(ma_ebuf,
 
3027
            "MA not yet initialized");
 
3028
        ma_error(EL_Nonfatal, ET_External, "MA_inquire_stack_no_partition", ma_ebuf);
 
3029
        return (Integer)0;
 
3030
    }
 
3031
 
 
3032
    /* verify datatype */
 
3033
    if (!mt_valid(datatype))
 
3034
    {
 
3035
        (void)sprintf(ma_ebuf,
 
3036
            "invalid datatype: %ld",
 
3037
            (long)datatype);
 
3038
        ma_error(EL_Fatal, ET_External, "MA_inquire_stack_no_partition", ma_ebuf);
 
3039
        return DONTCARE;
 
3040
    }
 
3041
 
 
3042
    /* convert datatype to internal (index-suitable) value */
 
3043
    datatype = mt_import(datatype);
 
3044
 
 
3045
    /*
 
3046
     * compute the # of elements for which space is available
 
3047
     */
 
3048
 
 
3049
    /* try space between heap and stack */
 
3050
    gap_length = (long)(ma_sp - ma_hp);
 
3051
    if (gap_length > 0)
 
3052
        nelem_gap = ma_nelem(ma_hp, (ulongi)gap_length, datatype);
 
3053
    else
 
3054
        nelem_gap = 0;
 
3055
 
 
3056
    /* success */
 
3057
    return nelem_gap;
 
3058
}
 
3059
 
 
3060
/* ------------------------------------------------------------------------- */
 
3061
/*
 
3062
 * Deallocate the given stack block, which must be the one most recently
 
3063
 * allocated.
 
3064
 *
 
3065
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
3066
 */
 
3067
/* ------------------------------------------------------------------------- */
 
3068
 
 
3069
public Boolean MA_pop_stack(Integer memhandle) /* the block to deallocate */
 
3070
{
 
3071
    AD        *ad;        /* AD for memhandle */
 
3072
 
 
3073
#ifdef STATS
 
3074
    ma_stats.calls[(int)FID_MA_pop_stack]++;
 
3075
#endif /* STATS */
 
3076
 
 
3077
#ifdef VERIFY
 
3078
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
3079
        return MA_FALSE;
 
3080
#endif /* VERIFY */
 
3081
 
 
3082
    /* verify memhandle and convert to AD */
 
3083
    if (!mh2ad(memhandle, &ad, BL_StackTop, "MA_pop_stack"))
 
3084
        return MA_FALSE;
 
3085
 
 
3086
    if (ma_trace) 
 
3087
    (void)printf("MA: popping '%s'\n", ad->name);
 
3088
 
 
3089
    /* delete block from used list */
 
3090
    if (list_delete(ad, &ma_sused) != ad)
 
3091
    {
 
3092
        (void)sprintf(ma_ebuf,
 
3093
            "memhandle %ld (name: '%s') not on stack used list",
 
3094
            (long)memhandle, ad->name);
 
3095
        ma_error(EL_Nonfatal, ET_Internal, "MA_pop_stack", ma_ebuf);
 
3096
        return MA_FALSE;
 
3097
    }
 
3098
 
 
3099
    /* pop block from stack */
 
3100
    ma_sp += ad->nbytes;
 
3101
 
 
3102
#ifdef STATS
 
3103
    ma_stats.sblocks--;
 
3104
    ma_stats.sbytes -= ad->nbytes;
 
3105
#endif /* STATS */
 
3106
 
 
3107
    /* free memhandle */
 
3108
    ma_table_deallocate(memhandle);
 
3109
 
 
3110
    /* success */
 
3111
    return MA_TRUE;
 
3112
}
 
3113
 
 
3114
/* ------------------------------------------------------------------------- */
 
3115
/*
 
3116
 * Print usage statistics.
 
3117
 */
 
3118
/* ------------------------------------------------------------------------- */
 
3119
 
 
3120
public void MA_print_stats(Boolean printroutines)
 
3121
{
 
3122
#ifdef STATS
 
3123
 
 
3124
    int        i;        /* loop index */
 
3125
 
 
3126
#ifdef STATS
 
3127
    ma_stats.calls[(int)FID_MA_print_stats]++;
 
3128
#endif /* STATS */
 
3129
 
 
3130
#ifdef VERIFY
 
3131
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
3132
        return;
 
3133
#endif /* VERIFY */
 
3134
 
 
3135
    (void)printf("MA usage statistics:\n");
 
3136
    (void)printf("\n\tallocation statistics:\n");
 
3137
    (void)printf("\t\t\t\t\t      heap\t     stack\n");
 
3138
    (void)printf("\t\t\t\t\t      ----\t     -----\n");
 
3139
    (void)printf("\tcurrent number of blocks\t%10lu\t%10lu\n",
 
3140
        ma_stats.hblocks,
 
3141
        ma_stats.sblocks);
 
3142
    (void)printf("\tmaximum number of blocks\t%10lu\t%10lu\n",
 
3143
        ma_stats.hblocks_max,
 
3144
        ma_stats.sblocks_max);
 
3145
    (void)printf("\tcurrent total bytes\t\t%10lu\t%10lu\n",
 
3146
        ma_stats.hbytes,
 
3147
        ma_stats.sbytes);
 
3148
    (void)printf("\tmaximum total bytes\t\t%10lu\t%10lu\n",
 
3149
        ma_stats.hbytes_max,
 
3150
        ma_stats.sbytes_max);
 
3151
    (void)printf("\tmaximum total K-bytes\t\t%10lu\t%10lu\n",
 
3152
        ((ma_stats.hbytes_max+999)/1000),
 
3153
        ((ma_stats.sbytes_max+999)/1000));
 
3154
    (void)printf("\tmaximum total M-bytes\t\t%10lu\t%10lu\n",
 
3155
        ((ma_stats.hbytes_max+999999)/1000000),
 
3156
        ((ma_stats.sbytes_max+999999)/1000000));
 
3157
    if (printroutines)
 
3158
    {
 
3159
        (void)printf("\n\tcalls per routine:\n");
 
3160
        for (i = 0; i < NUMROUTINES; i++)
 
3161
            (void)printf("\t\t%10lu  %s\n",
 
3162
                ma_stats.calls[i],
 
3163
                ma_routines[i]);
 
3164
    }
 
3165
 
 
3166
#else
 
3167
 
 
3168
    (void)sprintf(ma_ebuf,
 
3169
        "unavailable; recompile MA with -DSTATS");
 
3170
    ma_error(EL_Nonfatal, ET_External, "MA_print_stats", ma_ebuf);
 
3171
 
 
3172
#endif /* STATS */
 
3173
}
 
3174
 
 
3175
/* ------------------------------------------------------------------------- */
 
3176
/*
 
3177
 * Convenience function that combines MA_push_stack and MA_get_index.
 
3178
 */
 
3179
/* ------------------------------------------------------------------------- */
 
3180
 
 
3181
public Boolean MA_push_get(
 
3182
    Integer    datatype,    /* of elements in this block */
 
3183
    Integer    nelem,        /* # of elements in this block */
 
3184
    const char    *name,        /* assigned to this block by client */
 
3185
    Integer    *memhandle,    /* RETURN: handle for this block */
 
3186
    MA_AccessIndex  *index    /* RETURN: index for this block */)
 
3187
{
 
3188
#ifdef STATS
 
3189
    ma_stats.calls[(int)FID_MA_push_get]++;
 
3190
#endif /* STATS */
 
3191
 
 
3192
    if (MA_push_stack(datatype, nelem, name, memhandle))
 
3193
        /* MA_push_stack succeeded; try MA_get_index */
 
3194
        return MA_get_index(*memhandle, index);
 
3195
    else
 
3196
        /* MA_push_stack failed */
 
3197
        return MA_FALSE;
 
3198
}
 
3199
 
 
3200
/* ------------------------------------------------------------------------- */
 
3201
/*
 
3202
 * Allocate a stack block big enough to hold nelem elements
 
3203
 * of the given datatype.
 
3204
 *
 
3205
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
3206
 */
 
3207
/* ------------------------------------------------------------------------- */
 
3208
 
 
3209
public Boolean MA_push_stack(
 
3210
    Integer    datatype,    /* of elements in this block */
 
3211
    Integer    nelem,        /* # of elements in this block */
 
3212
    const char    *name,        /* assigned to this block by client */
 
3213
    Integer    *memhandle     /* RETURN: handle for this block */)
 
3214
{
 
3215
    AR        ar;        /* allocation request */
 
3216
    AD        *ad;        /* AD for newly allocated block */
 
3217
    Pointer    client_space;    /* location of client_space */
 
3218
    ulongi    nbytes;        /* length of block for ar */
 
3219
    Pointer    new_sp;        /* new ma_sp */
 
3220
 
 
3221
#ifdef STATS
 
3222
    ma_stats.calls[(int)FID_MA_push_stack]++;
 
3223
#endif /* STATS */
 
3224
 
 
3225
#ifdef VERIFY
 
3226
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
3227
        return MA_FALSE;
 
3228
#endif /* VERIFY */
 
3229
 
 
3230
    if (ma_trace) 
 
3231
    (void)printf("MA: pushing '%s' (%d)\n", name, (int)nelem);
 
3232
 
 
3233
    /* verify initialization */
 
3234
    if (!ma_initialized)
 
3235
    {
 
3236
        (void)sprintf(ma_ebuf,
 
3237
            "block '%s', MA not yet initialized",
 
3238
            name);
 
3239
        ma_error(EL_Nonfatal, ET_External, "MA_push_stack", ma_ebuf);
 
3240
        return MA_FALSE;
 
3241
    }
 
3242
 
 
3243
    /* verify datatype */
 
3244
    if (!mt_valid(datatype))
 
3245
    {
 
3246
        (void)sprintf(ma_ebuf,
 
3247
            "block '%s', invalid datatype: %ld",
 
3248
            name, (long)datatype);
 
3249
        ma_error(EL_Nonfatal, ET_External, "MA_push_stack", ma_ebuf);
 
3250
        return MA_FALSE;
 
3251
    }
 
3252
 
 
3253
    /* verify nelem */
 
3254
    if (nelem < 0)
 
3255
    {
 
3256
        (void)sprintf(ma_ebuf,
 
3257
            "block '%s', invalid nelem: %ld",
 
3258
            name, (long)nelem);
 
3259
        ma_error(EL_Nonfatal, ET_External, "MA_push_stack", ma_ebuf);
 
3260
        return MA_FALSE;
 
3261
    }
 
3262
 
 
3263
    /* convert datatype to internal (index-suitable) value */
 
3264
    datatype = mt_import(datatype);
 
3265
 
 
3266
    /*
 
3267
     * attempt to allocate space
 
3268
     */
 
3269
 
 
3270
    ar.datatype = datatype;
 
3271
    ar.nelem = nelem;
 
3272
 
 
3273
    balloc_before(&ar, ma_sp, &client_space, &nbytes);
 
3274
 
 
3275
    new_sp = ma_sp - nbytes;
 
3276
    /* if (new_sp < ma_hp) */
 
3277
    if (((ulongi)(ma_sp - ma_hp)) < nbytes)
 
3278
    {
 
3279
        (void)sprintf(ma_ebuf,
 
3280
            "block '%s', not enough space to allocate %lu bytes",
 
3281
            name, nbytes);
 
3282
        ma_error(EL_Nonfatal, ET_External, "MA_push_stack", ma_ebuf);
 
3283
        return MA_FALSE;
 
3284
    }
 
3285
    else
 
3286
    {
 
3287
        ad = (AD *)new_sp;
 
3288
    }
 
3289
 
 
3290
    /*
 
3291
     * space has been allocated
 
3292
     */
 
3293
 
 
3294
    /* initialize the AD */
 
3295
    ad->datatype = datatype;
 
3296
    ad->nelem = nelem;
 
3297
    str_ncopy(ad->name, (char*)name, MA_NAMESIZE);
 
3298
    ad->client_space = client_space;
 
3299
    ad->nbytes = nbytes;
 
3300
    list_insert(ad, &ma_sused);
 
3301
    ad->checksum = checksum(ad);
 
3302
 
 
3303
    /* set the guards */
 
3304
    guard_set(ad);
 
3305
 
 
3306
#ifdef DEBUG
 
3307
    debug_ad_print(ad);
 
3308
#endif /* DEBUG */
 
3309
 
 
3310
    /* update ma_sp */
 
3311
    ma_sp = new_sp;
 
3312
 
 
3313
#ifdef STATS
 
3314
    ma_stats.sblocks++;
 
3315
    ma_stats.sblocks_max = max(ma_stats.sblocks, ma_stats.sblocks_max);
 
3316
    ma_stats.sbytes += ad->nbytes;
 
3317
    ma_stats.sbytes_max = max(ma_stats.sbytes, ma_stats.sbytes_max);
 
3318
#endif /* STATS */
 
3319
 
 
3320
    /* convert AD to memhandle */
 
3321
    if ((*memhandle = ma_table_allocate((TableData)ad)) == TABLE_HANDLE_NONE)
 
3322
        /* failure */
 
3323
        return MA_FALSE;
 
3324
    else
 
3325
        /* success */
 
3326
        return MA_TRUE;
 
3327
}
 
3328
 
 
3329
/* ------------------------------------------------------------------------- */
 
3330
/*
 
3331
 * Set the ma_auto_verify flag to value and return its previous value.
 
3332
 */
 
3333
/* ------------------------------------------------------------------------- */
 
3334
 
 
3335
public Boolean MA_set_auto_verify(Boolean  value /* to set flag to */)
 
3336
{
 
3337
    Boolean    old_value;    /* of flag */
 
3338
 
 
3339
#ifdef STATS
 
3340
    ma_stats.calls[(int)FID_MA_set_auto_verify]++;
 
3341
#endif /* STATS */
 
3342
 
 
3343
    old_value = ma_auto_verify;
 
3344
    ma_auto_verify = value;
 
3345
    return old_value;
 
3346
}
 
3347
 
 
3348
/* ------------------------------------------------------------------------- */
 
3349
/*
 
3350
 * Set the ma_error_print flag to value and return its previous value.
 
3351
 */
 
3352
/* ------------------------------------------------------------------------- */
 
3353
 
 
3354
public Boolean MA_set_error_print(Boolean value /* to set flag to */)
 
3355
{
 
3356
    Boolean    old_value;    /* of flag */
 
3357
 
 
3358
#ifdef STATS
 
3359
    ma_stats.calls[(int)FID_MA_set_error_print]++;
 
3360
#endif /* STATS */
 
3361
 
 
3362
    old_value = ma_error_print;
 
3363
    ma_error_print = value;
 
3364
    return old_value;
 
3365
}
 
3366
 
 
3367
/* ------------------------------------------------------------------------- */
 
3368
/*
 
3369
 * Set the ma_hard_fail flag to value and return its previous value.
 
3370
 */
 
3371
/* ------------------------------------------------------------------------- */
 
3372
 
 
3373
public Boolean MA_set_hard_fail( Boolean value /* to set flag to */)
 
3374
{
 
3375
    Boolean    old_value;    /* of flag */
 
3376
 
 
3377
#ifdef STATS
 
3378
    ma_stats.calls[(int)FID_MA_set_hard_fail]++;
 
3379
#endif /* STATS */
 
3380
 
 
3381
    old_value = ma_hard_fail;
 
3382
    ma_hard_fail = value;
 
3383
    return old_value;
 
3384
}
 
3385
 
 
3386
/* ------------------------------------------------------------------------- */
 
3387
/*
 
3388
 * Set the requested alignment.
 
3389
 *
 
3390
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
3391
 */
 
3392
/* ------------------------------------------------------------------------- */
 
3393
 
 
3394
public Boolean MA_set_numalign(Integer  value)
 
3395
{
 
3396
#ifdef STATS
 
3397
    ma_stats.calls[(int)FID_MA_set_numalign]++;
 
3398
#endif /* STATS */
 
3399
 
 
3400
    if ((value < 0) || (value > 30))
 
3401
    {
 
3402
        (void)sprintf(ma_ebuf,
 
3403
            "invalid alignment: %ld",
 
3404
            (long)value);
 
3405
        ma_error(EL_Nonfatal, ET_External, "MA_set_numalign", ma_ebuf);
 
3406
        return MA_FALSE;
 
3407
    }
 
3408
    ma_numalign = value;
 
3409
    return MA_TRUE;
 
3410
}
 
3411
 
 
3412
/* ------------------------------------------------------------------------- */
 
3413
/*
 
3414
 * Return the number of elements of datatype2 required to contain
 
3415
 * nelem1 elements of datatype1.
 
3416
 */
 
3417
/* ------------------------------------------------------------------------- */
 
3418
 
 
3419
public Integer MA_sizeof(
 
3420
    Integer    datatype1,    /* of source elements */
 
3421
    Integer    nelem1,        /* # of source elements */
 
3422
    Integer    datatype2     /* of target elements */)
 
3423
{
 
3424
    ulongi    source_bytes;    /* nelem1 * ma_sizeof[datatype1] */
 
3425
    int        ceiling;    /* 1 iff ceiling alters result */
 
3426
 
 
3427
#ifdef STATS
 
3428
    ma_stats.calls[(int)FID_MA_sizeof]++;
 
3429
#endif /* STATS */
 
3430
 
 
3431
#ifdef VERIFY
 
3432
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
3433
        return DONTCARE;
 
3434
#endif /* VERIFY */
 
3435
 
 
3436
    /* preinitialize if necessary */
 
3437
    ma_preinitialize("MA_sizeof");
 
3438
 
 
3439
    /* verify datatype1 */
 
3440
    if (!mt_valid(datatype1))
 
3441
    {
 
3442
        (void)sprintf(ma_ebuf,
 
3443
            "invalid datatype: %ld",
 
3444
            (long)datatype1);
 
3445
        ma_error(EL_Fatal, ET_External, "MA_sizeof", ma_ebuf);
 
3446
        return DONTCARE;
 
3447
    }
 
3448
 
 
3449
    /* verify nelem1 */
 
3450
    if (nelem1 < 0)
 
3451
    {
 
3452
        (void)sprintf(ma_ebuf,
 
3453
            "invalid nelem: %ld",
 
3454
            (long)nelem1);
 
3455
        ma_error(EL_Fatal, ET_External, "MA_sizeof", ma_ebuf);
 
3456
        return DONTCARE;
 
3457
    }
 
3458
 
 
3459
    /* verify datatype2 */
 
3460
    if (!mt_valid(datatype2))
 
3461
    {
 
3462
        (void)sprintf(ma_ebuf,
 
3463
            "invalid datatype: %ld",
 
3464
            (long)datatype2);
 
3465
        ma_error(EL_Fatal, ET_External, "MA_sizeof", ma_ebuf);
 
3466
        return DONTCARE;
 
3467
    }
 
3468
 
 
3469
    /* convert datatype1 to internal (index-suitable) value */
 
3470
    datatype1 = mt_import(datatype1);
 
3471
 
 
3472
    /* convert datatype2 to internal (index-suitable) value */
 
3473
    datatype2 = mt_import(datatype2);
 
3474
 
 
3475
    /* compute and return the result */
 
3476
    source_bytes = nelem1 * ma_sizeof[datatype1];
 
3477
    ceiling = (source_bytes % ma_sizeof[datatype2]) ? 1 : 0;
 
3478
    return (Integer)((source_bytes / ma_sizeof[datatype2]) + ceiling);
 
3479
}
 
3480
 
 
3481
/* ------------------------------------------------------------------------- */
 
3482
/*
 
3483
 * Return the number of elements of datatype required to contain
 
3484
 * the worst case number of bytes of overhead for any block.
 
3485
 */
 
3486
/* ------------------------------------------------------------------------- */
 
3487
 
 
3488
public Integer MA_sizeof_overhead(Integer datatype) 
 
3489
{
 
3490
    int        overhead_bytes;    /* max bytes of overhead for any block */
 
3491
    int        ceiling;    /* 1 iff ceiling alters result */
 
3492
    int        max_sizeof;    /* max over i of ma_sizeof[i] */
 
3493
    int        biggest_datatype=0; /* corresponds to max_sizeof */
 
3494
    int        i;        /* loop index */
 
3495
 
 
3496
#ifdef STATS
 
3497
    ma_stats.calls[(int)FID_MA_sizeof_overhead]++;
 
3498
#endif /* STATS */
 
3499
 
 
3500
#ifdef VERIFY
 
3501
    if (ma_auto_verify && !MA_verify_allocator_stuff())
 
3502
        return DONTCARE;
 
3503
#endif /* VERIFY */
 
3504
 
 
3505
    /* preinitialize if necessary */
 
3506
    ma_preinitialize("MA_sizeof_overhead");
 
3507
 
 
3508
    /* verify datatype */
 
3509
    if (!mt_valid(datatype))
 
3510
    {
 
3511
        (void)sprintf(ma_ebuf,
 
3512
            "invalid datatype: %ld",
 
3513
            (long)datatype);
 
3514
        ma_error(EL_Fatal, ET_External, "MA_sizeof_overhead", ma_ebuf);
 
3515
        return DONTCARE;
 
3516
    }
 
3517
 
 
3518
    /* convert datatype to internal (index-suitable) value */
 
3519
    datatype = mt_import(datatype);
 
3520
 
 
3521
    /* compute and return the result */
 
3522
    for (max_sizeof = 0, i = 0; i < MT_NUMTYPES; i++)
 
3523
        if (ma_sizeof[i] > max_sizeof)
 
3524
        {
 
3525
            max_sizeof = ma_sizeof[i];
 
3526
            biggest_datatype = i;
 
3527
        }
 
3528
    overhead_bytes = max_block_overhead(biggest_datatype);
 
3529
    ceiling = (overhead_bytes % ma_sizeof[datatype]) ? 1 : 0;
 
3530
    return (Integer)((overhead_bytes / ma_sizeof[datatype]) + ceiling);
 
3531
}
 
3532
 
 
3533
/* ------------------------------------------------------------------------- */
 
3534
/*
 
3535
 * Print debugging information about all blocks currently in use
 
3536
 * on the heap or the stack.
 
3537
 */
 
3538
/* ------------------------------------------------------------------------- */
 
3539
 
 
3540
public void MA_summarize_allocated_blocks()
 
3541
{
 
3542
    /* C indices are 0-based */
 
3543
    MAi_summarize_allocated_blocks(0);
 
3544
}
 
3545
 
 
3546
/* ------------------------------------------------------------------------- */
 
3547
/*
 
3548
 * Control tracing of allocation and deallocation operations.
 
3549
 */
 
3550
/* ------------------------------------------------------------------------- */
 
3551
 
 
3552
public void MA_trace(Boolean value)
 
3553
{
 
3554
    ma_trace = value;
 
3555
}
 
3556
 
 
3557
/* ------------------------------------------------------------------------- */
 
3558
/*
 
3559
 * Sanity check the internal state of MA and print the results.
 
3560
 *
 
3561
 * Return MA_TRUE upon success, or MA_FALSE upon failure.
 
3562
 */
 
3563
/* ------------------------------------------------------------------------- */
 
3564
 
 
3565
public Boolean MA_verify_allocator_stuff()
 
3566
{
 
3567
#ifdef VERIFY
 
3568
 
 
3569
    char    *preamble;    /* printed before block error messages */
 
3570
 
 
3571
    int        heap_blocks;
 
3572
    int        bad_heap_blocks;
 
3573
    int        bad_heap_checksums;
 
3574
    int        bad_heap_lguards;
 
3575
    int        bad_heap_rguards;
 
3576
    int        stack_blocks;
 
3577
    int        bad_stack_blocks;
 
3578
    int        bad_stack_checksums;
 
3579
    int        bad_stack_lguards;
 
3580
    int        bad_stack_rguards;
 
3581
 
 
3582
#ifdef STATS
 
3583
    ma_stats.calls[(int)FID_MA_verify_allocator_stuff]++;
 
3584
#endif /* STATS */
 
3585
 
 
3586
    preamble = "MA_verify_allocator_stuff: starting scan ...\n";
 
3587
 
 
3588
    /* check each block on the heap used list */
 
3589
    list_verify(ma_hused,
 
3590
        "heap",
 
3591
        preamble,
 
3592
        &heap_blocks,
 
3593
        &bad_heap_blocks,
 
3594
        &bad_heap_checksums,
 
3595
        &bad_heap_lguards,
 
3596
        &bad_heap_rguards);
 
3597
 
 
3598
    if (bad_heap_blocks > 0)
 
3599
        /* only print preamble once */
 
3600
        preamble = (char *)NULL;
 
3601
 
 
3602
    /* check each block on the stack used list */
 
3603
    list_verify(ma_sused,
 
3604
        "stack",
 
3605
        preamble,
 
3606
        &stack_blocks,
 
3607
        &bad_stack_blocks,
 
3608
        &bad_stack_checksums,
 
3609
        &bad_stack_lguards,
 
3610
        &bad_stack_rguards);
 
3611
 
 
3612
    if ((bad_heap_blocks > 0) || (bad_stack_blocks > 0))
 
3613
    {
 
3614
        Boolean    old_ma_error_print;
 
3615
 
 
3616
        /* print postamble */
 
3617
        (void)printf("MA_verify_allocator_stuff: scan completed\n");
 
3618
 
 
3619
        /* construct a summary of the results */
 
3620
        (void)sprintf(ma_ebuf, "\n\t\t\t\theap\tstack\n\t\t\t\t----\t-----\n\tchecksum errors\t\t%4d\t%5d\n\tleft signature errors\t%4d\t%5d\n\tright signature errors\t%4d\t%5d\n\ttotal bad blocks\t%4d\t%5d\n\ttotal blocks\t\t%4d\t%5d",
 
3621
            bad_heap_checksums,
 
3622
            bad_stack_checksums,
 
3623
            bad_heap_lguards,
 
3624
            bad_stack_lguards,
 
3625
            bad_heap_rguards,
 
3626
            bad_stack_rguards,
 
3627
            bad_heap_blocks,
 
3628
            bad_stack_blocks,
 
3629
            heap_blocks,
 
3630
            stack_blocks);
 
3631
 
 
3632
        /* print the summary on stderr */
 
3633
        old_ma_error_print = ma_error_print;
 
3634
        ma_error_print = MA_TRUE;
 
3635
        ma_error(EL_Nonfatal, ET_External, "MA_verify_allocator_stuff", ma_ebuf);
 
3636
        ma_error_print = old_ma_error_print;
 
3637
 
 
3638
        /* problems were found */
 
3639
        return MA_FALSE;
 
3640
    }
 
3641
    else
 
3642
        /* no problems found */
 
3643
        return MA_TRUE;
 
3644
 
 
3645
#else
 
3646
 
 
3647
#ifdef STATS
 
3648
    ma_stats.calls[(int)FID_MA_verify_allocator_stuff]++;
 
3649
#endif /* STATS */
 
3650
 
 
3651
    (void)sprintf(ma_ebuf,
 
3652
        "unavailable; recompile MA with -DVERIFY");
 
3653
    ma_error(EL_Nonfatal, ET_External, "MA_verify_allocator_stuff", ma_ebuf);
 
3654
    return MA_FALSE;
 
3655
 
 
3656
#endif /* VERIFY */
 
3657
}