[comp.os.minix] Turbo C diff's; here is the right version of system.c

ASPEREN%HROEUR5.BITNET@wiscvm.wisc.edu (10/13/87)

On behalf of the original author .......

----------------------------Original message----------------------------
Hi,

you were right; I messed up the kernel/system.c file. The reason this
could happen was that I tried to read AT-format disks on my PC; this
worked fine for about 99% of the files but a few files were corrupted.
I thought I had checked it all but apparently this one slipped through;
below you'll find the complete and, I hope, correct version of system.c.
Due to some administrativia, we're not on the Usenet right now so I'll
have to postpone posting this file for a while; if you are on the net,
please post it for me. If you do, send me a message.

Sorry and Thanks,

Eelco van Asperen.

Erasmus University Rotterdam
Faculty Of Economics
Dept. of Computer Science/room H5-5
PObox 1738
3000 DR Rotterdam
The Netherlands

uucp:  ..!mcvax!{eurifb,olnl1}!euraiv1!evas
earn:  asperen@hroeur5

---------------------------------------------------------------------------
/* This task handles the interface between file system and kernel as well as
 * between memory manager and kernel.  System services are obtained by sending
 * sys_task() a message specifying what is needed.  To make life easier for
 * MM and FS, a library is provided with routines whose names are of the
 * form sys_xxx, e.g. sys_xit sends the SYS_XIT message to sys_task.  The
 * message types and parameters are:
 *
 *   SYS_FORK    informs kernel that a process has forked
 *   SYS_NEWMAP  allows MM to set up a process memory map
 *   SYS_EXEC    sets program counter and stack pointer after EXEC
 *   SYS_XIT     informs kernel that a process has exited
 *   SYS_GETSP   caller wants to read out some process' stack pointer
 *   SYS_TIMES   caller wants to get accounting times for a process
 *   SYS_ABORT   MM or FS cannot go on; abort MINIX
 *   SYS_SIG     send a signal to a process
 *   SYS_COPY    requests a block of data to be copied between processes
 *
 * Message type m1 is used for all except SYS_SIG and SYS_COPY, both of
 * which need special parameter types.
 *
 *    m_type       PROC1     PROC2      PID     MEM_PTR
 * ------------------------------------------------------
 * | SYS_FORK   | parent  |  child  |   pid   |         |
 * |------------+---------+---------+---------+---------|
 * | SYS_NEWMAP | proc nr |         |         | map ptr |
 * |------------+---------+---------+---------+---------|
 * | SYS_EXEC   | proc nr |         | new sp  |         |
 * |------------+---------+---------+---------+---------|
 * | SYS_XIT    | parent  | exitee  |         |         |
 * |------------+---------+---------+---------+---------|
 * | SYS_GETSP  | proc nr |         |         |         |
 * |------------+---------+---------+---------+---------|
 * | SYS_TIMES  | proc nr |         | buf ptr |         |
 * |------------+---------+---------+---------+---------|
 * | SYS_ABORT  |         |         |         |         |
 * ------------------------------------------------------
 *
 *
 *    m_type       m6_i1     m6_i2     m6_i3     m6_f1
 * ------------------------------------------------------
 * | SYS_SIG    | proc_nr  |  sig    |         | handler |
 * ------------------------------------------------------
 *
 *
 *    m_type      m5_c1   m5_i1    m5_l1   m5_c2   m5_i2    m5_l2   m5_l3
 * --------------------------------------------------------------------------
 * | SYS_COPY   |src seg|src proc|src vir|dst seg|dst proc|dst vir| byte ct |
 * --------------------------------------------------------------------------
 *
 * In addition to the main sys_task() entry point, there are three other minor
 * entry points:
 *   cause_sig: take action to cause a signal to occur, sooner or later
 *   inform:    tell MM about pending signals
 *   umap:      compute the physical address for a given virtual address
 */

#include "../h/const.h"
#include "../h/type.h"
#include "../h/callnr.h"
#include "../h/com.h"
#include "../h/error.h"
#include "../h/signal.h"
#include "const.h"
#include "type.h"
#include "glo.h"
#include "proc.h"

#define COPY_UNIT     65534L    /* max bytes to copy at once */

extern phys_bytes umap();

PRIVATE message m;
PRIVATE char sig_stuff[SIG_PUSH_BYTES]; /* used to send signals to processes */

/*===========================================================================*
 *                              sys_task                                     *
 *===========================================================================*/
