10. -》如果mini_send 函数返回OK,则会接着调用函数mini_receive(同样在\kernel\proc.c中)

点击(此处)折叠或打开

  1. /*===========================================================================*
  2.  *                mini_receive                 *
  3.  *===========================================================================*/
  4. PRIVATE int mini_receive(struct proc * caller_ptr,
  5.             endpoint_t src_e, /* which message source is wanted */
  6.             message * m_buff_usr, /* pointer to message buffer */
  7.             const int flags)
  8. {
  9. /* A process or task wants to get a message. If a message is already queued,
  10.  * acquire it and deblock the sender. If no message from the desired source
  11.  * is available block the caller.
  12.  */
  13.   register struct proc **xpp;
  14.   sys_map_t *map;
  15.   int r, src_id, src_proc_nr, src_p;

  16.   assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));

  17.   /* This is where we want our message. */
  18.   caller_ptr->p_delivermsg_vir = (vir_bytes) m_buff_usr;

  19.   if(src_e == ANY) src_p = ANY;
  20.   else
  21.   {
  22.     okendpt(src_e, &src_p);
  23.     if (RTS_ISSET(proc_addr(src_p), RTS_NO_ENDPOINT))
  24.     {
  25.         return EDEADSRCDST;
  26.     }
  27.   }


  28.   /* Check to see if a message from desired source is already available. The
  29.    * caller's RTS_SENDING flag may be set if SENDREC couldn't send. If it is
  30.    * set, the process should be blocked.
  31.    */
  32.   if (!RTS_ISSET(caller_ptr, RTS_SENDING)) {

  33.     /* Check if there are pending notifications, except for SENDREC. */
  34.     if (! (caller_ptr->p_misc_flags & MF_REPLY_PEND)) {
  35.         map = &priv(caller_ptr)->s_notify_pending;

  36.     /* Check for pending notifications */
  37.         if ((src_id = has_pending(map, src_p)) != NULL_PRIV_ID) {
  38.             endpoint_t hisep;

  39.             src_proc_nr = id_to_nr(src_id);        /* get source proc */
  40. #if DEBUG_ENABLE_IPC_WARNINGS
  41.      if(src_proc_nr == NONE) {
  42.         printf("mini_receive: sending notify from NONE\n");
  43.      }
  44. #endif
  45.             unset_sys_bit(*map, src_id);        /* no longer pending */

  46.             /* Found a suitable source, deliver the notification message. */
  47.      hisep = proc_addr(src_proc_nr)->p_endpoint;
  48.      assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));    
  49.      assert(src_e == ANY || hisep == src_e);

  50.      /* assemble message */
  51.      BuildNotifyMessage(&caller_ptr->p_delivermsg, src_proc_nr, caller_ptr);
  52.      caller_ptr->p_delivermsg.m_source = hisep;
  53.      caller_ptr->p_misc_flags |= MF_DELIVERMSG;

  54.      IPC_STATUS_ADD_CALL(caller_ptr, NOTIFY);

  55.      goto receive_done;
  56.         }
  57.     }

  58.     /* Check for pending asynchronous messages */
  59.     map = &priv(caller_ptr)->s_asyn_pending;

  60.     if (has_pending(map, src_p) != NULL_PRIV_ID) {
  61.         if (src_p != ANY)
  62.             r = try_one(proc_addr(src_p), caller_ptr);
  63.         else
  64.             r = try_async(caller_ptr);

  65.     if (r == OK) {
  66.             IPC_STATUS_ADD_CALL(caller_ptr, SENDA);
  67.             goto receive_done;
  68.         }
  69.     }

  70.     /* Check caller queue. Use pointer pointers to keep code simple. */
  71.     xpp = &caller_ptr->p_caller_q;
  72.     while (*xpp) {
  73.     struct proc * sender = *xpp;

  74.         if (src_e == ANY || src_p == proc_nr(sender)) {
  75.             int call;
  76.      assert(!RTS_ISSET(sender, RTS_SLOT_FREE));
  77.      assert(!RTS_ISSET(sender, RTS_NO_ENDPOINT));

  78.      /* Found acceptable message. Copy it and update status. */
  79.        assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
  80.      caller_ptr->p_delivermsg = sender->p_sendmsg;
  81.      caller_ptr->p_delivermsg.m_source = sender->p_endpoint;
  82.      caller_ptr->p_misc_flags |= MF_DELIVERMSG;
  83.      RTS_UNSET(sender, RTS_SENDING);

  84.      call = (sender->p_misc_flags & MF_REPLY_PEND ? SENDREC : SEND);
  85.      IPC_STATUS_ADD_CALL(caller_ptr, call);

  86.      /*
  87.      * if the message is originaly from the kernel on behalf of this
  88.      * process, we must send the status flags accordingly
  89.      */
  90.      if (sender->p_misc_flags & MF_SENDING_FROM_KERNEL) {
  91.         IPC_STATUS_ADD_FLAGS(caller_ptr, IPC_FLG_MSG_FROM_KERNEL);
  92.         /* we can clean the flag now, not need anymore */
  93.         sender->p_misc_flags &= ~MF_SENDING_FROM_KERNEL;
  94.      }
  95.      if (sender->p_misc_flags & MF_SIG_DELAY)
  96.         sig_delay_done(sender);

  97. #if DEBUG_IPC_HOOK
  98.             hook_ipc_msgrecv(&caller_ptr->p_delivermsg, *xpp, caller_ptr);
  99. #endif
  100.         
  101.             *xpp = sender->p_q_link;        /* remove from queue */
  102.      sender->p_q_link = NULL;
  103.      goto receive_done;
  104.     }
  105.     xpp = &sender->p_q_link;        /* proceed to next */
  106.     }
  107.   }

  108.   /* No suitable message is available or the caller couldn't send in SENDREC.
  109.    * Block the process trying to receive, unless the flags tell otherwise.
  110.    */
  111.   if ( ! (flags & NON_BLOCKING)) {
  112.       /* Check for a possible deadlock before actually blocking. */
  113.       if (deadlock(RECEIVE, caller_ptr, src_e)) {
  114.           return(ELOCKED);
  115.       }

  116.       caller_ptr->p_getfrom_e = src_e;        
  117.       RTS_SET(caller_ptr, RTS_RECEIVING);
  118.       return(OK);
  119.   } else {
  120.     return(ENOTREADY);
  121.   }

  122. receive_done:
  123.   if (caller_ptr->p_misc_flags & MF_REPLY_PEND)
  124.      caller_ptr->p_misc_flags &= ~MF_REPLY_PEND;
  125.   return OK;
  126. }
