Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


fix barrier hang w/ unitialized secondary cores
[palacios.git] / palacios / src / palacios / vmm_barrier.c
1 /*
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2011, Jack Lange <jacklange@cs.pitt.edu> 
11  * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jacklangel@cs.pitt.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21 #include <palacios/vmm_barrier.h>
22 #include <palacios/vmm.h>
23 #include <palacios/vm_guest.h>
24
25 int v3_init_barrier(struct v3_vm_info * vm_info) {
26     struct v3_barrier * barrier = &(vm_info->barrier);
27
28     memset(barrier, 0, sizeof(struct v3_barrier));
29     v3_bitmap_init(&(barrier->cpu_map), vm_info->num_cores); 
30     v3_lock_init(&(barrier->lock));
31
32     return 0;
33 }
34
35 int v3_deinit_barrier(struct v3_vm_info * vm_info) {
36     struct v3_barrier * barrier = &(vm_info->barrier);
37
38     v3_bitmap_deinit(&(barrier->cpu_map));
39     v3_lock_deinit(&(barrier->lock));
40
41     return 0;
42 }
43
44
45 /* Barrier synchronization primitive
46  *   -- This call will block until all the guest cores are waiting at a common synchronization point
47  *      in a yield loop. The core will block at the sync point until the barrier is lowered.
48  * 
49  *   ARGUMENTS: 
50  *       vm_info -- The VM for which the barrier is being activated
51  *       local_core -- The core whose thread this function is being called from, or NULL 
52  *                     if the calling thread is not associated with a VM's core context
53  */
54
55 int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core) {
56     struct v3_barrier * barrier = &(vm_info->barrier);
57     addr_t flag;
58     int acquired = 0;
59     int all_blocked = 0;
60
61     int local_vcpu = -1;
62     int i = 0;
63
64
65
66     flag = v3_lock_irqsave(barrier->lock);
67
68     if (barrier->active == 0) {
69         barrier->active = 1;
70         acquired = 1;
71     }
72
73     v3_unlock_irqrestore(barrier->lock, flag);
74
75     if (acquired == 0) {
76         /* If we are in a core context and the barrier has already been acquired 
77            we'll be safe and let the other barrier proceed. We will still report an error 
78            though to allow possible cleanups to occur at the call site.
79         */
80         if (local_core != NULL) {
81             v3_wait_at_barrier(local_core);
82         }
83
84         return -1;
85     }
86
87     // If we are raising the barrier from a core context
88     //   we have to mark ourselves blocked first to avoid deadlock
89     if (local_core != NULL) {
90         local_vcpu = local_core->vcpu_id;
91         v3_bitmap_set(&(barrier->cpu_map), local_vcpu);
92     }
93
94
95     // send out interrupts to force exits on all cores
96     for (i = 0; i < vm_info->num_cores; i++) {
97         if (vm_info->cores[i].vcpu_id != local_vcpu) {
98             v3_interrupt_cpu(vm_info, vm_info->cores[i].pcpu_id, 0);
99         }
100     }
101
102     // wait for barrier catch on all cores
103     while (all_blocked == 0) {
104         all_blocked = 1;
105
106         for (i = 0; i < vm_info->num_cores; i++) {
107             
108             // Tricky: If a core is not running then it is safe to ignore it. 
109             // Whenever we transition a core to the RUNNING state we MUST immediately wait on the barrier. 
110             // TODO: Wrap the state transitions in functions that do this automatically
111             if (vm_info->cores[i].core_run_state != CORE_RUNNING) {
112                 continue;
113             }
114
115             if (v3_bitmap_check(&(barrier->cpu_map), i) == 0) {
116                 // There is still a core that is not waiting at the barrier
117                 all_blocked = 0;
118             }
119         }
120
121         if (all_blocked == 1) {
122             break;
123         }
124
125         v3_yield(local_core);
126     }
127
128
129     return 0;
130 }
131
132
133
134 /* Lowers a barrier that has already been raised
135  *    guest cores will automatically resume execution 
136  *    once this has been called
137  * 
138  *   TODO: Need someway to check that the barrier is active
139  */
140
141 int v3_lower_barrier(struct v3_vm_info * vm_info) {
142     struct v3_barrier * barrier = &(vm_info->barrier);
143
144     // Clear the active flag, so cores won't wait 
145     barrier->active = 0;
146
147     // Clear all the cpu flags, so cores will proceed
148     v3_bitmap_reset(&(barrier->cpu_map));
149
150     return 0;
151 }
152
153
154 /* 
155  * Syncronization point for guest cores
156  *    -- called as part of the main VMM event loop for each core
157  *    -- if a barrier has been activated then the core will signal  
158  *       it has reached the barrier and sit in a yield loop until the 
159  *       barrier has been lowered
160  */
161 int v3_wait_at_barrier(struct guest_info * core) {
162     struct v3_barrier * barrier = &(core->vm_info->barrier);
163
164     if (barrier->active == 0) {
165         return 0;
166     }
167
168     V3_Print("Core %d waiting at barrier\n", core->vcpu_id);
169
170     /*  Barrier has been activated. 
171      *  Wait here until it's lowered
172      */
173     
174     
175     // set cpu bit in barrier bitmap
176     v3_bitmap_set(&(barrier->cpu_map), core->vcpu_id);
177     V3_Print("Core %d bit set as waiting\n", core->vcpu_id);
178
179     // wait for cpu bit to clear
180     while (v3_bitmap_check(&(barrier->cpu_map), core->vcpu_id) == 1) {
181         v3_yield(core);
182     }
183
184     return 0;
185 }