| 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.
|