Index: share/man/man9/srp_enter.9 =================================================================== RCS file: /cvs/src/share/man/man9/srp_enter.9,v retrieving revision 1.11 diff -u -p -r1.11 srp_enter.9 --- share/man/man9/srp_enter.9 18 May 2016 03:58:13 -0000 1.11 +++ share/man/man9/srp_enter.9 18 May 2016 05:35:09 -0000 @@ -22,10 +22,13 @@ .Nm srp_gc_init , .Nm srp_update , .Nm srp_update_locked , +.Nm srp_swap , +.Nm srp_swap_locked , .Nm srp_enter , .Nm srp_follow , .Nm srp_leave , .Nm srp_get_locked , +.Nm srp_finalize , .Nm srp_gc_finalize , .Nm SRP_INITIALIZER , .Nm SRP_GC_INITIALIZER @@ -40,6 +43,10 @@ .Fa "void (*dtor)(void *, void *)" .Fa "void *ctx" .Fc +.Ft void * +.Fn srp_swap "struct srp *p" "void *v" +.Ft void * +.Fn srp_swap_locked "struct srp *p" "void *v" .Ft void .Fn srp_update "struct srp_gc *gc" "struct srp *p" "void *v" .Ft void @@ -53,6 +60,8 @@ .Ft void * .Fn srp_get_locked "struct srp *p" .Ft void +.Fn srp_finalize "void *v" +.Ft void .Fn srp_gc_finalize "struct srp_gc *gc" .Fn SRP_INITIALIZER .Fo SRP_GC_INITIALIZER @@ -110,6 +119,23 @@ and .Fn srp_update_locked may sleep. .Pp +.Fn srp_swap +and +.Fn srp_swap_locked +replace the data referenced by the srp struct +.Fa p +with the data referenced by +.Fa v . +When clearing or replacing the last reference to a data structure, +.Fn srp_finalize +must be used to ensure that the data is longer in use via any srp structures. +.Fn srp_swap +uses atomic CPU operations to change the reference. +.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 @@ -138,6 +164,11 @@ provides access to the data referenced b if the caller has excluded updates to .Fa p . .Pp +.Fn srp_finalize +sleeps until there are no longer any references to +.Fa v +via any srp structure in the system. +.Pp .Fn srp_gc_finalize sleeps until all references to data by srp structures using the garbage collector @@ -166,15 +197,24 @@ as the first argument and the pointer to .Fn srp_update_locked , .Fn srp_get_locked , and +.Fn srp_finalize .Fn srp_gc_finalize can be called during autoconf, or from process context. .Pp +.Fn srp_swap , +.Fn srp_swap_locked , .Fn srp_enter , .Fn srp_follow , and .Fn srp_leave can be called during autoconf, from process context, or from interrupt context. .Sh RETURN VALUES +.Fn srp_swap +and +.Fn srp_swap_locked +return a pointer to the previous value referenced by the srp structure +.Fa p . +.Pp .Fn srp_enter , .Fn srp_follow , and Index: sys/kern/kern_srp.c =================================================================== RCS file: /cvs/src/sys/kern/kern_srp.c,v retrieving revision 1.9 diff -u -p -r1.9 kern_srp.c --- sys/kern/kern_srp.c 18 May 2016 03:58:13 -0000 1.9 +++ sys/kern/kern_srp.c 18 May 2016 05:35:09 -0000 @@ -47,14 +47,11 @@ srp_init(struct srp *srp) srp->ref = NULL; } -void -srp_update_locked(struct srp_gc *srp_gc, struct srp *srp, void *nv) +void * +srp_swap_locked(struct srp *srp, void *nv) { void *ov; - if (nv != NULL) - refcnt_take(&srp_gc->srp_gc_refcnt); - /* * this doesn't have to be as careful as the caller has already * prevented concurrent updates, eg. by holding the kernel lock. @@ -63,8 +60,20 @@ srp_update_locked(struct srp_gc *srp_gc, ov = srp->ref; srp->ref = nv; - if (ov != NULL) - srp_v_gc_start(srp_gc, srp, ov); + + return (ov); +} + +void +srp_update_locked(struct srp_gc *srp_gc, struct srp *srp, void *v) +{ + if (v != NULL) + refcnt_take(&srp_gc->srp_gc_refcnt); + + v = srp_swap_locked(srp, v); + + if (v != NULL) + srp_v_gc_start(srp_gc, srp, v); } void * @@ -174,13 +183,19 @@ srp_v_gc(void *x) pool_put(&srp_gc_ctx_pool, ctx); } +void * +srp_swap(struct srp *srp, void *v) +{ + return (atomic_swap_ptr(&srp->ref, v)); +} + void srp_update(struct srp_gc *srp_gc, struct srp *srp, void *v) { if (v != NULL) refcnt_take(&srp_gc->srp_gc_refcnt); - v = atomic_swap_ptr(&srp->ref, v); + v = srp_swap(srp, v); if (v != NULL) srp_v_gc_start(srp_gc, srp, v); } @@ -252,6 +267,33 @@ srp_v_gc_start(struct srp_gc *srp_gc, st { (*srp_gc->srp_gc_dtor)(srp_gc->srp_gc_cookie, v); refcnt_rele_wake(&srp_gc->srp_gc_refcnt); +} + +static inline int +srp_referenced(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 != NULL && hzrd->sh_v == v) + return (1); + } + } + + return (0); +} + +void +srp_finalize(void *v) +{ + while (srp_referenced(v)) + tsleep(v, PWAIT, "srpfini", 1); } #endif /* MULTIPROCESSOR */ Index: sys/sys/srp.h =================================================================== RCS file: /cvs/src/sys/sys/srp.h,v retrieving revision 1.9 diff -u -p -r1.9 srp.h --- sys/sys/srp.h 18 May 2016 03:58:13 -0000 1.9 +++ sys/sys/srp.h 18 May 2016 05:35:09 -0000 @@ -55,6 +55,7 @@ struct srp_gc { void srp_startup(void); void srp_gc_init(struct srp_gc *, void (*)(void *, void *), void *); +void *srp_swap_locked(struct srp *, void *); void srp_update_locked(struct srp_gc *, struct srp *, void *); void *srp_get_locked(struct srp *); void srp_gc_finalize(struct srp_gc *); @@ -62,12 +63,16 @@ void srp_gc_finalize(struct srp_gc *); void srp_init(struct srp *); #ifdef MULTIPROCESSOR +void *srp_swap(struct srp *, void *); void srp_update(struct srp_gc *, struct srp *, void *); +void srp_finalize(void *v); void *srp_enter(struct srp_ref *, struct srp *); void *srp_follow(struct srp_ref *, struct srp *); void srp_leave(struct srp_ref *); #else /* MULTIPROCESSOR */ +#define srp_swap(_srp, _v) srp_swap_locked((_srp), (_v)) #define srp_update(_gc, _srp, _v) srp_update_locked((_gc), (_srp), (_v)) +#define srp_finalize(_v) ((void)0) #define srp_enter(_sr, _srp) ((_srp)->ref) #define srp_follow(_sr, _srp) ((_srp)->ref) #define srp_leave(_sr) do { } while (0)