]> Zhao Yanbai Git Server - minix.git/commitdiff
do_ipc() rearrangements
authorTomas Hruby <tom@minix3.org>
Tue, 6 Apr 2010 11:24:26 +0000 (11:24 +0000)
committerTomas Hruby <tom@minix3.org>
Tue, 6 Apr 2010 11:24:26 +0000 (11:24 +0000)
this patch does not add or change any functionality of do_ipc(), it
only makes things a little cleaner (hopefully).

Until now do_ipc() was responsible for handling all ipc calls. The
catch is that SENDA is fairly different which results in some ugly
code like this typecasting and variables naming which does not make
much sense for SENDA and makes the code hard to read.

result = mini_senda(caller_ptr, (asynmsg_t *)m_ptr, (size_t)src_dst_e);

As it is called directly from assembly, the new do_ipc() takes as
input values of 3 registers in reg_t variables (it used to be 4,
however, bit_map wasn't used so I removed it), does the checks common
to all ipc calls and call the appropriate handler either for
do_sync_ipc() (all except SENDA) or mini_senda() (for SENDA) while
typecasting the reg_t values correctly. As a result, handling SENDA
differences in do_sync_ipc() is no more needed. Also the code that
uses msg_size variable is improved a little bit.

arch_do_syscall() is simplified too.

kernel/arch/i386/arch_system.c
kernel/arch/i386/mpx.S
kernel/proc.c
kernel/proto.h

index 91bc629a7337e03a94a8af6ee1ee7dd32003f4f7..486785d4f2eb88a867fdf06c173e3b78103aba11 100644 (file)
@@ -10,6 +10,7 @@
 #include <minix/portio.h>
 #include <minix/cpufeature.h>
 #include <a.out.h>
+#include <assert.h>
 
 #include "archconst.h"
 #include "proto.h"
@@ -455,20 +456,11 @@ PUBLIC int arch_set_params(char *params, int size)
 
 PUBLIC void arch_do_syscall(struct proc *proc)
 {
-/* Perform a previously postponed system call.
- */
-  int call_nr, src_dst_e;
-  message *m_ptr;
-  long bit_map;
-
-  /* Get the system call parameters from their respective registers. */
-  call_nr = proc->p_reg.cx;
-  src_dst_e = proc->p_reg.retreg;
-  m_ptr = (message *) proc->p_reg.bx;
-  bit_map = proc->p_reg.dx;
-
+  /* do_ipc assumes that it's running because of the current process */
+  assert(proc == proc_ptr);
   /* Make the system call, for real this time. */
-  proc->p_reg.retreg = do_ipc(call_nr, src_dst_e, m_ptr, bit_map);
+  proc->p_reg.retreg =
+         do_ipc(proc->p_reg.cx, proc->p_reg.retreg, proc->p_reg.bx);
 }
 
 PUBLIC struct proc * arch_finish_schedcheck(void)
index 4a98d84bf73be1691e37711e67d6187e06a937a3..f441d79afea7b1a33cc2972c193a054c70f5aa17 100644 (file)
@@ -396,7 +396,6 @@ ipc_entry:
         * SAVE_PROCESS_CTX() does not clobber these registers, they are still
         * set as the userspace have set them
         */
-       push    %edx
        push    %ebx
        push    %eax
        push    %ecx
@@ -412,7 +411,7 @@ ipc_entry:
        call    do_ipc
 
        /* restore the current process pointer and save the return value */
-       add     $4 * 4, %esp
+       add     $3 * 4, %esp
        pop     %esi
        mov     %eax, AXREG(%esi)
 
index 69b90213abf796200711377eb80e0e4c8d2bbb0a..3a143aa9be02edca1b42fd98039f39287d2962eb 100644 (file)
@@ -240,74 +240,25 @@ check_misc_flags:
        return proc_ptr;
 }
 
