点击(此处)折叠或打开
- /*===========================================================================*
- * mini_receive *
- *===========================================================================*/
- PRIVATE int mini_receive(struct proc * caller_ptr,
- endpoint_t src_e, /* which message source is wanted */
- message * m_buff_usr, /* pointer to message buffer */
- const int flags)
- {
- /* A process or task wants to get a message. If a message is already queued,
- * acquire it and deblock the sender. If no message from the desired source
- * is available block the caller.
- */
- register struct proc **xpp;
- sys_map_t *map;
- int r, src_id, src_proc_nr, src_p;
- assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
- /* This is where we want our message. */
- caller_ptr->p_delivermsg_vir = (vir_bytes) m_buff_usr;
- if(src_e == ANY) src_p = ANY;
- else
- {
- okendpt(src_e, &src_p);
- if (RTS_ISSET(proc_addr(src_p), RTS_NO_ENDPOINT))
- {
- return EDEADSRCDST;
- }
- }
- /* Check to see if a message from desired source is already available. The
- * caller's RTS_SENDING flag may be set if SENDREC couldn't send. If it is
- * set, the process should be blocked.
- */
- if (!RTS_ISSET(caller_ptr, RTS_SENDING)) {
- /* Check if there are pending notifications, except for SENDREC. */
- if (! (caller_ptr->p_misc_flags & MF_REPLY_PEND)) {
- map = &priv(caller_ptr)->s_notify_pending;
- /* Check for pending notifications */
- if ((src_id = has_pending(map, src_p)) != NULL_PRIV_ID) {
- endpoint_t hisep;
- src_proc_nr = id_to_nr(src_id); /* get source proc */
- #if DEBUG_ENABLE_IPC_WARNINGS
- if(src_proc_nr == NONE) {
- printf("mini_receive: sending notify from NONE\n");
- }
- #endif
- unset_sys_bit(*map, src_id); /* no longer pending */
- /* Found a suitable source, deliver the notification message. */
- hisep = proc_addr(src_proc_nr)->p_endpoint;
- assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
- assert(src_e == ANY || hisep == src_e);
- /* assemble message */
- BuildNotifyMessage(&caller_ptr->p_delivermsg, src_proc_nr, caller_ptr);
- caller_ptr->p_delivermsg.m_source = hisep;
- caller_ptr->p_misc_flags |= MF_DELIVERMSG;
- IPC_STATUS_ADD_CALL(caller_ptr, NOTIFY);
- goto receive_done;
- }
- }
- /* Check for pending asynchronous messages */
- map = &priv(caller_ptr)->s_asyn_pending;
- if (has_pending(map, src_p) != NULL_PRIV_ID) {
- if (src_p != ANY)
- r = try_one(proc_addr(src_p), caller_ptr);
- else
- r = try_async(caller_ptr);
- if (r == OK) {
- IPC_STATUS_ADD_CALL(caller_ptr, SENDA);
- goto receive_done;
- }
- }
- /* Check caller queue. Use pointer pointers to keep code simple. */
- xpp = &caller_ptr->p_caller_q;
- while (*xpp) {
- struct proc * sender = *xpp;
- if (src_e == ANY || src_p == proc_nr(sender)) {
- int call;
- assert(!RTS_ISSET(sender, RTS_SLOT_FREE));
- assert(!RTS_ISSET(sender, RTS_NO_ENDPOINT));
- /* Found acceptable message. Copy it and update status. */
- assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
- caller_ptr->p_delivermsg = sender->p_sendmsg;
- caller_ptr->p_delivermsg.m_source = sender->p_endpoint;
- caller_ptr->p_misc_flags |= MF_DELIVERMSG;
- RTS_UNSET(sender, RTS_SENDING);
- call = (sender->p_misc_flags & MF_REPLY_PEND ? SENDREC : SEND);
- IPC_STATUS_ADD_CALL(caller_ptr, call);
- /*
- * if the message is originaly from the kernel on behalf of this
- * process, we must send the status flags accordingly
- */
- if (sender->p_misc_flags & MF_SENDING_FROM_KERNEL) {
- IPC_STATUS_ADD_FLAGS(caller_ptr, IPC_FLG_MSG_FROM_KERNEL);
- /* we can clean the flag now, not need anymore */
- sender->p_misc_flags &= ~MF_SENDING_FROM_KERNEL;
- }
- if (sender->p_misc_flags & MF_SIG_DELAY)
- sig_delay_done(sender);
- #if DEBUG_IPC_HOOK
- hook_ipc_msgrecv(&caller_ptr->p_delivermsg, *xpp, caller_ptr);
- #endif
-
- *xpp = sender->p_q_link; /* remove from queue */
- sender->p_q_link = NULL;
- goto receive_done;
- }
- xpp = &sender->p_q_link; /* proceed to next */
- }
- }
- /* No suitable message is available or the caller couldn't send in SENDREC.
- * Block the process trying to receive, unless the flags tell otherwise.
- */
- if ( ! (flags & NON_BLOCKING)) {
- /* Check for a possible deadlock before actually blocking. */
- if (deadlock(RECEIVE, caller_ptr, src_e)) {
- return(ELOCKED);
- }
- caller_ptr->p_getfrom_e = src_e;
- RTS_SET(caller_ptr, RTS_RECEIVING);
- return(OK);
- } else {
- return(ENOTREADY);
- }
- receive_done:
- if (caller_ptr->p_misc_flags & MF_REPLY_PEND)
- caller_ptr->p_misc_flags &= ~MF_REPLY_PEND;
- return OK;
- }
点击(此处)折叠或打开
- PRIVATE int do_sync_ipc(struct proc * caller_ptr, /* who made the call */
int call_nr,/* system call number and flags */
endpoint_t src_dst_e,/* src or dst of the call */
message *m_ptr)/* users pointer to a message */
{
...... - switch(call_nr) {
- case SENDREC:
- /* A flag is set so that notifications cannot interrupt SENDREC. */
- caller_ptr->p_misc_flags |= MF_REPLY_PEND;
- /* fall through */
- case SEND:
- result = mini_send(caller_ptr, src_dst_e, m_ptr, 0);
- if (call_nr == SEND || result != OK)
- break; /* done, or SEND failed */
- /* fall through for SENDREC */
- case RECEIVE:
- if (call_nr == RECEIVE) {
- caller_ptr->p_misc_flags &= ~MF_REPLY_PEND;
- IPC_STATUS_CLEAR(caller_ptr); /* clear IPC status code */
- }
- result = mini_receive(caller_ptr, src_dst_e, m_ptr, 0);
- break;
- case NOTIFY:
- result = mini_notify(caller_ptr, src_dst_e);
- break;
- case SENDNB:
- result = mini_send(caller_ptr, src_dst_e, m_ptr, NON_BLOCKING);
- break;
- default:
- result = EBADCALL; /* illegal system call */
- }
- /* Now, return the result of the system call to the caller. */
- return(result);
- }
点击(此处)折叠或打开
- PUBLIC int do_ipc(reg_t r1, reg_t r2, reg_t r3)
- {
- ......
- switch(call_nr) {
- case SENDREC:
- case SEND:
- case RECEIVE:
- case NOTIFY:
- case SENDNB:
- {
- /* Process accounting for scheduling */
- caller_ptr->p_accounting.ipc_sync++;
- return do_sync_ipc(caller_ptr, call_nr, (endpoint_t) r2,
- (message *) r3);
- }
- ......
- }
点击(此处)折叠或打开
- ENTRY(ipc_entry)
- ......
- call _C_LABEL(do_ipc)
- /* restore the current process pointer and save the return value */
- add $3 * 4, %esp
- pop %esi
- mov %eax, AXREG(%esi)
- jmp _C_LABEL(switch_to_user)
点击(此处)折叠或打开
- ENTRY(_sendrec)
- push %ebp
- movl %esp, %ebp
- push %ebx
- movl SRC_DST(%ebp), %eax /* eax = dest-src */
- movl MESSAGE(%ebp), %ebx /* ebx = message pointer */
- movl $SENDREC, %ecx /* _sendrec(srcdest, ptr) */
- int $IPCVEC /* trap to the kernel */
- pop %ebx
- pop %ebp
- ret
点击(此处)折叠或打开
- int _syscall(endpoint_t who, int syscallnr, message *msgptr)
- {
- int status;
- msgptr->m_type = syscallnr;
- status = _sendrec(who, msgptr);
- if (status != 0) {
- /* 'sendrec' itself failed. */
- /* XXX - strerror doesn't know all the codes */
- msgptr->m_type = status;
- }
- if (msgptr->m_type < 0) {
- errno = -msgptr->m_type;
- return(-1);
- }
- return(msgptr->m_type);
- }