Index: share/man/man9/Makefile =================================================================== RCS file: /cvs/src/share/man/man9/Makefile,v retrieving revision 1.234 diff -u -p -r1.234 Makefile --- share/man/man9/Makefile 17 Jun 2015 06:24:46 -0000 1.234 +++ share/man/man9/Makefile 2 Jul 2015 00:56:26 -0000 @@ -29,7 +29,7 @@ MAN= aml_evalnode.9 atomic_add_int.9 ato radio.9 arc4random.9 rasops.9 ratecheck.9 resettodr.9 rssadapt.9 \ route.9 rt_ifa_add.9 rt_timer_add.9 rtalloc.9 rtable_add.9 \ rtlabel_id2name.9 rtrequest1.9 rwlock.9 SipHash24.9 sensor_attach.9 \ - tsleep.9 spl.9 startuphook_establish.9 \ + tsleep.9 spl.9 srp_enter.9 startuphook_establish.9 \ socreate.9 sosplice.9 style.9 syscall.9 systrace.9 sysctl_int.9 \ task_add.9 tc_init.9 time.9 timeout.9 tvtohz.9 uiomove.9 uvm.9 \ usbd_close_pipe.9 usbd_open_pipe.9 usbd_transfer.9 \ @@ -362,6 +362,11 @@ MLINKS+=spl.9 spl0.9 spl.9 splassert.9 s spl.9 splsoftnet.9 spl.9 splsofttty.9 \ spl.9 splstatclock.9 spl.9 spltty.9 spl.9 splvm.9 spl.9 splx.9 MLINKS+=startuphook_establish.9 startuphook_disestablish.9 +MLINKS+=srp_enter.9 srp_init.9 srp_enter.9 srp_gc_init.9 \ + srp_enter.9 srp_update.9 srp_enter.9 srp_update_locked.9 \ + srp_enter.9 srp_leave.9 srp_enter.9 srp_get_locked.9 \ + srp_enter.9 srp_finalize.9 \ + srp_enter.9 SRP_INITIALIZER.9 srp_enter.9 SRP_GC_INITIALIZER.9 MLINKS+=sysctl_int.9 sysctl_int_arr.9 sysctl_int.9 sysctl_quad.9 \ sysctl_int.9 sysctl_string.9 sysctl_int.9 sysctl_tstring.9 \ sysctl_int.9 sysctl_rdint.9 sysctl_int.9 sysctl_rdquad.9 \ Index: share/man/man9/srp_enter.9 =================================================================== RCS file: share/man/man9/srp_enter.9 diff -N share/man/man9/srp_enter.9 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ share/man/man9/srp_enter.9 2 Jul 2015 00:56:26 -0000 @@ -0,0 +1,168 @@ +.\" $OpenBSD$ +.\" +.\" Copyright (c) 2015 David Gwynne +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate$ +.Dt SRP_ENTER 9 +.Os +.Sh NAME +.Nm srp_init , +.Nm srp_gc_init , +.Nm srp_update , +.Nm srp_update_locked , +.Nm srp_enter , +.Nm srp_leave , +.Nm srp_get_locked , +.Nm srp_finalize , +.Nm SRP_INITIALIZER , +.Nm SRP_GC_INITIALIZER +.Nd shared reference pointers +.Sh SYNOPSIS +.In sys/srp.h +.Ft void +.Fn "srp_init" "struct srp *p" +.Ft void +.Fo "srp_gc_init" +.Fa "struct srp_gc *gc" +.Fa "void (*dtor)(void *, void *)" +.Fa "void *ctx" +.Fc +.Ft void +.Fn "srp_update" "struct srp_gc *gc" "struct srp *p" "void *v" +.Ft void +.Fn "srp_update_locked" "struct srp_gc *gc" "struct srp *p" "void *v" +.Ft void * +.Fn "srp_enter" "struct srp *p" +.Ft void +.Fn "srp_leave" "struct srp *p" "void *v" +.Ft void * +.Fn "srp_get_locked" "struct srp *p" +.Ft void +.Fn "srp_finalize" "struct srp_gc *gc" +.Fn "SRP_INITIALIZER" +.Fo "SRP_GC_INITIALIZER" +.Fa "void (*dtor)(void *, void *)" +.Fa "void *ctx" +.Fc +.Sh DESCRIPTION +The +srp +API provides concurrent lock free access to data structures and guarantees the +data isn't destroyed while it is in use. +.Pp +.Fn srp_init +initialises the srp structure +.Fa p +to an empty state. +.Pp +.Fn srp_gc_init +initialises the srp_gc structure +.Fa gc +so it can be used as a garbage collector for data that gets referenced by srp +structures. +An update to an srp structure will cause the old data to be destroyed when it +is no longer referenced by any CPU in the system. +The old data will be destroyed by the garbage collector by a call to +.Fa dtor +with +.Fa ctx +as the first argument and the pointer to the data as the second argument. +.Pp +.Fn srp_update +and +.Fn srp_update_locked +replace the data referenced by the srp struct +.Fa p +with the data referenced by +.Fa v . +When the original data is no longer in use it will be destroyed by the garbage +collector +.Fa gc . +.Fn srp_update +uses atomic CPU operations to change the references. +.Fn srp_update_locked +may be used if modifications to +.Fa p +are already serialised by the caller. +.Pp +.Fn srp_enter +returns a pointer to a data structure referenced by the srp struct +.Fa p +and guarantees it will remain available for use until a call to +.Fn srp_leave . +.Pp +.Fn srp_leave +releases the reference to +.Fa v +by the srp struct +.Fa p +and makes it available for garbage collection. +.Pp +.Fn srp_get_locked +provides access to the data referenced by the srp +.Fa p +if the caller has excluded updates to +.Fa p . +.Pp +.Fn srp_finalize +sleeps until all references to data by srp structures using the +garbage collector +.Fa gc +have completed. +That in turn means the +.Fa gc +structure will no longer be referenced and can itself be destroyed. +.Pp +A srp structure declaraction can be initialised with the +.Fn SRP_INITIALIZER +macro. +.Pp +A srp_gc structure declaraction can be initialised with the +.Fn SRP_GC_INITIALIZER +macro. +Data will be destroyed by the garbage collector by a call to +.Fa dtor +with +.Fa ctx +as the first argument and the pointer to the data as the second argument. +.Sh CONTEXT +.Fn srp_init , +.Fn srp_gc_init , +.Fn srp_update , +.Fn srp_update_locked , +.Fn srp_update_get_locked , +and +.Fn srp_finalize +can be called during autoconf, or from process context. +.Pp +.Fn srp_enter +and +.Fn srp_leave +can be called during autoconf, from process context, or from interrupt context. +.Sh RETURN VALUES +.Fn srp_enter +and +.Fn srp_get_locked +returns a pointer to the data referenced by the srp structure +.Fa p +or +.Dv NULL . +.Sh HISTORY +The srp API was originally written by +.An Jonathan Matthew Aq Mt jmatthew@openbsd.org +and +.An David Gwynne Aq Mt dlg@openbsd.org . +The srp API first appeared in +.Ox 5.8 . Index: sys/arch/alpha/include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/alpha/include/cpu.h,v retrieving revision 1.54 diff -u -p -r1.54 cpu.h --- sys/arch/alpha/include/cpu.h 17 Dec 2014 15:23:42 -0000 1.54 +++ sys/arch/alpha/include/cpu.h 2 Jul 2015 00:56:26 -0000 @@ -189,6 +189,10 @@ struct cpu_info { struct cpu_info *ci_next; u_int32_t ci_randseed; +#if defined(MULTIPROCESSOR) + struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM]; +#endif + /* * Private members. */ Index: sys/arch/amd64/include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/amd64/include/cpu.h,v retrieving revision 1.96 diff -u -p -r1.96 cpu.h --- sys/arch/amd64/include/cpu.h 28 Jun 2015 18:54:54 -0000 1.96 +++ sys/arch/amd64/include/cpu.h 2 Jul 2015 00:56:26 -0000 @@ -131,6 +131,10 @@ struct cpu_info { #define CI_DDB_ENTERDDB 3 #define CI_DDB_INDDB 4 +#ifdef MULTIPROCESSOR + struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM]; +#endif + struct ksensordev ci_sensordev; struct ksensor ci_sensor; #ifdef GPROF Index: sys/arch/hppa/include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/hppa/include/cpu.h,v retrieving revision 1.87 diff -u -p -r1.87 cpu.h --- sys/arch/hppa/include/cpu.h 11 Jul 2014 10:53:07 -0000 1.87 +++ sys/arch/hppa/include/cpu.h 2 Jul 2015 00:56:27 -0000 @@ -89,6 +89,10 @@ struct cpu_info { paddr_t ci_fpu_state; /* Process FPU state. */ paddr_t ci_stack; +#if defined(MULTIPROCESSOR) + struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM]; +#endif + register_t ci_psw; /* Processor Status Word. */ volatile int ci_cpl; volatile u_long ci_mask; /* Hardware interrupt mask. */ Index: sys/arch/i386/include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/i386/include/cpu.h,v retrieving revision 1.142 diff -u -p -r1.142 cpu.h --- sys/arch/i386/include/cpu.h 13 Jun 2015 21:41:42 -0000 1.142 +++ sys/arch/i386/include/cpu.h 2 Jul 2015 00:56:27 -0000 @@ -85,6 +85,10 @@ struct cpu_info { u_int ci_apicid; /* our APIC ID */ u_int32_t ci_randseed; +#if defined(MULTIPROCESSOR) + struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM]; +#endif + /* * Private members. */ Index: sys/arch/m88k/include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/m88k/include/cpu.h,v retrieving revision 1.63 diff -u -p -r1.63 cpu.h --- sys/arch/m88k/include/cpu.h 11 Feb 2015 07:05:39 -0000 1.63 +++ sys/arch/m88k/include/cpu.h 2 Jul 2015 00:56:27 -0000 @@ -96,6 +96,10 @@ struct cpu_info { u_int ci_cpuid; /* cpu number */ +#if defined(MULTIPROCESSOR) + struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM]; +#endif + /* * Function pointers used within mplock to ensure * non-interruptability. Index: sys/arch/mips64/include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/mips64/include/cpu.h,v retrieving revision 1.104 diff -u -p -r1.104 cpu.h --- sys/arch/mips64/include/cpu.h 11 Feb 2015 07:05:39 -0000 1.104 +++ sys/arch/mips64/include/cpu.h 2 Jul 2015 00:56:27 -0000 @@ -154,6 +154,10 @@ struct cpu_info { struct cpu_hwinfo ci_hw; +#if defined(MULTIPROCESSOR) + struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM]; +#endif + /* cache information and pending flush state */ uint ci_cacheconfiguration; uint64_t ci_cachepending_l1i; Index: sys/arch/powerpc/include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/powerpc/include/cpu.h,v retrieving revision 1.61 diff -u -p -r1.61 cpu.h --- sys/arch/powerpc/include/cpu.h 31 Mar 2015 16:00:38 -0000 1.61 +++ sys/arch/powerpc/include/cpu.h 2 Jul 2015 00:56:27 -0000 @@ -58,6 +58,10 @@ struct cpu_info { volatile int ci_flags; #define CI_FLAGS_SLEEPING 2 +#if defined(MULTIPROCESSOR) + struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM]; +#endif + int ci_intrdepth; char *ci_intstk; #define CPUSAVE_LEN 8 Index: sys/arch/sparc64/include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/sparc64/include/cpu.h,v retrieving revision 1.86 diff -u -p -r1.86 cpu.h --- sys/arch/sparc64/include/cpu.h 15 Oct 2014 21:54:13 -0000 1.86 +++ sys/arch/sparc64/include/cpu.h 2 Jul 2015 00:56:27 -0000 @@ -118,6 +118,7 @@ struct cpu_info { int ci_upaid; #ifdef MULTIPROCESSOR int ci_itid; + struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM]; #endif int ci_node; u_int32_t ci_randseed; Index: sys/conf/files =================================================================== RCS file: /cvs/src/sys/conf/files,v retrieving revision 1.593 diff -u -p -r1.593 files --- sys/conf/files 19 Jun 2015 11:12:24 -0000 1.593 +++ sys/conf/files 2 Jul 2015 00:56:27 -0000 @@ -678,6 +678,7 @@ file kern/kern_timeout.c file kern/kern_uuid.c gpt file kern/kern_watchdog.c !small_kernel file kern/kern_task.c +file kern/kern_srp.c file kern/kern_xxx.c file kern/kgdb_stub.c kgdb file kern/sched_bsd.c Index: sys/kern/init_main.c =================================================================== RCS file: /cvs/src/sys/kern/init_main.c,v retrieving revision 1.241 diff -u -p -r1.241 init_main.c --- sys/kern/init_main.c 24 Jun 2015 03:42:08 -0000 1.241 +++ sys/kern/init_main.c 2 Jul 2015 00:56:27 -0000 @@ -234,6 +234,9 @@ main(void *framep) /* Initialize sockets. */ soinit(); + /* Initialize SRP subsystem. */ + srp_startup(); + /* * Initialize process and pgrp structures. */ Index: sys/kern/kern_srp.c =================================================================== RCS file: sys/kern/kern_srp.c diff -N sys/kern/kern_srp.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/kern/kern_srp.c 2 Jul 2015 00:56:27 -0000 @@ -0,0 +1,265 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2014 Jonathan Matthew + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include + +void srp_v_gc_start(struct srp_gc *, struct srp *, void *); + +void +srp_gc_init(struct srp_gc *srp_gc, void (*dtor)(void *, void *), void *cookie) +{ + srp_gc->srp_gc_dtor = dtor; + srp_gc->srp_gc_cookie = cookie; + srp_gc->srp_gc_refcount = 1; +} + +void +srp_init(struct srp *srp) +{ + srp->ref = NULL; +} + +void +srp_update_locked(struct srp_gc *srp_gc, struct srp *srp, void *nv) +{ + void *ov; + + if (nv != NULL) + atomic_inc_int(&srp_gc->srp_gc_refcount); + + /* + * this doesn't have to be as careful as the caller has already + * prevented concurrent updates, eg. by holding the kernel lock. + * can't be mixed with non-locked updates though. + */ + + ov = srp->ref; + srp->ref = nv; + if (ov != NULL) + srp_v_gc_start(srp_gc, srp, ov); +} + +void * +srp_get_locked(struct srp *srp) +{ + return (srp->ref); +} + +#ifdef MULTIPROCESSOR +#include +#include + +struct srp_gc_ctx { + struct srp_gc *srp_gc; + struct timeout tick; + struct srp_hazard hzrd; +}; + +int srp_v_referenced(struct srp *, void *); +void srp_v_gc(void *); + +struct pool srp_gc_ctx_pool; + +void +srp_startup(void) +{ + pool_init(&srp_gc_ctx_pool, sizeof(struct srp_gc_ctx), 0, 0, + PR_WAITOK, "srpgc", NULL); + + /* items are allocated in a process, but freed from a timeout */ + pool_setipl(&srp_gc_ctx_pool, IPL_SOFTCLOCK); +} + +int +srp_v_referenced(struct srp *srp, void *v) +{ + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + u_int i; + struct srp_hazard *hzrd; + + CPU_INFO_FOREACH(cii, ci) { + for (i = 0; i < nitems(ci->ci_srp_hazards); i++) { + hzrd = &ci->ci_srp_hazards[i]; + + if (hzrd->sh_p != srp) + continue; + membar_consumer(); + if (hzrd->sh_v != v) + continue; + + return (1); + } + } + + return (0); +} + +void +srp_v_dtor(struct srp_gc *srp_gc, void *v) +{ + (*srp_gc->srp_gc_dtor)(srp_gc->srp_gc_cookie, v); + + if (atomic_dec_int_nv(&srp_gc->srp_gc_refcount) == 0) + wakeup_one(&srp_gc->srp_gc_refcount); +} + +void +srp_v_gc_start(struct srp_gc *srp_gc, struct srp *srp, void *v) +{ + struct srp_gc_ctx *ctx; + + if (!srp_v_referenced(srp, v)) { + /* we win */ + srp_v_dtor(srp_gc, v); + return; + } + + /* in use, try later */ + + ctx = pool_get(&srp_gc_ctx_pool, PR_WAITOK); + ctx->srp_gc = srp_gc; + ctx->hzrd.sh_p = srp; + ctx->hzrd.sh_v = v; + + timeout_set(&ctx->tick, srp_v_gc, ctx); + timeout_add(&ctx->tick, 1); +} + +void +srp_v_gc(void *x) +{ + struct srp_gc_ctx *ctx = x; + + if (srp_v_referenced(ctx->hzrd.sh_p, ctx->hzrd.sh_v)) { + /* oh well, try again later */ + timeout_add(&ctx->tick, 1); + return; + } + + srp_v_dtor(ctx->srp_gc, ctx->hzrd.sh_v); + pool_put(&srp_gc_ctx_pool, ctx); +} + +void +srp_update(struct srp_gc *srp_gc, struct srp *srp, void *v) +{ + if (v != NULL) + atomic_inc_int(&srp_gc->srp_gc_refcount); + + v = atomic_swap_ptr(&srp->ref, v); + if (v != NULL) + srp_v_gc_start(srp_gc, srp, v); +} + +void +srp_finalize(struct srp_gc *srp_gc) +{ + struct sleep_state sls; + u_int r; + + r = atomic_dec_int_nv(&srp_gc->srp_gc_refcount); + while (r > 0) { + sleep_setup(&sls, &srp_gc->srp_gc_refcount, PWAIT, "srpfini"); + r = srp_gc->srp_gc_refcount; + sleep_finish(&sls, r); + } +} + +void * +srp_enter(struct srp *srp) +{ + struct cpu_info *ci = curcpu(); + struct srp_hazard *hzrd; + void *v; + u_int i; + + for (i = 0; i < nitems(ci->ci_srp_hazards); i++) { + hzrd = &ci->ci_srp_hazards[i]; + if (hzrd->sh_p == NULL) + break; + } + if (__predict_false(i == nitems(ci->ci_srp_hazards))) + panic("%s: not enough srp hazard records", __func__); + + hzrd->sh_p = srp; + membar_producer(); + + /* + * ensure we update this cpu's hazard pointer to a value that's still + * current after the store finishes, otherwise the gc task may already + * be destroying it + */ + do { + v = srp->ref; + hzrd->sh_v = v; + membar_consumer(); + } while (__predict_false(v != srp->ref)); + + return (v); +} + +void +srp_leave(struct srp *srp, void *v) +{ + struct cpu_info *ci = curcpu(); + struct srp_hazard *hzrd; + u_int i; + + for (i = 0; i < nitems(ci->ci_srp_hazards); i++) { + hzrd = &ci->ci_srp_hazards[i]; + if (hzrd->sh_p == srp) { + hzrd->sh_p = NULL; + hzrd->sh_v = NULL; + return; + } + } + + panic("%s: unexpected ref %p via %p", __func__, v, srp); +} + +#else /* MULTIPROCESSOR */ + +void +srp_startup(void) +{ + +} + +void +srp_finalize(struct srp_gc *srp_gc) +{ + KASSERT(srp_gc->srp_gc_refcount == 1); + + srp_gc->srp_gc_refcount--; +} + +void +srp_v_gc_start(struct srp_gc *srp_gc, struct srp *srp, void *v) +{ + (*srp_gc->srp_gc_dtor)(srp_gc->srp_gc_cookie, v); + srp_gc->srp_gc_refcount--; +} + +#endif /* MULTIPROCESSOR */ Index: sys/sys/param.h =================================================================== RCS file: /cvs/src/sys/sys/param.h,v retrieving revision 1.117 diff -u -p -r1.117 param.h --- sys/sys/param.h 17 Jun 2015 22:35:08 -0000 1.117 +++ sys/sys/param.h 2 Jul 2015 00:56:27 -0000 @@ -83,6 +83,7 @@ #include #include #include +#include #endif /* Signals. */ Index: sys/sys/srp.h =================================================================== RCS file: sys/sys/srp.h diff -N sys/sys/srp.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/sys/srp.h 2 Jul 2015 00:56:27 -0000 @@ -0,0 +1,64 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2014 Jonathan Matthew + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SYS_SRP_H_ +#define _SYS_SRP_H_ + +struct srp { + void *ref; +}; + +struct srp_hazard { + struct srp *sh_p; + void *sh_v; +}; + +#define SRP_HAZARD_NUM 16 + +struct srp_gc { + void (*srp_gc_dtor)(void *, void *); + void *srp_gc_cookie; + u_int srp_gc_refcount; +}; + +#ifdef _KERNEL + +#define SRP_INITIALIZER() { NULL } +#define SRP_GC_INITIALIZER(_d, _c) { (_d), (_c), 1 } + +void srp_startup(void); +void srp_gc_init(struct srp_gc *, void (*)(void *, void *), void *); +void srp_update_locked(struct srp_gc *, struct srp *, void *); +void *srp_get_locked(struct srp *); +void srp_finalize(struct srp_gc *); + +void srp_init(struct srp *); + +#ifdef MULTIPROCESSOR +void srp_update(struct srp_gc *, struct srp *, void *); +void *srp_enter(struct srp *); +void srp_leave(struct srp *, void *); +#else /* MULTIPROCESSOR */ +#define srp_update(_gc, _srp, _v) srp_update_locked((_gc), (_srp), (_v)) +#define srp_enter(_srp) ((_srp)->ref) +#define srp_leave(_srp, _v) do { } while (0) +#endif /* MULTIPROCESSOR */ + +#endif /* _KERNEL */ + +#endif /* _SYS_SRP_H_ */