Introduction   Client Library API Reference   Demo1   Demo2   Demo3   File List   Index  

main.c

00001 
00011 /* (c) 2003 Technische Universitaet Dresden
00012  * This file is part of DROPS, which is distributed under the terms of the
00013  * GNU General Public License 2. Please see the COPYING file for details.
00014  */
00015 
00016 
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <string.h>
00020 
00021 #include <l4/crtx/crt0.h>
00022 #include <l4/log/l4log.h>
00023 #include <l4/names/libnames.h>
00024 #include <l4/rmgr/librmgr.h>
00025 #include <l4/sigma0/sigma0.h>
00026 #include <l4/sys/types.h>
00027 #include <l4/sys/syscalls.h>
00028 #include <l4/sys/ipc.h>
00029 #include <l4/sys/kernel.h>
00030 #include <l4/util/util.h>
00031 #include <l4/util/l4_macros.h>
00032 
00033 #include <l4/events/events.h>
00034 
00035 char LOG_tag[9]="ev_demo2";
00036 
00037 /* the virtual address range of this program */
00038 extern char _end, _start, _stext, _etext;
00039 
00040 /* debug variable, set to nonzero to get more output from the pager*/
00041 static int debugpager = 0;
00042 
00043 /* event_ch used for this demo */
00044 #define DEMO2_EVENTID 9
00045 
00046 /* priority used for this demo */
00047 #define DEMO2_PRIORITY  0
00048 
00049 /* region of acquired task numbers, get initialised in get_tasks */
00050 #define TASK_MAX 3
00051 static int task_min = -1;
00052 static int task_max = -1;
00053 
00054 /* pager thread variables */
00055 #define PAGER_THREAD 1  /* thread number definition */
00056 static l4_threadid_t pager_thread_id = L4_INVALID_ID; /* thread id */
00057 char pager_thread_stack[2048]; /* stack */
00058 
00059 /* varaiables for COW mechanism */
00060 #define COW_POOL_PAGES    2000
00061 static int copied_pages = 0;
00062 static l4_addr_t cow_pool;
00063 static l4_addr_t cow_pages;
00064 static l4_addr_t my_program_data_copy;
00065 
00066 static l4_addr_t unshare_data(l4_addr_t addr, l4_threadid_t tid);
00067 
00068 /* nicely report ipc errors */
00069 static void
00070 ipc_error(char * msg, int error)
00071 {
00072   if(error == 0){
00073     printf("%s : ok\n", msg);
00074   }
00075   else {
00076     if( error == L4_IPC_ENOT_EXISTENT ){
00077       printf("%s : L4_IPC_ENOT_EXISTENT "
00078        "(Non-existing destination or source)\n", msg);
00079     }
00080     if( error == L4_IPC_RETIMEOUT ){
00081       printf("%s : L4_IPC_RETIMEOUT (Timeout during receive)\n", msg);
00082     }
00083     if( error == L4_IPC_SETIMEOUT ){
00084       printf("%s : L4_IPC_SETIMEOUT (Timeout during send)\n", msg);
00085     }
00086     if( error == L4_IPC_RECANCELED ){
00087       printf("%s : L4_IPC_RECANCELED (Receive operation cancelled)\n", msg);
00088     }
00089     if( error == L4_IPC_SECANCELED ){
00090       printf("%s : L4_IPC_SECANCELED (Send operation cancelled)\n", msg);
00091     }
00092     if( error == L4_IPC_REMAPFAILED ){
00093       printf("%s : L4_IPC_REMAPFAILED (Map failed in send)\n", msg);
00094     }
00095     if( error == L4_IPC_SEMAPFAILED ){
00096       printf("%s : L4_IPC_SEMAPFAILED (Map failed in receive)\n", msg);
00097     }
00098     if( error == L4_IPC_RESNDPFTO ){
00099       printf("%s : L4_IPC_RESNDPFTO (Send pagefault timeout)\n", msg);
00100     }
00101     if( error == L4_IPC_SESNDPFTO ){
00102       printf("%s : L4_IPC_SESNDPFTO (?)\n", msg);
00103     }
00104     if( error == L4_IPC_RERCVPFTO ){
00105       printf("%s : L4_IPC_RERCVPFTO (?)\n", msg);
00106     }
00107     if( error == L4_IPC_SERCVPFTO ){
00108       printf("%s : L4_IPC_SERCVPFTO (Receive pagefault timeout)\n", msg);
00109     }
00110     if( error == L4_IPC_REABORTED ){
00111       printf("%s : L4_IPC_REABORTED (Receive operation aborted)\n", msg);
00112     }
00113     if( error == L4_IPC_SEABORTED ){
00114       printf("%s : L4_IPC_SEABORTED (Send operation aborted)\n", msg);
00115     }
00116     if( error == L4_IPC_REMSGCUT ){
00117       printf("%s : L4_IPC_REMSGCUT (Received message cut)\n", msg);
00118     }
00119     if( error == L4_IPC_SEMSGCUT ){
00120       printf("%s : L4_IPC_SEMSGCUT (?)\n", msg);
00121     }
00122   }
00123 }
00124 
00125 
00126 /* wait for 255 * 4 ^ (15 - exp)  micro seconds
00127  * on my platform inside bochs exp==8 gives about one second
00128  */
00129 static void
00130 sit_and_wait(int exp)
00131 {
00132   l4_ipc_sleep(l4_ipc_timeout(255,16-exp,255,16-exp));
00133 }
00134 
00135 
00136 /* shut down this thread */
00137 static void
00138 wait_forever(void)
00139 {
00140   l4_ipc_sleep(L4_IPC_NEVER);
00141 }
00142 
00143 
00144 /* get thread number, preempter, pager, and ESP of calling thread */
00145 static int
00146 get_thread_ids(l4_threadid_t *my_id,
00147        l4_threadid_t *my_preempter,
00148        l4_threadid_t *my_pager,
00149        l4_addr_t *esp)
00150 {
00151   l4_umword_t ignore, _esp;
00152   l4_threadid_t _my_id, _my_preempter, _my_pager;
00153 
00154   _my_id = l4_myself();
00155 
00156   _my_preempter = L4_INVALID_ID;
00157   _my_pager = L4_INVALID_ID;
00158 
00159   l4_thread_ex_regs( _my_id, -1, -1,       /* id, EIP, ESP */
00160          &_my_preempter,       /* preempter */
00161          &_my_pager,       /* pager */
00162          &ignore,        /* flags */
00163          &ignore,        /* old ip */
00164          &_esp         /* old sp */
00165          );
00166 
00167   if(my_id) *my_id = _my_id;
00168   if(my_preempter) *my_preempter = _my_preempter;
00169   if(my_pager) *my_pager = _my_pager;
00170   if(esp) *esp = _esp;
00171   return 0;
00172 }
00173 
00174 /* get the apropriate number of task ids */
00175 static int
00176 get_tasks(void)
00177 {
00178   int res, task;
00179   int got_flag = 0;
00180   int count = 0;
00181 
00182   /* use the rmgr library now */
00183   res = rmgr_init();
00184 
00185   if( res != 1){
00186     printf("rmgr_init failed with %x\n", res);
00187   }
00188 
00189   task = 0;
00190 
00191   while (count < TASK_MAX)
00192   {
00193     res = rmgr_get_task(task);
00194 
00195     if(res == 0)
00196     {
00197   count++;
00198   if(got_flag == 0)
00199   {
00200     got_flag = 1;
00201     if(task_min == -1) task_min = task;
00202   }
00203     }
00204     else
00205     {
00206       if(got_flag == 1)
00207       {
00208   got_flag = 0;
00209   if(task_max == -1) task_max = task;
00210   break;
00211       }
00212     }
00213 
00214     task++;
00215   }
00216 
00217   return count;
00218 }
00219 
00220 
00221 /* copy-on-write mechanism: allocate a new page and copy appropriate content
00222  of data into new page */
00223 static l4_addr_t
00224 unshare_data(l4_addr_t addr, l4_threadid_t tid)
00225 {
00226   l4_addr_t new_page = cow_pool;
00227   l4_addr_t img_base = l4_trunc_page(addr);
00228   l4_addr_t data_start = (l4_addr_t)&_etext;
00229   l4_addr_t data_end   = (l4_addr_t)&_end;
00230 
00231   if (!cow_pages)
00232     {
00233       printf("PANIC: Out of cow pages\n");
00234       exit(-1);
00235     }
00236 
00237   cow_pool += L4_PAGESIZE;
00238   cow_pages--;
00239 
00240   memcpy((void*)new_page, (void*)img_base, L4_PAGESIZE);
00241 
00242   /* bss is located at &__bss_start ... &_end-1 */
00243   if (!(   (img_base+L4_PAGESIZE <= data_start)
00244         || (img_base             >= data_end)))
00245     {
00246       /* some space of the page we want to give out
00247        * is bss -- clear it! */
00248       l4_addr_t dst_offs;
00249       l4_addr_t src_offs;
00250       l4_size_t src_size;
00251       if (data_start <= img_base)
00252   {
00253     src_offs = img_base - data_start;
00254     dst_offs = 0;
00255     if (data_end >= img_base + L4_PAGESIZE)
00256             src_size = L4_PAGESIZE;
00257     else
00258       src_size = data_end-img_base;
00259   }
00260       else
00261   {
00262     src_offs = 0;
00263     dst_offs = data_start - img_base;
00264     if (data_end >= img_base + L4_PAGESIZE)
00265       src_size = L4_PAGESIZE-dst_offs;
00266     else
00267       src_size = data_end-img_base-dst_offs;
00268   }
00269 
00270       memcpy((void*)new_page+dst_offs,
00271        (void*)my_program_data_copy+src_offs,
00272        src_size);
00273 #if 0
00274       printf("offs_shared_data=%08x\n"
00275        "copy from %08x-%08x to %08x-%08x\n"
00276        "data from %08x-%08x page %08x-%08x\n"
00277        "saved_data %08x-%08x\n",
00278        (l4_umword_t)&shared_data - (l4_umword_t)&_etext,
00279        my_program_data_copy+src_offs,
00280        my_program_data_copy+src_offs+src_size,
00281        new_page+dst_offs,
00282        new_page+dst_offs+src_size,
00283        data_start, data_end,
00284        img_base, img_base+L4_PAGESIZE,
00285        my_program_data_copy, my_program_data_copy+data_end-data_start);
00286       enter_kdebug("stop");
00287 #endif
00288     }
00289 
00290   if (debugpager)
00291    printf("unshared data page %08lx => %08lx client "l4util_idfmt"\n",
00292       addr, new_page, l4util_idstr(tid));
00293 
00294   if (debugpager)
00295    printf("copied pages: %d\n", ++copied_pages);
00296 
00297   return new_page;
00298 }
00299 
00300 
00301 /* The pager for our new tasks */
00302 static void
00303 pager_thread(void)
00304 {
00305   int res, rw_page_fault;
00306   l4_threadid_t src;
00307   l4_addr_t fault_address, fault_eip;
00308   l4_snd_fpage_t fp;
00309   l4_msgdope_t dope;
00310 
00311   /* get first page fault */
00312   res = l4_ipc_wait(&src,      /* source */
00313        L4_IPC_SHORT_MSG,   /* rcv desc */
00314        & fault_address,
00315        & fault_eip,    /* data */
00316        L4_IPC_NEVER,     /* timeout */
00317        &dope);     /* dope */
00318 
00319   if(res)
00320     ipc_error("first PF", res);
00321 
00322   while(1)
00323     {
00324       rw_page_fault = fault_address & 0x02;
00325       fault_address &= 0xfffffffc;
00326 
00327       // do not lock in pager, because this gives dead locks
00328       if(debugpager)
00329   printf("[%s page fault in "l4util_idfmt" at %08lx (EIP %08lx) ",
00330          rw_page_fault ? "write" : "read",
00331          l4util_idstr(src), fault_address, fault_eip);
00332         /* in Code */
00333       if(    (l4_addr_t) & _stext <= fault_address
00334    && ((l4_addr_t) & _etext > fault_address)
00335    && !rw_page_fault)
00336   {
00337     if(debugpager)
00338       printf("Code\n");
00339     fp.fpage = l4_fpage(fault_address, L4_LOG2_PAGESIZE,
00340             L4_FPAGE_RO, L4_FPAGE_MAP);
00341     fp.snd_base = l4_trunc_page(fault_address);
00342   }
00343         /* in Data/Bss? */
00344       else if((l4_addr_t) & _etext <= fault_address
00345    &&  ((l4_addr_t) & _end   > fault_address+3))
00346   {
00347     l4_addr_t new_page;
00348     if(debugpager)
00349      printf("Data\n");
00350 
00351     if (rw_page_fault)
00352       {
00353         new_page = unshare_data(fault_address, src);
00354         fp.fpage = l4_fpage(new_page, L4_LOG2_PAGESIZE,
00355                 L4_FPAGE_RW, L4_FPAGE_MAP);
00356         l4_fpage_unmap(l4_fpage(l4_trunc_page(fault_address),
00357                           L4_LOG2_PAGESIZE, 0, 0),
00358                           L4_FP_FLUSH_PAGE | L4_FP_OTHER_SPACES);
00359       }
00360     else
00361       {
00362         new_page = l4_trunc_page(fault_address);
00363         fp.fpage = l4_fpage(new_page, L4_LOG2_PAGESIZE,
00364                 L4_FPAGE_RO, L4_FPAGE_MAP);
00365       }
00366 
00367     fp.snd_base = l4_trunc_page(fault_address);
00368   }
00369 
00370         /* in Stack ? */
00371       else
00372   {
00373            if(!debugpager)
00374        printf("[%s page fault in "l4util_idfmt" at %08lx (EIP %08lx) ",
00375          rw_page_fault ? "write" : "read",
00376          l4util_idstr(src), fault_address, fault_eip);
00377       printf("stop pager]\n");
00378       enter_kdebug("stop");
00379       fp.snd_base = 0;
00380       l4_ipc_sleep(L4_IPC_NEVER);
00381   }
00382 
00383       if(debugpager)
00384   printf(" %s (%s), base : %08x, size : %d, offset : %08lx]\n",
00385          fp.fpage.fp.grant ? "grant" : "map",
00386          fp.fpage.fp.write ? "WR" : "RO",
00387          fp.fpage.fp.page << L4_PAGESHIFT,
00388          fp.fpage.fp.size,
00389          fp.snd_base
00390          );
00391 
00392       /* send reply and wait for next page fault */
00393       res = l4_ipc_reply_and_wait
00394   (src,          /* destination */
00395    L4_IPC_SHORT_FPAGE,       /* snd desc */
00396    fp.snd_base,        /* snd data 0 */
00397    fp.fpage.fpage ,      /* snd data 1 */
00398    &src,           /* source */
00399    L4_IPC_SHORT_MSG,       /* rcv desc */
00400    &fault_address,
00401    &fault_eip,
00402    L4_IPC_NEVER,
00403    &dope);
00404 
00405       if(res)
00406   ipc_error("PF", res);
00407     }
00408 }
00409 
00410 
00411 static void
00412 print_event(l4events_ch_t event_ch, l4events_event_t *event)
00413 {
00414   printf("event_ch: %d\n", event_ch);
00415   printf("event:   ");
00416   printf(event->str);
00417   printf("\n");
00418 
00419   return;
00420 }
00421 
00422 static void
00423 otask1(void)
00424 {
00425   l4events_ch_t event_ch = L4EVENTS_NO_CHANNEL;
00426   l4events_nr_t event_nr = L4EVENTS_NO_NR;
00427   l4events_event_t event;
00428   int res;
00429 
00430   //event.str = buffer2;
00431 
00432   strcpy(LOG_tag, "task1");
00433 
00434   printf("start.\n");
00435 
00436   printf("register.\n");
00437   l4events_register(DEMO2_EVENTID, DEMO2_PRIORITY);
00438 
00439   printf("receive first try.\n");
00440   res = l4events_receive(&event_ch, &event, &event_nr,
00441             l4_ipc_timeout(0,0,1,0), 0);
00442 
00443   if (res == L4EVENTS_OK)
00444   {
00445     printf("receive event successful!\n");
00446 
00447     print_event(event_ch, &event);
00448   }
00449   else
00450   {
00451     printf("receive event failed!\n");
00452   }
00453 
00454   sit_and_wait(7);
00455 
00456   printf("receive second try.\n");
00457   event_ch = L4EVENTS_NO_CHANNEL;
00458   res = l4events_receive(&event_ch, &event, &event_nr,
00459             L4_IPC_NEVER, 0);
00460 
00461   if (res == L4EVENTS_OK)
00462   {
00463     printf("receive event successful!\n");
00464     print_event(event_ch, &event);
00465   }
00466   else
00467   {
00468     printf("receive event failed!\n");
00469   }
00470 
00471   printf("unregister.\n");
00472   l4events_unregister(DEMO2_EVENTID);
00473 
00474   printf("stop.\n");
00475 
00476   wait_forever();
00477 }
00478 
00479 
00480 static void
00481 otask2(void)
00482 {
00483   l4events_event_t e;
00484   l4events_nr_t nr;
00485 
00486   strcpy(e.str, "ein kleiner text.");
00487   e.len = strlen(e.str)+1;
00488 
00489   strcpy(LOG_tag, "task2");
00490 
00491   printf("start.\n");
00492 
00493   sit_and_wait(8);
00494 
00495   printf("send event.\n");
00496 
00497   l4events_send(DEMO2_EVENTID, &e, &nr, 0);
00498 
00499   printf("stop.\n");
00500 
00501   wait_forever();
00502 }
00503 
00504 /* callback function for waiting */
00505 static void
00506 callback(l4events_ch_t event_ch, l4events_event_t *event)
00507 {
00508   print_event(event_ch, event);
00509 }
00510 
00511 static void
00512 otask3(void)
00513 {
00514   strcpy(LOG_tag, "task3");
00515 
00516   printf("start.\n");
00517 
00518   l4events_register(DEMO2_EVENTID, DEMO2_PRIORITY);
00519   l4events_wait(1, L4EVENTS_NO_CHANNEL, callback);
00520 
00521   printf("end...\n");
00522 
00523   wait_forever();
00524 }
00525 
00526 
00527 // save data segment so we are able to copy-on-write it for new childs */
00528 static void
00529 save_data(l4_threadid_t pager)
00530 {
00531   l4_addr_t beg  = l4_trunc_page(&_etext);
00532   l4_addr_t end  = l4_round_page(&_end);
00533 
00534   my_program_data_copy = rmgr_reserve_mem(end-beg, L4_LOG2_PAGESIZE, 0, 0, 0);
00535   if (my_program_data_copy == ~0U)
00536     {
00537       printf("Cannot allocate %ldkB memory for unsharing data section\n",
00538     (end-beg)/1024);
00539       enter_kdebug("out of memory");
00540     }
00541 
00542   l4sigma0_map_mem(pager,
00543              my_program_data_copy, my_program_data_copy, end-beg);
00544   memcpy((void*)my_program_data_copy, (void*)&_etext, &_end-&_etext);
00545 }
00546 
00547 // reserve pool for copy-on-write
00548 static void
00549 reserve_cow(l4_threadid_t pager)
00550 {
00551   cow_pool = rmgr_reserve_mem(COW_POOL_PAGES*L4_PAGESIZE,
00552                               L4_LOG2_PAGESIZE, 0, 0, 0);
00553   if (cow_pool == ~0U)
00554     {
00555       printf("Cannot allocate %dkB memory for cow pool!\n",
00556     COW_POOL_PAGES*L4_PAGESIZE/1024);
00557       enter_kdebug("out of memory");
00558     }
00559 
00560   l4sigma0_map_mem(pager,
00561              (l4_addr_t)&_stext, (l4_addr_t)&_stext, &_etext-&_stext);
00562   l4sigma0_map_mem(pager,
00563              cow_pool, cow_pool, COW_POOL_PAGES*L4_PAGESIZE);
00564   cow_pages = COW_POOL_PAGES;
00565 }
00566 
00567 
00568 int
00569 main(void)
00570 {
00571   l4_threadid_t my_id, my_preempter, my_pager, new_pager;
00572 
00573   l4_umword_t ignore;
00574   l4_threadid_t t, new_t;
00575 
00576   int tasks;
00577 
00578   rmgr_init();
00579 
00580   l4events_init();
00581 
00582   /* this call initialized the names library
00583      -- must be done before save_data()! */
00584   names_register("eventdemo");
00585   
00586   get_thread_ids(&my_id,&my_preempter,&my_pager,NULL);
00587 
00588   /* call this at the very beginning! */
00589   save_data(my_pager);
00590   reserve_cow(my_pager);
00591 
00592   printf("starting event server demo...\n");
00593 
00594   /* get task numbers */
00595   tasks = get_tasks();
00596 
00597     if (tasks < TASK_MAX)
00598   {
00599     printf("got not enough tasks!!!");
00600     enter_kdebug("main");
00601   }
00602 
00603   /* start pager */
00604   get_thread_ids(&my_id,&my_preempter,&my_pager,NULL);
00605   pager_thread_id = my_id;
00606   pager_thread_id.id.lthread = PAGER_THREAD;
00607   my_preempter = L4_INVALID_ID;
00608   new_pager = my_pager;
00609   l4_thread_ex_regs( pager_thread_id,    /* dest thread */
00610          (l4_umword_t)pager_thread,  /* EIP */
00611          (l4_umword_t)pager_thread_stack + 2048,
00612              /* ESP */
00613          &my_preempter,    /* preempter */
00614          &new_pager,     /* pager */
00615          &ignore,      /* flags */
00616          &ignore,      /* old ip */
00617          &ignore       /* old sp */
00618          );
00619 
00620 
00621   get_thread_ids(&t,NULL,NULL,NULL);
00622 
00623   t.id.task = task_min;
00624   t.id.lthread = 0;
00625 
00626   printf("start task1\n");
00627 
00628   new_t = l4_task_new(t,       /* dest task */
00629           255,       /* prio */
00630           (l4_umword_t)&crt0_stack_high,       /* ESP */
00631           (l4_umword_t)otask1,   /* EIP */
00632           pager_thread_id );   /* pager */
00633 
00634   t.id.task = task_min+1;
00635   t.id.lthread = 0;
00636 
00637   printf("start task2\n");
00638 
00639   new_t = l4_task_new(t,       /* dest task */
00640           255,       /* prio */
00641           (l4_umword_t)&crt0_stack_high,     /* ESP */
00642           (l4_umword_t)otask2,     /* EIP */
00643           pager_thread_id );   /* pager */
00644 
00645 
00646   t.id.task = task_min+2;
00647   t.id.lthread = 0;
00648 
00649   printf("start task3\n");
00650 
00651   new_t = l4_task_new(t,       /* dest task */
00652           255,       /* prio */
00653           (l4_umword_t)&crt0_stack_high,   /* ESP */
00654           (l4_umword_t)otask3,     /* EIP */
00655           pager_thread_id );   /* pager */
00656 
00657 
00658   /* wait forever */
00659   l4_ipc_sleep(L4_IPC_NEVER);
00660 
00661   return 0;
00662 }
00663 

Events Reference Manual, written by Torsten Frenzel  © 2003