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