17aec1d6eScindi /*
27aec1d6eScindi  * CDDL HEADER START
37aec1d6eScindi  *
47aec1d6eScindi  * The contents of this file are subject to the terms of the
57aec1d6eScindi  * Common Development and Distribution License, Version 1.0 only
67aec1d6eScindi  * (the "License").  You may not use this file except in compliance
77aec1d6eScindi  * with the License.
87aec1d6eScindi  *
97aec1d6eScindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107aec1d6eScindi  * or http://www.opensolaris.org/os/licensing.
117aec1d6eScindi  * See the License for the specific language governing permissions
127aec1d6eScindi  * and limitations under the License.
137aec1d6eScindi  *
147aec1d6eScindi  * When distributing Covered Code, include this CDDL HEADER in each
157aec1d6eScindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167aec1d6eScindi  * If applicable, add the following below this CDDL HEADER, with the
177aec1d6eScindi  * fields enclosed by brackets "[]" replaced with your own identifying
187aec1d6eScindi  * information: Portions Copyright [yyyy] [name of copyright owner]
197aec1d6eScindi  *
207aec1d6eScindi  * CDDL HEADER END
217aec1d6eScindi  */
227aec1d6eScindi /*
237aec1d6eScindi  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247aec1d6eScindi  * Use is subject to license terms.
257aec1d6eScindi  */
26*2b1b28a8SRob Johnston /*
27*2b1b28a8SRob Johnston  * Copyright 2019 Joyent, Inc.
28*2b1b28a8SRob Johnston  */
297aec1d6eScindi 
30*2b1b28a8SRob Johnston #include <string.h>
317aec1d6eScindi #include <unistd.h>
327aec1d6eScindi #include <assert.h>
337aec1d6eScindi 
34*2b1b28a8SRob Johnston #include <topo_error.h>
357aec1d6eScindi #include <topo_list.h>
367aec1d6eScindi #include <topo_tree.h>
377aec1d6eScindi 
387aec1d6eScindi /*
397aec1d6eScindi  * Embedded Linked Lists
407aec1d6eScindi  *
417aec1d6eScindi  * Simple doubly-linked list implementation.  This implementation assumes that
427aec1d6eScindi  * each list element contains an embedded topo_list_t (previous and next
437aec1d6eScindi  * pointers), which is typically the first member of the element struct.
447aec1d6eScindi  * An additional topo_list_t is used to store the head (l_next) and tail
457aec1d6eScindi  * (l_prev) pointers.  The current head and tail list elements have their
467aec1d6eScindi  * previous and next pointers set to NULL, respectively.
477aec1d6eScindi  *
487aec1d6eScindi  * NOTE: The embeddable list code in this file intentionally provides no
497aec1d6eScindi  * locking of any kind.  The implementation of any list in topo must provide
507aec1d6eScindi  * an appropriate locking strategy to protect the list or to protect access
517aec1d6eScindi  * to the embedded topo_list_t inside of each list element to avoid corruption.
527aec1d6eScindi  * Refer to comments in the source files that use topo_list_t for lock details.
537aec1d6eScindi  */
547aec1d6eScindi 
557aec1d6eScindi 
567aec1d6eScindi void
topo_list_append(topo_list_t * lp,void * new)577aec1d6eScindi topo_list_append(topo_list_t *lp, void *new)
587aec1d6eScindi {
597aec1d6eScindi 	topo_list_t *p = lp->l_prev;	/* p = tail list element */
607aec1d6eScindi 	topo_list_t *q = new;		/* q = new list element */
617aec1d6eScindi 
627aec1d6eScindi 	lp->l_prev = q;
637aec1d6eScindi 	q->l_prev = p;
647aec1d6eScindi 	q->l_next = NULL;
657aec1d6eScindi 
667aec1d6eScindi 	if (p != NULL) {
677aec1d6eScindi 		assert(p->l_next == NULL);
687aec1d6eScindi 		p->l_next = q;
697aec1d6eScindi 	} else {
707aec1d6eScindi 		assert(lp->l_next == NULL);
717aec1d6eScindi 		lp->l_next = q;
727aec1d6eScindi 	}
737aec1d6eScindi }
747aec1d6eScindi 
757aec1d6eScindi void
topo_list_prepend(topo_list_t * lp,void * new)767aec1d6eScindi topo_list_prepend(topo_list_t *lp, void *new)
777aec1d6eScindi {
787aec1d6eScindi 	topo_list_t *p = new;		/* p = new list element */
797aec1d6eScindi 	topo_list_t *q = lp->l_next;	/* q = head list element */
807aec1d6eScindi 
817aec1d6eScindi 	lp->l_next = p;
827aec1d6eScindi 	p->l_prev = NULL;
837aec1d6eScindi 	p->l_next = q;
847aec1d6eScindi 
857aec1d6eScindi 	if (q != NULL) {
867aec1d6eScindi 		assert(q->l_prev == NULL);
877aec1d6eScindi 		q->l_prev = p;
887aec1d6eScindi 	} else {
897aec1d6eScindi 		assert(lp->l_prev == NULL);
907aec1d6eScindi 		lp->l_prev = p;
917aec1d6eScindi 	}
927aec1d6eScindi }
937aec1d6eScindi 
947aec1d6eScindi void
topo_list_insert_before(topo_list_t * lp,void * before_me,void * new)957aec1d6eScindi topo_list_insert_before(topo_list_t *lp, void *before_me, void *new)
967aec1d6eScindi {
977aec1d6eScindi 	topo_list_t *p = before_me;
987aec1d6eScindi 	topo_list_t *q = new;
997aec1d6eScindi 
1007aec1d6eScindi 	if (p == NULL || p->l_prev == NULL) {
1017aec1d6eScindi 		topo_list_prepend(lp, new);
1027aec1d6eScindi 		return;
1037aec1d6eScindi 	}
1047aec1d6eScindi 
1057aec1d6eScindi 	q->l_prev = p->l_prev;
1067aec1d6eScindi 	q->l_next = p;
1077aec1d6eScindi 	p->l_prev = q;
1087aec1d6eScindi 	q->l_prev->l_next = q;
1097aec1d6eScindi }
1107aec1d6eScindi 
1117aec1d6eScindi void
topo_list_insert_after(topo_list_t * lp,void * after_me,void * new)1127aec1d6eScindi topo_list_insert_after(topo_list_t *lp, void *after_me, void *new)
1137aec1d6eScindi {
1147aec1d6eScindi 	topo_list_t *p = after_me;
1157aec1d6eScindi 	topo_list_t *q = new;
1167aec1d6eScindi 
1177aec1d6eScindi 	if (p == NULL || p->l_next == NULL) {
1187aec1d6eScindi 		topo_list_append(lp, new);
1197aec1d6eScindi 		return;
1207aec1d6eScindi 	}
1217aec1d6eScindi 
1227aec1d6eScindi 	q->l_next = p->l_next;
1237aec1d6eScindi 	q->l_prev = p;
1247aec1d6eScindi 	p->l_next = q;
1257aec1d6eScindi 	q->l_next->l_prev = q;
1267aec1d6eScindi }
1277aec1d6eScindi 
1287aec1d6eScindi void
topo_list_delete(topo_list_t * lp,void * existing)1297aec1d6eScindi topo_list_delete(topo_list_t *lp, void *existing)
1307aec1d6eScindi {
1317aec1d6eScindi 	topo_list_t *p = existing;
1327aec1d6eScindi 
1337aec1d6eScindi 	if (p->l_prev != NULL)
1347aec1d6eScindi 		p->l_prev->l_next = p->l_next;
1357aec1d6eScindi 	else
1367aec1d6eScindi 		lp->l_next = p->l_next;
1377aec1d6eScindi 
1387aec1d6eScindi 	if (p->l_next != NULL)
1397aec1d6eScindi 		p->l_next->l_prev = p->l_prev;
1407aec1d6eScindi 	else
1417aec1d6eScindi 		lp->l_prev = p->l_prev;
1427aec1d6eScindi }
1437aec1d6eScindi 
1447aec1d6eScindi tnode_t *
topo_child_first(tnode_t * pnode)1457aec1d6eScindi topo_child_first(tnode_t *pnode)
1467aec1d6eScindi {
1477aec1d6eScindi 	int i;
1487aec1d6eScindi 	topo_nodehash_t *nhp;
1497aec1d6eScindi 
1507aec1d6eScindi 	for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
1517aec1d6eScindi 	    nhp = topo_list_next(nhp)) {
1527aec1d6eScindi 		for (i = 0; i < nhp->th_arrlen; ++i) {
1537aec1d6eScindi 			if (nhp->th_nodearr[i] != NULL)
1547aec1d6eScindi 				return (nhp->th_nodearr[i]);
1557aec1d6eScindi 		}
1567aec1d6eScindi 	}
1577aec1d6eScindi 
1587aec1d6eScindi 	return (NULL);
1597aec1d6eScindi }
1607aec1d6eScindi 
1617aec1d6eScindi tnode_t *
topo_child_next(tnode_t * pnode,tnode_t * node)1627aec1d6eScindi topo_child_next(tnode_t *pnode, tnode_t *node)
1637aec1d6eScindi {
1647aec1d6eScindi 	int i;
1657aec1d6eScindi 	int index;
1667aec1d6eScindi 	topo_nodehash_t *nhp;
1677aec1d6eScindi 
1687aec1d6eScindi 	if (node == NULL) {
1697aec1d6eScindi 		return (topo_child_first(pnode));
1707aec1d6eScindi 	}
1717aec1d6eScindi 
1727aec1d6eScindi 	/*
1737aec1d6eScindi 	 * Begin search for next child in the current hash array
1747aec1d6eScindi 	 * If none found or we are at the end of the array, move
1757aec1d6eScindi 	 * on to the next array
1767aec1d6eScindi 	 */
1777aec1d6eScindi 	index = topo_node_hash(node->tn_phash, node->tn_instance) + 1;
1787aec1d6eScindi 	for (nhp = node->tn_phash; nhp != NULL; nhp = topo_list_next(nhp)) {
1797aec1d6eScindi 		for (i = index; i < nhp->th_arrlen; ++i) {
1807aec1d6eScindi 			if (nhp->th_nodearr[i] != NULL) {
1817aec1d6eScindi 				return (nhp->th_nodearr[i]);
1827aec1d6eScindi 			}
1837aec1d6eScindi 		}
1847aec1d6eScindi 		index = 0;
1857aec1d6eScindi 	}
1867aec1d6eScindi 
1877aec1d6eScindi 	return (NULL);
1887aec1d6eScindi }
189*2b1b28a8SRob Johnston 
190*2b1b28a8SRob Johnston int
topo_list_deepcopy(topo_hdl_t * thp,topo_list_t * dest,topo_list_t * src,size_t elem_sz)191*2b1b28a8SRob Johnston topo_list_deepcopy(topo_hdl_t *thp, topo_list_t *dest, topo_list_t *src,
192*2b1b28a8SRob Johnston     size_t elem_sz)
193*2b1b28a8SRob Johnston {
194*2b1b28a8SRob Johnston 	void *elem;
195*2b1b28a8SRob Johnston 
196*2b1b28a8SRob Johnston 	/* if the destination list is not empty - bail out */
197*2b1b28a8SRob Johnston 	if (topo_list_next(dest) != NULL)
198*2b1b28a8SRob Johnston 		return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
199*2b1b28a8SRob Johnston 
200*2b1b28a8SRob Johnston 	for (elem = topo_list_next(src); elem != NULL;
201*2b1b28a8SRob Johnston 	    elem = topo_list_next(elem)) {
202*2b1b28a8SRob Johnston 		void *elem_copy;
203*2b1b28a8SRob Johnston 
204*2b1b28a8SRob Johnston 		if ((elem_copy = topo_hdl_alloc(thp, elem_sz)) == NULL) {
205*2b1b28a8SRob Johnston 			goto err;
206*2b1b28a8SRob Johnston 		}
207*2b1b28a8SRob Johnston 		(void) memcpy(elem_copy, elem, elem_sz);
208*2b1b28a8SRob Johnston 		topo_list_append(dest, elem_copy);
209*2b1b28a8SRob Johnston 	}
210*2b1b28a8SRob Johnston 	return (0);
211*2b1b28a8SRob Johnston 
212*2b1b28a8SRob Johnston err:
213*2b1b28a8SRob Johnston 	/*
214*2b1b28a8SRob Johnston 	 * If we hit an error, cleanup any partially copied list elements
215*2b1b28a8SRob Johnston 	 * before we return.
216*2b1b28a8SRob Johnston 	 */
217*2b1b28a8SRob Johnston 	elem = topo_list_next(dest);
218*2b1b28a8SRob Johnston 	while (elem != NULL) {
219*2b1b28a8SRob Johnston 		void *tmp = elem;
220*2b1b28a8SRob Johnston 
221*2b1b28a8SRob Johnston 		elem = topo_list_next(elem);
222*2b1b28a8SRob Johnston 		topo_list_delete(dest, tmp);
223*2b1b28a8SRob Johnston 		topo_hdl_free(thp, tmp, elem_sz);
224*2b1b28a8SRob Johnston 	}
225*2b1b28a8SRob Johnston 	return (topo_hdl_seterrno(thp, ETOPO_NOMEM));
226*2b1b28a8SRob Johnston }
227