uint32_t ipc_deliver(void *data) { tcb_t *thr = NULL, *from_thr = NULL, *to_thr = NULL; l4_thread_t receiver; int i; for (i = 1; i < thread_count; ++i) { thr = thread_map[i]; switch (thr->state) { case T_RECV_BLOCKED: if (thr->ipc_from != L4_NILTHREAD && thr->ipc_from != L4_ANYTHREAD && thr->ipc_from != TID_TO_GLOBALID(THREAD_INTERRUPT)) { from_thr = thread_by_globalid(thr->ipc_from); if (from_thr->state == T_SEND_BLOCKED) do_ipc(from_thr, thr); } break; case T_SEND_BLOCKED: receiver = thr->utcb->intended_receiver; if (receiver != L4_NILTHREAD && receiver != L4_ANYTHREAD) { to_thr = thread_by_globalid(receiver); if (to_thr->state == T_RECV_BLOCKED) do_ipc(thr, to_thr); } break; default: break; } } return 4096; }
void sys_ipc(uint32_t *param1) { /* TODO: Checking of recv-mask */ tcb_t *to_thr = NULL; l4_thread_t to_tid = param1[REG_R0], from_tid = param1[REG_R1]; if (to_tid != L4_NILTHREAD) { to_thr = thread_by_globalid(to_tid); if (to_tid == TID_TO_GLOBALID(THREAD_LOG)) { user_log(caller); caller->state = T_RUNNABLE; } else if ((to_thr && to_thr->state == T_RECV_BLOCKED) || to_tid == caller->t_globalid) { /* To thread who is waiting for us or sends to myself */ do_ipc(caller, to_thr); } else if (to_thr && to_thr->state == T_INACTIVE && GLOBALID_TO_TID(to_thr->utcb->t_pager) == GLOBALID_TO_TID(caller->t_globalid)) { if (ipc_read_mr(caller, 0) == 0x00000003) { /* thread start protocol */ memptr_t sp = ipc_read_mr(caller, 2); size_t stack_size = ipc_read_mr(caller, 3); dbg_printf(DL_IPC, "IPC: %t thread start\n", to_tid); to_thr->stack_base = sp - stack_size; to_thr->stack_size = stack_size; thread_init_ctx((void *) sp, (void *) ipc_read_mr(caller, 1), to_thr); caller->state = T_RUNNABLE; /* Start thread */ to_thr->state = T_RUNNABLE; } else { do_ipc(caller, to_thr); to_thr->state = T_INACTIVE; } } else { /* No waiting, block myself */ caller->state = T_SEND_BLOCKED; caller->utcb->intended_receiver = to_tid; dbg_printf(DL_IPC, "IPC: %t sending\n", caller->t_globalid); return; } } if (from_tid != L4_NILTHREAD) { /* Only receive phases, simply lock myself */ caller->state = T_RECV_BLOCKED; caller->ipc_from = from_tid; dbg_printf(DL_IPC, "IPC: %t receiving\n", caller->t_globalid); } }
void sys_ipc(uint32_t *param1) { /* TODO: Checking of recv-mask */ tcb_t *to_thr = NULL; l4_thread_t to_tid = param1[REG_R0], from_tid = param1[REG_R1]; uint32_t timeout = param1[REG_R2]; if (to_tid == L4_NILTHREAD && from_tid == L4_NILTHREAD) { caller->state = T_INACTIVE; if (timeout) sys_ipc_timeout(timeout); return; } if (to_tid != L4_NILTHREAD) { to_thr = thread_by_globalid(to_tid); if (to_tid == TID_TO_GLOBALID(THREAD_LOG)) { user_log(caller); caller->state = T_RUNNABLE; return; } else if (to_tid == TID_TO_GLOBALID(THREAD_IRQ_REQUEST)) { user_interrupt_config(caller); caller->state = T_RUNNABLE; return; } else if ((to_thr && to_thr->state == T_RECV_BLOCKED) || to_tid == caller->t_globalid) { /* To thread who is waiting for us or sends to myself */ do_ipc(caller, to_thr); return; } else if (to_thr && to_thr->state == T_INACTIVE && GLOBALID_TO_TID(to_thr->utcb->t_pager) == GLOBALID_TO_TID(caller->t_globalid)) { if (ipc_read_mr(caller, 0) == 0x00000005) { /* mr1: thread func, mr2: stack addr, mr3: stack size*/ /* mr4: thread entry, mr5: thread args */ /* thread start protocol */ memptr_t sp = ipc_read_mr(caller, 2); size_t stack_size = ipc_read_mr(caller, 3); uint32_t regs[4]; /* r0, r1, r2, r3 */ dbg_printf(DL_IPC, "IPC: %t thread start\n", to_tid); to_thr->stack_base = sp - stack_size; to_thr->stack_size = stack_size; regs[REG_R0] = (uint32_t)&kip; regs[REG_R1] = (uint32_t)to_thr->utcb; regs[REG_R2] = ipc_read_mr(caller, 4); regs[REG_R3] = ipc_read_mr(caller, 5); thread_init_ctx((void *) sp, (void *) ipc_read_mr(caller, 1), regs, to_thr); caller->state = T_RUNNABLE; /* Start thread */ to_thr->state = T_RUNNABLE; return; } else { do_ipc(caller, to_thr); to_thr->state = T_INACTIVE; return; } } else { /* No waiting, block myself */ caller->state = T_SEND_BLOCKED; caller->utcb->intended_receiver = to_tid; dbg_printf(DL_IPC, "IPC: %t sending\n", caller->t_globalid); if (timeout) sys_ipc_timeout(timeout); return; } } if (from_tid != L4_NILTHREAD) { tcb_t *thr = NULL; if (from_tid == L4_ANYTHREAD) { int i; /* Find out if there is any sending thread waiting for caller */ for (i = 1; i < thread_count; ++i) { thr = thread_map[i]; if (thr->state == T_SEND_BLOCKED && thr->utcb->intended_receiver == caller->t_globalid) { do_ipc(thr, caller); return; } } } else if (from_tid != TID_TO_GLOBALID(THREAD_INTERRUPT)) { thr = thread_by_globalid(from_tid); if (thr->state == T_SEND_BLOCKED && thr->utcb->intended_receiver == caller->t_globalid) { do_ipc(thr, caller); return; } } /* Only receive phases, simply lock myself */ caller->state = T_RECV_BLOCKED; caller->ipc_from = from_tid; if (from_tid == TID_TO_GLOBALID(THREAD_INTERRUPT)) { /* Threaded interrupt is ready */ user_interrupt_handler_update(caller); } if (timeout) sys_ipc_timeout(timeout); dbg_printf(DL_IPC, "IPC: %t receiving\n", caller->t_globalid); return; } caller->state = T_SEND_BLOCKED; }