LCOV - code coverage report
Current view: top level - kern - kern_srp.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 106 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: kern_srp.c,v 1.12 2017/09/08 05:36:53 deraadt Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2014 Jonathan Matthew <jmatthew@openbsd.org>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : #include <sys/param.h>
      20             : #include <sys/systm.h>
      21             : #include <sys/timeout.h>
      22             : #include <sys/srp.h>
      23             : #include <sys/atomic.h>
      24             : 
      25             : void    srp_v_gc_start(struct srp_gc *, struct srp *, void *);
      26             : 
      27             : void
      28           0 : srpl_rc_init(struct srpl_rc *rc,  void (*ref)(void *, void *),
      29             :     void (*unref)(void *, void *), void *cookie)
      30             : {
      31           0 :         rc->srpl_ref = ref;
      32           0 :         srp_gc_init(&rc->srpl_gc, unref, cookie);
      33           0 : }
      34             : 
      35             : void
      36           0 : srp_gc_init(struct srp_gc *srp_gc, void (*dtor)(void *, void *), void *cookie)
      37             : {
      38           0 :         srp_gc->srp_gc_dtor = dtor;
      39           0 :         srp_gc->srp_gc_cookie = cookie;
      40           0 :         refcnt_init(&srp_gc->srp_gc_refcnt);
      41           0 : }
      42             : 
      43             : void
      44           0 : srp_init(struct srp *srp)
      45             : {
      46           0 :         srp->ref = NULL;
      47           0 : }
      48             : 
      49             : void *
      50           0 : srp_swap_locked(struct srp *srp, void *nv)
      51             : {
      52             :         void *ov;
      53             : 
      54             :         /*
      55             :          * this doesn't have to be as careful as the caller has already
      56             :          * prevented concurrent updates, eg. by holding the kernel lock.
      57             :          * can't be mixed with non-locked updates though.
      58             :          */
      59             : 
      60           0 :         ov = srp->ref;
      61           0 :         srp->ref = nv;
      62             : 
      63           0 :         return (ov);
      64             : }
      65             : 
      66             : void
      67           0 : srp_update_locked(struct srp_gc *srp_gc, struct srp *srp, void *v)
      68             : {
      69           0 :         if (v != NULL)
      70           0 :                 refcnt_take(&srp_gc->srp_gc_refcnt);
      71             : 
      72           0 :         v = srp_swap_locked(srp, v);
      73             : 
      74           0 :         if (v != NULL)
      75           0 :                 srp_v_gc_start(srp_gc, srp, v);
      76           0 : }
      77             : 
      78             : void *
      79           0 : srp_get_locked(struct srp *srp)
      80             : {
      81           0 :         return (srp->ref);
      82             : }
      83             : 
      84             : void
      85           0 : srp_gc_finalize(struct srp_gc *srp_gc)
      86             : {
      87           0 :         refcnt_finalize(&srp_gc->srp_gc_refcnt, "srpfini");
      88           0 : }
      89             : 
      90             : #ifdef MULTIPROCESSOR
      91             : #include <machine/cpu.h>
      92             : #include <sys/pool.h>
      93             : 
      94             : struct srp_gc_ctx {
      95             :         struct srp_gc           *srp_gc;
      96             :         struct timeout          tick;
      97             :         struct srp_hazard       hzrd;
      98             : };
      99             : 
     100             : int     srp_v_referenced(struct srp *, void *);
     101             : void    srp_v_gc(void *);
     102             : 
     103             : struct pool srp_gc_ctx_pool;
     104             : 
     105             : void
     106           0 : srp_startup(void)
     107             : {
     108           0 :         pool_init(&srp_gc_ctx_pool, sizeof(struct srp_gc_ctx), 0,
     109             :             IPL_SOFTCLOCK, PR_WAITOK, "srpgc", NULL);
     110           0 : }
     111             : 
     112             : int
     113           0 : srp_v_referenced(struct srp *srp, void *v)
     114             : {
     115             :         struct cpu_info *ci;
     116             :         CPU_INFO_ITERATOR cii;
     117             :         u_int i;
     118             :         struct srp_hazard *hzrd;
     119             : 
     120           0 :         CPU_INFO_FOREACH(cii, ci) {
     121           0 :                 for (i = 0; i < nitems(ci->ci_srp_hazards); i++) {
     122           0 :                         hzrd = &ci->ci_srp_hazards[i];
     123             : 
     124           0 :                         if (hzrd->sh_p != srp)
     125             :                                 continue;
     126           0 :                         membar_consumer();
     127           0 :                         if (hzrd->sh_v != v)
     128             :                                 continue;
     129             : 
     130           0 :                         return (1);
     131             :                 }
     132             :         }
     133             : 
     134           0 :         return (0);
     135           0 : }
     136             : 
     137             : void
     138           0 : srp_v_dtor(struct srp_gc *srp_gc, void *v)
     139             : {
     140           0 :         (*srp_gc->srp_gc_dtor)(srp_gc->srp_gc_cookie, v);
     141             : 
     142           0 :         refcnt_rele_wake(&srp_gc->srp_gc_refcnt);
     143           0 : }
     144             : 
     145             : void
     146           0 : srp_v_gc_start(struct srp_gc *srp_gc, struct srp *srp, void *v)
     147             : {
     148             :         struct srp_gc_ctx *ctx;
     149             : 
     150           0 :         if (!srp_v_referenced(srp, v)) {
     151             :                 /* we win */
     152           0 :                 srp_v_dtor(srp_gc, v);
     153           0 :                 return;
     154             :         }
     155             : 
     156             :         /* in use, try later */
     157             : 
     158           0 :         ctx = pool_get(&srp_gc_ctx_pool, PR_WAITOK);
     159           0 :         ctx->srp_gc = srp_gc;
     160           0 :         ctx->hzrd.sh_p = srp;
     161           0 :         ctx->hzrd.sh_v = v;
     162             : 
     163           0 :         timeout_set(&ctx->tick, srp_v_gc, ctx);
     164           0 :         timeout_add(&ctx->tick, 1);
     165           0 : }
     166             : 
     167             : void
     168           0 : srp_v_gc(void *x)
     169             : {
     170           0 :         struct srp_gc_ctx *ctx = x;
     171             : 
     172           0 :         if (srp_v_referenced(ctx->hzrd.sh_p, ctx->hzrd.sh_v)) {
     173             :                 /* oh well, try again later */
     174           0 :                 timeout_add(&ctx->tick, 1);
     175           0 :                 return;
     176             :         }
     177             : 
     178           0 :         srp_v_dtor(ctx->srp_gc, ctx->hzrd.sh_v);
     179           0 :         pool_put(&srp_gc_ctx_pool, ctx);
     180           0 : }
     181             : 
     182             : void *
     183           0 : srp_swap(struct srp *srp, void *v)
     184             : {
     185           0 :         return (atomic_swap_ptr(&srp->ref, v));
     186             : }
     187             : 
     188             : void
     189           0 : srp_update(struct srp_gc *srp_gc, struct srp *srp, void *v)
     190             : {
     191           0 :         if (v != NULL)
     192           0 :                 refcnt_take(&srp_gc->srp_gc_refcnt);
     193             : 
     194           0 :         v = srp_swap(srp, v);
     195           0 :         if (v != NULL)
     196           0 :                 srp_v_gc_start(srp_gc, srp, v);
     197           0 : }
     198             : 
     199             : static inline void *
     200           0 : srp_v(struct srp_hazard *hzrd, struct srp *srp)
     201             : {
     202             :         void *v;
     203             : 
     204           0 :         hzrd->sh_p = srp;
     205             : 
     206             :         /*
     207             :          * ensure we update this cpu's hazard pointer to a value that's still
     208             :          * current after the store finishes, otherwise the gc task may already
     209             :          * be destroying it
     210             :          */
     211           0 :         do {
     212           0 :                 v = srp->ref;
     213           0 :                 hzrd->sh_v = v;
     214           0 :                 membar_consumer();
     215           0 :         } while (__predict_false(v != srp->ref));
     216             : 
     217           0 :         return (v);
     218             : }
     219             : 
     220             : void *
     221           0 : srp_enter(struct srp_ref *sr, struct srp *srp)
     222             : {
     223           0 :         struct cpu_info *ci = curcpu();
     224             :         struct srp_hazard *hzrd;
     225             :         u_int i;
     226             : 
     227           0 :         for (i = 0; i < nitems(ci->ci_srp_hazards); i++) {
     228           0 :                 hzrd = &ci->ci_srp_hazards[i];
     229           0 :                 if (hzrd->sh_p == NULL) {
     230           0 :                         sr->hz = hzrd;
     231           0 :                         return (srp_v(hzrd, srp));
     232             :                 }
     233             :         }
     234             : 
     235           0 :         panic("%s: not enough srp hazard records", __func__);
     236             : 
     237             :         /* NOTREACHED */
     238             :         return (NULL);
     239             : }
     240             : 
     241             : void *
     242           0 : srp_follow(struct srp_ref *sr, struct srp *srp)
     243             : {
     244           0 :         return (srp_v(sr->hz, srp));
     245             : }
     246             : 
     247             : void
     248           0 : srp_leave(struct srp_ref *sr)
     249             : {
     250           0 :         sr->hz->sh_p = NULL;
     251           0 : }
     252             : 
     253             : static inline int
     254           0 : srp_referenced(void *v)
     255             : {
     256             :         struct cpu_info *ci;
     257             :         CPU_INFO_ITERATOR cii;
     258             :         u_int i;
     259             :         struct srp_hazard *hzrd;
     260             : 
     261           0 :         CPU_INFO_FOREACH(cii, ci) {
     262           0 :                 for (i = 0; i < nitems(ci->ci_srp_hazards); i++) {
     263           0 :                         hzrd = &ci->ci_srp_hazards[i];
     264             : 
     265           0 :                         if (hzrd->sh_p != NULL && hzrd->sh_v == v)
     266           0 :                                 return (1);
     267             :                 }
     268             :         }
     269             : 
     270           0 :         return (0);
     271           0 : }
     272             : 
     273             : void
     274           0 : srp_finalize(void *v, const char *wmesg)
     275             : {
     276           0 :         while (srp_referenced(v))
     277           0 :                 tsleep(v, PWAIT, wmesg, 1);
     278           0 : }
     279             : 
     280             : #else /* MULTIPROCESSOR */
     281             : 
     282             : void
     283             : srp_startup(void)
     284             : {
     285             : 
     286             : }
     287             : 
     288             : void
     289             : srp_v_gc_start(struct srp_gc *srp_gc, struct srp *srp, void *v)
     290             : {
     291             :         (*srp_gc->srp_gc_dtor)(srp_gc->srp_gc_cookie, v);
     292             :         refcnt_rele_wake(&srp_gc->srp_gc_refcnt);
     293             : }
     294             : 
     295             : #endif /* MULTIPROCESSOR */

Generated by: LCOV version 1.13