1 |
2 |
drasko |
Thread Local Storage and UTCB Access
|
2 |
|
|
|
3 |
|
|
In an L4-like microkernel such as Codezero, there needs to be a way of
|
4 |
|
|
accessing the User Thread Control Block (UTCB) in order to push argument
|
5 |
|
|
registers and write the IPC payload. This necessitates a convenient method
|
6 |
|
|
of accessing the thread-specific utcb structure. Here are some of the
|
7 |
|
|
possible methods of accessing a thread local storage in general:
|
8 |
|
|
|
9 |
|
|
1.) Map the private physical TLS page to thread address space at same virtual
|
10 |
|
|
offset, everytime there is a context switch.
|
11 |
|
|
|
12 |
|
|
2.) Keep a global pointer to it. The scheduler updates the pointer to TLS
|
13 |
|
|
upon every context switch.
|
14 |
|
|
|
15 |
|
|
3.) Manage everything by the run-time library in the application. This includes
|
16 |
|
|
the following:
|
17 |
|
|
|
18 |
|
|
* Predefine a fixed TLS table area on the address space.
|
19 |
|
|
* Possibly allocate local thread ids E.g. [1..n]
|
20 |
|
|
* Get current thread id
|
21 |
|
|
* Take a lock (on the TLS table)
|
22 |
|
|
* Lookup the pointer to the TLS block by thread id
|
23 |
|
|
* Release the lock
|
24 |
|
|
* Return that pointer
|
25 |
|
|
|
26 |
|
|
The third one is least flexible solution since it requires management of the
|
27 |
|
|
TLS area, has concurrency issues, and limits the number of TLS areas available.
|
28 |
|
|
|
29 |
|
|
Since UTCB concept is at the heart of Codezero IPC mechanisms, it has to be
|
30 |
|
|
done neatly and flexibly. In that respect lets evaluate solutions:
|
31 |
|
|
|
32 |
|
|
1.) This is most convenient since user applications can simply reference a
|
33 |
|
|
pointer to get their unique TLS. By this approach no need to spend excessive
|
34 |
|
|
memory by using a page per TLS (in case TLS is less than a page). The downside
|
35 |
|
|
is the UTCB region still needs to be defined by a limit in the address space
|
36 |
|
|
and managed by the pager, if not by the application. This is because every UTCB
|
37 |
|
|
shall be part of an array or a table of unique UTCBs.
|
38 |
|
|
|
39 |
|
|
2.) Mapping a per-thread physical page to a fixed virtual address upon a context
|
40 |
|
|
switch is the most flexible, since the pager can simply allocate a physical page
|
41 |
|
|
as new threads come to life, and map this when they run, without managing utcb
|
42 |
|
|
table size. The downside is that a page is wasted per-thread.
|
43 |
|
|
|
44 |
|
|
The solution Codezero uses includes a mixture of both (1) and (2). Upon a
|
45 |
|
|
context switch, a page private to each context is mapped by the pager, but also
|
46 |
|
|
the UTCB pointer is updated to point at an offset in this page. As an example,
|
47 |
|
|
if a UTCB is sized 1/4th of a page, a single page is used by 4 UTCBs. This way,
|
48 |
|
|
the pager needs to manage 4 entries per-private page, utcbs utilise page memory
|
49 |
|
|
fully, and there is no need for a fixed table of utcbs per address space. Of
|
50 |
|
|
course, utcb pages are only shared by threads in the same address space.
|