11. 如果函数mini_send 返回值result==OK,则会接着调用函数mini_receive,随后将mini_receive的返回值result作为函数do_sync_ipc的返回值;如果函数mini_send的返回值result!=OK,将不会调用mini_receive函数,将mini_send的返回值result作为函数do_sync_ipc的返回值

点击(此处)折叠或打开

  1. 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 */
    {
    ......
  2. switch(call_nr) {
  3.   case SENDREC:
  4.     /* A flag is set so that notifications cannot interrupt SENDREC. */
  5.     caller_ptr->p_misc_flags |= MF_REPLY_PEND;
  6.     /* fall through */
  7.   case SEND:            
  8.     result = mini_send(caller_ptr, src_dst_e, m_ptr, 0);
  9.     if (call_nr == SEND || result != OK)
  10.         break;                /* done, or SEND failed */
  11.     /* fall through for SENDREC */
  12.   case RECEIVE:            
  13.     if (call_nr == RECEIVE) {
  14.         caller_ptr->p_misc_flags &= ~MF_REPLY_PEND;
  15.         IPC_STATUS_CLEAR(caller_ptr); /* clear IPC status code */
  16.     }
  17.     result = mini_receive(caller_ptr, src_dst_e, m_ptr, 0);
  18.     break;
  19.   case NOTIFY:
  20.     result = mini_notify(caller_ptr, src_dst_e);
  21.     break;
  22.   case SENDNB:
  23.         result = mini_send(caller_ptr, src_dst_e, m_ptr, NON_BLOCKING);
  24.         break;
  25.   default:
  26.     result = EBADCALL;            /* illegal system call */
  27.   }

  28.   /* Now, return the result of the system call to the caller. */
  29.   return(result);
  30. }
12. 函数do_sync_ipc返回到函数do_ipc中,与此同时将do_sync_ipc的返回值作为do_ipc的返回值返回

点击(此处)折叠或打开

  1. PUBLIC int do_ipc(reg_t r1, reg_t r2, reg_t r3)
  2. {
  3. ......
  4. switch(call_nr) {
  5.       case SENDREC:
  6.       case SEND:            
  7.       case RECEIVE:            
  8.       case NOTIFY:
  9.       case SENDNB:
  10.       {
  11.        /* Process accounting for scheduling */
  12.      caller_ptr->p_accounting.ipc_sync++;

  13.        return do_sync_ipc(caller_ptr, call_nr, (endpoint_t) r2,
  14.              (message *) r3);
  15.       }
  16. ......
  17. }
13. 函数do_ipc返回到33号中断(软中断对应的中断号)的中断处理程序(ipc_entry)中,然后调用函数switch_to_user

点击(此处)折叠或打开

  1. ENTRY(ipc_entry)
  2. ......
  3.     call    _C_LABEL(do_ipc)

  4.     /* restore the current process pointer and save the return value */
  5.     add    $3 * 4, %esp
  6.     pop    %esi
  7.     mov %eax, AXREG(%esi)

  8.     jmp    _C_LABEL(switch_to_user)
14. 函数switch_to_user最后由内核空间跳转到用户空间,如果运行的进程仍为发出系统调用的进程,那么将马上进行以下步骤的操作;如果不是发出系统调用的进程,那么待发出系统调用的进程得到正确的返回值时从阻塞队列进入就绪队列,在下一次执行时才进行以下步骤。

点击(此处)折叠或打开

  1. ENTRY(_sendrec)
  2.     push %ebp
  3.     movl %esp, %ebp
  4.     push %ebx
  5.     movl SRC_DST(%ebp), %eax /* eax = dest-src */
  6.     movl MESSAGE(%ebp), %ebx /* ebx = message pointer */
  7.     movl $SENDREC, %ecx /* _sendrec(srcdest, ptr) */
  8.     int $IPCVEC /* trap to the kernel */
  9.     pop %ebx
  10.     pop %ebp
  11.     ret
15. 执行到ret语句_sendrec返回,返回到函数_syscall继续下面的代码,然后返回到fork(_fork.c)中,最终返回到发出fork系统调用的用户进程中。

点击(此处)折叠或打开

  1. int _syscall(endpoint_t who, int syscallnr, message *msgptr)
  2. {
  3.   int status;

  4.   msgptr->m_type = syscallnr;
  5.   status = _sendrec(who, msgptr);
  6.   if (status != 0) {
  7.     /* 'sendrec' itself failed. */
  8.     /* XXX - strerror doesn't know all the codes */
  9.     msgptr->m_type = status;
  10.   }
  11.   if (msgptr->m_type < 0) {
  12.     errno = -msgptr->m_type;
  13.     return(-1);
  14.   }
  15.   return(msgptr->m_type);
  16. }
16. 至此,用户进程调用系统函数整个过程已分析完毕,后续会对mini_send和mini_receive函数做详细说明。







09-29 18:06