-/*===========================================================================*
- *                             sys_call                                     * 
- *===========================================================================*/
-PUBLIC int do_ipc(call_nr, src_dst_e, m_ptr, bit_map)
-int call_nr;                   /* system call number and flags */
-endpoint_t src_dst_e;          /* src to receive from or dst to send to */
-message *m_ptr;                        /* pointer to message in the caller's space */
-long bit_map;                  /* notification event set or flags */
-{
-/* System calls are done by trapping to the kernel with an INT instruction.
- * The trap is caught and sys_call() is called to send or receive a message
- * (or both). The caller is always given by 'proc_ptr'.
+/*
+ * handler for all synchronous IPC callsi
  */
-  struct proc *const caller_ptr = proc_ptr;    /* get pointer to caller */
+PUBLIC 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 */
+{
   int result;                                  /* the system call's result */
   int src_dst_p;                               /* Process slot number */
-  size_t msg_size;
-
-  assert(!RTS_ISSET(caller_ptr, RTS_SLOT_FREE));
-
-  /* If this process is subject to system call tracing, handle that first. */
-  if (caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) {
-       /* Are we tracing this process, and is it the first sys_call entry? */
-       if ((caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) ==
-                                                       MF_SC_TRACE) {
-               /* We must notify the tracer before processing the actual
-                * system call. If we don't, the tracer could not obtain the
-                * input message. Postpone the entire system call.
-                */
-               caller_ptr->p_misc_flags &= ~MF_SC_TRACE;
-               caller_ptr->p_misc_flags |= MF_SC_DEFER;
 
-               /* Signal the "enter system call" event. Block the process. */
-               cause_sig(proc_nr(caller_ptr), SIGTRAP);
-
-               /* Preserve the return register's value. */
-               return caller_ptr->p_reg.retreg;
-       }
-
-       /* If the MF_SC_DEFER flag is set, the syscall is now being resumed. */
-       caller_ptr->p_misc_flags &= ~MF_SC_DEFER;
-
-       assert (!(caller_ptr->p_misc_flags & MF_SC_ACTIVE));
-
-       /* Set a flag to allow reliable tracing of leaving the system call. */
-       caller_ptr->p_misc_flags |= MF_SC_ACTIVE;
-  }
-
-  if(caller_ptr->p_misc_flags & MF_DELIVERMSG) {
-       panic("sys_call: MF_DELIVERMSG on for %s / %d\n",
-               caller_ptr->p_name, caller_ptr->p_endpoint);
-  }
-
-  /* Clear IPC status code. */
-  IPC_STATUS_CLEAR(caller_ptr);
-
-  /* Check destination. SENDA is special because its argument is a table and
-   * not a single destination. RECEIVE is the only call that accepts ANY (in
-   * addition to a real endpoint). The other calls (SEND, SENDREC,
-   * and NOTIFY) require an endpoint to corresponds to a process. In addition,
-   * it is necessary to check whether a process is allowed to send to a given
-   * destination.
+  /* Check destination. RECEIVE is the only call that accepts ANY (in addition
+   * to a real endpoint). The other calls (SEND, SENDREC, and NOTIFY) require an
+   * endpoint to corresponds to a process. In addition, it is necessary to check
+   * whether a process is allowed to send to a given destination.
    */
-  if (call_nr == SENDA)
-  {
-       /* No destination argument */
-  }
-  else if (src_dst_e == ANY)
+  assert(call_nr != SENDA);
+
+  if (src_dst_e == ANY)
   {
        if (call_nr != RECEIVE)
        {
@@ -317,7 +268,7 @@ long bit_map;                       /* notification event set or flags */
 #endif
                return EINVAL;
        }
-       src_dst_p = src_dst_e;
+       src_dst_p = (int) src_dst_e;
   }
   else
   {
@@ -369,10 +320,7 @@ long bit_map;                      /* notification event set or flags */
        return(ETRAPDENIED);            /* trap denied by mask or kernel */
   }
 
-  /* SENDA has no src_dst value here, so this check is in mini_senda() as well.
-   */
-  if (call_nr != SENDREC && call_nr != RECEIVE && call_nr != SENDA &&
-       iskerneln(src_dst_p)) {
+  if (call_nr != SENDREC && call_nr != RECEIVE && iskerneln(src_dst_p)) {
 #if DEBUG_ENABLE_IPC_WARNINGS
       printf("sys_call: trap %d not allowed, caller %d, src_dst %d\n", 
           call_nr, proc_nr(caller_ptr), src_dst_e);
@@ -380,31 +328,6 @@ long bit_map;                      /* notification event set or flags */
        return(ETRAPDENIED);            /* trap denied by mask or kernel */
   }
 
-  /* Get and check the size of the argument in bytes.
-   * Normally this is just the size of a regular message, but in the
-   * case of SENDA the argument is a table.
-   */
-  if(call_nr == SENDA) {
-       msg_size = (size_t) src_dst_e;
-
-       /* Limit size to something reasonable. An arbitrary choice is 16
-        * times the number of process table entries.
-        */
-       if (msg_size > 16*(NR_TASKS + NR_PROCS))
-               return EDOM;
-       msg_size *= sizeof(asynmsg_t);  /* convert to bytes */
-  } else {
-       msg_size = sizeof(*m_ptr);
-  }
-
-  /* Now check if the call is known and try to perform the request. The only
-   * system calls that exist in MINIX are sending and receiving messages.
-   *   - SENDREC: combines SEND and RECEIVE in a single system call
-   *   - SEND:    sender blocks until its message has been delivered
-   *   - RECEIVE: receiver blocks until an acceptable message has arrived
-   *   - NOTIFY:  asynchronous call; deliver notification or mark pending
-   *   - SENDA:   list of asynchronous send requests
-   */
   switch(call_nr) {
   case SENDREC:
        /* A flag is set so that notifications cannot interrupt SENDREC. */
@@ -426,9 +349,6 @@ long bit_map;                       /* notification event set or flags */
   case SENDNB:
         result = mini_send(caller_ptr, src_dst_e, m_ptr, NON_BLOCKING);
         break;
-  case SENDA:
-       result = mini_senda(caller_ptr, (asynmsg_t *)m_ptr, (size_t)src_dst_e);
-       break;
   default:
        result = EBADCALL;                      /* illegal system call */
   }
@@ -437,6 +357,85 @@ long bit_map;                      /* notification event set or flags */
   return(result);
 }
 
+PUBLIC int do_ipc(reg_t r1, reg_t r2, reg_t r3)
+{
+  struct proc * caller_ptr = proc_ptr; /* always the current process */
+  int call_nr = (int) r1;
+
+  assert(!RTS_ISSET(caller_ptr, RTS_SLOT_FREE));
+
+  /* If this process is subject to system call tracing, handle that first. */
+  if (caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) {
+       /* Are we tracing this process, and is it the first sys_call entry? */
+       if ((caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) ==
+                                                       MF_SC_TRACE) {
+               /* We must notify the tracer before processing the actual
+                * system call. If we don't, the tracer could not obtain the
+                * input message. Postpone the entire system call.
+                */
+               caller_ptr->p_misc_flags &= ~MF_SC_TRACE;
+               caller_ptr->p_misc_flags |= MF_SC_DEFER;
+
+               /* Signal the "enter system call" event. Block the process. */
+               cause_sig(proc_nr(caller_ptr), SIGTRAP);
+
+               /* Preserve the return register's value. */
+               return caller_ptr->p_reg.retreg;
+       }
+
+       /* If the MF_SC_DEFER flag is set, the syscall is now being resumed. */
+       caller_ptr->p_misc_flags &= ~MF_SC_DEFER;
+
+       assert (!(caller_ptr->p_misc_flags & MF_SC_ACTIVE));
+
+       /* Set a flag to allow reliable tracing of leaving the system call. */
+       caller_ptr->p_misc_flags |= MF_SC_ACTIVE;
+  }
+
+  if(caller_ptr->p_misc_flags & MF_DELIVERMSG) {
+       panic("sys_call: MF_DELIVERMSG on for %s / %d\n",
+               caller_ptr->p_name, caller_ptr->p_endpoint);
+  }
+
+  /* Clear IPC status code. */
+  IPC_STATUS_CLEAR(caller_ptr);
+
+  /* Now check if the call is known and try to perform the request. The only
+   * system calls that exist in MINIX are sending and receiving messages.
+   *   - SENDREC: combines SEND and RECEIVE in a single system call
+   *   - SEND:    sender blocks until its message has been delivered
+   *   - RECEIVE: receiver blocks until an acceptable message has arrived
+   *   - NOTIFY:  asynchronous call; deliver notification or mark pending
+   *   - SENDA:   list of asynchronous send requests
+   */
+  switch(call_nr) {
+       case SENDREC:
+       case SEND:                      
+       case RECEIVE:                   
+       case NOTIFY:
+       case SENDNB:
+           return do_sync_ipc(caller_ptr, call_nr, (endpoint_t) r2,
+                           (message *) r3);
+       case SENDA:
+       {
+           /*
+            * Get and check the size of the argument in bytes as it is a
+            * table
+            */
+           size_t msg_size = (size_t) r2;
+  
+           /* Limit size to something reasonable. An arbitrary choice is 16
+            * times the number of process table entries.
+            */
+           if (msg_size > 16*(NR_TASKS + NR_PROCS))
+               return EDOM;
+           return mini_senda(caller_ptr, (asynmsg_t *) r3, msg_size);
+       }
+       default:
+       return EBADCALL;                /* illegal system call */
+  }
+}
+
 /*===========================================================================*
  *                             deadlock                                     * 
  *===========================================================================*/
index 8a0040e4f377cffce9c639cddf062d282e4cfd3c..58fed5f6e96b94d458d1fe91c628a9256b9d4632 100644 (file)
@@ -35,8 +35,8 @@ _PROTOTYPE( void prepare_shutdown, (int how)                          );
 _PROTOTYPE( void minix_shutdown, (struct timer *tp)                    );
 
 /* proc.c */
-_PROTOTYPE( int do_ipc, (int call_nr, endpoint_t src_dst, 
-                                       message *m_ptr, long bit_map)   );
+
+_PROTOTYPE( int do_ipc, (reg_t r1, reg_t r2, reg_t r3)                 );
 _PROTOTYPE( int mini_notify, (const struct proc *src, endpoint_t dst)  );
 _PROTOTYPE( void enqueue, (struct proc *rp)                            );
 _PROTOTYPE( void dequeue, (const struct proc *rp)                      );