The owner of a lock now passes ownership to the first waiting process.

This commit is contained in:
Juan Jose Garcia Ripoll 2012-07-30 22:49:56 +02:00
parent 14d2960135
commit 7a4a98d020
3 changed files with 54 additions and 7 deletions

View file

@ -113,12 +113,15 @@ mp_giveup_lock(cl_object lock)
FEerror_not_owned(lock);
}
if (--lock->lock.counter == 0) {
lock->lock.owner = ECL_NIL;
print_lock("releasing %p\t", lock, lock);
ecl_wakeup_waiters(env, lock, ECL_WAKEUP_ONE);
} else {
print_lock("released %p\t", lock, lock);
}
cl_object first = ecl_waiter_pop(env, lock);;
if (first == ECL_NIL) {
lock->lock.owner = ECL_NIL;
} else {
lock->lock.counter = 1;
lock->lock.owner = first;
ecl_wakeup_process(first);
}
}
ecl_return1(env, ECL_T);
}
@ -158,6 +161,26 @@ mp_get_lock_nowait(cl_object lock)
ecl_return1(env, get_lock_inner(env, lock));
}
static cl_object
own_or_get_lock(cl_env_ptr env, cl_object lock)
{
cl_object output;
cl_object own_process = env->own_process;
ecl_disable_interrupts_env(env);
if (AO_compare_and_swap_full((AO_t*)&(lock->lock.owner),
(AO_t)ECL_NIL, (AO_t)own_process)) {
lock->lock.counter = 1;
output = ECL_T;
print_lock("acquired %p\t", lock, lock);
} else if (lock->lock.owner == own_process) {
output = ECL_T;
} else {
output = ECL_NIL;
}
ecl_enable_interrupts_env(env);
return output;
}
cl_object
mp_get_lock_wait(cl_object lock)
{
@ -166,7 +189,7 @@ mp_get_lock_wait(cl_object lock)
FEerror_not_a_lock(lock);
}
if (get_lock_inner(env, lock) == ECL_NIL) {
ecl_wait_on(env, get_lock_inner, lock);
ecl_wait_on(env, own_or_get_lock, lock);
}
@(return ECL_T)
}

View file

@ -302,6 +302,29 @@ ecl_wait_on(cl_env_ptr env, cl_object (*condition)(cl_env_ptr, cl_object), cl_ob
#endif
}
cl_object
ecl_waiter_pop(cl_env_ptr the_env, cl_object q)
{
cl_object output;
ecl_disable_interrupts_env(the_env);
ecl_get_spinlock(the_env, &q->queue.spinlock);
{
cl_object l;
output = ECL_NIL;
for (l = q->queue.list; l != ECL_NIL; l = ECL_CONS_CDR(l)) {
cl_object p = ECL_CONS_CAR(l);
if (p->process.phase != ECL_PROCESS_INACTIVE &&
p->process.phase != ECL_PROCESS_EXITING) {
output = p;
break;
}
}
}
ecl_giveup_spinlock(&q->queue.spinlock);
ecl_enable_interrupts_env(the_env);
return output;
}
void
ecl_wakeup_waiters(cl_env_ptr the_env, cl_object q, int flags)
{

View file

@ -497,6 +497,7 @@ extern void ecl_giveup_spinlock(cl_object *lock);
extern cl_object ecl_wait_on(cl_env_ptr env, cl_object (*condition)(cl_env_ptr, cl_object), cl_object o);
extern void ecl_wakeup_waiters(cl_env_ptr the_env, cl_object o, int flags);
extern void ecl_wakeup_process(cl_object process);
extern cl_object ecl_waiter_pop(cl_env_ptr the_env, cl_object q);
#endif
/* threads/rwlock.d */