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.


added barrier synchronization and integrated it with pause/continue functionality
[palacios.git] / palacios / src / palacios / vmm_barrier.c
index 614ceca..ab0aae4 100644 (file)
  */
 
 
-#include <util/vmm_barrier.h>
+#include <palacios/vmm_barrier.h>
+#include <palacios/vmm.h>
+#include <palacios/vm_guest.h>
 
+int v3_init_barrier(struct v3_vm_info * vm_info) {
+    struct v3_barrier * barrier = &(vm_info->barrier);
 
-
-int v3_init_barrier(struct v3_barrier * barrier) {
     memset(barrier, 0, sizeof(struct v3_barrier));
+    v3_bitmap_init(&(barrier->cpu_map), vm_info->num_cores); 
     v3_lock_init(&(barrier->lock));
 
     return 0;
 }
 
+int v3_deinit_barrier(struct v3_vm_info * vm_info) {
+    struct v3_barrier * barrier = &(vm_info->barrier);
+
+    v3_bitmap_deinit(&(barrier->cpu_map));
+    v3_lock_deinit(&(barrier->lock));
+
+    return 0;
+}
+
+
+/* Barrier synchronization primitive
+ *   -- This call will block until all the guest cores are waiting at a common synchronization point
+ *      in a yield loop. The core will block at the sync point until the barrier is lowered.
+ * 
+ *   ARGUMENTS: 
+ *       vm_info -- The VM for which the barrier is being activated
+ *       local_core -- The core whose thread this function is being called from, or NULL 
+ *                     if the calling thread is not associated with a VM's core context
+ */
 
-int v3_activate_barrier(struct guest_info * core, struct v3_barrier * barrier) {
+int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core) {
+    struct v3_barrier * barrier = &(vm_info->barrier);
     addr_t flag;
     int acquired = 0;
-    
+    int all_blocked = 0;
+
+    int local_vcpu = -1;
+    int i = 0;
+
+
+
     flag = v3_lock_irqsave(barrier->lock);
 
     if (barrier->active == 0) {
@@ -44,11 +73,49 @@ int v3_activate_barrier(struct guest_info * core, struct v3_barrier * barrier) {
     v3_unlock_irqrestore(barrier->lock, flag);
 
     if (acquired == 0) {
+       /* If we are in a core context and the barrier has already been acquired 
+          we'll be safe and let the other barrier proceed. We will still report an error 
+          though to allow possible cleanups to occur at the call site.
+       */
+       if (local_core != NULL) {
+           v3_wait_at_barrier(local_core);
+       }
+
        return -1;
     }
 
+    // If we are raising the barrier from a core context
+    //   we have to mark ourselves blocked first to avoid deadlock
+    if (local_core != NULL) {
+       local_vcpu = local_core->vcpu_id;
+       v3_bitmap_set(&(barrier->cpu_map), local_vcpu);
+    }
+
 
-    // wait for barrier catch
+    // send out interrupts to force exits on all cores
+    for (i = 0; i < vm_info->num_cores; i++) {
+       if (vm_info->cores[i].vcpu_id != local_vcpu) {
+           v3_interrupt_cpu(vm_info, vm_info->cores[i].pcpu_id, 0);
+       }
+    }
+
+    // wait for barrier catch on all cores
+    while (all_blocked == 0) {
+       all_blocked = 1;
+
+       for (i = 0; i < vm_info->num_cores; i++) {
+           if (v3_bitmap_check(&(barrier->cpu_map), i) == 0) {
+               // There is still a core that is not waiting at the barrier
+               all_blocked = 0;
+           }
+       }
+
+       if (all_blocked == 1) {
+           break;
+       }
+
+       v3_yield(local_core);
+    }
 
 
     return 0;
@@ -56,20 +123,52 @@ int v3_activate_barrier(struct guest_info * core, struct v3_barrier * barrier) {
 
 
 
+/* Lowers a barrier that has already been raised
+ *    guest cores will automatically resume execution 
+ *    once this has been called
+ * 
+ *   TODO: Need someway to check that the barrier is active
+ */
+
+int v3_lower_barrier(struct v3_vm_info * vm_info) {
+    struct v3_barrier * barrier = &(vm_info->barrier);
+
+    // Clear the active flag, so cores won't wait 
+    barrier->active = 0;
 
-int v3_deactivate_barrier(struct v3_barrier * barrier) {
+    // Clear all the cpu flags, so cores will proceed
+    v3_bitmap_reset(&(barrier->cpu_map));
 
+    return 0;
 }
 
 
-int v3_check_barrier(struct guest_info * core, struct v3_barrier * barrier) {
+/* 
+ * Syncronization point for guest cores
+ *    -- called as part of the main VMM event loop for each core
+ *    -- if a barrier has been activated then the core will signal  
+ *       it has reached the barrier and sit in a yield loop until the 
+ *       barrier has been lowered
+ */
+int v3_wait_at_barrier(struct guest_info * core) {
+    struct v3_barrier * barrier = &(core->vm_info->barrier);
 
-    if (barrier->activated == 0) {
+    if (barrier->active == 0) {
        return 0;
     }
+
+    /*  Barrier has been activated. 
+     *  Wait here until it's lowered
+     */
+    
     
-    // set cpu bit
+    // set cpu bit in barrier bitmap
+    v3_bitmap_set(&(barrier->cpu_map), core->vcpu_id);
 
     // wait for cpu bit to clear
+    while (v3_bitmap_check(&(barrier->cpu_map), core->vcpu_id) == 1) {
+       v3_yield(core);
+    }
 
+    return 0;
 }