| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- /** BEGIN COPYRIGHT BLOCK
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- *
- * License: GPL (version 3 or any later version).
- * See LICENSE for details.
- * END COPYRIGHT BLOCK **/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- #include "slapi-plugin.h"
- #include "slapi-private.h"
- /*
- * The "wrapper" placed around objects in our object set.
- */
- typedef struct objset_object
- {
- Object *obj; /* pointer to actual object */
- struct objset_object *next; /* pointer to next object in list */
- } objset_object;
- /*
- * The object set itself.
- */
- typedef struct objset
- {
- objset_object *head; /* pointer to linked list of objects */
- objset_object *tail; /* pointer to tail of linked list */
- PRLock *lock; /* Lock - protects addition/deletion from list */
- FNFree destructor; /* Destructor callback for objset itself */
- } objset;
-
- /* Forward declarations */
- static void unlinkObjsetObjectNoLock(Objset *o, objset_object *obj_to_unlink);
- /*
- * Create a new, empty object set.
- * Returns a pointer to the new object set, or NULL if an error occurred.
- */
- Objset *
- objset_new(FNFree objset_destructor)
- {
- objset *set;
- set = (objset *)slapi_ch_malloc(sizeof(objset));
- set->lock = PR_NewLock();
- if (NULL == set->lock)
- {
- slapi_ch_free((void **)&set);
- }
- else
- {
- set->head = set->tail = NULL;
- set->destructor = objset_destructor;
- }
- return set;
- }
- /*
- * Delete an object set. All references to contained objects
- * are released, and the objset is deleted.
- */
- void
- objset_delete(Objset **setp)
- {
- objset_object *o, *o_next;
- Objset *set;
- PR_ASSERT(NULL != setp);
- set = *setp;
- PR_ASSERT(NULL != set);
- PR_Lock(set->lock);
- o = set->head;
- while (NULL != o)
- {
- o_next = o->next;
- object_release(o->obj); /* release our reference */
- slapi_ch_free((void **)&o); /* Free wrapper */
- o = o_next;
- }
- PR_Unlock(set->lock);
- PR_DestroyLock(set->lock);
- if (NULL != set->destructor)
- {
- set->destructor((void **)setp);
- }
- slapi_ch_free((void **)setp);
- }
-
- /*
- * Add a new object to an object set.
- * Return values:
- * OBJSET_SUCCESS: the insertion was succesful.
- * OBJSET_ALREADY_EXISTS: the object already exists in the set.
- */
- int
- objset_add_obj(Objset *set, Object *object)
- {
- objset_object *p;
- int exists = 0;
- int rc = OBJSET_SUCCESS;
- PR_ASSERT(NULL != set);
- PR_ASSERT(NULL != object);
- PR_Lock(set->lock);
- /* Make sure this object isn't already in the set */
- p = set->head;
- while (NULL != p)
- {
- if (p->obj == object)
- {
- exists = 1;
- break;
- }
- p = p->next;
- }
- if (exists)
- {
- rc = OBJSET_ALREADY_EXISTS;
- }
- else
- {
- objset_object *new_node = (objset_object *)slapi_ch_malloc(sizeof(objset_object));
- object_acquire(object); /* Record our reference */
- new_node->obj = object;
- new_node->next = NULL;
- if (NULL == set->head)
- {
- set->head = set->tail = new_node;
- }
- else
- {
- set->tail->next = new_node;
- set->tail = new_node;
- }
- }
- PR_Unlock(set->lock);
- return rc;
- }
- /*
- * Locate an object in an object set.
- *
- * Arguments:
- * set: the object set to search
- * compare_fn: a caller-provided function used to compare the
- * name against an object. This function should return
- * a negtive value, zero, or a positive value if the
- * object's name is, respectively, less that, equal
- * to, or greater than the provided name.
- * name: the name (value) to find.
- *
- * The returned object, if any, is referenced. The caller must
- * call object_release() when finished with the object.
- *
- * Returns the object, if found. Otherwise, returns NULL.
- * Implementation note: since we store objects in an unordered
- * linked list, all that's really important is that the compare_fn
- * return 0 when a match is found, and non-zero otherwise.
- * Other types of implementations might try to optimize the
- * storage, e.g. binary search.
- */
- Object *
- objset_find(Objset *set, CMPFn compare_fn, const void *name)
- {
- objset_object *found = NULL;
- PR_ASSERT(NULL != set);
- PR_ASSERT(NULL != name);
- PR_ASSERT(NULL != compare_fn);
- PR_Lock(set->lock);
- found = set->head;
- while (NULL != found)
- {
- if (compare_fn(found->obj, name) == 0)
- {
- break;
- }
- found = found->next;
- }
- if (NULL != found)
- {
- /* acquire object */
- object_acquire(found->obj);
- }
- PR_Unlock(set->lock);
- return found == NULL ? NULL : found->obj;
- }
- /*
- * Remove an object from an objset.
- * Returns OBJSET_SUCCESS if the object was found and removed, or
- * OBJSET_NO_SUCH_OBJECT if the object was not found in the list.
- */
- int
- objset_remove_obj(Objset *set, Object *object)
- {
- int rc = OBJSET_SUCCESS;
- objset_object *found;
- PR_ASSERT(NULL != set);
- PR_ASSERT(NULL != object);
- PR_Lock(set->lock);
- found = set->head;
- while (NULL != found)
- {
- if (found->obj == object)
- {
- break;
- }
- found = found->next;
- }
- if (NULL == found)
- {
- rc = OBJSET_NO_SUCH_OBJECT;
- }
- else
- {
- Object *saved = found->obj;
- /* Unlink from list */
- unlinkObjsetObjectNoLock(set, found);
- /* Release reference on object */
- object_release(saved);
- }
- PR_Unlock(set->lock);
- return rc;
- }
- /*
- * Prepare for iteration across an object set. Returns the first
- * object in the set. The returned object is referenced, therefore
- * the caller must either release the object, or
- * pass it to an objset_next_obj call, which will
- * implicitly release the object.
- * Returns the first object, or NULL if the objset contains no
- * objects.
- */
- Object *
- objset_first_obj(Objset *set)
- {
- Object *return_object;
- /* Be tolerant (for the replication plugin) */
- if (set == NULL) return NULL;
- PR_Lock(set->lock);
- if (NULL == set->head)
- {
- return_object = NULL;
- }
- else
- {
- object_acquire(set->head->obj);
- return_object = set->head->obj;
- }
- PR_Unlock(set->lock);
- return return_object;
- }
- /*
- * Return the next object in an object set, or NULL if there are
- * no more objects.
- * The returned object is referenced, therefore
- * the caller must either release the object, or
- * pass it to an objset_next_ob call, which will
- * implicitly release the object.
- */
- Object *
- objset_next_obj(Objset *set, Object *previous)
- {
- Object *return_object = NULL;
- objset_object *p;
- PR_ASSERT(NULL != set);
- PR_Lock(set->lock);
- /* First, find the current object */
- p = set->head;
- while (NULL != p && p->obj != previous)
- {
- p = p->next;
- }
- /* Find the next object */
- if (NULL != p && NULL != p->next)
- {
- return_object = p->next->obj;
- object_acquire(return_object);
- }
- PR_Unlock(set->lock);
- object_release(previous); /* Release the previous object */
- return return_object;
- }
- /*
- * Return a non-zero value if the object set is empty, or
- * zero if the object set is empty.
- */
- int
- objset_is_empty(Objset *set)
- {
- int return_value;
- PR_ASSERT(NULL != set);
- PR_Lock(set->lock);
- return_value = (set->head == NULL);
- PR_Unlock(set->lock);
- return return_value;
- }
- /*
- * Return the count of objects in the object set.
- */
- int objset_size(Objset *set)
- {
- int count = 0;
- objset_object *p;
- PR_ASSERT(NULL != set);
- PR_Lock(set->lock);
- for (p = set->head; p; p = p->next)
- count++;
- PR_Unlock(set->lock);
- return count;
- }
- /*
- * Utility function: remove object from list.
- * This needs to be called with the objset locked.
- */
- static void
- unlinkObjsetObjectNoLock(Objset *o, objset_object *obj_to_unlink)
- {
- objset_object *p = o->head;
- PR_ASSERT(NULL != o->head);
- /* Unlink from list */
- if (o->head == obj_to_unlink) {
- /* Object to unlink was at head of list */
- p = o->head->next;
- o->head = obj_to_unlink->next;
- } else {
- while (NULL != p->next && p->next != obj_to_unlink) {
- p = p->next;
- }
- if (NULL != p->next)
- {
- /* p points to object prior to one being removed */
- p->next = p->next->next;
- }
- }
- if (o->tail == obj_to_unlink)
- {
- o->tail = p;
- }
-
- /* Free the wrapper */
- slapi_ch_free((void **)&obj_to_unlink);
- }
|