linux/include/linux/srcutiny.h
<<
>>
Prefs
   1/*
   2 * Sleepable Read-Copy Update mechanism for mutual exclusion,
   3 *      tiny variant.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, you can access it online at
  17 * http://www.gnu.org/licenses/gpl-2.0.html.
  18 *
  19 * Copyright (C) IBM Corporation, 2017
  20 *
  21 * Author: Paul McKenney <paulmck@us.ibm.com>
  22 */
  23
  24#ifndef _LINUX_SRCU_TINY_H
  25#define _LINUX_SRCU_TINY_H
  26
  27#include <linux/swait.h>
  28
  29struct srcu_struct {
  30        short srcu_lock_nesting[2];     /* srcu_read_lock() nesting depth. */
  31        short srcu_idx;                 /* Current reader array element. */
  32        u8 srcu_gp_running;             /* GP workqueue running? */
  33        u8 srcu_gp_waiting;             /* GP waiting for readers? */
  34        struct swait_queue_head srcu_wq;
  35                                        /* Last srcu_read_unlock() wakes GP. */
  36        struct rcu_head *srcu_cb_head;  /* Pending callbacks: Head. */
  37        struct rcu_head **srcu_cb_tail; /* Pending callbacks: Tail. */
  38        struct work_struct srcu_work;   /* For driving grace periods. */
  39#ifdef CONFIG_DEBUG_LOCK_ALLOC
  40        struct lockdep_map dep_map;
  41#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
  42};
  43
  44void srcu_drive_gp(struct work_struct *wp);
  45
  46#define __SRCU_STRUCT_INIT(name)                                        \
  47{                                                                       \
  48        .srcu_wq = __SWAIT_QUEUE_HEAD_INITIALIZER(name.srcu_wq),        \
  49        .srcu_cb_tail = &name.srcu_cb_head,                             \
  50        .srcu_work = __WORK_INITIALIZER(name.srcu_work, srcu_drive_gp), \
  51        __SRCU_DEP_MAP_INIT(name)                                       \
  52}
  53
  54/*
  55 * This odd _STATIC_ arrangement is needed for API compatibility with
  56 * Tree SRCU, which needs some per-CPU data.
  57 */
  58#define DEFINE_SRCU(name) \
  59        struct srcu_struct name = __SRCU_STRUCT_INIT(name)
  60#define DEFINE_STATIC_SRCU(name) \
  61        static struct srcu_struct name = __SRCU_STRUCT_INIT(name)
  62
  63void synchronize_srcu(struct srcu_struct *sp);
  64
  65/*
  66 * Counts the new reader in the appropriate per-CPU element of the
  67 * srcu_struct.  Can be invoked from irq/bh handlers, but the matching
  68 * __srcu_read_unlock() must be in the same handler instance.  Returns an
  69 * index that must be passed to the matching srcu_read_unlock().
  70 */
  71static inline int __srcu_read_lock(struct srcu_struct *sp)
  72{
  73        int idx;
  74
  75        idx = READ_ONCE(sp->srcu_idx);
  76        WRITE_ONCE(sp->srcu_lock_nesting[idx], sp->srcu_lock_nesting[idx] + 1);
  77        return idx;
  78}
  79
  80static inline void synchronize_srcu_expedited(struct srcu_struct *sp)
  81{
  82        synchronize_srcu(sp);
  83}
  84
  85static inline void srcu_barrier(struct srcu_struct *sp)
  86{
  87        synchronize_srcu(sp);
  88}
  89
  90/* Defined here to avoid size increase for non-torture kernels. */
  91static inline void srcu_torture_stats_print(struct srcu_struct *sp,
  92                                            char *tt, char *tf)
  93{
  94        int idx;
  95
  96        idx = READ_ONCE(sp->srcu_idx) & 0x1;
  97        pr_alert("%s%s Tiny SRCU per-CPU(idx=%d): (%hd,%hd)\n",
  98                 tt, tf, idx,
  99                 READ_ONCE(sp->srcu_lock_nesting[!idx]),
 100                 READ_ONCE(sp->srcu_lock_nesting[idx]));
 101}
 102
 103#endif
 104