ia64/xen-unstable

view xen/include/xen/sched.h @ 6214:027812e4a63c

Fix context switching race which could cause vcpu_pause()
to not actually do its job properly. This requires us to
move clearing of VCPUF_running to be protected by the
scheduler lock.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Tue Aug 16 18:02:24 2005 +0000 (2005-08-16)
parents 9d0120a5aa45
children 3b0ce44f7b7a
line source
2 #ifndef __SCHED_H__
3 #define __SCHED_H__
5 #include <xen/config.h>
6 #include <xen/types.h>
7 #include <xen/spinlock.h>
8 #include <xen/smp.h>
9 #include <public/xen.h>
10 #include <public/dom0_ops.h>
11 #include <xen/time.h>
12 #include <xen/ac_timer.h>
13 #include <xen/grant_table.h>
14 #include <asm/domain.h>
16 extern unsigned long volatile jiffies;
17 extern rwlock_t domlist_lock;
19 /* A global pointer to the initial domain (DOM0). */
20 extern struct domain *dom0;
22 #define MAX_EVTCHNS 1024
23 #define EVTCHNS_PER_BUCKET 128
24 #define NR_EVTCHN_BUCKETS (MAX_EVTCHNS / EVTCHNS_PER_BUCKET)
26 struct evtchn
27 {
28 #define ECS_FREE 0 /* Channel is available for use. */
29 #define ECS_RESERVED 1 /* Channel is reserved. */
30 #define ECS_UNBOUND 2 /* Channel is waiting to bind to a remote domain. */
31 #define ECS_INTERDOMAIN 3 /* Channel is bound to another domain. */
32 #define ECS_PIRQ 4 /* Channel is bound to a physical IRQ line. */
33 #define ECS_VIRQ 5 /* Channel is bound to a virtual IRQ line. */
34 #define ECS_IPI 6 /* Channel is bound to a virtual IPI line. */
35 u16 state; /* ECS_* */
36 u16 notify_vcpu_id; /* VCPU for local delivery notification */
37 union {
38 struct {
39 domid_t remote_domid;
40 } unbound; /* state == ECS_UNBOUND */
41 struct {
42 u16 remote_port;
43 struct domain *remote_dom;
44 } interdomain; /* state == ECS_INTERDOMAIN */
45 u16 pirq; /* state == ECS_PIRQ */
46 u16 virq; /* state == ECS_VIRQ */
47 } u;
48 };
50 int evtchn_init(struct domain *d);
51 void evtchn_destroy(struct domain *d);
53 #define CPUMAP_RUNANYWHERE 0xFFFFFFFF
55 struct vcpu
56 {
57 int vcpu_id;
59 int processor;
61 vcpu_info_t *vcpu_info;
63 struct domain *domain;
64 struct vcpu *next_in_list;
66 struct ac_timer timer; /* one-shot timer for timeout values */
67 unsigned long sleep_tick; /* tick at which this vcpu started sleep */
69 s_time_t lastschd; /* time this domain was last scheduled */
70 s_time_t lastdeschd; /* time this domain was last descheduled */
71 s_time_t cpu_time; /* total CPU time received till now */
72 s_time_t wokenup; /* time domain got woken up */
73 void *sched_priv; /* scheduler-specific data */
75 unsigned long vcpu_flags;
77 u16 virq_to_evtchn[NR_VIRQS];
79 atomic_t pausecnt;
81 cpumap_t cpumap; /* which cpus this domain can run on */
83 struct arch_vcpu arch;
84 };
86 /* Per-domain lock can be recursively acquired in fault handlers. */
87 #define LOCK_BIGLOCK(_d) spin_lock_recursive(&(_d)->big_lock)
88 #define UNLOCK_BIGLOCK(_d) spin_unlock_recursive(&(_d)->big_lock)
90 struct domain
91 {
92 domid_t domain_id;
94 shared_info_t *shared_info; /* shared data area */
96 spinlock_t big_lock;
98 spinlock_t page_alloc_lock; /* protects all the following fields */
99 struct list_head page_list; /* linked list, of size tot_pages */
100 struct list_head xenpage_list; /* linked list, of size xenheap_pages */
101 unsigned int tot_pages; /* number of pages currently possesed */
102 unsigned int max_pages; /* maximum value for tot_pages */
103 unsigned int next_io_page; /* next io pfn to give to domain */
104 unsigned int xenheap_pages; /* # pages allocated from Xen heap */
106 /* Scheduling. */
107 int shutdown_code; /* code value from OS (if DOMF_shutdown) */
108 void *sched_priv; /* scheduler-specific data */
110 struct domain *next_in_list;
111 struct domain *next_in_hashbucket;
113 /* Event channel information. */
114 struct evtchn *evtchn[NR_EVTCHN_BUCKETS];
115 spinlock_t evtchn_lock;
117 grant_table_t *grant_table;
119 /*
120 * Interrupt to event-channel mappings. Updates should be protected by the
121 * domain's event-channel spinlock. Read accesses can also synchronise on
122 * the lock, but races don't usually matter.
123 */
124 #define NR_PIRQS 256 /* Put this somewhere sane! */
125 u16 pirq_to_evtchn[NR_PIRQS];
126 u32 pirq_mask[NR_PIRQS/32];
128 unsigned long domain_flags;
129 unsigned long vm_assist;
131 atomic_t refcnt;
133 struct vcpu *vcpu[MAX_VIRT_CPUS];
135 /* Bitmask of CPUs which are holding onto this domain's state. */
136 cpumask_t cpumask;
138 struct arch_domain arch;
140 void *ssid; /* sHype security subject identifier */
141 };
143 struct domain_setup_info
144 {
145 /* Initialised by caller. */
146 unsigned long image_addr;
147 unsigned long image_len;
148 /* Initialised by loader: Public. */
149 unsigned long v_start;
150 unsigned long v_end;
151 unsigned long v_kernstart;
152 unsigned long v_kernend;
153 unsigned long v_kernentry;
154 /* Initialised by loader: Private. */
155 unsigned int load_symtab;
156 unsigned long symtab_addr;
157 unsigned long symtab_len;
158 /* Indicate whether it's xen specific image */
159 char *xen_section_string;
160 };
162 extern struct domain idle0_domain;
163 extern struct vcpu idle0_vcpu;
165 extern struct vcpu *idle_task[NR_CPUS];
166 #define IDLE_DOMAIN_ID (0x7FFFU)
167 #define is_idle_task(_d) (test_bit(_DOMF_idle_domain, &(_d)->domain_flags))
169 struct vcpu *alloc_vcpu_struct(struct domain *d,
170 unsigned long vcpu);
172 void free_domain_struct(struct domain *d);
173 struct domain *alloc_domain_struct();
175 #define DOMAIN_DESTRUCTED (1<<31) /* assumes atomic_t is >= 32 bits */
176 #define put_domain(_d) \
177 if ( atomic_dec_and_test(&(_d)->refcnt) ) domain_destruct(_d)
179 /*
180 * Use this when you don't have an existing reference to @d. It returns
181 * FALSE if @d is being destructed.
182 */
183 static always_inline int get_domain(struct domain *d)
184 {
185 atomic_t old, new, seen = d->refcnt;
186 do
187 {
188 old = seen;
189 if ( unlikely(_atomic_read(old) & DOMAIN_DESTRUCTED) )
190 return 0;
191 _atomic_set(new, _atomic_read(old) + 1);
192 seen = atomic_compareandswap(old, new, &d->refcnt);
193 }
194 while ( unlikely(_atomic_read(seen) != _atomic_read(old)) );
195 return 1;
196 }
198 /*
199 * Use this when you already have, or are borrowing, a reference to @d.
200 * In this case we know that @d cannot be destructed under our feet.
201 */
202 static inline void get_knownalive_domain(struct domain *d)
203 {
204 atomic_inc(&d->refcnt);
205 ASSERT(!(atomic_read(&d->refcnt) & DOMAIN_DESTRUCTED));
206 }
208 extern struct domain *do_createdomain(
209 domid_t dom_id, unsigned int cpu);
210 extern int construct_dom0(
211 struct domain *d,
212 unsigned long image_start, unsigned long image_len,
213 unsigned long initrd_start, unsigned long initrd_len,
214 char *cmdline);
215 extern int set_info_guest(struct domain *d, dom0_setdomaininfo_t *);
217 struct domain *find_domain_by_id(domid_t dom);
218 extern void domain_destruct(struct domain *d);
219 extern void domain_kill(struct domain *d);
220 extern void domain_shutdown(u8 reason);
221 extern void domain_pause_for_debugger(void);
223 /*
224 * Mark current domain as crashed. This function returns: the domain is not
225 * synchronously descheduled from any processor.
226 */
227 extern void domain_crash(void);
229 /*
230 * Mark current domain as crashed and synchronously deschedule from the local
231 * processor. This function never returns.
232 */
233 extern void domain_crash_synchronous(void) __attribute__((noreturn));
235 void new_thread(struct vcpu *d,
236 unsigned long start_pc,
237 unsigned long start_stack,
238 unsigned long start_info);
240 #define set_current_state(_s) do { current->state = (_s); } while (0)
241 void scheduler_init(void);
242 void schedulers_start(void);
243 void sched_add_domain(struct vcpu *);
244 void sched_rem_domain(struct vcpu *);
245 long sched_ctl(struct sched_ctl_cmd *);
246 long sched_adjdom(struct sched_adjdom_cmd *);
247 int sched_id();
248 void domain_wake(struct vcpu *d);
249 void domain_sleep_nosync(struct vcpu *d);
250 void domain_sleep_sync(struct vcpu *d);
252 /*
253 * Force loading of currently-executing domain state on the specified set
254 * of CPUs. This is used to counteract lazy state switching where required.
255 */
256 extern void sync_lazy_execstate_cpu(unsigned int cpu);
257 extern void sync_lazy_execstate_mask(cpumask_t mask);
258 extern void sync_lazy_execstate_all(void);
259 extern int __sync_lazy_execstate(void);
261 /*
262 * Called by the scheduler to switch to another VCPU. On entry, although
263 * VCPUF_running is no longer asserted for @prev, its context is still running
264 * on the local CPU and is not committed to memory. The local scheduler lock
265 * is therefore still held, and interrupts are disabled, because the local CPU
266 * is in an inconsistent state.
267 *
268 * The callee must ensure that the local CPU is no longer running in @prev's
269 * context, and that the context is saved to memory, before returning.
270 * Alternatively, if implementing lazy context switching, it suffices to ensure
271 * that invoking __sync_lazy_execstate() will switch and commit @prev's state.
272 */
273 extern void context_switch(
274 struct vcpu *prev,
275 struct vcpu *next);
277 /*
278 * On some architectures (notably x86) it is not possible to entirely load
279 * @next's context with interrupts disabled. These may implement a function to
280 * finalise loading the new context after interrupts are re-enabled. This
281 * function is not given @prev and is not permitted to access it.
282 */
283 extern void context_switch_finalise(
284 struct vcpu *next);
286 /* Called by the scheduler to continue running the current VCPU. */
287 extern void continue_running(
288 struct vcpu *same);
290 int idle_cpu(int cpu); /* Is CPU 'cpu' idle right now? */
292 void startup_cpu_idle_loop(void);
294 unsigned long __hypercall_create_continuation(
295 unsigned int op, unsigned int nr_args, ...);
296 #define hypercall0_create_continuation(_op) \
297 __hypercall_create_continuation((_op), 0)
298 #define hypercall1_create_continuation(_op, _a1) \
299 __hypercall_create_continuation((_op), 1, \
300 (unsigned long)(_a1))
301 #define hypercall2_create_continuation(_op, _a1, _a2) \
302 __hypercall_create_continuation((_op), 2, \
303 (unsigned long)(_a1), (unsigned long)(_a2))
304 #define hypercall3_create_continuation(_op, _a1, _a2, _a3) \
305 __hypercall_create_continuation((_op), 3, \
306 (unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3))
307 #define hypercall4_create_continuation(_op, _a1, _a2, _a3, _a4) \
308 __hypercall_create_continuation((_op), 4, \
309 (unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3), \
310 (unsigned long)(_a4))
311 #define hypercall5_create_continuation(_op, _a1, _a2, _a3, _a4, _a5) \
312 __hypercall_create_continuation((_op), 5, \
313 (unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3), \
314 (unsigned long)(_a4), (unsigned long)(_a5))
315 #define hypercall6_create_continuation(_op, _a1, _a2, _a3, _a4, _a5, _a6) \
316 __hypercall_create_continuation((_op), 6, \
317 (unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3), \
318 (unsigned long)(_a4), (unsigned long)(_a5), (unsigned long)(_a6))
320 #define hypercall_preempt_check() (unlikely( \
321 softirq_pending(smp_processor_id()) | \
322 event_pending(current) \
323 ))
325 /* This domain_hash and domain_list are protected by the domlist_lock. */
326 #define DOMAIN_HASH_SIZE 256
327 #define DOMAIN_HASH(_id) ((int)(_id)&(DOMAIN_HASH_SIZE-1))
328 extern struct domain *domain_hash[DOMAIN_HASH_SIZE];
329 extern struct domain *domain_list;
331 #define for_each_domain(_d) \
332 for ( (_d) = domain_list; (_d) != NULL; (_d) = (_d)->next_in_list )
334 #define for_each_vcpu(_d,_ed) \
335 for ( (_ed) = (_d)->vcpu[0]; \
336 (_ed) != NULL; \
337 (_ed) = (_ed)->next_in_list )
339 /*
340 * Per-VCPU flags (vcpu_flags).
341 */
342 /* Has the FPU been initialised? */
343 #define _VCPUF_fpu_initialised 0
344 #define VCPUF_fpu_initialised (1UL<<_VCPUF_fpu_initialised)
345 /* Has the FPU been used since it was last saved? */
346 #define _VCPUF_fpu_dirtied 1
347 #define VCPUF_fpu_dirtied (1UL<<_VCPUF_fpu_dirtied)
348 /* Domain is blocked waiting for an event. */
349 #define _VCPUF_blocked 3
350 #define VCPUF_blocked (1UL<<_VCPUF_blocked)
351 /* Domain is paused by controller software. */
352 #define _VCPUF_ctrl_pause 4
353 #define VCPUF_ctrl_pause (1UL<<_VCPUF_ctrl_pause)
354 /* Currently running on a CPU? */
355 #define _VCPUF_running 5
356 #define VCPUF_running (1UL<<_VCPUF_running)
357 /* Disables auto-migration between CPUs. */
358 #define _VCPUF_cpu_pinned 6
359 #define VCPUF_cpu_pinned (1UL<<_VCPUF_cpu_pinned)
360 /* Domain migrated between CPUs. */
361 #define _VCPUF_cpu_migrated 7
362 #define VCPUF_cpu_migrated (1UL<<_VCPUF_cpu_migrated)
363 /* Initialization completed. */
364 #define _VCPUF_initialised 8
365 #define VCPUF_initialised (1UL<<_VCPUF_initialised)
366 /* VCPU is not-runnable */
367 #define _VCPUF_down 9
368 #define VCPUF_down (1UL<<_VCPUF_down)
370 /*
371 * Per-domain flags (domain_flags).
372 */
373 /* Has the guest OS been fully built yet? */
374 #define _DOMF_constructed 0
375 #define DOMF_constructed (1UL<<_DOMF_constructed)
376 /* Is this one of the per-CPU idle domains? */
377 #define _DOMF_idle_domain 1
378 #define DOMF_idle_domain (1UL<<_DOMF_idle_domain)
379 /* Is this domain privileged? */
380 #define _DOMF_privileged 2
381 #define DOMF_privileged (1UL<<_DOMF_privileged)
382 /* May this domain do IO to physical devices? */
383 #define _DOMF_physdev_access 3
384 #define DOMF_physdev_access (1UL<<_DOMF_physdev_access)
385 /* Guest shut itself down for some reason. */
386 #define _DOMF_shutdown 4
387 #define DOMF_shutdown (1UL<<_DOMF_shutdown)
388 /* Guest is in process of shutting itself down (becomes DOMF_shutdown). */
389 #define _DOMF_shuttingdown 5
390 #define DOMF_shuttingdown (1UL<<_DOMF_shuttingdown)
391 /* Death rattle. */
392 #define _DOMF_dying 6
393 #define DOMF_dying (1UL<<_DOMF_dying)
395 static inline int domain_runnable(struct vcpu *v)
396 {
397 return ( (atomic_read(&v->pausecnt) == 0) &&
398 !(v->vcpu_flags & (VCPUF_blocked|VCPUF_ctrl_pause|VCPUF_down)) &&
399 !(v->domain->domain_flags & (DOMF_shutdown|DOMF_shuttingdown)) );
400 }
402 void vcpu_pause(struct vcpu *v);
403 void domain_pause(struct domain *d);
404 void vcpu_unpause(struct vcpu *v);
405 void domain_unpause(struct domain *d);
406 void domain_pause_by_systemcontroller(struct domain *d);
407 void domain_unpause_by_systemcontroller(struct domain *d);
408 void cpu_init(void);
410 static inline void vcpu_unblock(struct vcpu *v)
411 {
412 if ( test_and_clear_bit(_VCPUF_blocked, &v->vcpu_flags) )
413 domain_wake(v);
414 }
416 #define IS_PRIV(_d) \
417 (test_bit(_DOMF_privileged, &(_d)->domain_flags))
418 #define IS_CAPABLE_PHYSDEV(_d) \
419 (test_bit(_DOMF_physdev_access, &(_d)->domain_flags))
421 #define VM_ASSIST(_d,_t) (test_bit((_t), &(_d)->vm_assist))
423 #endif /* __SCHED_H__ */
425 /*
426 * Local variables:
427 * mode: C
428 * c-set-style: "BSD"
429 * c-basic-offset: 4
430 * tab-width: 4
431 * indent-tabs-mode: nil
432 * End:
433 */