ia64/xen-unstable

view xen/common/stop_machine.c @ 17062:0769835cf50f

x86 shadow: Reduce scope of shadow lock.

emulate_map_dest doesn't require holding lock, since
only shadow related operation possibly involved is to
remove shadow which is less frequent and can acquire
lock inside. Rest are either guest table walk or
per-vcpu monitor table manipulation

Signed-off-by Kevin Tian <kevin.tian@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Feb 14 10:33:12 2008 +0000 (2008-02-14)
parents e1dde6f8bc87
children 675fb031df88
line source
1 /******************************************************************************
2 * common/stop_machine.c
3 *
4 * Facilities to put whole machine in a safe 'stop' state
5 *
6 * Copyright 2005 Rusty Russell rusty@rustcorp.com.au IBM Corporation
7 * Copyright 2008 Kevin Tian <kevin.tian@intel.com>, Intel Corporation.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20 * Place - Suite 330, Boston, MA 02111-1307 USA.
21 */
23 #include <xen/config.h>
24 #include <xen/init.h>
25 #include <xen/sched.h>
26 #include <xen/spinlock.h>
27 #include <xen/softirq.h>
28 #include <xen/errno.h>
29 #include <xen/smp.h>
30 #include <asm/current.h>
31 #include <asm/processor.h>
33 enum stopmachine_state {
34 STOPMACHINE_START,
35 STOPMACHINE_PREPARE,
36 STOPMACHINE_DISABLE_IRQ,
37 STOPMACHINE_INVOKE,
38 STOPMACHINE_EXIT
39 };
41 struct stopmachine_data {
42 unsigned int nr_cpus;
44 enum stopmachine_state state;
45 atomic_t done;
47 unsigned int fn_cpu;
48 int fn_result;
49 int (*fn)(void *);
50 void *fn_data;
51 };
53 static struct stopmachine_data stopmachine_data;
54 static DEFINE_SPINLOCK(stopmachine_lock);
56 static void stopmachine_set_state(enum stopmachine_state state)
57 {
58 atomic_set(&stopmachine_data.done, 0);
59 smp_wmb();
60 stopmachine_data.state = state;
61 while ( atomic_read(&stopmachine_data.done) != stopmachine_data.nr_cpus )
62 cpu_relax();
63 }
65 int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu)
66 {
67 cpumask_t allbutself;
68 unsigned int i, nr_cpus;
69 int ret;
71 BUG_ON(!local_irq_is_enabled());
73 allbutself = cpu_online_map;
74 cpu_clear(smp_processor_id(), allbutself);
75 nr_cpus = cpus_weight(allbutself);
77 if ( nr_cpus == 0 )
78 {
79 BUG_ON(cpu != smp_processor_id());
80 return (*fn)(data);
81 }
83 /* Note: We shouldn't spin on lock when it's held by others since others
84 * is expecting this cpus to enter softirq context. Or else deadlock
85 * is caused.
86 */
87 if ( !spin_trylock(&stopmachine_lock) )
88 return -EBUSY;
90 stopmachine_data.fn = fn;
91 stopmachine_data.fn_data = data;
92 stopmachine_data.nr_cpus = nr_cpus;
93 stopmachine_data.fn_cpu = cpu;
94 atomic_set(&stopmachine_data.done, 0);
95 stopmachine_data.state = STOPMACHINE_START;
97 smp_wmb();
99 for_each_cpu_mask ( i, allbutself )
100 cpu_raise_softirq(i, STOPMACHINE_SOFTIRQ);
102 stopmachine_set_state(STOPMACHINE_PREPARE);
104 local_irq_disable();
105 stopmachine_set_state(STOPMACHINE_DISABLE_IRQ);
107 if ( cpu == smp_processor_id() )
108 stopmachine_data.fn_result = (*fn)(data);
109 stopmachine_set_state(STOPMACHINE_INVOKE);
110 ret = stopmachine_data.fn_result;
112 stopmachine_set_state(STOPMACHINE_EXIT);
113 local_irq_enable();
115 spin_unlock(&stopmachine_lock);
117 return ret;
118 }
120 static void stopmachine_softirq(void)
121 {
122 enum stopmachine_state state = STOPMACHINE_START;
124 smp_mb();
126 while ( state != STOPMACHINE_EXIT )
127 {
128 while ( stopmachine_data.state == state )
129 cpu_relax();
131 state = stopmachine_data.state;
132 switch ( state )
133 {
134 case STOPMACHINE_DISABLE_IRQ:
135 local_irq_disable();
136 break;
137 case STOPMACHINE_INVOKE:
138 if ( stopmachine_data.fn_cpu == smp_processor_id() )
139 stopmachine_data.fn_result =
140 stopmachine_data.fn(stopmachine_data.fn_data);
141 break;
142 default:
143 break;
144 }
146 smp_mb();
147 atomic_inc(&stopmachine_data.done);
148 }
150 local_irq_enable();
151 }
153 static int __init cpu_stopmachine_init(void)
154 {
155 open_softirq(STOPMACHINE_SOFTIRQ, stopmachine_softirq);
156 return 0;
157 }
158 __initcall(cpu_stopmachine_init);