Add (and use) generic reference counter, to improve signal:noise ratio
authorMichael Brown <mcb30@etherboot.org>
Sun, 29 Apr 2007 23:53:39 +0000 (23:53 +0000)
committerMichael Brown <mcb30@etherboot.org>
Sun, 29 Apr 2007 23:53:39 +0000 (23:53 +0000)
in code defining reference-counted objects.

src/core/interface.c
src/core/job.c
src/core/refcnt.c [new file with mode: 0644]
src/core/xfer.c
src/include/gpxe/interface.h
src/include/gpxe/job.h
src/include/gpxe/refcnt.h [new file with mode: 0644]
src/include/gpxe/xfer.h

index 15df49d..8498425 100644 (file)
@@ -16,7 +16,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <assert.h>
 #include <gpxe/interface.h>
 
 /** @file
  *
  */
 
-/**
- * Obtain reference to interface
- *
- * @v intf             Interface
- * @ret intf           Interface
- *
- * Increases the reference count on the interface.
- */
-static struct interface * intf_get ( struct interface *intf ) {
-       intf->refcnt ( intf, +1 );
-       return intf;
-}
-
-/**
- * Drop reference to interface
- *
- * @v intf             Interface
- *
- * Decreases the reference count on the interface.
- */
-static void intf_put ( struct interface *intf ) {
-       intf->refcnt ( intf, -1 );
-}
-
 /**
  * Plug an interface into a new destination interface
  *
@@ -63,19 +38,7 @@ static void intf_put ( struct interface *intf ) {
  * interface into a null interface.
  */
 void plug ( struct interface *intf, struct interface *dest ) {
-       intf_put ( intf->dest );
-       intf->dest = intf_get ( dest );
-}
-
-/**
- * Null update reference count
- *
- * @v intf             Interface
- * @v delta            Change to apply to reference count
- *
- * Use this as the refcnt() method for an interface that does not need
- * to support reference counting.
- */
-void null_refcnt ( struct interface *intf __unused, int delta __unused ) {
-       /* Do nothing */
+       ref_put ( intf->refcnt );
+       ref_get ( dest->refcnt );
+       intf->dest = dest;
 }
