10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51682Srie * Common Development and Distribution License (the "License"). 61682Srie * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211682Srie 220Sstevel@tonic-gate /* 23*5892Sab196087 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate * 260Sstevel@tonic-gate * Define an Alist, a list maintained as a reallocable array, and a for() loop 270Sstevel@tonic-gate * macro to generalize its traversal. Note that the array can be reallocated 280Sstevel@tonic-gate * as it is being traversed, thus the offset of each element is recomputed from 290Sstevel@tonic-gate * the start of the structure. 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #ifndef _ALIST_H 330Sstevel@tonic-gate #define _ALIST_H 340Sstevel@tonic-gate 350Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 360Sstevel@tonic-gate 370Sstevel@tonic-gate #ifdef __cplusplus 380Sstevel@tonic-gate extern "C" { 390Sstevel@tonic-gate #endif 400Sstevel@tonic-gate 410Sstevel@tonic-gate #include <sys/types.h> 420Sstevel@tonic-gate #include <sys/machelf.h> 430Sstevel@tonic-gate 44*5892Sab196087 /* 45*5892Sab196087 * An Alist implements array lists. The functionality is similar to 46*5892Sab196087 * that of a linked list. However, an Alist is represented by a single 47*5892Sab196087 * contigious allocation of memory. The head of the memory is a header 48*5892Sab196087 * that contains control information for the list. Following the header 49*5892Sab196087 * is an array used to hold the user data. In the type definitions that 50*5892Sab196087 * follow, we define these as an array with a single element, but when 51*5892Sab196087 * we allocate the memory, we actually allocate the amount of memory needed. 52*5892Sab196087 * 53*5892Sab196087 * There are two "flavors" of array list: 54*5892Sab196087 * 55*5892Sab196087 * Alist - Contain arbitrary data, usually structs. 56*5892Sab196087 * APlist - Contain pointers to data allocated elsewhere. 57*5892Sab196087 * 58*5892Sab196087 * This differentiation is useful, because pointer lists are heavily 59*5892Sab196087 * used, and support a slightly different set of operations that are 60*5892Sab196087 * unique to their purpose. 61*5892Sab196087 * 62*5892Sab196087 * Array lists are initially represented by a NULL pointer. The memory 63*5892Sab196087 * for the list is only allocated if an item is inserted. This is very 64*5892Sab196087 * efficient for data structures that may or may not be needed for a 65*5892Sab196087 * given linker operation --- you only pay for what you use. In addition: 66*5892Sab196087 * 67*5892Sab196087 * - Array lists grow as needed (memory is reallocated as necessary) 68*5892Sab196087 * - Data is kept contiguously (no unused holes in between elements) 69*5892Sab196087 * at the beginning of the data area. This locality has 70*5892Sab196087 * good cache behavior, as access to adjacent items are 71*5892Sab196087 * highly likely to be in the same page of memory. 72*5892Sab196087 * - Insert/Delete operations at the end of the list are very 73*5892Sab196087 * efficient. However, insert/delete operations elsewhere 74*5892Sab196087 * will cause a relatively expensive overlapped memory 75*5892Sab196087 * copy of the data following the insert/delete location. 76*5892Sab196087 * - As with any generic memory alloctor (i.e. malloc()/free()), 77*5892Sab196087 * array lists are not type safe for the data they contain. 78*5892Sab196087 * Data is managed as (void *) pointers to data of a given 79*5892Sab196087 * length, so the Alist module cannot prevent the caller from 80*5892Sab196087 * inserting/extracting the wrong type of data. The caller 81*5892Sab196087 * must guard against this. 82*5892Sab196087 * - To free an array list, simply call the standard free() function 83*5892Sab196087 * on the list pointer. 84*5892Sab196087 */ 85*5892Sab196087 86*5892Sab196087 87*5892Sab196087 88*5892Sab196087 /* 89*5892Sab196087 * Aliste is used to represent list indexes, offsets, and sizes. 90*5892Sab196087 */ 91*5892Sab196087 typedef size_t Aliste; 92*5892Sab196087 93*5892Sab196087 940Sstevel@tonic-gate 95*5892Sab196087 /* 96*5892Sab196087 * Alist is used to hold non-pointer items --- usually structs: 97*5892Sab196087 * - There must be an even number of Aliste fields before the 98*5892Sab196087 * al_data field. This ensures that al_data will have 99*5892Sab196087 * an alignment of 8, no matter whether sizeof(Aliste) 100*5892Sab196087 * is 4 or 8. That means that al_data will have sufficient 101*5892Sab196087 * alignment for any use, just like memory allocated via 102*5892Sab196087 * malloc(). 103*5892Sab196087 * - al_nitems and al_next are redundant, in that they are 104*5892Sab196087 * directly related: 105*5892Sab196087 * al_next = al_nitems * al_size 106*5892Sab196087 * We do this to make ALIST_TRAVERSE_BYOFFSET maximally 107*5892Sab196087 * efficient. This doesn't waste space, because of the 108*5892Sab196087 * requirement to have an even # of Alist fields (above). 109*5892Sab196087 * 110*5892Sab196087 * Note that Alists allow the data to be referenced by 0 based array 111*5892Sab196087 * index, or by their byte offset from the start of the Alist memory 112*5892Sab196087 * allocation. The index form is preferred for most use, as it is simpler. 113*5892Sab196087 * However, by-offset access is used by rtld link maps, and this ability 114*5892Sab196087 * is convenient in that case. 115*5892Sab196087 */ 116*5892Sab196087 typedef struct { 117*5892Sab196087 Aliste al_arritems; /* # of items in al_data allocation */ 118*5892Sab196087 Aliste al_nitems; /* # items (index of next avail item) */ 119*5892Sab196087 Aliste al_next; /* offset of next available al_data[] */ 120*5892Sab196087 Aliste al_size; /* size of each al_data[] item */ 121*5892Sab196087 void *al_data[1]; /* data (can grow) */ 122*5892Sab196087 } Alist; 123*5892Sab196087 124*5892Sab196087 /* 125*5892Sab196087 * APlist is a variant of Alist that contains pointers. There are several 126*5892Sab196087 * benefits to this special type: 127*5892Sab196087 * - API is simpler 128*5892Sab196087 * - Pointers are used directly, instead of requiring a 129*5892Sab196087 * pointer-to-pointer double indirection. 130*5892Sab196087 * - The implementation is slightly more efficient. 131*5892Sab196087 * - Operations that make particular sense for pointers 132*5892Sab196087 * can be supported without confusing the API for the 133*5892Sab196087 * regular Alists. 134*5892Sab196087 */ 135*5892Sab196087 typedef struct { 136*5892Sab196087 Aliste apl_arritems; /* # of items in apl_data allocation */ 137*5892Sab196087 Aliste apl_nitems; /* # items (index of next avail item) */ 138*5892Sab196087 void *apl_data[1]; /* data area: (arrcnt * size) bytes */ 139*5892Sab196087 } APlist; 140*5892Sab196087 141*5892Sab196087 142*5892Sab196087 /* 143*5892Sab196087 * The ALIST_OFF_DATA and APLIST_OFF_DATA macros give the byte offset 144*5892Sab196087 * from the start of an array list to the first byte of the data area 145*5892Sab196087 * used to hold user data. The same trick used by the standard offsetof() 146*5892Sab196087 * macro is used. 147*5892Sab196087 */ 148*5892Sab196087 #define ALIST_OFF_DATA ((size_t)(((Alist *)0)->al_data)) 149*5892Sab196087 #define APLIST_OFF_DATA ((size_t)(((APlist *)0)->apl_data)) 150*5892Sab196087 151*5892Sab196087 152*5892Sab196087 /* 153*5892Sab196087 * The TRAVERSE macros are intended to be used within a for(), and 154*5892Sab196087 * cause the resulting loop to iterate over each item in the loop, 155*5892Sab196087 * in order. 156*5892Sab196087 * ALIST_TRAVERSE: Traverse over the items in an Alist, 157*5892Sab196087 * using the zero based item array index to refer to 158*5892Sab196087 * each item. 159*5892Sab196087 * ALIST_TRAVERSE_BY_OFFSET: Traverse over the items in an 160*5892Sab196087 * Alist using the byte offset from the head of the 161*5892Sab196087 * Alist pointer to refer to each item. It should be noted 162*5892Sab196087 * that the first such offset is given by ALIST_OFF_DATA, 163*5892Sab196087 * and as such, there will never be a 0 offset. Some code 164*5892Sab196087 * uses this fact to treat 0 as a reserved value with 165*5892Sab196087 * special meaning. 166*5892Sab196087 * 167*5892Sab196087 * By-offset access is convenient for some parts of 168*5892Sab196087 * rtld, where a value of 0 is used to indicate an 169*5892Sab196087 * uninitialized link map control. 170*5892Sab196087 * 171*5892Sab196087 * APLIST_TRAVERSE: Traverse over the pointers in an APlist, using 172*5892Sab196087 * the zero based item array index to refer to each pointer. 173*5892Sab196087 */ 174*5892Sab196087 175*5892Sab196087 /* 176*5892Sab196087 * Within the loop: 177*5892Sab196087 * 178*5892Sab196087 * LIST - Pointer to Alist structure for list 179*5892Sab196087 * IDX - The current item index 180*5892Sab196087 * OFF - The current item offset 181*5892Sab196087 * DATA - Pointer to item 182*5892Sab196087 */ 183*5892Sab196087 #define ALIST_TRAVERSE(LIST, IDX, DATA) \ 184*5892Sab196087 (IDX) = 0, \ 185*5892Sab196087 ((LIST) != NULL) && ((DATA) = (void *)(LIST)->al_data); \ 186*5892Sab196087 \ 187*5892Sab196087 ((LIST) != NULL) && ((IDX) < (LIST)->al_nitems); \ 188*5892Sab196087 \ 189*5892Sab196087 (IDX)++, \ 190*5892Sab196087 (DATA) = (void *) (((LIST)->al_size * (IDX)) + (char *)(LIST)->al_data) 191*5892Sab196087 192*5892Sab196087 #define ALIST_TRAVERSE_BY_OFFSET(LIST, OFF, DATA) \ 193*5892Sab196087 (((LIST) != NULL) && ((OFF) = ALIST_OFF_DATA) && \ 1940Sstevel@tonic-gate (((DATA) = (void *)((char *)(LIST) + (OFF))))); \ 195*5892Sab196087 \ 196*5892Sab196087 (((LIST) != NULL) && ((OFF) < (LIST)->al_next)); \ 197*5892Sab196087 \ 1980Sstevel@tonic-gate (((OFF) += ((LIST)->al_size)), \ 1990Sstevel@tonic-gate ((DATA) = (void *)((char *)(LIST) + (OFF)))) 2000Sstevel@tonic-gate 201*5892Sab196087 /* 202*5892Sab196087 * Within the loop: 203*5892Sab196087 * 204*5892Sab196087 * LIST - Pointer to APlist structure for list 205*5892Sab196087 * IDX - The current item index 206*5892Sab196087 * PTR - item value 207*5892Sab196087 * 208*5892Sab196087 * Note that this macro is designed to ensure that PTR retains the 209*5892Sab196087 * value of the final pointer in the list after exiting the for loop, 210*5892Sab196087 * and to avoid dereferencing an out of range address. This is done by 211*5892Sab196087 * doing the dereference in the middle expression, using the comma 212*5892Sab196087 * operator to ensure that a NULL pointer won't stop the loop. 213*5892Sab196087 */ 214*5892Sab196087 #define APLIST_TRAVERSE(LIST, IDX, PTR) \ 215*5892Sab196087 (IDX) = 0; \ 216*5892Sab196087 \ 217*5892Sab196087 ((LIST) != NULL) && ((IDX) < (LIST)->apl_nitems) && \ 218*5892Sab196087 (((PTR) = ((LIST)->apl_data)[IDX]), 1); \ 219*5892Sab196087 \ 220*5892Sab196087 (IDX)++ 2210Sstevel@tonic-gate 222*5892Sab196087 223*5892Sab196087 /* 224*5892Sab196087 * Possible values returned by aplist_test() 225*5892Sab196087 */ 226*5892Sab196087 typedef enum { 227*5892Sab196087 ALE_ALLOCFAIL = 0, /* Memory allocation error */ 228*5892Sab196087 ALE_EXISTS = 1, /* alist entry already exists */ 229*5892Sab196087 ALE_NOTFND = 2, /* item not found and insert not required */ 230*5892Sab196087 ALE_CREATE = 3 /* alist entry created */ 231*5892Sab196087 } aplist_test_t; 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate /* 235*5892Sab196087 * Access to an Alist item by index or offset. This is needed because the 236*5892Sab196087 * size of an item in an Alist is not known by the C compiler, and we 237*5892Sab196087 * have to do the indexing arithmetic explicitly. 238*5892Sab196087 * 239*5892Sab196087 * For an APlist, index the apl_data field directly --- No macro is needed. 2400Sstevel@tonic-gate */ 241*5892Sab196087 #define alist_item(_lp, _idx) \ 242*5892Sab196087 ((void *)(ALIST_OFF_DATA + ((_idx) * (_lp)->al_size) + (char *)(_lp))) 243*5892Sab196087 #define alist_item_by_offset(_lp, _off) \ 244*5892Sab196087 ((void *)((_off) + (char *)(_lp))) 245*5892Sab196087 246*5892Sab196087 /* 247*5892Sab196087 * # of items currently found in a list. These macros handle the case 248*5892Sab196087 * where the list has not been allocated yet. 249*5892Sab196087 */ 250*5892Sab196087 #define alist_nitems(_lp) (((_lp) == NULL) ? 0 : (_lp)->al_nitems) 251*5892Sab196087 #define aplist_nitems(_lp) (((_lp) == NULL) ? 0 : (_lp)->apl_nitems) 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate 254*5892Sab196087 extern void *alist_append(Alist **, const void *, size_t, Aliste); 255*5892Sab196087 extern void alist_delete(Alist *, Aliste *); 256*5892Sab196087 extern void alist_delete_by_offset(Alist *, Aliste *); 257*5892Sab196087 extern void *alist_insert(Alist **, const void *, size_t, 258*5892Sab196087 Aliste, Aliste); 259*5892Sab196087 extern void *alist_insert_by_offset(Alist **, const void *, size_t, 260*5892Sab196087 Aliste, Aliste); 261*5892Sab196087 extern void alist_reset(Alist *); 262*5892Sab196087 263*5892Sab196087 264*5892Sab196087 extern void *aplist_append(APlist **, const void *, Aliste); 265*5892Sab196087 extern void aplist_delete(APlist *, Aliste *); 266*5892Sab196087 extern int aplist_delete_value(APlist *, const void *); 267*5892Sab196087 extern void *aplist_insert(APlist **, const void *, 268*5892Sab196087 Aliste, Aliste idx); 269*5892Sab196087 extern void aplist_reset(APlist *); 270*5892Sab196087 extern aplist_test_t aplist_test(APlist **, const void *, Aliste); 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate #ifdef __cplusplus 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate #endif 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate #endif /* _ALIST_H */ 277