From owner-freebsd-current Sat Jan 31 21:09:14 1998 Return-Path: Received: (from majordom@localhost) by hub.freebsd.org (8.8.8/8.8.8) id VAA14309 for current-outgoing; Sat, 31 Jan 1998 21:09:14 -0800 (PST) (envelope-from owner-freebsd-current@FreeBSD.ORG) Received: from smtp04.primenet.com (smtp04.primenet.com [206.165.6.134]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id VAA14297 for ; Sat, 31 Jan 1998 21:09:08 -0800 (PST) (envelope-from tlambert@usr02.primenet.com) Received: (from daemon@localhost) by smtp04.primenet.com (8.8.8/8.8.8) id WAA19034 for ; Sat, 31 Jan 1998 22:09:07 -0700 (MST) Received: from usr02.primenet.com(206.165.6.202) via SMTP by smtp04.primenet.com, id smtpd019020; Sat Jan 31 22:09:02 1998 Received: (from tlambert@localhost) by usr02.primenet.com (8.8.5/8.8.5) id WAA09147 for current@freebsd.org; Sat, 31 Jan 1998 22:09:03 -0700 (MST) From: Terry Lambert Message-Id: <199802010509.WAA09147@usr02.primenet.com> Subject: General reference counting for structures To: current@FreeBSD.ORG Date: Sun, 1 Feb 1998 05:09:03 +0000 (GMT) X-Mailer: ELM [version 2.4 PL25] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: owner-freebsd-current@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG X-To-Unsubscribe: mail to majordomo@FreeBSD.org "unsubscribe current" As things become more and more dynamic, it's as important to know when *not* to unload something as when to load it. In addition, it's likely to be useful to have a general method you can use to schedule the unload of something that is currently in use. Here are some patches to kernel.h to provide this service: --------------------------------------------------------------------------- Index: sys/kernel.h =================================================================== RCS file: /b/cvstree/ncvs/src/sys/sys/kernel.h,v retrieving revision 1.29 diff -c -r1.29 kernel.h *** 1.29 1997/04/26 11:46:20 --- kernel.h 1998/02/01 04:44:44 *************** *** 119,124 **** --- 119,156 ---- /* + * Generalized reference counting for use by structures + * + * Assumes "REFCOUNT" declared in structure; will declare + * unqualified member stricture "reference". This makes the + * counting independent of the location of the declaration. + * + * XXX Macros are used to allow for fine grain locking (later) + */ + /* structure*/ + typedef struct refcnt { + int r_count; /* number of references*/ + void (*r_doref) __P(( int)); /* call when changed*/ + } REFERENCE; + /* instance*/ + #define REFCOUNT REFERENCE reference; + /* static initializer for users of instances*/ + #define REFINITIALZER(func) { 0, func } + /* internal macros*/ + DOREF(x,y) \ + { \ + (x)->reference.r_count += (y); \ + if( (x)->reference.r_doref) \ + (*(x)->reference.r_doref)( \ + (x)->reference.r_count \ + ); \ + } + /* external macros*/ + ADDREF(x) DOREF(x,1) /* add a reference*/ + UNREF(x) DOREF(x,-1) /* remove a reference*/ + + + /* * Enumerated types for known system startup interfaces. * * Startup occurs in ascending numeric order; the list entries are --------------------------------------------------------------------------- USAGE: When declaring a structure: struct mystruct { ...; ...; REFCOUNT; ...; ...; }; When declaring a static instance of the structure: struct mystruct foo = { ..., ..., REFINITIALZER(NULL), ..., ... }; When referncing an instance of the structure: ADDREF(&foo); When finished referencing an instance of the structure: UNREF(&foo); EXAMPLE: SLIP line discipline: Structure: struct linesw { ... REFCOUNT; }; Declaration: static struct linesw slipdisc = { slopen, slclose, l_noread, l_nowrite, sltioctl, slinput, slstart, ttymodem, REFINITIALZER(slref) }; On use: /* when set*/ ADDREF( slipdisc); /* when cleared*/ UNREF( slipdisc); /* called when reference count has changed*/ void slref( refcount) int refcount; { static int firstref = 1; if( firstref) { /* reference count 0 -> 1*/ firstref = 0; /* mark as "not OK to unload"*/ ... } if( refcount) return; /* reference count 1 -> 0; mark as "OK to unload"*/ firstref = 1; /* in case rereferenced...*/ ... /* if marked "pending unload", queue unload now*/ ... return; } Works for FS, system calls, etc., as well. Terry Lambert terry@lambert.org --- Any opinions in this posting are my own and not those of my present or previous employers. }