Chinaunix首页 | 论坛 | 博客
  • 博客访问: 65986
  • 博文数量: 21
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 170
  • 用 户 组: 普通用户
  • 注册时间: 2015-10-15 14:23
个人简介

-计算机-每天学习一点专业知识

文章分类

全部博文(21)

文章存档

2019年(1)

2018年(15)

2015年(5)

我的朋友

分类: 其他UNIX

2015-11-11 16:53:31

8.  -》\kernel\proc.c

点击(此处)折叠或打开

  1. PUBLIC int do_ipc(reg_t r1, reg_t r2, reg_t r3)
  2. {
  3.   struct proc *const caller_ptr = get_cpulocal_var(proc_ptr);    /* get pointer to caller */
  4.   int call_nr = (int) r1;

  5.   assert(!RTS_ISSET(caller_ptr, RTS_SLOT_FREE));

  6.   /* bill kernel time to this process. */
  7.   kbill_ipc = caller_ptr;

  8.   /* If this process is subject to system call tracing, handle that first. */
  9.   if (caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) {
  10.     /* Are we tracing this process, and is it the first sys_call entry? */
  11.     if ((caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) ==
  12.                             MF_SC_TRACE) {
  13.         /* We must notify the tracer before processing the actual
  14.          * system call. If we don't, the tracer could not obtain the
  15.          * input message. Postpone the entire system call.
  16.          */
  17.         caller_ptr->p_misc_flags &= ~MF_SC_TRACE;
  18.         caller_ptr->p_misc_flags |= MF_SC_DEFER;

  19.         /* Signal the "enter system call" event. Block the process. */
  20.         cause_sig(proc_nr(caller_ptr), SIGTRAP);

  21.         /* Preserve the return register's value. */
  22.         return caller_ptr->p_reg.retreg;
  23.     }

  24.     /* If the MF_SC_DEFER flag is set, the syscall is now being resumed. */
  25.     caller_ptr->p_misc_flags &= ~MF_SC_DEFER;

  26.     assert (!(caller_ptr->p_misc_flags & MF_SC_ACTIVE));

  27.     /* Set a flag to allow reliable tracing of leaving the system call. */
  28.     caller_ptr->p_misc_flags |= MF_SC_ACTIVE;
  29.   }

  30.   if(caller_ptr->p_misc_flags & MF_DELIVERMSG) {
  31.     panic("sys_call: MF_DELIVERMSG on for %s / %d\n",
  32.         caller_ptr->p_name, caller_ptr->p_endpoint);
  33.   }

  34.   /* Now check if the call is known and try to perform the request. The only
  35.    * system calls that exist in MINIX are sending and receiving messages.
  36.    * - SENDREC: combines SEND and RECEIVE in a single system call
  37.    * - SEND: sender blocks until its message has been delivered
  38.    * - RECEIVE: receiver blocks until an acceptable message has arrived
  39.    * - NOTIFY: asynchronous call; deliver notification or mark pending
  40.    * - SENDA: list of asynchronous send requests
  41.    */
  42.   switch(call_nr) {
  43.       case SENDREC:
  44.       case SEND:            
  45.       case RECEIVE:            
  46.       case NOTIFY:
  47.       case SENDNB:
  48.       {
  49.        /* Process accounting for scheduling */
  50.      caller_ptr->p_accounting.ipc_sync++;

  51.        return do_sync_ipc(caller_ptr, call_nr, (endpoint_t) r2,
  52.              (message *) r3);
  53.       }
  54.       case SENDA:
  55.       {
  56.       /*
  57.        * Get and check the size of the argument in bytes as it is a
  58.        * table
  59.        */
  60.        size_t msg_size = (size_t) r2;
  61.   
  62.        /* Process accounting for scheduling */
  63.      caller_ptr->p_accounting.ipc_async++;
  64.  
  65.        /* Limit size to something reasonable. An arbitrary choice is 16
  66.        * times the number of process table entries.
  67.        */
  68.        if (msg_size > 16*(NR_TASKS + NR_PROCS))
  69.      return EDOM;
  70.        return mini_senda(caller_ptr, (asynmsg_t *) r3, msg_size);
  71.       }
  72.       default:
  73.     return EBADCALL;        /* illegal system call */
  74.   }
  75. }

