mirror of
				https://github.com/xcat2/xNBA.git
				synced 2025-10-31 19:32:34 +00:00 
			
		
		
		
	Add (and use) generic reference counter, to improve signal:noise ratio
in code defining reference-counted objects.
This commit is contained in:
		| @@ -16,7 +16,6 @@ | ||||
|  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
|  */ | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <gpxe/interface.h> | ||||
|  | ||||
| /** @file | ||||
| @@ -25,30 +24,6 @@ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * 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; | ||||
| } | ||||
|   | ||||
| @@ -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, | ||||
| }; | ||||
|   | ||||
							
								
								
									
										73
									
								
								src/core/refcnt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/core/refcnt.c
									
									
									
									
									
										Normal file
									
								
							| @@ -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 ); | ||||
| 	} | ||||
| } | ||||
| @@ -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, | ||||
| }; | ||||
|   | ||||
| @@ -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 | ||||
| 	/** Reference counter | ||||
| 	 * | ||||
| 	 * @v intf		Interface | ||||
| 	 * @v delta		Change to apply to reference count | ||||
| 	 * | ||||
| 	 * 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 */ | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
							
								
								
									
										39
									
								
								src/include/gpxe/refcnt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/include/gpxe/refcnt.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 */ | ||||
| @@ -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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user