summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/object.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/slapd/object.c')
-rw-r--r--ldap/servers/slapd/object.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/ldap/servers/slapd/object.c b/ldap/servers/slapd/object.c
new file mode 100644
index 00000000..7fb90164
--- /dev/null
+++ b/ldap/servers/slapd/object.c
@@ -0,0 +1,95 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* Implementation note:
+ PR_AtomicIncrement and PR_AtomicDecrement both return a value whose
+ sign is the same sign (or zero) as the variable *after* it was updated.
+ They do not return the previous value.
+*/
+
+#include "slapi-plugin.h"
+#include "slapi-private.h"
+
+typedef struct object
+{
+ PRInt32 refcnt; /* reference count for the object */
+ FNFree destructor; /* Destructor for the object */
+ void *data; /* pointer to actual node data */
+} object;
+
+
+/*
+ * Create a new object.
+ * The object is created with refcnt set to 1. The caller implicitly gets
+ * a reference to the object, to prevent a race condition where the object
+ * is destroyed immediately after contruction.
+ * The provided destructor function will be called when all references to
+ * the object have been released.
+ *
+ * Returns a pointer to the new object.
+ */
+Object *
+object_new(void *user_data, FNFree destructor)
+{
+ Object *o;
+ o = (object *)slapi_ch_malloc(sizeof(object));
+ o->refcnt = 1;
+ o->destructor = destructor;
+ o->data = user_data;
+ return o;
+}
+
+
+/*
+ * Acquire a reference object. The caller must hold a reference
+ * to the object, or know for certain that a reference is held
+ * and will continue to be held while this call is in progress.
+ */
+void
+object_acquire(Object *o)
+{
+ PR_ASSERT(NULL != o);
+ PR_AtomicIncrement(&o->refcnt);
+}
+
+
+/*
+ * Release a reference to an object. The pointer to the object
+ * should not be referenced after this call is made, since the
+ * object may be destroyed if this is the last reference to it.
+ */
+void
+object_release(Object *o)
+{
+ PRInt32 refcnt_after_release;
+
+ PR_ASSERT(NULL != o);
+ refcnt_after_release = PR_AtomicDecrement(&o->refcnt);
+ PR_ASSERT(refcnt_after_release >= 0);
+ if (refcnt_after_release == 0)
+ {
+ /* Object can be destroyed */
+ if (o->destructor)
+ o->destructor(&o->data);
+ /* Make it harder to reuse a dangling pointer */
+ o->data = NULL;
+ o->destructor = NULL;
+ o->refcnt = -9999;
+ slapi_ch_free((void **)&o);
+ }
+}
+
+/*
+ * Get the data pointer from an object.
+ * Results are undefined if the caller does not hold a reference
+ * to the object.
+ */
+void *
+object_get_data(Object *o)
+{
+ PR_ASSERT(NULL != o);
+ return o->data;
+}