threading: faster interrupt safe frame/binding stack manipulations
Only use one memory barrier for pushing in the frame/binding stack
and ensure interrupt safety by saving/restoring the stack frame in
which writes could happen during an interrupt.
This commit is contained in:
parent
319b7ef79b
commit
a7353369ea
3 changed files with 33 additions and 47 deletions
|
|
@ -322,15 +322,10 @@ ecl_bds_bind(cl_env_ptr env, cl_object s, cl_object v)
|
|||
}
|
||||
location = env->thread_local_bindings + index;
|
||||
slot = env->bds_top+1;
|
||||
if (slot >= env->bds_limit){
|
||||
slot = ecl_bds_overflow();
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
} else {
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->bds_top;
|
||||
}
|
||||
if (slot >= env->bds_limit) slot = ecl_bds_overflow();
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->bds_top;
|
||||
ecl_disable_interrupts_env(env);
|
||||
slot->symbol = s;
|
||||
slot->value = *location;
|
||||
|
|
@ -359,15 +354,10 @@ ecl_bds_push(cl_env_ptr env, cl_object s)
|
|||
}
|
||||
location = env->thread_local_bindings + index;
|
||||
slot = env->bds_top+1;
|
||||
if (slot >= env->bds_limit){
|
||||
slot = ecl_bds_overflow();
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
} else {
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->bds_top;
|
||||
}
|
||||
if (slot >= env->bds_limit) slot = ecl_bds_overflow();
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->bds_top;
|
||||
ecl_disable_interrupts_env(env);
|
||||
slot->symbol = s;
|
||||
slot->value = *location;
|
||||
|
|
@ -565,16 +555,13 @@ _ecl_frs_push(register cl_env_ptr env)
|
|||
* needed to ensure that the CPU doesn't reorder the memory
|
||||
* stores. */
|
||||
ecl_frame_ptr output = env->frs_top+1;
|
||||
if (output >= env->frs_limit){
|
||||
if (output >= env->frs_limit) {
|
||||
frs_overflow();
|
||||
output = env->frs_top;
|
||||
output->frs_val = ECL_DUMMY_TAG;
|
||||
} else {
|
||||
output->frs_val = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->frs_top;
|
||||
output = env->frs_top+1;
|
||||
}
|
||||
output->frs_val = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->frs_top;
|
||||
output->frs_bds_top_index = env->bds_top - env->bds_org;
|
||||
output->frs_ihs = env->ihs_top;
|
||||
output->frs_sp = ECL_STACK_INDEX(env);
|
||||
|
|
|
|||
|
|
@ -378,8 +378,7 @@ handle_all_queued_interrupt_safe(cl_env_ptr env)
|
|||
/* We have to save and later restore thread-local variables to
|
||||
* ensure that they don't get overwritten by the interrupting
|
||||
* code */
|
||||
/* INV: - Frame, Binding and IHS stack manipulations are
|
||||
* interrupt safe
|
||||
/* INV: - IHS stack manipulations are interrupt safe
|
||||
* - The rest of the thread local variables are
|
||||
* guaranteed to be used in an interrupt safe way. This
|
||||
* is not true for the compiler environment and ffi
|
||||
|
|
@ -397,9 +396,19 @@ handle_all_queued_interrupt_safe(cl_env_ptr env)
|
|||
* stack. Increasing env->stack_top ensures that we don't
|
||||
* overwrite the topmost stack value. */
|
||||
env->stack_top++;
|
||||
/* Finally we can handle the queued signals */
|
||||
/* We also need to save and restore the (top+1)'th frame and
|
||||
* binding stack value to prevent overwriting it.
|
||||
* INV: Due to the stack safety areas we don't need to check
|
||||
* for env->frs/bds_limit */
|
||||
struct ecl_frame top_frame;
|
||||
memcpy(&top_frame, env->frs_top+1, sizeof(struct ecl_frame));
|
||||
struct ecl_bds_frame top_binding;
|
||||
memcpy(&top_binding, env->bds_top+1, sizeof(struct ecl_bds_frame));
|
||||
/* Finally we can handle the queued signals ... */
|
||||
handle_all_queued(env);
|
||||
/* And restore thread local variables again */
|
||||
/* ... and restore everything again */
|
||||
memcpy(env->bds_top+1, &top_binding, sizeof(struct ecl_bds_frame));
|
||||
memcpy(env->frs_top+1, &top_frame, sizeof(struct ecl_frame));
|
||||
env->stack_top--;
|
||||
env->packages_to_be_created_p = packages_to_be_created_p;
|
||||
env->packages_to_be_created = packages_to_be_created;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ extern "C" {
|
|||
* handler. This can be achieved by either increasing the stack
|
||||
* pointer temporarily during the execution of the interrupt code
|
||||
* or by saving/restoring the topmost stack value. However due to
|
||||
* the second requirement, this simple method is only possible
|
||||
* the second requirement, this simple method is sufficient only
|
||||
* for the arguments stack.
|
||||
* The second requirement requires the stack to be in a consistent
|
||||
* state during the interrupt. The easiest solution would be to
|
||||
|
|
@ -117,18 +117,13 @@ static inline void ecl_bds_bind_inl(cl_env_ptr env, cl_object s, cl_object v)
|
|||
} else {
|
||||
location = env->thread_local_bindings + index;
|
||||
slot = env->bds_top+1;
|
||||
if (slot >= env->bds_limit){
|
||||
slot = ecl_bds_overflow();
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
} else {
|
||||
/* First, we push a dummy symbol in the stack to
|
||||
* prevent segfaults when we are interrupted with a
|
||||
* call to ecl_bds_unwind. */
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->bds_top;
|
||||
}
|
||||
if (slot >= env->bds_limit) slot = ecl_bds_overflow();
|
||||
/* First, we push a dummy symbol in the stack to
|
||||
* prevent segfaults when we are interrupted with a
|
||||
* call to ecl_bds_unwind. */
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->bds_top;
|
||||
/* Then we disable interrupts to ensure that
|
||||
* ecl_bds_unwind doesn't overwrite the symbol with
|
||||
* some random value. */
|
||||
|
|
@ -160,15 +155,10 @@ static inline void ecl_bds_push_inl(cl_env_ptr env, cl_object s)
|
|||
} else {
|
||||
location = env->thread_local_bindings + index;
|
||||
slot = env->bds_top+1;
|
||||
if (slot >= env->bds_limit){
|
||||
slot = ecl_bds_overflow();
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
} else {
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->bds_top;
|
||||
}
|
||||
if (slot >= env->bds_limit) slot = ecl_bds_overflow();
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->bds_top;
|
||||
ecl_disable_interrupts_env(env);
|
||||
slot->symbol = s;
|
||||
slot->value = *location;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue