A better locking scheme for address spaces.

Same shall be done for the tcb list.
This commit is contained in:
Bahadir Balban
2009-11-01 14:32:55 +02:00
parent 003976e99e
commit 83a740f597
4 changed files with 28 additions and 51 deletions

View File

@@ -41,12 +41,7 @@ struct address_space {
struct address_space_list {
struct link list;
/* Lock for list add/removal */
struct spinlock list_lock;
/* Used when delete/creating spaces */
struct mutex ref_lock;
struct mutex lock;
int count;
};
@@ -56,8 +51,6 @@ void address_space_attach(struct ktcb *tcb, struct address_space *space);
struct address_space *address_space_find(l4id_t spid);
void address_space_add(struct address_space *space);
void address_space_remove(struct address_space *space);
void address_space_reference_lock();
void address_space_reference_unlock();
void init_address_space_list(struct address_space_list *space_list);
int check_access(unsigned long vaddr, unsigned long size,
unsigned int flags, int page_in);

View File

@@ -271,30 +271,38 @@ int thread_setup_space(struct ktcb *tcb, struct task_ids *ids, unsigned int flag
struct address_space *space, *new;
int ret = 0;
address_space_reference_lock();
if (flags & TC_SHARE_SPACE) {
mutex_lock(&curcont->space_list.lock);
if (!(space = address_space_find(ids->spid))) {
mutex_unlock(&curcont->space_list.lock);
ret = -ESRCH;
goto out;
}
mutex_lock(&space->lock);
mutex_unlock(&curcont->space_list.lock);
address_space_attach(tcb, space);
mutex_unlock(&space->lock);
}
if (flags & TC_COPY_SPACE) {
else if (flags & TC_COPY_SPACE) {
mutex_lock(&curcont->space_list.lock);
if (!(space = address_space_find(ids->spid))) {
ret = -ESRCH;
goto out;
}
mutex_lock(&space->lock);
if (IS_ERR(new = address_space_create(space))) {
mutex_unlock(&curcont->space_list.lock);
mutex_unlock(&space->lock);
ret = (int)new;
goto out;
}
/* New space id to be returned back to caller */
ids->spid = new->spid;
mutex_unlock(&space->lock);
ids->spid = new->spid; /* Return newid to caller */
address_space_attach(tcb, new);
address_space_add(new);
mutex_unlock(&curcont->space_list.lock);
}
if (flags & TC_NEW_SPACE) {
else if (flags & TC_NEW_SPACE) {
if (IS_ERR(new = address_space_create(0))) {
ret = (int)new;
goto out;
@@ -302,11 +310,12 @@ int thread_setup_space(struct ktcb *tcb, struct task_ids *ids, unsigned int flag
/* New space id to be returned back to caller */
ids->spid = new->spid;
address_space_attach(tcb, new);
mutex_lock(&curcont->space_list.lock);
address_space_add(new);
mutex_unlock(&curcont->space_list.lock);
}
out:
address_space_reference_unlock();
return ret;
}

View File

@@ -20,19 +20,8 @@ void init_address_space_list(struct address_space_list *space_list)
{
memset(space_list, 0, sizeof(*space_list));
mutex_init(&space_list->ref_lock);
spin_lock_init(&space_list->list_lock);
link_init(&space_list->list);
}
void address_space_reference_lock()
{
mutex_lock(&curcont->space_list.ref_lock);
}
void address_space_reference_unlock()
{
mutex_unlock(&curcont->space_list.ref_lock);
mutex_init(&space_list->lock);
}
void address_space_attach(struct ktcb *tcb, struct address_space *space)
@@ -45,38 +34,24 @@ struct address_space *address_space_find(l4id_t spid)
{
struct address_space *space;
spin_lock(&curcont->space_list.list_lock);
list_foreach_struct(space, &curcont->space_list.list, list) {
if (space->spid == spid) {
spin_unlock(&curcont->space_list.list_lock);
list_foreach_struct(space, &curcont->space_list.list, list)
if (space->spid == spid)
return space;
}
}
spin_unlock(&curcont->space_list.list_lock);
return 0;
}
void address_space_add(struct address_space *space)
{
spin_lock(&curcont->space_list.list_lock);
BUG_ON(!list_empty(&space->list));
list_insert(&space->list, &curcont->space_list.list);
BUG_ON(!++curcont->space_list.count);
spin_unlock(&curcont->space_list.list_lock);
}
void address_space_remove(struct address_space *space)
{
spin_lock(&curcont->space_list.list_lock);
/*
* If current is quitting as the last task of this space,
* its tcb may already be removed, and this is fine
*/
BUG_ON(list_empty(&space->list) && space != current->space);
BUG_ON(list_empty(&space->list));
BUG_ON(--curcont->space_list.count < 0);
list_remove_init(&space->list);
spin_unlock(&curcont->space_list.list_lock);
}
/* Assumes address space reflock is already held */

View File

@@ -77,21 +77,21 @@ void tcb_delete(struct ktcb *tcb)
BUG_ON(tcb->waiting_on);
BUG_ON(tcb->wq);
/*
* Take this lock as we may delete
* the address space as well
*/
address_space_reference_lock();
mutex_lock(&curcont->space_list.lock);
mutex_lock(&tcb->space->lock);
BUG_ON(--tcb->space->ktcb_refs < 0);
/* No refs left for the space, delete it */
if (tcb->space->ktcb_refs == 0) {
address_space_remove(tcb->space);
mutex_unlock(&tcb->space->lock);
address_space_delete(tcb->space);
mutex_unlock(&curcont->space_list.lock);
} else {
mutex_unlock(&tcb->space->lock);
mutex_unlock(&curcont->space_list.lock);
}
address_space_reference_unlock();
/* Deallocate tcb ids */
id_del(&kernel_resources.ktcb_ids, tcb->tid);