1*0250b4d7Sozaki-r.\" $NetBSD: psref.9,v 1.5 2016/04/27 08:18:40 ozaki-r Exp $ 2c03dceb1Sriastradh.\" 3c03dceb1Sriastradh.\" Copyright (c) 2016 The NetBSD Foundation, Inc. 4c03dceb1Sriastradh.\" All rights reserved. 5c03dceb1Sriastradh.\" 6c03dceb1Sriastradh.\" This code is derived from software contributed to The NetBSD Foundation 7c03dceb1Sriastradh.\" by Taylor R. Campbell. 8c03dceb1Sriastradh.\" 9c03dceb1Sriastradh.\" Redistribution and use in source and binary forms, with or without 10c03dceb1Sriastradh.\" modification, are permitted provided that the following conditions 11c03dceb1Sriastradh.\" are met: 12c03dceb1Sriastradh.\" 1. Redistributions of source code must retain the above copyright 13c03dceb1Sriastradh.\" notice, this list of conditions and the following disclaimer. 14c03dceb1Sriastradh.\" 2. Redistributions in binary form must reproduce the above copyright 15c03dceb1Sriastradh.\" notice, this list of conditions and the following disclaimer in the 16c03dceb1Sriastradh.\" documentation and/or other materials provided with the distribution. 17c03dceb1Sriastradh.\" 18c03dceb1Sriastradh.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19c03dceb1Sriastradh.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20c03dceb1Sriastradh.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21c03dceb1Sriastradh.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22c03dceb1Sriastradh.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23c03dceb1Sriastradh.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24c03dceb1Sriastradh.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25c03dceb1Sriastradh.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26c03dceb1Sriastradh.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27c03dceb1Sriastradh.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28c03dceb1Sriastradh.\" POSSIBILITY OF SUCH DAMAGE. 29c03dceb1Sriastradh.\" 3028a15dd4Sozaki-r.Dd April 27, 2016 31c03dceb1Sriastradh.Dt PSREF 9 32c03dceb1Sriastradh.Os 33c03dceb1Sriastradh.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 34c03dceb1Sriastradh.Sh NAME 35c03dceb1Sriastradh.Nm psref 36c03dceb1Sriastradh.Nd passive references 37c03dceb1Sriastradh.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 38c03dceb1Sriastradh.Sh SYNOPSIS 39c03dceb1Sriastradh.In sys/psref.h 40c03dceb1Sriastradh.\" 41c03dceb1Sriastradh.Ft struct psref_class * 42c03dceb1Sriastradh.Fn psref_class_create "const char *name" "int ipl" 43c03dceb1Sriastradh.Ft void 44c03dceb1Sriastradh.Fn psref_class_destroy "struct psref_class *class" 45c03dceb1Sriastradh.\" 46c03dceb1Sriastradh.Ft void 47c03dceb1Sriastradh.Fn psref_target_init "struct psref_target *target" "struct psref_class *class" 48c03dceb1Sriastradh.Ft void 49c03dceb1Sriastradh.Fn psref_target_destroy "struct psref_target *target" "struct psref_class *class" 50c03dceb1Sriastradh.\" 51c03dceb1Sriastradh.Ft void 52c03dceb1Sriastradh.Fn psref_acquire "struct psref *ref" "const struct psref_target *target" "struct psref_class *class" 53c03dceb1Sriastradh.Ft void 54c03dceb1Sriastradh.Fn psref_release "struct psref *ref" "const struct psref_target *target" "struct psref_class *class" 55c03dceb1Sriastradh.Ft void 56c03dceb1Sriastradh.Fn psref_copy "struct psref *pto" "const struct psref *pfrom" "struct psref_class *class" 57c03dceb1Sriastradh.\" 58c03dceb1Sriastradh.Pp 59c03dceb1Sriastradh.Fd "#ifdef DIAGNOSTIC" 60c03dceb1Sriastradh.Ft bool 61c03dceb1Sriastradh.Fn psref_held "const struct psref_target *target" "struct psref_class *class" 62c03dceb1Sriastradh.Fd "#endif" 63c03dceb1Sriastradh.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 64c03dceb1Sriastradh.Sh DESCRIPTION 65c03dceb1SriastradhThe 66c03dceb1Sriastradh.Nm 6710a4418eSriastradhabstraction allows CPUs to cheaply acquire and release 6810a4418eSriastradh.Em passive references 6910a4418eSriastradhto a resource, which guarantee the resource will not be destroyed 7010a4418eSriastradhuntil the reference is released. 7110a4418eSriastradhAcquiring and releasing passive references requires no interprocessor 7210a4418eSriastradhsynchronization, except when the resource is pending destruction. 73c03dceb1Sriastradh.\" 74c03dceb1Sriastradh.Pp 75c03dceb1SriastradhPassive references are an intermediate between 76c03dceb1Sriastradh.Xr pserialize 9 77c03dceb1Sriastradhand reference counting: 78c03dceb1Sriastradh.Bl -hyphen 79c03dceb1Sriastradh.It 80c03dceb1Sriastradh.Xr pserialize 9 81c03dceb1Sriastradhread sections require no interprocessor synchronization, but must be 82c03dceb1Sriastradhof short duration, and may not sleep. 83c03dceb1SriastradhA 84c03dceb1Sriastradh.Xr pserialize 9 85c03dceb1Sriastradhread section blocks soft interrupts on the local CPU until it is 86c03dceb1Sriastradhcomplete. 87c03dceb1Sriastradh.It 88c03dceb1SriastradhReference counting requires interprocessor synchronization via 893133e4c3Swiz.Xr atomic_ops 3 90c03dceb1Sriastradhor 91c03dceb1Sriastradh.Xr mutex 9 . 92c03dceb1SriastradhHowever, with reference counting, a reference may be held for arbitrary 93c03dceb1Sriastradhdurations, may be transferred between owners across CPUs and threads, 94c03dceb1Sriastradhand may be held by a caller that sleeps. 95c03dceb1Sriastradh.El 96c03dceb1Sriastradh.\" 97c03dceb1Sriastradh.Pp 98c03dceb1SriastradhPassive references share some properties of both: passive references 9910a4418eSriastradhavoid interprocessor synchronization, and do not block soft interrupts, 10010a4418eSriastradhbut can be held by a caller that sleeps. 101c03dceb1SriastradhHowever, a caller holding a passive reference may not transfer it from 102c03dceb1Sriastradhone LWP to another, and the caller's LWP must be bound to a single CPU 103c03dceb1Sriastradhwhile it holds any passive references. 104c03dceb1Sriastradh.Pp 105c03dceb1SriastradhThus, passive references are useful for incrementally parallelizing 106c03dceb1Sriastradhresources whose operations may sleep, such as in the network stack, 107c03dceb1Sriastradhbefore comprehensively removing sleeps from the code paths involved. 108c03dceb1Sriastradh.\" 109c03dceb1Sriastradh.Pp 110c03dceb1SriastradhResources to which callers may hold passive references are called 111c03dceb1Sriastradh.Em targets , 112c03dceb1Sriastradhand must contain an embedded 113c03dceb1Sriastradh.Vt struct psref_target 114c03dceb1Sriastradhobject, initialized with 115c03dceb1Sriastradh.Fn psref_target_init . 116c03dceb1Sriastradh.Pp 117c03dceb1SriastradhWhen a caller wants to guarantee that a resource will not be destroyed 118c03dceb1Sriastradhuntil it is done, it must allocate storage for a 119c03dceb1Sriastradh.Vt struct psref 120c03dceb1Sriastradhobject, find the 121c03dceb1Sriastradh.Vt struct psref_target 122c03dceb1Sriastradhfor the resource it seeks, and use 123c03dceb1Sriastradh.Fn psref_acquire 124c03dceb1Sriastradhto acquire a passive reference. 125c03dceb1SriastradhWhen a caller is done with the resource, it must release the resource 126c03dceb1Sriastradhwith 127c03dceb1Sriastradh.Fn psref_release . 128c03dceb1Sriastradh.Pp 129c03dceb1SriastradhWhen a resource is about to go away, its passive reference target must 130c03dceb1Sriastradhbe passed to 131c03dceb1Sriastradh.Fn psref_target_destroy 132c03dceb1Sriastradhto wait until all extant passive references are released; then the 133c03dceb1Sriastradhresource itself may be freed. 134c03dceb1Sriastradh.\" 135c03dceb1Sriastradh.Pp 136c03dceb1Sriastradh.Vt struct psref_target 137c03dceb1Sriastradhand 138c03dceb1Sriastradh.Vt struct psref 139c03dceb1Sriastradhobjects must be allocated by the caller, but they should be treated as 140c03dceb1Sriastradhopaque and should not be inspected or copied. 141c03dceb1Sriastradh.\" 142c03dceb1Sriastradh.Pp 143c03dceb1SriastradhPassive reference targets are grouped into 144c03dceb1Sriastradh.Em classes , 145c03dceb1Sriastradhrepresented by an opaque 146c03dceb1Sriastradh.Vt struct psref_class 147c03dceb1Sriastradhobject, e.g. the class of all network routes, or the class of all file 148c03dceb1Sriastradhsystems mount points, which may be needed at different interrupt 149c03dceb1Sriastradhpriority levels. 150c03dceb1Sriastradh.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 151c03dceb1Sriastradh.Sh FUNCTIONS 152c03dceb1Sriastradh.Bl -tag -width abcd 153c03dceb1Sriastradh.It Fn psref_class_create name ipl 154c03dceb1SriastradhCreate a passive reference class with the given name and interrupt 155c03dceb1Sriastradhpriority level, and return an opaque pointer describing it. 156c03dceb1SriastradhThe name must be at most eight characters long, and will be shown in 157c03dceb1Sriastradhutilities such as 158c03dceb1Sriastradh.Xr ps 1 159c03dceb1Sriastradhfor threads that are waiting to destroy passive reference targets. 160c03dceb1SriastradhOn failure, return 161c03dceb1Sriastradh.Dv NULL 162c03dceb1Sriastradhinstead. 163c03dceb1Sriastradh.\"""""""""""""""" 164c03dceb1Sriastradh.It Fn psref_class_destroy class 165c03dceb1SriastradhDestroy a passive reference class created with 166c03dceb1Sriastradh.Fn psref_class_create . 167c03dceb1SriastradhThere must be no more passive references in this class. 168c03dceb1Sriastradh.\"""""""""""""""" 169c03dceb1Sriastradh.It Fn psref_target_init target class 170c03dceb1SriastradhInitialize a passive reference target in a 171c03dceb1Sriastradh.Vt struct psref_target 172c03dceb1Sriastradhobject allocated by the caller in the given class. 173c03dceb1Sriastradh.Pp 174c03dceb1SriastradhThe caller must issue a 175c03dceb1Sriastradh.Xr membar_producer 3 176c03dceb1Sriastradhafter calling 177c03dceb1Sriastradh.Fn psref_target_init 178c03dceb1Sriastradhand before publishing a pointer to the target so that other CPUs can 179c03dceb1Sriastradhsee it, e.g. by inserting it into a 180c03dceb1Sriastradh.Xr pslist 9 . 181c03dceb1Sriastradh.\"""""""""""""""" 182c03dceb1Sriastradh.It Fn psref_target_destroy target class 183c03dceb1SriastradhWait for all extant passive references to 184c03dceb1Sriastradh.Fa target 185c03dceb1Sriastradhon all CPUs to be released, and then destroy it. 186c03dceb1SriastradhThe passive reference target 187c03dceb1Sriastradh.Fa target 188c03dceb1Sriastradhmust have been initialized with 189c03dceb1Sriastradh.Fn psref_target_init 190c03dceb1Sriastradhin the same 191c03dceb1Sriastradh.Fa class . 192c03dceb1SriastradhMay sleep. 193c03dceb1Sriastradh.Pp 194c03dceb1SriastradhThe caller must guarantee that no new references to 195c03dceb1Sriastradh.Fa target 196c03dceb1Sriastradhwill be acquired once it calls 197c03dceb1Sriastradh.Fn psref_target_destroy , 198c03dceb1Sriastradhe.g. by removing the target from a 199c03dceb1Sriastradh.Xr pslist 9 200c03dceb1Sriastradhand calling 201c03dceb1Sriastradh.Xr pserialize_perform 9 202c03dceb1Sriastradhto wait for 203c03dceb1Sriastradh.Xr pserialize 9 204c03dceb1Sriastradhreaders to complete. 205c03dceb1Sriastradh.Pp 206c03dceb1SriastradhNo further use of the target is allowed unless it is reinitialized with 207c03dceb1Sriastradh.Fn psref_target_init . 208c03dceb1SriastradhMultiple concurrent calls to 209c03dceb1Sriastradh.Fn psref_target_destroy 210c03dceb1Sriastradhare not allowed. 211c03dceb1Sriastradh.\"""""""""""""""" 212c03dceb1Sriastradh.It Fn psref_acquire ref target class 213c03dceb1SriastradhAcquire a passive reference to 214c03dceb1Sriastradh.Fa target , 215c03dceb1Sriastradhstoring per-CPU bookkeeping in 216c03dceb1Sriastradh.Fa ref . 217c03dceb1SriastradhThe class of 218c03dceb1Sriastradh.Fa target 219c03dceb1Sriastradhmust be 220c03dceb1Sriastradh.Fa class . 221c03dceb1Sriastradh.Pp 222c03dceb1SriastradhThe caller must ensure by some other mechanism than passive references 223c03dceb1Sriastradhthat the target will not be destroyed before the call to 224c03dceb1Sriastradh.Fn psref_acquire ; 225c03dceb1Sriastradhtypically this will be via a 226c03dceb1Sriastradh.Xr pserialize 9 227c03dceb1Sriastradhread section. 228c03dceb1Sriastradh.Pp 229c03dceb1SriastradhThe caller's LWP must be bound to a CPU. 230c03dceb1Sriastradh.\"""""""""""""""" 231c03dceb1Sriastradh.It Fn psref_release ref target class 232c03dceb1SriastradhRelease the passive reference 233c03dceb1Sriastradh.Fa ref , 234c03dceb1Sriastradhwhich must have been acquired to point at 235c03dceb1Sriastradh.Fa target 236c03dceb1Sriastradhin the class 237c03dceb1Sriastradh.Fa class , 238c03dceb1Sriastradhwaking a thread calling 239c03dceb1Sriastradh.Fn psref_target_destroy 240c03dceb1Sriastradhif any. 241c03dceb1Sriastradh.Pp 242c03dceb1SriastradhFurther use of the resource represented by 243c03dceb1Sriastradh.Fa target 244c03dceb1Sriastradhis not allowed, unless it is re-acquired in the same way that it was 245c03dceb1Sriastradhoriginally acquired. 246c03dceb1Sriastradh.\"""""""""""""""" 247c03dceb1Sriastradh.It Fn psref_copy pto pfrom class 248c03dceb1SriastradhCopy the passive reference 249c03dceb1Sriastradh.Fa pfrom 250c03dceb1Sriastradhto 251c03dceb1Sriastradh.Fa pto , 252c03dceb1Sriastradhwhich must be to a target in 253c03dceb1Sriastradh.Fa class . 254c03dceb1SriastradhThe resource represented by the target of the passive references will 255c03dceb1Sriastradhnot be destroyed before both references are released. 256c03dceb1Sriastradh.\"""""""""""""""" 257c03dceb1Sriastradh.It Fn psref_held target class 258c03dceb1SriastradhReturn true if the current CPU holds a passive reference to 259c03dceb1Sriastradh.Fa target 260c03dceb1Sriastradhin the passive reference class 261c03dceb1Sriastradh.Fa class , 262c03dceb1Sriastradhor false if not. 263c03dceb1Sriastradh.Pp 26410a4418eSriastradhThis does not answer about other CPUs \(em it does not tell you whether 265c03dceb1Sriastradh.Em any 266c03dceb1SriastradhCPU holds a passive reference to 267c03dceb1Sriastradh.Fa target . 268c03dceb1Sriastradh.Pp 269c03dceb1SriastradhThis may be used only in assertions, e.g. with 270c03dceb1Sriastradh.Xr KASSERT 9 , 271c03dceb1Sriastradhnot for making run-time decisions. 272c03dceb1SriastradhThis should be used only for positive assertions, as in 273c03dceb1Sriastradh.Li KASSERT(psref_held( Ns Fa target Ns Li , Fa class Ns Li )) , 274c03dceb1Sriastradhnot for negative assertions, as in 275c03dceb1Sriastradh.Li KASSERT(!psref_held( Ns Fa target Ns Li , Fa class Ns Li )) , 276c03dceb1Sriastradhunless you are sure you can prove that no caller holds a reference 277c03dceb1Sriastradheither. 278c03dceb1Sriastradh.El 279c03dceb1Sriastradh.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 280c03dceb1Sriastradh.Sh EXAMPLES 281c03dceb1Sriastradh.Bd -literal 282c03dceb1Sriastradhstruct frotz { 283c03dceb1Sriastradh int f_key; 284c03dceb1Sriastradh ... 285c03dceb1Sriastradh struct pslist_entry f_entry; 286c03dceb1Sriastradh struct psref_target f_target; 287c03dceb1Sriastradh}; 288c03dceb1Sriastradh 289c03dceb1Sriastradhstatic struct { 290c03dceb1Sriastradh kmutex_t lock; 291c03dceb1Sriastradh struct pslist_head list; 292c03dceb1Sriastradh} frobbotzim __cacheline_aligned; 293c03dceb1Sriastradh 294c03dceb1Sriastradhstatic pserialize_t frobbotzim_psz __read_mostly; 295c03dceb1Sriastradhstatic struct psref_class *frobbotzim_prc __read_mostly; 296c03dceb1Sriastradh 297c03dceb1Sriastradhvoid 298c03dceb1Sriastradhpublish_as_frotz(uint64_t key, ...) 299c03dceb1Sriastradh{ 300c03dceb1Sriastradh struct frotz *f; 301c03dceb1Sriastradh 302c03dceb1Sriastradh f = kmem_alloc(sizeof(*f), KM_SLEEP); 303c03dceb1Sriastradh f->f_key = key; 304c03dceb1Sriastradh f->f_... = ...; 305*0250b4d7Sozaki-r PSLIST_ENTRY_INIT(f, f_entry); 306c03dceb1Sriastradh psref_target_init(&f->f_target, frobbotzim_prc); 307c03dceb1Sriastradh 308c03dceb1Sriastradh mutex_enter(&frobbotzim.lock); 309c03dceb1Sriastradh PSLIST_WRITER_INSERT_HEAD(&frobbotzim.list, f, f_entry); 310c03dceb1Sriastradh mutex_exit(&frobbotzim.lock); 311c03dceb1Sriastradh} 312c03dceb1Sriastradh 313c03dceb1Sriastradhint 314c03dceb1Sriastradhuse_frotz(int key, int op) 315c03dceb1Sriastradh{ 316c03dceb1Sriastradh struct frotz *f; 317c03dceb1Sriastradh struct psref ref; 318c03dceb1Sriastradh 319c03dceb1Sriastradh /* Acquire a passive reference. */ 320c03dceb1Sriastradh if ((f = lookup_frotz(key, &ref)) == NULL) 321c03dceb1Sriastradh return ENOENT; 322c03dceb1Sriastradh 323c03dceb1Sriastradh /* Do something that may sleep. */ 324c03dceb1Sriastradh do_stuff_with_frotz(f, op); 325c03dceb1Sriastradh 326c03dceb1Sriastradh /* Release passive reference, possibly waking destroy_frotz. */ 32728a15dd4Sozaki-r psref_release(&ref, &f->f_psref, frobbotzim_prc); 328c03dceb1Sriastradh 329c03dceb1Sriastradh return 0; 330c03dceb1Sriastradh} 331c03dceb1Sriastradh 332c03dceb1Sriastradhstruct frotz * 333c03dceb1Sriastradhlookup_frotz(int key, struct psref *ref) 334c03dceb1Sriastradh{ 335c03dceb1Sriastradh struct frotz *f; 336c03dceb1Sriastradh int s; 337c03dceb1Sriastradh 338c03dceb1Sriastradh /* Look up a frotz in a pserialized list. */ 339c03dceb1Sriastradh s = pserialize_read_enter(); 340c03dceb1Sriastradh PSLIST_READER_FOREACH(f, &frobbotzim.list, struct frotz, f_next) { 341c03dceb1Sriastradh /* f is stable until pserialize_read_exit. */ 342c03dceb1Sriastradh if (f->f_key == key) { 343c03dceb1Sriastradh /* Acquire a passive reference. */ 34428a15dd4Sozaki-r psref_acquire(ref, &f->f_target, frobbotzim_prc); 345c03dceb1Sriastradh /* f is now stable until psref_release. */ 346c03dceb1Sriastradh break; 347c03dceb1Sriastradh } 348c03dceb1Sriastradh } 349c03dceb1Sriastradh pserialize_read_exit(s); 350c03dceb1Sriastradh 351c03dceb1Sriastradh return f; 352c03dceb1Sriastradh} 353c03dceb1Sriastradh 354c03dceb1Sriastradhvoid 355c03dceb1Sriastradhdestroy_frotz(int key) 356c03dceb1Sriastradh{ 357c03dceb1Sriastradh struct frotz *f; 358c03dceb1Sriastradh 359c03dceb1Sriastradh /* Look up and delete a frotz. */ 360c03dceb1Sriastradh mutex_enter(&frobbotzim.lock); 361c03dceb1Sriastradh PSLIST_WRITER_FOREACH(f, &frobbotzim.list, struct frotz, f_entry) { 362c03dceb1Sriastradh if (f->f_key == key) { 363c03dceb1Sriastradh /* 364c03dceb1Sriastradh * Unlink the frotz from the list to stop new 365c03dceb1Sriastradh * pserialize read sections from seeing it. 366c03dceb1Sriastradh */ 367c03dceb1Sriastradh PSLIST_WRITER_REMOVE(f, f_entry); 368c03dceb1Sriastradh 369c03dceb1Sriastradh /* 370c03dceb1Sriastradh * Wait until extant pserialize read sections 371c03dceb1Sriastradh * have completed. 372c03dceb1Sriastradh */ 373c03dceb1Sriastradh pserialize_perform(frobbotzim_psz); 374c03dceb1Sriastradh break; 375c03dceb1Sriastradh } 376c03dceb1Sriastradh } 377c03dceb1Sriastradh mutex_exit(&frobbotzim.lock); 378c03dceb1Sriastradh 379c03dceb1Sriastradh if (f != NULL) { 380c03dceb1Sriastradh /* Wait for all readers to drain before freeing. */ 38128a15dd4Sozaki-r psref_target_destroy(&f->f_target, frobbotzim_prc); 382*0250b4d7Sozaki-r PSLIST_ENTRY_DESTROY(f, f_entry); 383c03dceb1Sriastradh kmem_free(f, sizeof(*f)); 384c03dceb1Sriastradh } 385c03dceb1Sriastradh} 386c03dceb1Sriastradh.Ed 387c03dceb1Sriastradh.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 388c03dceb1Sriastradh.Sh CODE REFERENCES 389c03dceb1SriastradhThe 390c03dceb1Sriastradh.Nm 391c03dceb1Sriastradhabstraction is implemented in 392c03dceb1Sriastradh.Pa sys/kern/subr_psref.c . 393c03dceb1Sriastradh.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 394c03dceb1Sriastradh.Sh SEE ALSO 395c03dceb1Sriastradh.Xr pserialize 9 , 396c03dceb1Sriastradh.Xr pslist 9 397c03dceb1Sriastradh.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 398c03dceb1Sriastradh.Sh HISTORY 399c03dceb1SriastradhThe 400c03dceb1Sriastradh.Nm 401c03dceb1Sriastradhdata structure first appeared in 402c03dceb1Sriastradh.Nx 8.0 . 403c03dceb1Sriastradh.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 404c03dceb1Sriastradh.Sh AUTHORS 405c03dceb1Sriastradh.An Taylor R Campbell Aq Mt riastradh@NetBSD.org 406