PUBLIC sys_task()
{
/* Main entry point of sys_task.  Get the message and dispatch on type. */

  register int r;

  while (TRUE) {
        receive(ANY, &m);

        switch (m.m_type) {     /* which system call */
            case SYS_FORK:      r = do_fork(&m);        break;
            case SYS_NEWMAP:    r = do_newmap(&m);      break;
            case SYS_EXEC:      r = do_exec(&m);        break;
            case SYS_XIT:       r = do_xit(&m);         break;
            case SYS_GETSP:     r = do_getsp(&m);       break;
            case SYS_TIMES:     r = do_times(&m);       break;
            case SYS_ABORT:     r = do_abort(&m);       break;
            case SYS_SIG:       r = do_sig(&m);         break;
            case SYS_COPY:      r = do_copy(&m);        break;
            default:            r = E_BAD_FCN;
        }

        m.m_type = r;           /* 'r' reports status of call */
        send(m.m_source, &m);   /* send reply to caller */
  }
}


/*===========================================================================*
 *                              do_fork                                      *
 *===========================================================================*/
PRIVATE int do_fork(m_ptr)
message *m_ptr;                 /* pointer to request message */
{
/* Handle sys_fork().  'k1' has forked.  The child is 'k2'. */

  register struct proc *rpc;
  register char *sptr, *dptr;   /* pointers for copying proc struct */
  int k1;                       /* number of parent process */
  int k2;                       /* number of child process */
  int pid;                      /* process id of child */
  int bytes;                    /* counter for copying proc struct */

  k1 = m_ptr->PROC1;            /* extract parent slot number from msg */
  k2 = m_ptr->PROC2;            /* extract child slot number */
  pid = m_ptr->PID;             /* extract child process id */

  if (k1 < 0 || k1 >= NR_PROCS || k2 < 0 || k2 >= NR_PROCS)return(E_BAD_PROC);
  rpc = proc_addr(k2);

  /* Copy parent 'proc' struct to child. */
  sptr = (char *) proc_addr(k1);        /* parent pointer */
  dptr = (char *) proc_addr(k2);        /* child pointer */
  bytes = sizeof(struct proc);          /* # bytes to copy */
  while (bytes--) *dptr++ = *sptr++;    /* copy parent struct to child */

  rpc->p_flags |= NO_MAP;       /* inhibit the process from running */
  rpc->p_pid = pid;             /* install child's pid */
  rpc->p_reg[RET_REG] = 0;      /* child sees pid = 0 to know it is child */

  rpc->user_time = 0;           /* set all the accounting times to 0 */
  rpc->sys_time = 0;
  rpc->child_utime = 0;
  rpc->child_stime = 0;
  return(OK);
}


/*===========================================================================*
 *                              do_newmap                                    *
 *===========================================================================*/
PRIVATE int do_newmap(m_ptr)
message *m_ptr;                 /* pointer to request message */
{
/* Handle sys_newmap().  Fetch the memory map from MM. */

  register struct proc *rp, *rsrc;
  phys_bytes src_phys, dst_phys, pn;
  vir_bytes vmm, vsys, vn;
  int caller;                   /* whose space has the new map (usually MM) */
  int k;                        /* process whose map is to be loaded */
  int old_flags;                /* value of flags before modification */
  struct mem_map *map_ptr;      /* virtual address of map inside caller (MM) */

  /* Extract message parameters and copy new memory map from MM. */
  caller = m_ptr->m_source;
  k = m_ptr->PROC1;
  map_ptr = (struct mem_map *) m_ptr->MEM_PTR;
  if (k < -NR_TASKS || k >= NR_PROCS) return(E_BAD_PROC);
  rp = proc_addr(k);            /* ptr to entry of user getting new map */
  rsrc = proc_addr(caller);     /* ptr to MM's proc entry */
  vn = NR_SEGS * sizeof(struct mem_map);
  pn = vn;
  vmm = (vir_bytes) map_ptr;    /* careful about sign extension */
  vsys = (vir_bytes) rp->p_map; /* again, careful about sign extension */
  if ( (src_phys = umap(rsrc, D, vmm, vn)) == 0)
        panic("bad call to sys_newmap (src)", NO_NUM);
  if ( (dst_phys = umap(proc_addr(SYSTASK), D, vsys, vn)) == 0)
        panic("bad call to sys_newmap (dst)", NO_NUM);
  phys_copy(src_phys, dst_phys, pn);

#ifdef i8088
  /* On 8088, set segment registers. */
  rp->p_reg[CS_REG] = rp->p_map[T].mem_phys;    /* set cs */
  rp->p_reg[DS_REG] = rp->p_map[D].mem_phys;    /* set ds */
  rp->p_reg[SS_REG] = rp->p_map[D].mem_phys;    /* set ss */
  rp->p_reg[ES_REG] = rp->p_map[D].mem_phys;    /* set es */
#endif

  old_flags = rp->p_flags;      /* save the previous value of the flags */
  rp->p_flags &= ~NO_MAP;
  if (old_flags != 0 && rp->p_flags == 0) ready(rp);
  return(OK);
}


