X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fpalacios%2Fvmm_barrier.c;h=a94e40f157eb5d82c2b370886ce2022eb2d73d85;hb=6fa605075d1944da0a88a389122ea24bbc583329;hp=ab0aae42a4bb2704a3368c2c5e0fbd620ccf8ac6;hpb=9a9c14099c09e9ed86d8ac2f73f7406d0ac8a90b;p=palacios.git diff --git a/palacios/src/palacios/vmm_barrier.c b/palacios/src/palacios/vmm_barrier.c index ab0aae4..a94e40f 100644 --- a/palacios/src/palacios/vmm_barrier.c +++ b/palacios/src/palacios/vmm_barrier.c @@ -41,28 +41,14 @@ int v3_deinit_barrier(struct v3_vm_info * vm_info) { 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) { +int v3_raise_barrier_nowait(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) { @@ -99,11 +85,31 @@ int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core } } + return 0; +} + +int v3_wait_for_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core) { + struct v3_barrier * barrier = &(vm_info->barrier); + int all_blocked = 0; + int i = 0; + + if (barrier->active == 0) { + return -1; + } + // 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; @@ -114,15 +120,45 @@ int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core break; } - v3_yield(local_core); + // return immediately and spin if there is no one to yield to + v3_yield(local_core,-1); } - 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) { + int ret = 0; + + + if ((vm_info->run_state != VM_RUNNING) && + (vm_info->run_state != VM_SIMULATING)) { + return 0; + } + + ret = v3_raise_barrier_nowait(vm_info, local_core); + + if (ret != 0) { + return ret; + } + + return v3_wait_for_barrier(vm_info, local_core); +} + + + /* Lowers a barrier that has already been raised * guest cores will automatically resume execution * once this has been called @@ -133,6 +169,12 @@ int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core int v3_lower_barrier(struct v3_vm_info * vm_info) { struct v3_barrier * barrier = &(vm_info->barrier); + + if ((vm_info->run_state != VM_RUNNING) && + (vm_info->run_state != VM_SIMULATING)) { + return 0; + } + // Clear the active flag, so cores won't wait barrier->active = 0; @@ -156,6 +198,15 @@ int v3_wait_at_barrier(struct guest_info * core) { if (barrier->active == 0) { return 0; } +#ifndef V3_CONFIG_FP_SWITCH + v3_get_fp_state(core); // snapshot FP state now +#else +# ifdef V3_CONFIG_LAZY_FP_SWITCH + v3_get_fp_state(core); // snapshot FP state now regardless of lazy eval +# endif +#endif + + V3_Print(core->vm_info, core, "Core %d waiting at barrier\n", core->vcpu_id); /* Barrier has been activated. * Wait here until it's lowered @@ -164,11 +215,21 @@ int v3_wait_at_barrier(struct guest_info * core) { // set cpu bit in barrier bitmap v3_bitmap_set(&(barrier->cpu_map), core->vcpu_id); + V3_Print(core->vm_info, core, "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); + while (v3_bitmap_check(&(barrier->cpu_map), core->vcpu_id)) { + // Barrier wait will spin if there is no competing work + v3_yield(core,-1); } +#ifndef V3_CONFIG_FP_SWITCH + core->fp_state.need_restore=1; // restore FP on next entry +#else +# ifdef V3_CONFIG_LAZY_FP_SWITCH + core->fp_state.need_restore=1; // restore FP on next entry +# endif +#endif + return 0; }