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.
This commit is contained in:
Bahadir Balban
2009-05-27 14:36:11 +03:00
parent 3ff519439b
commit 53310aa31b
3 changed files with 35 additions and 25 deletions

View File

@@ -113,9 +113,12 @@ struct ktcb {
struct waitqueue_head *waiting_on; struct waitqueue_head *waiting_on;
struct waitqueue *wq; 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; unsigned long extended_ipc_size;
char extended_ipc_buffer[];
}; };
/* Per thread kernel stack unified on a single page. */ /* Per thread kernel stack unified on a single page. */

View File

@@ -389,34 +389,39 @@ int ipc_recv_extended(l4id_t sendertid, unsigned int flags)
/* Obtain extended ipc address */ /* Obtain extended ipc address */
ipc_address = (unsigned long)mr0_current[msg_index]; 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 */ /* Obtain extended ipc size */
size = extended_ipc_msg_size(flags); size = extended_ipc_msg_size(flags);
/* Check size is good */ /* Check size is good */
if (size > L4_IPC_EXTENDED_MAX_SIZE) if (size > L4_IPC_EXTENDED_MAX_SIZE)
return -EINVAL; return -EINVAL;
/* Set extended ipc copy size */
current->extended_ipc_size = 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 * NOTE: After this point primary mrs may be trashed.
* in page fault ipc. Currently after extended ipc address * We need to save them here if we want to retain their values
* is obtained, primaries are not used during the ipc. * after a page fault ipc. Currently they're not needed.
* In the future if needed, we should save them.
*/ */
/* Page fault those pages on the current task if needed */ /* Page fault user pages if needed */
if ((err = check_access(ipc_address, size, if ((err = check_access(ipc_address, size,
MAP_USR_RW_FLAGS, 1)) < 0) MAP_USR_RW_FLAGS, 1)) < 0)
return err; return err;
/* /*
* Now we can engage in the real ipc, copying of ipc data * Now copy from ktcb to user buffers
* shall occur during the message copying.
*/ */
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; current->extended_ipc_size = size;
/* /*
* TODO: We may need to save primary mrs before engaging * NOTE: After this point primary mrs may be trashed.
* in page fault ipc. Currently after extended ipc address * We need to save them here if we want to retain their values
* is obtained, primaries are not used during the ipc. * after a page fault ipc. Currently they're not needed.
* In the future if needed, we should save them.
*/ */
/* Page fault those pages on the current task if 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) MAP_USR_RW_FLAGS, 1)) < 0)
return err; 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. * 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, memcpy(current->extended_ipc_buffer,
(void *)ipc_address, size); (void *)ipc_address, size);

View File

@@ -89,7 +89,8 @@ void ipc_extended_test(void)
*/ */
ipcbuf = base + PAGE_SIZE - L4_IPC_EXTENDED_MAX_SIZE / 2; 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 */ /* Child creates a string of maximum extended ipc size */
for (int i = 0; i < L4_IPC_EXTENDED_MAX_SIZE; i++) { for (int i = 0; i < L4_IPC_EXTENDED_MAX_SIZE; i++) {
ipcbuf[i] = 'A' + i % 20; ipcbuf[i] = 'A' + i % 20;
@@ -107,6 +108,7 @@ void ipc_extended_test(void)
goto out_err; goto out_err;
} }
/* Parent receiving message */
} else { } else {
/* /*
* Parent receives on the buffer - we are sure that the * 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", printf("(%d): Message received from child: %s\n",
getpid(), ipcbuf); getpid(), ipcbuf);
/* Check that child string is there */ /* Check that string received from child is an exact match */
for (int i = 0; i < L4_IPC_EXTENDED_MAX_SIZE; i++) { for (int i = 0; i < L4_IPC_EXTENDED_MAX_SIZE - 2; i++) {
if (ipcbuf[i] != ('A' + i % 20)) if (ipcbuf[i] != ('A' + i % 20))
goto out_err; 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"); printf("EXTENDED IPC TEST: -- PASSED --\n");
} }
return; return;