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.


Change to internal v3_yield/yield_cond semantics:
[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 int v3_raise_barrier_nowait(struct v3_vm_info * vm_info, struct guest_info * local_core) {
45     struct v3_barrier * barrier = &(vm_info->barrier);
46     addr_t flag;
47     int acquired = 0;
48
49     int local_vcpu = -1;
50     int i = 0;
51
52     flag = v3_lock_irqsave(barrier->lock);
53
54     if (barrier->active == 0) {
55         barrier->active = 1;
56         acquired = 1;
57     }
58
59     v3_unlock_irqrestore(barrier->lock, flag);
60
61     if (acquired == 0) {
62         /* If we are in a core context and the barrier has already been acquired 
63            we'll be safe and let the other barrier proceed. We will still report an error 
64            though to allow possible cleanups to occur at the call site.
65         */
66         if (local_core != NULL) {
67             v3_wait_at_barrier(local_core);
68         }
69
70         return -1;
71     }
72
73     // If we are raising the barrier from a core context
74     //   we have to mark ourselves blocked first to avoid deadlock
75     if (local_core != NULL) {
76         local_vcpu = local_core->vcpu_id;
77         v3_bitmap_set(&(barrier->cpu_map), local_vcpu);
78     }
79
80
81     // send out interrupts to force exits on all cores
82     for (i = 0; i < vm_info->num_cores; i++) {
83         if (vm_info->cores[i].vcpu_id != local_vcpu) {
84             v3_interrupt_cpu(vm_info, vm_info->cores[i].pcpu_id, 0);
85         }
86     }
87
88     return 0;
89 }
90
91 int v3_wait_for_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core) {
92     struct v3_barrier * barrier = &(vm_info->barrier);
93     int all_blocked = 0;
94     int i = 0;
95
96     if (barrier->active == 0) {
97         return -1;
98     }
99
100     // wait for barrier catch on all cores
101     while (all_blocked == 0) {
102         all_blocked = 1;
103
104         for (i = 0; i < vm_info->num_cores; i++) {
105             
106             // Tricky: If a core is not running then it is safe to ignore it. 
107             // Whenever we transition a core to the RUNNING state we MUST immediately wait on the barrier. 
108             // TODO: Wrap the state transitions in functions that do this automatically
109             if (vm_info->cores[i].core_run_state != CORE_RUNNING) {
110                 continue;
111             }
112
113             if (v3_bitmap_check(&(barrier->cpu_map), i) == 0) {
114                 // There is still a core that is not waiting at the barrier
115                 all_blocked = 0;
116             }
117         }
118
119         if (all_blocked == 1) {
120             break;
121         }
122
123         v3_yield(local_core,-1);
124     }
125
126     return 0;
127 }
128
129
130
131 /* Barrier synchronization primitive
132  *   -- This call will block until all the guest cores are waiting at a common synchronization point
133  *      in a yield loop. The core will block at the sync point until the barrier is lowered.
134  * 
135  *   ARGUMENTS: 
136  *       vm_info -- The VM for which the barrier is being activated
137  *       local_core -- The core whose thread this function is being called from, or NULL 
138  *                     if the calling thread is not associated with a VM's core context
139  */
140
141 int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core) {
142     int ret = 0;
143
144     ret = v3_raise_barrier_nowait(vm_info, local_core);
145
146     if (ret != 0) {
147         return ret;
148     }
149
150     return v3_wait_for_barrier(vm_info, local_core);
151 }
152
153
154
155 /* Lowers a barrier that has already been raised
156  *    guest cores will automatically resume execution 
157  *    once this has been called
158  * 
159  *   TODO: Need someway to check that the barrier is active
160  */
161
162 int v3_lower_barrier(struct v3_vm_info * vm_info) {
163     struct v3_barrier * barrier = &(vm_info->barrier);
164
165     // Clear the active flag, so cores won't wait 
166     barrier->active = 0;
167
168     // Clear all the cpu flags, so cores will proceed
169     v3_bitmap_reset(&(barrier->cpu_map));
170
171     return 0;
172 }
173
174
175 /* 
176  * Syncronization point for guest cores
177  *    -- called as part of the main VMM event loop for each core
178  *    -- if a barrier has been activated then the core will signal  
179  *       it has reached the barrier and sit in a yield loop until the 
180  *       barrier has been lowered
181  */
182 int v3_wait_at_barrier(struct guest_info * core) {
183     struct v3_barrier * barrier = &(core->vm_info->barrier);
184
185     if (barrier->active == 0) {
186         return 0;
187     }
188
189     V3_Print("Core %d waiting at barrier\n", core->vcpu_id);
190
191     /*  Barrier has been activated. 
192      *  Wait here until it's lowered
193      */
194     
195     
196     // set cpu bit in barrier bitmap
197     v3_bitmap_set(&(barrier->cpu_map), core->vcpu_id);
198     V3_Print("Core %d bit set as waiting\n", core->vcpu_id);
199
200     // wait for cpu bit to clear
201     while (v3_bitmap_check(&(barrier->cpu_map), core->vcpu_id)) {
202         v3_yield(core,-1);
203     }
204
205     return 0;
206 }