点击(此处)折叠或打开

  1. PRIVATE int do_sync_ipc(struct proc * caller_ptr, /* who made the call */
  2.             int call_nr,    /* system call number and flags */
  3.             endpoint_t src_dst_e,    /* src or dst of the call */
  4.             message *m_ptr)    /* users pointer to a message */
  5. {
  6.   int result;                    /* the system call's result */
  7.   int src_dst_p;                /* Process slot number */
  8.   char *callname;

  9.   /* Check destination. RECEIVE is the only call that accepts ANY (in addition
  10.    * to a real endpoint). The other calls (SEND, SENDREC, and NOTIFY) require an
  11.    * endpoint to corresponds to a process. In addition, it is necessary to check
  12.    * whether a process is allowed to send to a given destination.
  13.    */
  14.   assert(call_nr != SENDA);

  15.   /* Only allow non-negative call_nr values less than 32 */
  16.   if (call_nr < 0 || call_nr > IPCNO_HIGHEST || call_nr >= 32
  17.       || !(callname = ipc_call_names[call_nr])) {
  18. #if DEBUG_ENABLE_IPC_WARNINGS
  19.       printf("sys_call: trap %d not allowed, caller %d, src_dst %d\n",
  20.           call_nr, proc_nr(caller_ptr), src_dst_p);
  21. #endif
  22.     return(ETRAPDENIED);        /* trap denied by mask or kernel */
  23.   }

  24.   if (src_dst_e == ANY)
  25.   {
  26.     if (call_nr != RECEIVE)
  27.     {
  28. #if 0
  29.         printf("sys_call: %s by %d with bad endpoint %d\n",
  30.             callname,
  31.             proc_nr(caller_ptr), src_dst_e);
  32. #endif
  33.         return EINVAL;
  34.     }
  35.     src_dst_p = (int) src_dst_e;
  36.   }
  37.   else
  38.   {
  39.     /* Require a valid source and/or destination process. */
  40.     if(!isokendpt(src_dst_e, &src_dst_p)) {
  41. #if 0
  42.         printf("sys_call: %s by %d with bad endpoint %d\n",
  43.             callname,
  44.             proc_nr(caller_ptr), src_dst_e);
  45. #endif
  46.         return EDEADSRCDST;
  47.     }

  48.     /* If the call is to send to a process, i.e., for SEND, SENDNB,
  49.      * SENDREC or NOTIFY, verify that the caller is allowed to send to
  50.      * the given destination.
  51.      */
  52.     if (call_nr != RECEIVE)
  53.     {
  54.         if (!may_send_to(caller_ptr, src_dst_p)) {
  55. #if DEBUG_ENABLE_IPC_WARNINGS
  56.             printf(
  57.             "sys_call: ipc mask denied %s from %d to %d\n",
  58.                 callname,
  59.                 caller_ptr->p_endpoint, src_dst_e);
  60. #endif
  61.             return(ECALLDENIED);    /* call denied by ipc mask */
  62.         }
  63.     }
  64.   }

  65.   /* Check if the process has privileges for the requested call. Calls to the
  66.    * kernel may only be SENDREC, because tasks always reply and may not block
  67.    * if the caller doesn't do receive().
  68.    */
  69.   if (!(priv(caller_ptr)->s_trap_mask & (1 << call_nr))) {
  70. #if DEBUG_ENABLE_IPC_WARNINGS
  71.       printf("sys_call: %s not allowed, caller %d, src_dst %d\n",
  72.           callname, proc_nr(caller_ptr), src_dst_p);
  73. #endif
  74.     return(ETRAPDENIED);        /* trap denied by mask or kernel */
  75.   }

  76.   if (call_nr != SENDREC && call_nr != RECEIVE && iskerneln(src_dst_p)) {
  77. #if DEBUG_ENABLE_IPC_WARNINGS
  78.       printf("sys_call: trap %s not allowed, caller %d, src_dst %d\n",
  79.            callname, proc_nr(caller_ptr), src_dst_e);
  80. #endif
  81.     return(ETRAPDENIED);        /* trap denied by mask or kernel */
  82.   }

  83.   switch(call_nr) {
  84.   case SENDREC:
  85.     /* A flag is set so that notifications cannot interrupt SENDREC. */
  86.     caller_ptr->p_misc_flags |= MF_REPLY_PEND;
  87.     /* fall through */
  88.   case SEND:            
  89.     result = mini_send(caller_ptr, src_dst_e, m_ptr, 0);
  90.     if (call_nr == SEND || result != OK)
  91.         break;                /* done, or SEND failed */
  92.     /* fall through for SENDREC */
  93.   case RECEIVE:            
  94.     if (call_nr == RECEIVE) {
  95.         caller_ptr->p_misc_flags &= ~MF_REPLY_PEND;
  96.         IPC_STATUS_CLEAR(caller_ptr); /* clear IPC status code */
  97.     }
  98.     result = mini_receive(caller_ptr, src_dst_e, m_ptr, 0);
  99.     break;
  100.   case NOTIFY:
  101.     result = mini_notify(caller_ptr, src_dst_e);
  102.     break;
  103.   case SENDNB:
  104.         result = mini_send(caller_ptr, src_dst_e, m_ptr, NON_BLOCKING);
  105.         break;
  106.   default:
  107.     result = EBADCALL;            /* illegal system call */
  108.   }

  109.   /* Now, return the result of the system call to the caller. */
  110.   return(result);
  111. }
