Inter-Process communication (IPC)
Exercise 15. Implement sys_ipc_recv and sys_ipc_try_send in kern/syscall.c. Read the comments on both before implementing them, since they have to work together. When you call envid2env in these routines, you should set the checkperm flag to 0, meaning that any environment is allowed to send IPC messages to any other environment, and the kernel does no special permission checking other than verifying that the target envid is valid.
Then implement the ipc_recv and ipc_send functions in lib/ipc.c.
static int
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm)
{
struct Env *e;
int ret = envid2env(envid, &e, 0);
if (ret) return ret;//bad env
if (!e->env_ipc_recving) return -E_IPC_NOT_RECV;
if (srcva < (void*)UTOP) {
pte_t *pte;
struct PageInfo *pg = page_lookup(curenv->env_pgdir, srcva, &pte);
if (!pg) return -E_INVAL;
if ((*pte & perm) != perm) return -E_INVAL;
if ((perm & PTE_W) && !(*pte & PTE_W)) return -E_INVAL;
if (srcva != ROUNDDOWN(srcva, PGSIZE)) return -E_INVAL;
if (e->env_ipc_dstva < (void*)UTOP) {
ret = page_insert(e->env_pgdir, pg, e->env_ipc_dstva, perm);
if (ret) return ret;
e->env_ipc_perm = perm;
}
}
e->env_ipc_recving = 0;
e->env_ipc_from = curenv->env_id;
e->env_ipc_value = value;
e->env_status = ENV_RUNNABLE;
e->env_tf.tf_regs.reg_eax = 0;
return 0;
panic("sys_ipc_try_send not implemented");
}
static int
sys_ipc_recv(void *dstva)
{
if (dstva < (void*)UTOP)
if (dstva != ROUNDDOWN(dstva, PGSIZE))
return -E_INVAL;
curenv->env_ipc_recving = 1;
curenv->env_status = ENV_NOT_RUNNABLE;
curenv->env_ipc_dstva = dstva;
sys_yield();
return 0;
}
int32_t
ipc_recv(envid_t *from_env_store, void *pg, int *perm_store)
{
// LAB 4: Your code here.
if (from_env_store) *from_env_store = 0;
if (perm_store) *perm_store = 0;
if (!pg) pg = (void*) -1;
int ret = sys_ipc_recv(pg);
if (ret) return ret;
if (from_env_store)
*from_env_store = thisenv->env_ipc_from;
if (perm_store)
*perm_store = thisenv->env_ipc_perm;
return thisenv->env_ipc_value;
}
void
ipc_send(envid_t to_env, uint32_t val, void *pg, int perm)
{
// LAB 4: Your code here.
if (!pg) pg = (void*)-1;
int ret;
while ((ret = sys_ipc_try_send(to_env, val, pg, perm))) {
if (ret == 0) break;
if (ret != -E_IPC_NOT_RECV) panic("not E_IPC_NOT_RECV, %e", ret);
sys_yield();
}
}