next up previous
Next: Messaging system Up: Solution description Previous: The system call set

Tasks and threads

All the processing (even interrupt handling!) in a Sartoris based system is performed in the context of a task, and a thread within that task. A task is loaded into memory upon it's creation, and remains in main memory until it is terminated. No swapping of tasks is directly supported3.

A task is composed by a flat virtual address space and communication mechanisms (ports and shared memory objects) and is identified by a number between zero and MAX_TSK4, which is the parameter address passed to the system call create_task(int address, struct task *tsk, int *src, int init_size), where *src points to the beginning of the task image within the calling task's address space, and *tsk points to a structure of the type

struct task {
int mem_adr;
int size;
int priv_level;
};

where mem_adr indicates the physical address where this task should be placed in main memory5, size indicates the size (in processor words) of the task being created, and priv_level indicates it's privilege level. This number might be used by the operating system to restrict the ability to send messages to ports and to run specific threads using privilege levels. Zero is the most privileged level, and levels zero and one are currently the only levels that can access the input$/$output space. Also, the system calls to create and destroy tasks, threads and interrupt handlers are restricted to tasks running in privilege level zero. The system call ret_from_int is restricted to levels zero and one. Tasks are destroyed using the similar function destroy_task, which receives the address of the task being destroyed.

A thread is a path of execution within a given task. A task might have zero or more threads. Threads are created using the system call create_thread(int id, struct thread *thr). The parameter id is an integer that uniquely identifies each thread, and must not exceed MAX_THR-1. The structure thread is defined as

struct thread {
int task_num;
int invoke_mode;
int invoke_level;
int ep;
int stack;
};

where task_num is the task that defines the context in which this thread is to be created (which must already exist), ep is the thread's entry point, stack is the initial stack value, and invoke mode is one of the following:

PERM_REQ: In this mode, it is necessary (additionally to the privilege level constraints) to have specific authorization (obtained through the function set_thread_run_perm) to run this thread.
PRIV_LEVEL_ONLY: In this mode, the invoking thread must have a privilege level numerically not greater than the invoke_level of the target thread. No per-thread specific permissions are required in this mode, only the described privilege-level restriction is applied.
DISABLED: The thread is disabled, and it can't be invoked by anyone.
The value of the field invoke_level indicates the numerically higher privilege level that can invoke this thread.

Threads are destroyed using the destroy_thread system call, and may be started (or resumed) by interrupt requests signaled to the processor, software generated interrupts, exceptions, traps and the already mentioned run_thread system call.

As a non-restrictive policy, the run_thread system call can be used by threads running at every privilege level, but the mechanisms described above restrict which threads might be invoked from a given thread-task pair. A thread is able to modify it's invoke_mode using the set_thread_run_mode system call.


next up previous
Next: Messaging system Up: Solution description Previous: The system call set
2002-09-17