9. 由于call_nr==SENDREC,所以,首先调用mini_send函数(同样在源文件\kernel\proc.c

点击(此处)折叠或打开

  1. /*===========================================================================*
  2.  *                mini_send                 *
  3.  *===========================================================================*/
  4. PUBLIC int mini_send(
  5.   register struct proc *caller_ptr,    /* who is trying to send a message? */
  6.   endpoint_t dst_e,            /* to whom is message being sent? */
  7.   message *m_ptr,            /* pointer to message buffer */
  8.   const int flags
  9. )
  10. {
  11. /* Send a message from 'caller_ptr' to 'dst'. If 'dst' is blocked waiting
  12.  * for this message, copy the message to it and unblock 'dst'. If 'dst' is
  13.  * not waiting at all, or is waiting for another source, queue 'caller_ptr'.
  14.  */
  15.   register struct proc *dst_ptr;
  16.   register struct proc **xpp;
  17.   int dst_p;
  18.   dst_p = _ENDPOINT_P(dst_e);
  19.   dst_ptr = proc_addr(dst_p);

  20.   if (RTS_ISSET(dst_ptr, RTS_NO_ENDPOINT))
  21.   {
  22.     return EDEADSRCDST;
  23.   }

  24.   /* Check if 'dst' is blocked waiting for this message. The destination's
  25.    * RTS_SENDING flag may be set when its SENDREC call blocked while sending.
  26.    */
  27.   if (WILLRECEIVE(dst_ptr, caller_ptr->p_endpoint)) {
  28.     int call;
  29.     /* Destination is indeed waiting for this message. */
  30.     assert(!(dst_ptr->p_misc_flags & MF_DELIVERMSG));    

  31.     if (!(flags & FROM_KERNEL)) {
  32.         if(copy_msg_from_user(caller_ptr, m_ptr, &dst_ptr->p_delivermsg))
  33.             return EFAULT;
  34.     } else {
  35.         dst_ptr->p_delivermsg = *m_ptr;
  36.         IPC_STATUS_ADD_FLAGS(dst_ptr, IPC_FLG_MSG_FROM_KERNEL);
  37.     }

  38.     dst_ptr->p_delivermsg.m_source = caller_ptr->p_endpoint;
  39.     dst_ptr->p_misc_flags |= MF_DELIVERMSG;

  40.     call = (caller_ptr->p_misc_flags & MF_REPLY_PEND ? SENDREC
  41.         : (flags & NON_BLOCKING ? SENDNB : SEND));
  42.     IPC_STATUS_ADD_CALL(dst_ptr, call);

  43.     if (dst_ptr->p_misc_flags & MF_REPLY_PEND)
  44.         dst_ptr->p_misc_flags &= ~MF_REPLY_PEND;

  45.     RTS_UNSET(dst_ptr, RTS_RECEIVING)
阅读(1199) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~