summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2016-06-01 03:34:33 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2016-06-01 03:34:33 +0000
commit6761d1fab9d9a9de5ccb577e156eaad74c8ed28d (patch)
treec13347d6bca264b96be39d08a531d2454c6dcc77
parent3047149596e3477683aacb135109e37af21ed5f5 (diff)
add support for using SRPs without the garbage collection machinery.
the gc machinery may sleep during srp_update, which makes it hard to use from an interrupt context. srp_swap simply swaps the references in an srp and relies ont he caller to schedule work in a process context where it may sleep with srp_finalise until the reference is no longer in use. our network stack currently modifies routing tables in an interrupt context, so this is built to be used to support rtable updates in our current stack while supporting concurrent lookups. ok jmatthew@ mpi@
-rw-r--r--sys/kern/kern_srp.c60
-rw-r--r--sys/sys/srp.h7
2 files changed, 57 insertions, 10 deletions
diff --git a/sys/kern/kern_srp.c b/sys/kern/kern_srp.c
index fbb2fa207ed..b43b42ae6e4 100644
--- a/sys/kern/kern_srp.c
+++ b/sys/kern/kern_srp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_srp.c,v 1.9 2016/05/18 03:58:13 dlg Exp $ */
+/* $OpenBSD: kern_srp.c,v 1.10 2016/06/01 03:34:32 dlg Exp $ */
/*
* Copyright (c) 2014 Jonathan Matthew <jmatthew@openbsd.org>
@@ -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, struct srp *srp, void *nv)
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);
}
@@ -239,6 +254,33 @@ srp_leave(struct srp_ref *sr)
sr->hz->sh_p = NULL;
}
+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, const char *wmesg)
+{
+ while (srp_referenced(v))
+ tsleep(v, PWAIT, wmesg, 1);
+}
+
#else /* MULTIPROCESSOR */
void
diff --git a/sys/sys/srp.h b/sys/sys/srp.h
index 030ca48371e..45013743969 100644
--- a/sys/sys/srp.h
+++ b/sys/sys/srp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: srp.h,v 1.9 2016/05/18 03:58:13 dlg Exp $ */
+/* $OpenBSD: srp.h,v 1.10 2016/06/01 03:34:32 dlg Exp $ */
/*
* Copyright (c) 2014 Jonathan Matthew <jmatthew@openbsd.org>
@@ -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 *, const char *);
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, _wchan) ((void)0)
#define srp_enter(_sr, _srp) ((_srp)->ref)
#define srp_follow(_sr, _srp) ((_srp)->ref)
#define srp_leave(_sr) do { } while (0)