diff nss/lib/base/list.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/base/list.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,401 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * list.c
+ *
+ * This contains the implementation of NSS's thread-safe linked list.
+ */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+struct nssListElementStr {
+    PRCList  link;
+    void    *data;
+};
+
+typedef struct nssListElementStr nssListElement;
+
+struct nssListStr {
+    NSSArena       *arena;
+    PZLock         *lock;
+    nssListElement *head;
+    PRUint32        count;
+    nssListCompareFunc compareFunc;
+    nssListSortFunc    sortFunc;
+    PRBool i_alloced_arena;
+};
+
+struct nssListIteratorStr {
+    PZLock *lock;
+    nssList *list;
+    nssListElement *current;
+};
+
+#define NSSLIST_LOCK_IF(list) \
+    if ((list)->lock) PZ_Lock((list)->lock)
+
+#define NSSLIST_UNLOCK_IF(list) \
+    if ((list)->lock) PZ_Unlock((list)->lock)
+
+static PRBool
+pointer_compare(void *a, void *b)
+{
+    return (PRBool)(a == b);
+}
+
+static nssListElement *
+nsslist_get_matching_element(nssList *list, void *data)
+{
+    PRCList *link;
+    nssListElement *node;
+    node = list->head;
+    if (!node) {
+	return NULL;
+    }
+    link = &node->link;
+    while (node) {
+	/* using a callback slows things down when it's just compare ... */
+	if (list->compareFunc(node->data, data)) {
+	    break;
+	}
+	link = &node->link;
+	if (link == PR_LIST_TAIL(&list->head->link)) {
+	    node = NULL;
+	    break;
+	}
+	node = (nssListElement *)PR_NEXT_LINK(&node->link);
+    }
+    return node;
+}
+
+NSS_IMPLEMENT nssList *
+nssList_Create
+(
+  NSSArena *arenaOpt,
+  PRBool threadSafe
+)
+{
+    NSSArena *arena;
+    nssList *list;
+    PRBool i_alloced;
+    if (arenaOpt) {
+	arena = arenaOpt;
+	i_alloced = PR_FALSE;
+    } else {
+	arena = nssArena_Create();
+	i_alloced = PR_TRUE;
+    }
+    if (!arena) {
+	return (nssList *)NULL;
+    }
+    list = nss_ZNEW(arena, nssList);
+    if (!list) {
+	if (!arenaOpt) {
+	    NSSArena_Destroy(arena);
+	}
+	return (nssList *)NULL;
+    }
+    if (threadSafe) {
+	list->lock = PZ_NewLock(nssILockOther);
+	if (!list->lock) {
+	    if (arenaOpt) {
+		nss_ZFreeIf(list);
+	    } else {
+		NSSArena_Destroy(arena);
+	    }
+	    return (nssList *)NULL;
+	}
+    }
+    list->arena = arena;
+    list->i_alloced_arena = i_alloced;
+    list->compareFunc = pointer_compare;
+    return list;
+}
+
+NSS_IMPLEMENT PRStatus
+nssList_Destroy(nssList *list)
+{
+    if (!list->i_alloced_arena) {
+	nssList_Clear(list, NULL);
+    }
+    if (list->lock) {
+	(void)PZ_DestroyLock(list->lock);
+    }
+    if (list->i_alloced_arena) {
+	NSSArena_Destroy(list->arena);
+	list = NULL;
+    }
+    nss_ZFreeIf(list);
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT void
+nssList_SetCompareFunction(nssList *list, nssListCompareFunc compareFunc)
+{
+    list->compareFunc = compareFunc;
+}
+
+NSS_IMPLEMENT void
+nssList_SetSortFunction(nssList *list, nssListSortFunc sortFunc)
+{
+    /* XXX if list already has elements, sort them */
+    list->sortFunc = sortFunc;
+}
+
+NSS_IMPLEMENT nssListCompareFunc
+nssList_GetCompareFunction(nssList *list)
+{
+    return list->compareFunc;
+}
+
+NSS_IMPLEMENT void
+nssList_Clear(nssList *list, nssListElementDestructorFunc destructor)
+{
+    PRCList *link;
+    nssListElement *node, *tmp;
+    NSSLIST_LOCK_IF(list);
+    node = list->head;
+    list->head = NULL;
+    while (node && list->count > 0) {
+	if (destructor) (*destructor)(node->data);
+	link = &node->link;
+	tmp = (nssListElement *)PR_NEXT_LINK(link);
+	PR_REMOVE_LINK(link);
+	nss_ZFreeIf(node);
+	node = tmp;
+	--list->count;
+    }
+    NSSLIST_UNLOCK_IF(list);
+}
+
+static PRStatus
+nsslist_add_element(nssList *list, void *data)
+{
+    nssListElement *node = nss_ZNEW(list->arena, nssListElement);
+    if (!node) {
+	return PR_FAILURE;
+    }
+    PR_INIT_CLIST(&node->link);
+    node->data = data;
+    if (list->head) {
+	if (list->sortFunc) {
+	    PRCList *link;
+	    nssListElement *currNode;
+	    currNode = list->head;
+	    /* insert in ordered list */
+	    while (currNode) {
+		link = &currNode->link;
+		if (list->sortFunc(data, currNode->data) <= 0) {
+		    /* new element goes before current node */
+		    PR_INSERT_BEFORE(&node->link, link);
+		    /* reset head if this is first */
+		    if (currNode == list->head) list->head = node;
+		    break;
+		}
+		if (link == PR_LIST_TAIL(&list->head->link)) {
+		    /* reached end of list, append */
+		    PR_INSERT_AFTER(&node->link, link);
+		    break;
+		}
+		currNode = (nssListElement *)PR_NEXT_LINK(&currNode->link);
+	    }
+	} else {
+	    /* not sorting */
+	    PR_APPEND_LINK(&node->link, &list->head->link);
+	}
+    } else {
+	list->head = node;
+    }
+    ++list->count;
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssList_Add(nssList *list, void *data)
+{
+    PRStatus nssrv;
+    NSSLIST_LOCK_IF(list);
+    nssrv = nsslist_add_element(list, data);
+    NSSLIST_UNLOCK_IF(list);
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssList_AddUnique(nssList *list, void *data)
+{
+    PRStatus nssrv;
+    nssListElement *node;
+    NSSLIST_LOCK_IF(list);
+    node = nsslist_get_matching_element(list, data);
+    if (node) {
+	/* already in, finish */
+	NSSLIST_UNLOCK_IF(list);
+	return PR_SUCCESS;
+    }
+    nssrv = nsslist_add_element(list, data);
+    NSSLIST_UNLOCK_IF(list);
+    return nssrv;
+}
+
+NSS_IMPLEMENT PRStatus
+nssList_Remove(nssList *list, void *data)
+{
+    nssListElement *node;
+    NSSLIST_LOCK_IF(list);
+    node = nsslist_get_matching_element(list, data);
+    if (node) {
+	if (node == list->head) {
+	    list->head = (nssListElement *)PR_NEXT_LINK(&node->link);
+	}
+	PR_REMOVE_LINK(&node->link);
+	nss_ZFreeIf(node);
+	if (--list->count == 0) {
+	    list->head = NULL;
+	}
+    }
+    NSSLIST_UNLOCK_IF(list);
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT void *
+nssList_Get(nssList *list, void *data)
+{
+    nssListElement *node;
+    NSSLIST_LOCK_IF(list);
+    node = nsslist_get_matching_element(list, data);
+    NSSLIST_UNLOCK_IF(list);
+    return (node) ? node->data : NULL;
+}
+
+NSS_IMPLEMENT PRUint32
+nssList_Count(nssList *list)
+{
+    return list->count;
+}
+
+NSS_IMPLEMENT PRStatus
+nssList_GetArray(nssList *list, void **rvArray, PRUint32 maxElements)
+{
+    nssListElement *node;
+    PRUint32 i = 0;
+    PR_ASSERT(maxElements > 0);
+    node = list->head;
+    if (!node) {
+	return PR_SUCCESS;
+    }
+    NSSLIST_LOCK_IF(list);
+    while (node) {
+	rvArray[i++] = node->data;
+	if (i == maxElements) break;
+	node = (nssListElement *)PR_NEXT_LINK(&node->link);
+	if (node == list->head) {
+	    break;
+	}
+    }
+    NSSLIST_UNLOCK_IF(list);
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT nssList *
+nssList_Clone(nssList *list)
+{
+    nssList *rvList;
+    nssListElement *node;
+    rvList = nssList_Create(NULL, (list->lock != NULL));
+    if (!rvList) {
+	return NULL;
+    }
+    NSSLIST_LOCK_IF(list);
+    if (list->count > 0) {
+	node = list->head;
+	while (PR_TRUE) {
+	    nssList_Add(rvList, node->data);
+	    node = (nssListElement *)PR_NEXT_LINK(&node->link);
+	    if (node == list->head) {
+		break;
+	    }
+	}
+    }
+    NSSLIST_UNLOCK_IF(list);
+    return rvList;
+}
+
+NSS_IMPLEMENT nssListIterator *
+nssList_CreateIterator(nssList *list)
+{
+    nssListIterator *rvIterator;
+    rvIterator = nss_ZNEW(NULL, nssListIterator);
+    if (!rvIterator) {
+	return NULL;
+    }
+    rvIterator->list = nssList_Clone(list);
+    if (!rvIterator->list) {
+	nss_ZFreeIf(rvIterator);
+	return NULL;
+    }
+    rvIterator->current = rvIterator->list->head;
+    if (list->lock) {
+	rvIterator->lock = PZ_NewLock(nssILockOther);
+	if (!rvIterator->lock) {
+	    nssList_Destroy(rvIterator->list);
+	    nss_ZFreeIf(rvIterator);
+	    rvIterator = NULL;
+	}
+    }
+    return rvIterator;
+}
+
+NSS_IMPLEMENT void
+nssListIterator_Destroy(nssListIterator *iter)
+{
+    if (iter->lock) {
+	(void)PZ_DestroyLock(iter->lock);
+    }
+    nssList_Destroy(iter->list);
+    nss_ZFreeIf(iter);
+}
+
+NSS_IMPLEMENT void *
+nssListIterator_Start(nssListIterator *iter)
+{
+    NSSLIST_LOCK_IF(iter);
+    if (iter->list->count == 0) {
+	return NULL;
+    }
+    iter->current = iter->list->head;
+    return iter->current->data;
+}
+
+NSS_IMPLEMENT void *
+nssListIterator_Next(nssListIterator *iter)
+{
+    nssListElement *node;
+    PRCList *link;
+    if (iter->list->count == 1 || iter->current == NULL) {
+	/* Reached the end of the list.  Don't change the state, force to
+	 * user to call nssList_Finish to clean up.
+	 */
+	return NULL;
+    }
+    node = (nssListElement *)PR_NEXT_LINK(&iter->current->link);
+    link = &node->link;
+    if (link == PR_LIST_TAIL(&iter->list->head->link)) {
+	/* Signal the end of the list. */
+	iter->current = NULL;
+	return node->data;
+    }
+    iter->current = node;
+    return node->data;
+}
+
+NSS_IMPLEMENT PRStatus
+nssListIterator_Finish(nssListIterator *iter)
+{
+    iter->current = iter->list->head;
+    return (iter->lock) ? PZ_Unlock(iter->lock) : PR_SUCCESS;
+}
+
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)