mirror of
https://github.com/drasko/codezero.git
synced 2026-07-10 09:24:11 +02:00
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:
@@ -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. */
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user