/*===========================================================================*
 *                              do_exec                                      *
 *===========================================================================*/
PRIVATE int do_exec(m_ptr)
message *m_ptr;                 /* pointer to request message */
{
/* Handle sys_exec().  A process has done a successful EXEC. Patch it up. */

  register struct proc *rp;
  int k;                        /* which process */
  int *sp;                      /* new sp */

  k = m_ptr->PROC1;             /* 'k' tells which process did EXEC */
  sp = (int *) m_ptr->STACK_PTR;
  if (k < 0 || k >= NR_PROCS) return(E_BAD_PROC);
  rp = proc_addr(k);
  rp->p_sp = sp;                /* set the stack pointer */
  rp->p_pcpsw.pc = (int (*)()) 0;       /* reset pc */
  rp->p_alarm = 0;              /* reset alarm timer */
  rp->p_flags &= ~RECEIVING;    /* MM does not reply to EXEC call */
  if (rp->p_flags == 0) ready(rp);
  set_name(k, sp);              /* save command string for F1 display */
  return(OK);
}


/*===========================================================================*
 *                              do_xit                                       *
 *===========================================================================*/
PRIVATE int do_xit(m_ptr)
message *m_ptr;                 /* pointer to request message */
{
/* Handle sys_xit().  A process has exited. */

  register struct proc *rp, *rc;
  struct proc *np, *xp;
  int parent;                   /* number of exiting proc's parent */
  int proc_nr;                  /* number of process doing the exit */

  parent = m_ptr->PROC1;        /* slot number of parent process */
  proc_nr = m_ptr->PROC2;       /* slot number of exiting process */
  if (parent < 0 || parent >= NR_PROCS || proc_nr < 0 || proc_nr >= NR_PROCS)
        return(E_BAD_PROC);
  rp = proc_addr(parent);
  rc = proc_addr(proc_nr);
  rp->child_utime += rc->user_time + rc->child_utime;   /* accum child times */
  rp->child_stime += rc->sys_time + rc->child_stime;
  unready(rc);
  rc->p_alarm = 0;              /* turn off alarm timer */
  set_name(proc_nr, (char *) 0);        /* disable command printing for F1 */

  /* If the process being terminated happens to be queued trying to send a
   * message (i.e., the process was killed by a signal, rather than it doing an
   * EXIT), then it must be removed from the message queues.
   */
  if (rc->p_flags & SENDING) {
        /* Check all proc slots to see if the exiting process is queued. */
        for (rp = &proc[0]; rp < &proc[NR_TASKS + NR_PROCS]; rp++) {
                if (rp->p_callerq == NIL_PROC) continue;
                if (rp->p_callerq == rc) {
                        /* Exiting process is on front of this queue. */
                        rp->p_callerq = rc->p_sendlink;
                        break;
                } else {
                        /* See if exiting process is in middle of queue. */
                        np = rp->p_callerq;
                        while ( ( xp = np->p_sendlink) != NIL_PROC)
                                if (xp == rc) {
                                        np->p_sendlink = xp->p_sendlink;
                                        break;
                                } else {
                                        np = xp;
                                }
                }
        }
  }
  rc->p_flags = P_SLOT_FREE;
  return(OK);
}


/*===========================================================================*
 *                              do_getsp                                     *
 *===========================================================================*/
PRIVATE int do_getsp(m_ptr)
message *m_ptr;                 /* pointer to request message */
{
/* Handle sys_getsp().  MM wants to know what sp is. */

  register struct proc *rp;
  int k;                                /* whose stack pointer is wanted? */

  k = m_ptr->PROC1;
  if (k < 0 || k >= NR_PROCS) return(E_BAD_PROC);
  rp = proc_addr(k);
  m.STACK_PTR = (char *) rp->p_sp;      /* return sp here */
  return(OK);
}


/*===========================================================================*
 *                              do_times                                     *
 *===========================================================================*/
PRIVATE int do_times(m_ptr)
message *m_ptr;                 /* pointer to request message */
{
/* Handle sys_times().  Retrieve the accounting information. */

  register struct proc *rp;
  int k;

  k = m_ptr->PROC1;             /* k tells whose times are wanted */
  if (k < 0 || k >= NR_PROCS) return(E_BAD_PROC);
  rp = proc_addr(k);

  /* Insert the four times needed by the TIMES system call in the message. */
  m_ptr->USER_TIME   = rp->user_time;
  m_ptr->SYSTEM_TIME = rp->sys_time;
  m_ptr->CHILD_UTIME = rp->child_utime;
  m_ptr->CHILD_STIME = rp->child_stime;
  return(OK);
}


