mm-only debug patch...
[mmotm.git] / lib / shm_signal.c
blobfbba74f914b956a6898e6ab6962f8887effa2a88
1 /*
2 * Copyright 2009 Novell. All Rights Reserved.
4 * See include/linux/shm_signal.h for documentation
6 * Author:
7 * Gregory Haskins <ghaskins@novell.com>
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License
11 * as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <linux/module.h>
24 #include <linux/interrupt.h>
25 #include <linux/shm_signal.h>
27 int shm_signal_enable(struct shm_signal *s, int flags)
29 struct shm_signal_irq *irq = &s->desc->irq[s->locale];
30 unsigned long iflags;
32 spin_lock_irqsave(&s->lock, iflags);
34 irq->enabled = 1;
35 wmb();
37 if ((irq->dirty || irq->pending)
38 && !test_bit(shm_signal_in_wakeup, &s->flags)) {
39 rmb();
40 tasklet_schedule(&s->deferred_notify);
43 spin_unlock_irqrestore(&s->lock, iflags);
45 return 0;
47 EXPORT_SYMBOL_GPL(shm_signal_enable);
49 int shm_signal_disable(struct shm_signal *s, int flags)
51 struct shm_signal_irq *irq = &s->desc->irq[s->locale];
53 irq->enabled = 0;
54 wmb();
56 return 0;
58 EXPORT_SYMBOL_GPL(shm_signal_disable);
61 * signaling protocol:
63 * each side of the shm_signal has an "irq" structure with the following
64 * fields:
66 * - enabled: controlled by shm_signal_enable/disable() to mask/unmask
67 * the notification locally
68 * - dirty: indicates if the shared-memory is dirty or clean. This
69 * is updated regardless of the enabled/pending state so that
70 * the state is always accurately tracked.
71 * - pending: indicates if a signal is pending to the remote locale.
72 * This allows us to determine if a remote-notification is
73 * already in flight to optimize spurious notifications away.
75 int shm_signal_inject(struct shm_signal *s, int flags)
77 /* Load the irq structure from the other locale */
78 struct shm_signal_irq *irq = &s->desc->irq[!s->locale];
81 * We always mark the remote side as dirty regardless of whether
82 * they need to be notified.
84 irq->dirty = 1;
85 wmb(); /* dirty must be visible before we test the pending state */
87 if (irq->enabled && !irq->pending) {
88 rmb();
91 * If the remote side has enabled notifications, and we do
92 * not see a notification pending, we must inject a new one.
94 irq->pending = 1;
95 wmb(); /* make it visible before we do the injection */
97 s->ops->inject(s);
100 return 0;
102 EXPORT_SYMBOL_GPL(shm_signal_inject);
104 void _shm_signal_wakeup(struct shm_signal *s)
106 struct shm_signal_irq *irq = &s->desc->irq[s->locale];
107 int dirty;
108 unsigned long flags;
110 spin_lock_irqsave(&s->lock, flags);
112 __set_bit(shm_signal_in_wakeup, &s->flags);
115 * The outer loop protects against race conditions between
116 * irq->dirty and irq->pending updates
118 while (irq->enabled && (irq->dirty || irq->pending)) {
121 * Run until we completely exhaust irq->dirty (it may
122 * be re-dirtied by the remote side while we are in the
123 * callback). We let "pending" remain untouched until we have
124 * processed them all so that the remote side knows we do not
125 * need a new notification (yet).
127 do {
128 irq->dirty = 0;
129 /* the unlock is an implicit wmb() for dirty = 0 */
130 spin_unlock_irqrestore(&s->lock, flags);
132 if (s->notifier)
133 s->notifier->signal(s->notifier);
135 spin_lock_irqsave(&s->lock, flags);
136 dirty = irq->dirty;
137 rmb();
139 } while (irq->enabled && dirty);
141 barrier();
144 * We can finally acknowledge the notification by clearing
145 * "pending" after all of the dirty memory has been processed
146 * Races against this clearing are handled by the outer loop.
147 * Subsequent iterations of this loop will execute with
148 * pending=0 potentially leading to future spurious
149 * notifications, but this is an acceptable tradeoff as this
150 * will be rare and harmless.
152 irq->pending = 0;
153 wmb();
157 __clear_bit(shm_signal_in_wakeup, &s->flags);
158 spin_unlock_irqrestore(&s->lock, flags);
161 EXPORT_SYMBOL_GPL(_shm_signal_wakeup);
163 void _shm_signal_release(struct kref *kref)
165 struct shm_signal *s = container_of(kref, struct shm_signal, kref);
167 s->ops->release(s);
169 EXPORT_SYMBOL_GPL(_shm_signal_release);
171 static void
172 deferred_notify(unsigned long data)
174 struct shm_signal *s = (struct shm_signal *)data;
176 _shm_signal_wakeup(s);
179 void shm_signal_init(struct shm_signal *s, enum shm_signal_locality locale,
180 struct shm_signal_ops *ops, struct shm_signal_desc *desc)
182 memset(s, 0, sizeof(*s));
183 kref_init(&s->kref);
184 spin_lock_init(&s->lock);
185 tasklet_init(&s->deferred_notify,
186 deferred_notify,
187 (unsigned long)s);
188 s->locale = locale;
189 s->ops = ops;
190 s->desc = desc;
192 EXPORT_SYMBOL_GPL(shm_signal_init);