From 53310aa31b3f3e91f46f38cfc74a4b0253353b0d Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Wed, 27 May 2009 14:36:11 +0300 Subject: [PATCH] Extended IPC Support added. Benefits & Facts: - Messages up to 2 kilobytes may be sent. - Both parties may use non-disjoint user buffers. E.g. any userspace address. - Userspace buffers can page fault. - Page faults punish timeslice of only the faulting thread. - Any number of extended ipcs can take place at any one time, since only ktcbs of ipc parties are engaged. No global buffer is used. - This also provides smp-safety benefit. Disadvantages: - There is triple copying penalty. This has to be done: - Sender buffer to sender ktcb - Sender ktcb to receiver ktcb - Receiver ktcb to receiver buffer. This is due to the fact that buffers can be on non-disjoint userspace addresses. If you want to avoid disadvantages and lose some of the benefits, (e.g. address freedom, shorter copy size) use FULL IPC. --- include/l4/generic/tcb.h | 7 +++++-- src/api/ipc.c | 40 +++++++++++++++++++-------------------- tasks/test0/src/ipctest.c | 13 ++++++++++--- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index e1cc8da..ec33d35 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -113,9 +113,12 @@ struct ktcb { struct waitqueue_head *waiting_on; struct waitqueue *wq; - /* Extended ipc buffer, points to the space after ktcb */ - char *extended_ipc_buffer; + /* + * Extended ipc size and buffer that + * points to the space after ktcb + */ unsigned long extended_ipc_size; + char extended_ipc_buffer[]; }; /* Per thread kernel stack unified on a single page. */ diff --git a/src/api/ipc.c b/src/api/ipc.c index f175021..0894db1 100644 --- a/src/api/ipc.c +++ b/src/api/ipc.c @@ -389,34 +389,39 @@ int ipc_recv_extended(l4id_t sendertid, unsigned int flags) /* Obtain extended ipc address */ ipc_address = (unsigned long)mr0_current[msg_index]; - /* Set extended ipc buffer as the user buffer address */ - current->extended_ipc_buffer = (char *)ipc_address; - /* Obtain extended ipc size */ size = extended_ipc_msg_size(flags); /* Check size is good */ if (size > L4_IPC_EXTENDED_MAX_SIZE) return -EINVAL; + + /* Set extended ipc copy size */ current->extended_ipc_size = size; + /* Engage in real ipc to copy to ktcb buffer */ + if ((err = ipc_recv(sendertid, flags)) < 0) + return err; + /* - * TODO: We may need to save primary mrs before engaging - * in page fault ipc. Currently after extended ipc address - * is obtained, primaries are not used during the ipc. - * In the future if needed, we should save them. + * NOTE: After this point primary mrs may be trashed. + * We need to save them here if we want to retain their values + * after a page fault ipc. Currently they're not needed. */ - /* Page fault those pages on the current task if needed */ + /* Page fault user pages if needed */ if ((err = check_access(ipc_address, size, MAP_USR_RW_FLAGS, 1)) < 0) return err; /* - * Now we can engage in the real ipc, copying of ipc data - * shall occur during the message copying. + * Now copy from ktcb to user buffers */ - return ipc_recv(sendertid, flags); + memcpy((void *)ipc_address, + current->extended_ipc_buffer, + current->extended_ipc_size); + + return 0; } @@ -454,10 +459,9 @@ int ipc_send_extended(l4id_t recv_tid, unsigned int flags) current->extended_ipc_size = size; /* - * TODO: We may need to save primary mrs before engaging - * in page fault ipc. Currently after extended ipc address - * is obtained, primaries are not used during the ipc. - * In the future if needed, we should save them. + * NOTE: After this point primary mrs may be trashed. + * We need to save them here if we want to retain their values + * after a page fault ipc. Currently they're not needed. */ /* Page fault those pages on the current task if needed */ @@ -465,13 +469,9 @@ int ipc_send_extended(l4id_t recv_tid, unsigned int flags) MAP_USR_RW_FLAGS, 1)) < 0) return err; - /* Set extended ipc buffer as the end of ktcb */ - current->extended_ipc_buffer = - (void *)current + sizeof(struct ktcb); - /* * It is now safe to access user pages. - * Copy message from user buffer into kernel stack + * Copy message from user buffer into current kernel stack */ memcpy(current->extended_ipc_buffer, (void *)ipc_address, size); diff --git a/tasks/test0/src/ipctest.c b/tasks/test0/src/ipctest.c index fb2d61e..0665a3a 100644 --- a/tasks/test0/src/ipctest.c +++ b/tasks/test0/src/ipctest.c @@ -89,7 +89,8 @@ void ipc_extended_test(void) */ ipcbuf = base + PAGE_SIZE - L4_IPC_EXTENDED_MAX_SIZE / 2; - if (!child) { + /* Child sending message */ + if (child == 0) { /* Child creates a string of maximum extended ipc size */ for (int i = 0; i < L4_IPC_EXTENDED_MAX_SIZE; i++) { ipcbuf[i] = 'A' + i % 20; @@ -107,6 +108,7 @@ void ipc_extended_test(void) goto out_err; } + /* Parent receiving message */ } else { /* * Parent receives on the buffer - we are sure that the @@ -125,11 +127,16 @@ void ipc_extended_test(void) printf("(%d): Message received from child: %s\n", getpid(), ipcbuf); - /* Check that child string is there */ - for (int i = 0; i < L4_IPC_EXTENDED_MAX_SIZE; i++) { + /* Check that string received from child is an exact match */ + for (int i = 0; i < L4_IPC_EXTENDED_MAX_SIZE - 2; i++) { if (ipcbuf[i] != ('A' + i % 20)) goto out_err; } + if (ipcbuf[L4_IPC_EXTENDED_MAX_SIZE - 2] != '\n') + goto out_err; + if (ipcbuf[L4_IPC_EXTENDED_MAX_SIZE - 1] != '\0') + goto out_err; + printf("EXTENDED IPC TEST: -- PASSED --\n"); } return;