创建线程create_thread()
创建进程可参考l4ka-pistachio-cb2d287364bc/user/apps/l4test/threads.cc:
create_thread (bool new_space, int cpu)
{      
       static L4_Fpage_t kip_area, utcb_area;
       static L4_Word_t utcb_base;
       static bool initialized = false;
       static void  kip;
       if (! initialized)
       {
           kip = L4_KernelInterface ();
       
           // Put the kip at the same location in all address spaces
           // to make sure we can reuse the syscall jump table.
           kip_area = L4_FpageLog2 ((L4_Word_t) kip, L4_KipAreaSizeLog2 (kip));
       
           L4_ThreadId_t mylocalid = L4_MyLocalId ();
           utcb_base = (L4_Word_t ) &mylocalid;
           utcb_base &= ~(L4_UtcbAreaSize (kip) - 1);
           // Make room for at least 1000 threads in the UTCB area
           utcb_area = L4_Fpage (utcb_base, L4_UtcbSize (kip)  1000);
       
           initialized = true;
       }
如果没有初始化,会先获得kip、kip_area、utcb_base、utcb_area这四个变量,后面创建thread时会用到。
在IA-32体系下,L4_MylocalId()返回的local_id正好是当前thread的utcb起始地址(类似Linux将sp设置为task struct末端),gs:[0]指向UTCB address,偏移 -60 的位置存储的是 MyGlobalId,参见“L4 eXperimental Kernel Reference Manual (Version X.2)A.1 Virtual Registers(TCRS)”。
L4的UTCB有点类似Windows中的TEB(Thread Environment Block),先预留一片空间,每当新创建线程时,在这片空间(看作UTCB或TEB结构体的数组)中分配一项。
接下来要分配新的tid号:
       L4_ThreadId_t me = L4_Myself ();
       L4_ThreadId_t tid = get_new_tid ();
       
get_new_tid (void)
{
       static L4_Word_t next_no = 0;
       if (next_no == 0)
           // Initialize with my thread_no + 1
           next_no = L4_ThreadNo (L4_MyGlobalId ()) + 1;
       return L4_GlobalId (next_no++, 1);
}
可以看到新分配的tid号一定会比当前roottask的GlobalId号大,这是L4内核的规定,参考“L4 eXperimental Kernel Reference Manual (Version X.2)2.1 ThreadId”
tid得到后,计算新线程的utcb地址,这样计算所有线程的utcb决不会重叠:
       L4_Word_t utcb_location =
           utcb_base + L4_UtcbSize (kip)  L4_ThreadNo (tid);
如果创建的线程将运行于新的address space,将分三步走。第一次L4_ThreadControl时内核将创建一个address space为空的线程结构体,然后L4_SpaceControl为该thread指定kip和utcb,最后第二次L4_ThreadControl让该线程变为active状态。
        if (new_space)
       {
           // Create inactive thread
           int res = L4_ThreadControl (tid, tid, me, L4_nilthread, (void ) -1);
           if (res != 1)
               printf ("ERROR: ThreadControl returned %dn", res);
           L4_Word_t control;
           res = L4_SpaceControl (tid, 0, kip_area, utcb_area,
                                  L4_nilthread, &control);
           if (res != 1)
               printf ("ERROR: SpaceControl returned %dn", res);
           // Activate thread
           res = L4_ThreadControl (tid, tid, me, me, (void ) utcb_location);
           if (res != 1)
               printf ("ERROR: ThreadControl returned %dn", res);
       }
如果线程运行在同一个address space,工作更简单
       else
       {
           // Create active thread
           int res = L4_ThreadControl (tid, me, me, me, (void ) utcb_location);
           if (res != 1)
               printf ("ERROR: ThreadControl returned %dn", res);
       }
最后设置一下运行的CPU,一个thread就创建好了
       if (cpu != -1)
           L4_Set_ProcessorNo (tid, cpu);
       return tid;
}
运行线程start_thread()
void
start_thread( L4_ThreadId_t tid, L4_Word_t ip, L4_Word_t sp )
{
           L4_Msg_t msg;
           L4_Clear( &msg );
           L4_Append( &msg, ip );
           L4_Append( &msg, sp );
           L4_Load( &msg );
           L4_Send( tid );
}
运行一个线程只需向该线程发送一个ipc,ipc参数包括线程运行时的入口点ip、堆栈sp
注意:这个ipc必须由待运行线程的pager发送才有效!
一个简单的example
L4_ThreadId_t thread1;
L4_ThreadId_t thread2;
int n_switch;
void func1() 
{
       L4_Clock_t usec1;
       L4_Clock_t usec2;
       printf("start thread1n");
//  L4_Sleep (L4_TimePeriod (10001000));
       
       usec1 = L4_SystemClock();
       for(int i = 0; i < 300; i++)
           L4_ThreadSwitch(thread2);
       
       usec2 = L4_SystemClock();
       printf("usec1 %un", usec1.raw);
       printf("usec2 %un", usec2.raw);
       printf("delta %un", usec2.raw - usec1.raw);
       printf("average thread switch time: %fn", (double)(usec2.raw - usec1.raw) / 2000);
       printf("n_switch: %dn", n_switch);
}
void func2() 
{
       printf("start thread2n");
       while(true)
       {
//        L4_ThreadSwitch(L4_nilthread);
           L4_ThreadSwitch(thread1);
           n_switch++;
       }
}
int main()
{
       thread1 = create_thread(false, 0);
       thread2 = create_thread(false, 0);
       n_switch = 0;
       printf("in mainn");
       // Touch the memory to make sure we never get pagefaults
       extern L4_Word_t _end, _start;
       for (L4_Word_t  x = (&_start); x < &_end; x++)
       {
          volatile L4_Word_t q;
          q = (volatile L4_Word_t) x;
       }
       
       start_thread(thread2, func2); 
       start_thread(thread1, func1); 
       L4_Sleep(L4_Never);
}end