Multiple updates on sleeping, vma dropping and thread suspend.

- Updated sleeping paths such that a task is atomically put into
  a runqueue and made RUNNABLE, or removed from a runqueue and made SLEEPING.
- Modified vma dropping sources to handle both copy_on_write() and exit() cases
  in a common function.
- Added the first infrastructure to have a pager to suspend a task and wait for
  suspend completion from the scheduler.
This commit is contained in:
Bahadir Balban
2008-10-13 12:22:10 +03:00
parent f6d0a79298
commit 0db0f7e334
23 changed files with 416 additions and 200 deletions

View File

@@ -82,6 +82,7 @@ int ipc_send(l4id_t recv_tid)
/* Remove from waitqueue */
list_del_init(&wq->task_list);
wqhr->sleepers--;
task_unset_wqh(receiver);
/* Release locks */
spin_unlock(&wqhr->slock);
@@ -103,7 +104,7 @@ int ipc_send(l4id_t recv_tid)
wqhs->sleepers++;
list_add_tail(&wq.task_list, &wqhs->task_list);
task_set_wqh(current, wqhs, &wq);
current->state = TASK_SLEEPING;
sched_prepare_sleep();
spin_unlock(&wqhr->slock);
spin_unlock(&wqhs->slock);
// printk("%s: (%d) waiting for (%d)\n", __FUNCTION__,
@@ -168,7 +169,7 @@ int ipc_recv(l4id_t senderid)
wqhr->sleepers++;
list_add_tail(&wq.task_list, &wqhr->task_list);
task_set_wqh(current, wqhr, &wq);
current->state = TASK_SLEEPING;
sched_prepare_sleep();
// printk("%s: (%d) waiting for (%d)\n", __FUNCTION__,
// current->tid, current->expected_sender);
spin_unlock(&wqhr->slock);

View File

@@ -87,8 +87,8 @@ void do_exchange_registers(struct ktcb *task, struct exregs_data *exregs)
* the register context of a thread. The thread's registers can be
* set only when the thread is in user mode. A newly created thread
* that is the copy of another thread (forked or cloned) will also
* be given its user mode context so such threads can also be
* modified by this call before execution.
* be given its user mode context on the first chance to execute so
* such threads can also be modified by this call before execution.
*
* A thread executing in the kernel cannot be modified since this
* would compromise the kernel. Also the thread must be in suspended

View File

@@ -10,6 +10,7 @@
#include <l4/generic/tcb.h>
#include <l4/lib/idpool.h>
#include <l4/lib/mutex.h>
#include <l4/lib/wait.h>
#include <l4/generic/pgalloc.h>
#include INC_ARCH(asm.h)
#include INC_SUBARCH(mm.h)
@@ -20,8 +21,68 @@ int sys_thread_switch(syscall_context_t *regs)
return 0;
}
/*
* This suspends a thread which is in either suspended,
* sleeping or runnable state.
*/
int thread_suspend(struct task_ids *ids)
{
struct ktcb *task;
int ret;
if (!(task = find_task(ids->tid)))
return -ESRCH;
if (task->state == TASK_INACTIVE)
return 0;
/* First show our intention to suspend thread */
task->flags |= TASK_SUSPENDING;
/*
* Interrupt the task in case it was sleeping
* so that it will be caught and suspended by
* the scheduler.
*/
wake_up_task(task, 1);
/* Wait until scheduler wakes us up */
WAIT_EVENT(&task->wqh_pager,
task->state == TASK_INACTIVE, ret);
return ret;
}
int thread_destroy(struct task_ids *ids)
{
struct ktcb *task;
int ret;
if (!(task = find_task(ids->tid)))
return -ESRCH;
if ((ret = thread_suspend(ids)) < 0)
return ret;
/* Delete it from global list so any callers will get -ESRCH */
list_del(&task->task_list);
/*
* If there are any sleepers on any of the task's
* waitqueues, we need to wake those tasks up.
*/
wake_up_all(&task->wqh_send, 0);
wake_up_all(&task->wqh_recv, 0);
/*
* The thread cannot have a pager waiting for it
* since we ought to be the pager.
*/
BUG_ON(task->wqh_pager.sleepers > 0);
/* We can now safely delete the task */
free_page(task);
return 0;
}
@@ -257,6 +318,7 @@ out:
/* Initialise ipc waitqueues */
waitqueue_head_init(&new->wqh_send);
waitqueue_head_init(&new->wqh_recv);
waitqueue_head_init(&new->wqh_pager);
arch_setup_new_thread(new, task, flags);
@@ -290,6 +352,8 @@ int sys_thread_control(syscall_context_t *regs)
case THREAD_RESUME:
ret = thread_resume(ids);
break;
case THREAD_DESTROY:
ret = thread_destroy(ids);
default:
ret = -EINVAL;
}