index fc60f4e..d6ec27b 100644 (file)
@@ -71,7 +71,7 @@ struct job_interface_operations null_job_ops = {
 struct job_interface null_job = {
        .intf = {
                .dest = &null_job.intf,
-               .refcnt = null_refcnt,
+               .refcnt = NULL,
        },
        .op = &null_job_ops,
 };
diff --git a/src/core/refcnt.c b/src/core/refcnt.c
new file mode 100644 (file)
index 0000000..4efd9d7
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <gpxe/refcnt.h>
+
+/** @file
+ *
+ * Reference counting
+ *
+ */
+
+/**
+ * Increment reference count
+ *
+ * @v refcnt           Reference counter, or NULL
+ *
+ * If @c refcnt is NULL, no action is taken.
+ */
+void ref_get ( struct refcnt *refcnt ) {
+
+       if ( ! refcnt )
+               return;
+
+       refcnt->refcnt++;
+
+       DBGC ( refcnt, "REFCNT %p incremented to %d\n",
+              refcnt, refcnt->refcnt );
+}
+
+/**
+ * Decrement reference count
+ *
+ * @v refcnt           Reference counter, or NULL
+ *
+ * If the reference count decreases below zero, the object's free()
+ * method will be called.
+ *
+ * If @c refcnt is NULL, no action is taken.
+ */
+void ref_put ( struct refcnt *refcnt ) {
+
+       if ( ! refcnt )
+               return;
+
+       refcnt->refcnt--;
+       DBGC ( refcnt, "REFCNT %p decremented to %d\n",
+              refcnt, refcnt->refcnt );
+
+       if ( refcnt->refcnt >= 0 )
+               return;
+
+       if ( refcnt->free ) {
+               refcnt->free ( refcnt );
+       } else {
+               free ( refcnt );
+       }
+}
index d348081..f927269 100644 (file)
@@ -230,7 +230,7 @@ struct xfer_interface_operations null_xfer_ops = {
 struct xfer_interface null_xfer = {
        .intf = {
                .dest = &null_xfer.intf,
-               .refcnt = null_refcnt,
+               .refcnt = NULL,
        },
        .op = &null_xfer_ops,
 };
index 38e6272..6ec9b14 100644 (file)
@@ -7,6 +7,8 @@
  *
  */
 
+#include <gpxe/refcnt.h>
+
 /** An object communication interface */
 struct interface {
        /** Destination interface
@@ -18,19 +20,14 @@ struct interface {
         * unplugged, it should point to a null interface.
         */
        struct interface *dest;
-       /** Update reference count
-        *
-        * @v intf              Interface
-        * @v delta             Change to apply to reference count
+       /** Reference counter
         *
-        * This method updates the reference count for the object
-        * containing the interface.
+        * If this interface is not part of a reference-counted
+        * object, this field may be NULL.
         */
-       void ( * refcnt ) ( struct interface *intf, int delta );
+       struct refcnt *refcnt;
 };
 
 extern void plug ( struct interface *intf, struct interface *dest );
 
-extern void null_refcnt ( struct interface *intf, int delta );
-
 #endif /* _GPXE_INTERFACE_H */
index 3adc6e1..ded6c84 100644 (file)
@@ -76,12 +76,11 @@ extern void ignore_progress ( struct job_interface *job,
  *
  * @v job              Job control interface
  * @v op               Job control interface operations
- * @v refcnt           Job control interface reference counting method
+ * @v refcnt           Containing object reference counter, or NULL
  */
 static inline void job_init ( struct job_interface *job,
-                              struct job_interface_operations *op,
-                              void ( * refcnt ) ( struct interface *intf,
-                                                  int delta ) ) {
+                             struct job_interface_operations *op,
+                             struct refcnt *refcnt ) {
        job->intf.dest = &null_job.intf;
        job->intf.refcnt = refcnt;
        job->op = op;
diff --git a/src/include/gpxe/refcnt.h b/src/include/gpxe/refcnt.h
new file mode 100644 (file)
index 0000000..ed147b9
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _GPXE_REFCNT_H
+#define _GPXE_REFCNT_H
+
+/** @file
+ *
+ * Reference counting
+ *
+ */
+
+/**
+ * A reference counter
+ *
+ * This data structure is designed to be embedded within a
+ * reference-counted object.
+ */
+struct refcnt {
+       /** Current reference count
+        *
+        * When this count is decremented below zero, the free()
+        * method will be called.
+        */
+       int refcnt;
+       /** Free containing object
+        *
+        * This method is called when the reference count is
+        * decremented below zero.
+        *
+        * If this method is left NULL, the standard library free()
+        * function will be called.  The upshot of this is that you
+        * may omit the free() method if the @c refcnt object is the
+        * first element of your reference-counted struct.
+        */
+       void ( * free ) ( struct refcnt *refcnt );
+};
+
+extern void ref_get ( struct refcnt *refcnt );
+extern void ref_put ( struct refcnt *refcnt );
+
+#endif /* _GPXE_REFCNT_H */
index dfbde89..2423c03 100644 (file)
@@ -114,12 +114,11 @@ extern int ignore_deliver_raw ( struct xfer_interface *xfer,
  *
  * @v xfer             Data transfer interface
  * @v op               Data transfer interface operations
- * @v refcnt           Data transfer interface reference counting method
+ * @v refcnt           Containing object reference counter, or NULL
  */
 static inline void xfer_init ( struct xfer_interface *xfer,
                               struct xfer_interface_operations *op,
-                              void ( * refcnt ) ( struct interface *intf,
-                                                  int delta ) ) {
+                              struct refcnt *refcnt ) {
        xfer->intf.dest = &null_xfer.intf;
        xfer->intf.refcnt = refcnt;
        xfer->op = op;