Table of Contents

<< Back to Writing Codezero Applications

Standalone L4 Applications

2.) Management of Threads (Pagers Only)

Pagers are responsible for creating, destroying and managing the execution of threads that they are associated with. As a general rule, each pager is responsible for the set of all threads inside a particular container.

Threads may be created in an existing address space, on a brand new, clean address space, or an address space that has been created as a copy of an existing address space.

Below are example code snippets that achieve various thread manipulation operations.

Thread Creation

 
/* Create a new thread in a new address space */
void thread_new(void)
{
        struct task_ids ids;
        int err;
 
        ids.tid = TASK_ID_INVALID;
        ids.spid = TASK_ID_INVALID;
        ids.tgid = TASK_ID_INVALID;
 
        if ((err = l4_thread_control(THREAD_CREATE | THREAD_NEW_SPACE, &ids)) < 0) {
                 printf("l4_thread_control failed: %d\n", err);
        }
}
 
/* Create a new thread in an existing address space */
void thread_new(struct task_ids *parent)
{
        struct task_ids ids;
        int err;
 
        /* Specify parent ids */
        ids.tid = parent->tid;
        ids.spid = parent->spid;
        ids.tgid = TASK_ID_INVALID;
 
        if ((err = l4_thread_control(THREAD_CREATE | THREAD_SAME_SPACE, &ids)) < 0) {
                 printf("l4_thread_control failed: %d\n", err);
        }
}
 
/* Create a new thread in a new, copied space */
void thread_new(struct task_ids *parent)
{
        struct task_ids ids;
        int err;
 
        /* Specify parent ids */
        ids.tid = parent->tid;
        ids.spid = parent->spid;
        ids.tgid = TASK_ID_INVALID;
 
        if ((err = l4_thread_control(THREAD_CREATE | THREAD_COPY_SPACE, &ids)) < 0) {
                 printf("l4_thread_control failed: %d\n", err);
        }
}

Thread Context Manipulation

 
void thread_manipulate(struct task_ids *new_ids, unsigned long new_stack,
                                   unsigned long utcb_address)
{
        struct exregs_data exregs;
        int err;
 
        memset(&exregs, 0, sizeof(exregs));
 
        /* Set new stack for child */
        exregs_set_stack(&exregs, new_stack);
 
        /* Set child return value to 0 */
        exregs_set_mr(&exregs, MR_RETURN, 0);
 
        /* Set child utcb */
        exregs_set_utcb(&exregs, utcb_address);
 
        /* Do the actual exchange registers call to microkernel */
        if ((err = l4_exchange_registers(&exregs, new_ids->tid)) < 0)
                printf("Exchange registers error: %d\n", err);
}

Operational Model

Note, that l4_thread_control and l4_exchange_registers() are privileged system calls that may only be executed by pagers. In that respect, the operational model in the above system calls are as follows:

  1. In one example, a client thread requests a new thread is created in its own address space via IPC.
  2. The pager handles the request by creating a new thread via l4_thread_control and modifying its context as requested via l4_exchange_registers.
  3. Pager replies back to client that new thread is ready for execution.
  4. Depending on the implementation, the pager may initiate new thread's execution if requested by the client.

In conclusion, the above code snippets are used usually as part of an IPC request/reply pair between the pager on the system and its client.

<< Back to Writing Codezero Applications