/*===========================================================================*
 *                              do_abort                                     *
 *===========================================================================*/
PRIVATE int do_abort(m_ptr)
message *m_ptr;                 /* pointer to request message */
{
/* Handle sys_abort.  MINIX is unable to continue.  Terminate operation. */

  panic("", NO_NUM);
}


/*===========================================================================*
 *                              do_sig                                       *
 *===========================================================================*/
PRIVATE int do_sig(m_ptr)
message *m_ptr;                 /* pointer to request message */
{
/* Handle sys_sig(). Signal a process.  The stack is known to be big enough. */

  register struct proc *rp;
  phys_bytes src_phys, dst_phys;
  vir_bytes vir_addr, sig_size, new_sp;
  int proc_nr;                  /* process number */
  int sig;                      /* signal number 1-16 */
  int (*sig_handler)();         /* pointer to the signal handler */

  /* Extract parameters and prepare to build the words that get pushed. */
  proc_nr = m_ptr->PR;          /* process being signalled */
  sig = m_ptr->SIGNUM;          /* signal number, 1 to 16 */
  sig_handler = m_ptr->FUNC;    /* run time system addr for catching sigs */
  if (proc_nr < LOW_USER || proc_nr >= NR_PROCS) return(E_BAD_PROC);
  rp = proc_addr(proc_nr);
  vir_addr = (vir_bytes) sig_stuff;     /* info to be pushed is in 'sig_stuff' *
/
  new_sp = (vir_bytes) rp->p_sp;

  /* Actually build the block of words to push onto the stack. */
  build_sig(sig_stuff, rp, sig);        /* build up the info to be pushed */

  /* Prepare to do the push, and do it. */
  sig_size = SIG_PUSH_BYTES;
  new_sp -= sig_size;
  src_phys = umap(proc_addr(SYSTASK), D, vir_addr, sig_size);
  dst_phys = umap(rp, S, new_sp, sig_size);
  if (dst_phys == 0) panic("do_sig can't signal; SP bad", NO_NUM);
  phys_copy(src_phys, dst_phys, (phys_bytes) sig_size); /* push pc, psw */

  /* Change process' sp and pc to reflect the interrupt. */
  rp->p_sp = (int *) new_sp;
  rp->p_pcpsw.pc = sig_handler;
  return(OK);
}


/*===========================================================================*
 *                              do_copy                                      *
 *===========================================================================*/
PRIVATE int do_copy(m_ptr)
message *m_ptr;                 /* pointer to request message */
{
/* Handle sys_copy().  Copy data for MM or FS. */

  int src_proc, dst_proc, src_space, dst_space;
  vir_bytes src_vir, dst_vir;
  phys_bytes src_phys, dst_phys, bytes;

  /* Dismember the command message. */
  src_proc = m_ptr->SRC_PROC_NR;
  dst_proc = m_ptr->DST_PROC_NR;
  src_space = m_ptr->SRC_SPACE;
  dst_space = m_ptr->DST_SPACE;
  src_vir = (vir_bytes) m_ptr->SRC_BUFFER;
  dst_vir = (vir_bytes) m_ptr->DST_BUFFER;
  bytes = (phys_bytes) m_ptr->COPY_BYTES;

  /* Compute the source and destination addresses and do the copy. */
  if (src_proc == ABS)
        src_phys = (phys_bytes) m_ptr->SRC_BUFFER;
  else
        src_phys = umap(proc_addr(src_proc),src_space,src_vir,(vir_bytes)bytes);

  if (dst_proc == ABS)
        dst_phys = (phys_bytes) m_ptr->DST_BUFFER;
  else
        dst_phys = umap(proc_addr(dst_proc),dst_space,dst_vir,(vir_bytes)bytes);

  if (src_phys == 0 || dst_phys == 0) return(EFAULT);
  phys_copy(src_phys, dst_phys, bytes);
  return(OK);
}


/*===========================================================================*
 *                              cause_sig                                    *
 *===========================================================================*/
