X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fpalacios%2Fvmm_barrier.c;h=7718fc8840f096e916a7c12c6bdc947152ea481c;hb=94429f4b9268cf4d5f86dee5c3d929110811ac80;hp=1115ce0cfc1658f5eeef4e932ef877e5d12e6a5d;hpb=882a72ee6359eb1f28754827a7e41380f275d148;p=palacios.git diff --git a/palacios/src/palacios/vmm_barrier.c b/palacios/src/palacios/vmm_barrier.c index 1115ce0..7718fc8 100644 --- a/palacios/src/palacios/vmm_barrier.c +++ b/palacios/src/palacios/vmm_barrier.c @@ -18,4 +18,168 @@ */ -#include +#include +#include +#include + +int v3_init_barrier(struct v3_vm_info * vm_info) { + struct v3_barrier * barrier = &(vm_info->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_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) { + barrier->active = 1; + acquired = 1; + } + + 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); + } + + + // 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++) { + + // Tricky: If a core is not running then it is safe to ignore it. + // Whenever we transition a core to the RUNNING state we MUST immediately wait on the barrier. + // TODO: Wrap the state transitions in functions that do this automatically + if (vm_info->cores[i].core_run_state != CORE_RUNNING) { + continue; + } + + 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; +} + + + +/* 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; + + // Clear all the cpu flags, so cores will proceed + v3_bitmap_reset(&(barrier->cpu_map)); + + return 0; +} + + +/* + * 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->active == 0) { + return 0; + } + + V3_Print("Core %d waiting at barrier\n", core->vcpu_id); + + /* Barrier has been activated. + * Wait here until it's lowered + */ + + + // set cpu bit in barrier bitmap + v3_bitmap_set(&(barrier->cpu_map), core->vcpu_id); + V3_Print("Core %d bit set as waiting\n", 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; +}