xref: /illumos-gate/usr/src/cmd/sgs/include/alist.h (revision 2017c9656f884256b400be40fa25d96d630bf02a)
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