PUBLIC cause_sig(proc_nr, sig_nr)
int proc_nr;                    /* process to be signalled */
int sig_nr;                     /* signal to be sent in range 1 - 16 */
{
/* A task wants to send a signal to a process.   Examples of such tasks are:
 *   TTY wanting to cause SIGINT upon getting a DEL
 *   CLOCK wanting to cause SIGALRM when timer expires
 * Signals are handled by sending a message to MM.  The tasks don't dare do
 * that directly, for fear of what would happen if MM were busy.  Instead they
 * call cause_sig, which sets bits in p_pending, and then carefully checks to
 * see if MM is free.  If so, a message is sent to it.  If not, when it becomes
 * free, a message is sent.  The calling task always gets control back from
 * cause_sig() immediately.
 */

  register struct proc *rp;

  rp = proc_addr(proc_nr);
  if (rp->p_pending == 0) sig_procs++;  /* incr if a new proc is now pending */
  rp->p_pending |= 1 << (sig_nr - 1);
  inform(MM_PROC_NR);           /* see if MM is free */
}


/*===========================================================================*
 *                              inform                                       *
 *===========================================================================*/
PUBLIC inform(proc_nr)
int proc_nr;                    /* MM_PROC_NR or FS_PROC_NR */
{
/* When a signal is detected by the kernel (e.g., DEL), or generated by a task
 * (e.g. clock task for SIGALRM), cause_sig() is called to set a bit in the
 * p_pending field of the process to signal.  Then inform() is called to see
 * if MM is idle and can be told about it.  Whenever MM blocks, a check is
 * made to see if 'sig_procs' is nonzero; if so, inform() is called.
 */

  register struct proc *rp, *mmp;

  /* If MM is not waiting for new input, forget it. */
  mmp = proc_addr(proc_nr);
  if ( ((mmp->p_flags & RECEIVING) == 0) || mmp->p_getfrom != ANY) return;

  /* MM is waiting for new input.  Find a process with pending signals. */
  for (rp = proc_addr(0); rp < proc_addr(NR_PROCS); rp++)
        if (rp->p_pending != 0) {
                m.m_type = KSIG;
                m.PROC1 = rp - proc - NR_TASKS;
                m.SIG_MAP = rp->p_pending;
                sig_procs--;
                if (mini_send(HARDWARE, proc_nr, &m) != OK)
                        panic("can't inform MM", NO_NUM);
                rp->p_pending = 0;      /* the ball is now in MM's court */
                return;
        }
}


/*===========================================================================*
 *                              umap                                         *
 *===========================================================================*/
PUBLIC phys_bytes umap(rp, seg, vir_addr, bytes)
register struct proc *rp;       /* pointer to proc table entry for process */
int seg;                        /* T, D, or S segment */
vir_bytes vir_addr;             /* virtual address in bytes within the seg */
vir_bytes bytes;                /* # of bytes to be copied */
{
/* Calculate the physical memory address for a given virtual address. */
  vir_clicks vc;                /* the virtual address in clicks */
  phys_bytes seg_base, pa;      /* intermediate variables as phys_bytes */

  /* If 'seg' is D it could really be S and vice versa.  T really means T.
   * If the virtual address falls in the gap,  it causes a problem. On the
   * 8088 it is probably a legal stack reference, since "stackfaults" are
   * not detected by the hardware.  On 8088s, the gap is called S and
   * accepted, but on other machines it is called D and rejected.
   */
  if (bytes <= 0) return( (phys_bytes) 0);
  vc = (vir_addr + bytes - 1) >> CLICK_SHIFT;   /* last click of data */

#ifdef i8088
  if (seg != T)
        seg = (vc < rp->p_map[D].mem_vir + rp->p_map[D].mem_len ? D : S);
#else
  if (seg != T)
        seg = (vc < rp->p_map[S].mem_vir ? D : S);
#endif

  if((vir_addr>>CLICK_SHIFT) >= rp->p_map[seg].mem_vir + rp->p_map[seg].mem_len)
        return( (phys_bytes) 0 );
  seg_base = (phys_bytes) rp->p_map[seg].mem_phys;
  seg_base = seg_base << CLICK_SHIFT;   /* segment orgin in bytes */
  pa = (phys_bytes) vir_addr;
  pa -= rp->p_map[seg].mem_vir << CLICK_SHIFT;
  return(seg_base + pa);
}

pxd3563@ritcv.UUCP (Patrick Deupree) (10/16/87)

I have recently found out about MINIX and I am probably going to buy the
book and give it a shot.  However, I was wondering how efficient it is to
compile it using Turbo C.  I have noticed all these fixes posted, and I
know that in Turbo C, the creating of a child process halts the parent
process until the child is done executing.

Is there a compiler (like possibly Microsoft C) that will allow the parent
to continue processing at the same time as the child process?  Also, does
the offer in the back of the book, for the binaries and source code, include
a compiler?

I'm just sort of curious.