The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/servers/pm/main.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* This file contains the main program of the process manager and some related
    2  * procedures.  When MINIX starts up, the kernel runs for a little while,
    3  * initializing itself and its tasks, and then it runs PM and FS.  Both PM
    4  * and FS initialize themselves as far as they can. PM asks the kernel for
    5  * all free memory and starts serving requests.
    6  *
    7  * The entry points into this file are:
    8  *   main:      starts PM running
    9  *   setreply:  set the reply to be sent to process making an PM system call
   10  */
   11 
   12 #include "pm.h"
   13 #include <minix/keymap.h>
   14 #include <minix/callnr.h>
   15 #include <minix/com.h>
   16 #include <signal.h>
   17 #include <stdlib.h>
   18 #include <fcntl.h>
   19 #include <sys/resource.h>
   20 #include <string.h>
   21 #include "mproc.h"
   22 #include "param.h"
   23 
   24 #include "../../kernel/const.h"
   25 #include "../../kernel/config.h"
   26 #include "../../kernel/type.h"
   27 #include "../../kernel/proc.h"
   28 
   29 FORWARD _PROTOTYPE( void get_work, (void)                               );
   30 FORWARD _PROTOTYPE( void pm_init, (void)                                );
   31 FORWARD _PROTOTYPE( int get_nice_value, (int queue)                     );
   32 FORWARD _PROTOTYPE( void get_mem_chunks, (struct memory *mem_chunks)    );
   33 FORWARD _PROTOTYPE( void patch_mem_chunks, (struct memory *mem_chunks, 
   34         struct mem_map *map_ptr)        );
   35 
   36 #define click_to_round_k(n) \
   37         ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
   38 
   39 /*===========================================================================*
   40  *                              main                                         *
   41  *===========================================================================*/
   42 PUBLIC int main()
   43 {
   44 /* Main routine of the process manager. */
   45   int result, s, proc_nr;
   46   struct mproc *rmp;
   47   sigset_t sigset;
   48 
   49   pm_init();                    /* initialize process manager tables */
   50 
   51   /* This is PM's main loop-  get work and do it, forever and forever. */
   52   while (TRUE) {
   53         get_work();             /* wait for an PM system call */
   54 
   55         /* Check for system notifications first. Special cases. */
   56         if (call_nr == SYN_ALARM) {
   57                 pm_expire_timers(m_in.NOTIFY_TIMESTAMP);
   58                 result = SUSPEND;               /* don't reply */
   59         } else if (call_nr == SYS_SIG) {        /* signals pending */
   60                 sigset = m_in.NOTIFY_ARG;
   61                 if (sigismember(&sigset, SIGKSIG))  (void) ksig_pending();
   62                 result = SUSPEND;               /* don't reply */
   63         }
   64         /* Else, if the system call number is valid, perform the call. */
   65         else if ((unsigned) call_nr >= NCALLS) {
   66                 result = ENOSYS;
   67         } else {
   68                 result = (*call_vec[call_nr])();
   69         }
   70 
   71         /* Send the results back to the user to indicate completion. */
   72         if (result != SUSPEND) setreply(who, result);
   73 
   74         swap_in();              /* maybe a process can be swapped in? */
   75 
   76         /* Send out all pending reply messages, including the answer to
   77          * the call just made above.  The processes must not be swapped out.
   78          */
   79         for (proc_nr=0, rmp=mproc; proc_nr < NR_PROCS; proc_nr++, rmp++) {
   80                 /* In the meantime, the process may have been killed by a
   81                  * signal (e.g. if a lethal pending signal was unblocked)
   82                  * without the PM realizing it. If the slot is no longer in
   83                  * use or just a zombie, don't try to reply.
   84                  */
   85                 if ((rmp->mp_flags & (REPLY | ONSWAP | IN_USE | ZOMBIE)) ==
   86                    (REPLY | IN_USE)) {
   87                         if ((s=send(proc_nr, &rmp->mp_reply)) != OK) {
   88                                 panic(__FILE__,"PM can't reply to", proc_nr);
   89                         }
   90                         rmp->mp_flags &= ~REPLY;
   91                 }
   92         }
   93   }
   94   return(OK);
   95 }
   96 
   97 /*===========================================================================*
   98  *                              get_work                                     *
   99  *===========================================================================*/
  100 PRIVATE void get_work()
  101 {
  102 /* Wait for the next message and extract useful information from it. */
  103   if (receive(ANY, &m_in) != OK) panic(__FILE__,"PM receive error", NO_NUM);
  104   who = m_in.m_source;          /* who sent the message */
  105   call_nr = m_in.m_type;        /* system call number */
  106 
  107   /* Process slot of caller. Misuse PM's own process slot if the kernel is
  108    * calling. This can happen in case of synchronous alarms (CLOCK) or or 
  109    * event like pending kernel signals (SYSTEM).
  110    */
  111   mp = &mproc[who < 0 ? PM_PROC_NR : who];
  112 }
  113 
  114 /*===========================================================================*
  115  *                              setreply                                     *
  116  *===========================================================================*/
  117 PUBLIC void setreply(proc_nr, result)
  118 int proc_nr;                    /* process to reply to */
  119 int result;                     /* result of call (usually OK or error #) */
  120 {
  121 /* Fill in a reply message to be sent later to a user process.  System calls
  122  * may occasionally fill in other fields, this is only for the main return
  123  * value, and for setting the "must send reply" flag.
  124  */
  125   register struct mproc *rmp = &mproc[proc_nr];
  126 
  127   rmp->mp_reply.reply_res = result;
  128   rmp->mp_flags |= REPLY;       /* reply pending */
  129 
  130   if (rmp->mp_flags & ONSWAP)
  131         swap_inqueue(rmp);      /* must swap this process back in */
  132 }
  133 
  134 /*===========================================================================*
  135  *                              pm_init                                      *
  136  *===========================================================================*/
  137 PRIVATE void pm_init()
  138 {
  139 /* Initialize the process manager. 
  140  * Memory use info is collected from the boot monitor, the kernel, and
  141  * all processes compiled into the system image. Initially this information
  142  * is put into an array mem_chunks. Elements of mem_chunks are struct memory,
  143  * and hold base, size pairs in units of clicks. This array is small, there
  144  * should be no more than 8 chunks. After the array of chunks has been built
  145  * the contents are used to initialize the hole list. Space for the hole list
  146  * is reserved as an array with twice as many elements as the maximum number
  147  * of processes allowed. It is managed as a linked list, and elements of the
  148  * array are struct hole, which, in addition to storage for a base and size in 
  149  * click units also contain space for a link, a pointer to another element.
  150 */
  151   int s;
  152   static struct boot_image image[NR_BOOT_PROCS];
  153   register struct boot_image *ip;
  154   static char core_sigs[] = { SIGQUIT, SIGILL, SIGTRAP, SIGABRT,
  155                         SIGEMT, SIGFPE, SIGUSR1, SIGSEGV, SIGUSR2 };
  156   static char ign_sigs[] = { SIGCHLD, SIGWINCH };
  157   static char mess_sigs[] = { SIGTERM, SIGHUP, SIGABRT, SIGQUIT };
  158   register struct mproc *rmp;
  159   register int i;
  160   register char *sig_ptr;
  161   phys_clicks total_clicks, minix_clicks, free_clicks;
  162   message mess;
  163   struct mem_map mem_map[NR_LOCAL_SEGS];
  164   struct memory mem_chunks[NR_MEMS];
  165 
  166   /* Initialize process table, including timers. */
  167   for (rmp=&mproc[0]; rmp<&mproc[NR_PROCS]; rmp++) {
  168         tmr_inittimer(&rmp->mp_timer);
  169   }
  170 
  171   /* Build the set of signals which cause core dumps, and the set of signals
  172    * that are by default ignored.
  173    */
  174   sigemptyset(&core_sset);
  175   for (sig_ptr = core_sigs; sig_ptr < core_sigs+sizeof(core_sigs); sig_ptr++)
  176         sigaddset(&core_sset, *sig_ptr);
  177   sigemptyset(&ign_sset);
  178   for (sig_ptr = ign_sigs; sig_ptr < ign_sigs+sizeof(ign_sigs); sig_ptr++)
  179         sigaddset(&ign_sset, *sig_ptr);
  180 
  181   /* Obtain a copy of the boot monitor parameters and the kernel info struct.  
  182    * Parse the list of free memory chunks. This list is what the boot monitor 
  183    * reported, but it must be corrected for the kernel and system processes.
  184    */
  185   if ((s=sys_getmonparams(monitor_params, sizeof(monitor_params))) != OK)
  186       panic(__FILE__,"get monitor params failed",s);
  187   get_mem_chunks(mem_chunks);
  188   if ((s=sys_getkinfo(&kinfo)) != OK)
  189       panic(__FILE__,"get kernel info failed",s);
  190 
  191   /* Get the memory map of the kernel to see how much memory it uses. */
  192   if ((s=get_mem_map(SYSTASK, mem_map)) != OK)
  193         panic(__FILE__,"couldn't get memory map of SYSTASK",s);
  194   minix_clicks = (mem_map[S].mem_phys+mem_map[S].mem_len)-mem_map[T].mem_phys;
  195   patch_mem_chunks(mem_chunks, mem_map);
  196 
  197   /* Initialize PM's process table. Request a copy of the system image table 
  198    * that is defined at the kernel level to see which slots to fill in.
  199    */
  200   if (OK != (s=sys_getimage(image))) 
  201         panic(__FILE__,"couldn't get image table: %d\n", s);
  202   procs_in_use = 0;                             /* start populating table */
  203   printf("Building process table:");            /* show what's happening */
  204   for (ip = &image[0]; ip < &image[NR_BOOT_PROCS]; ip++) {              
  205         if (ip->proc_nr >= 0) {                 /* task have negative nrs */
  206                 procs_in_use += 1;              /* found user process */
  207 
  208                 /* Set process details found in the image table. */
  209                 rmp = &mproc[ip->proc_nr];      
  210                 strncpy(rmp->mp_name, ip->proc_name, PROC_NAME_LEN); 
  211                 rmp->mp_parent = RS_PROC_NR;
  212                 rmp->mp_nice = get_nice_value(ip->priority);
  213                 sigemptyset(&rmp->mp_sig2mess);
  214                 sigemptyset(&rmp->mp_ignore);   
  215                 sigemptyset(&rmp->mp_sigmask);
  216                 sigemptyset(&rmp->mp_catch);
  217                 if (ip->proc_nr == INIT_PROC_NR) {      /* user process */
  218                         rmp->mp_pid = INIT_PID;
  219                         rmp->mp_flags |= IN_USE; 
  220                 }
  221                 else {                                  /* system process */
  222                         rmp->mp_pid = get_free_pid();
  223                         rmp->mp_flags |= IN_USE | DONT_SWAP | PRIV_PROC; 
  224 #if DEAD_CODE
  225                         for (sig_ptr = mess_sigs; 
  226                                 sig_ptr < mess_sigs+sizeof(mess_sigs); 
  227                                 sig_ptr++)
  228                         sigaddset(&rmp->mp_sig2mess, *sig_ptr);
  229 #endif
  230                 }
  231 
  232                 /* Get memory map for this process from the kernel. */
  233                 if ((s=get_mem_map(ip->proc_nr, rmp->mp_seg)) != OK)
  234                         panic(__FILE__,"couldn't get process entry",s);
  235                 if (rmp->mp_seg[T].mem_len != 0) rmp->mp_flags |= SEPARATE;
  236                 minix_clicks += rmp->mp_seg[S].mem_phys + 
  237                         rmp->mp_seg[S].mem_len - rmp->mp_seg[T].mem_phys;
  238                 patch_mem_chunks(mem_chunks, rmp->mp_seg);
  239 
  240                 /* Tell FS about this system process. */
  241                 mess.PR_PROC_NR = ip->proc_nr;
  242                 mess.PR_PID = rmp->mp_pid;
  243                 if (OK != (s=send(FS_PROC_NR, &mess)))
  244                         panic(__FILE__,"can't sync up with FS", s);
  245                 printf(" %s", ip->proc_name);   /* display process name */
  246         }
  247   }
  248   printf(".\n");                                /* last process done */
  249 
  250   /* Override some details. INIT, PM, FS and RS are somewhat special. */
  251   mproc[PM_PROC_NR].mp_pid = PM_PID;            /* PM has magic pid */
  252   mproc[RS_PROC_NR].mp_parent = INIT_PROC_NR;   /* INIT is root */
  253   sigfillset(&mproc[PM_PROC_NR].mp_ignore);     /* guard against signals */
  254   sigfillset(&mproc[FS_PROC_NR].mp_sig2mess);   /* forward signals */
  255   sigfillset(&mproc[TTY_PROC_NR].mp_sig2mess);  /* forward signals */
  256   sigfillset(&mproc[MEM_PROC_NR].mp_sig2mess);  /* forward signals */
  257 
  258   /* Tell FS that no more system processes follow and synchronize. */
  259   mess.PR_PROC_NR = NONE;
  260   if (sendrec(FS_PROC_NR, &mess) != OK || mess.m_type != OK)
  261         panic(__FILE__,"can't sync up with FS", NO_NUM);
  262 
  263 #if ENABLE_BOOTDEV
  264   /* Possibly we must correct the memory chunks for the boot device. */
  265   if (kinfo.bootdev_size > 0) {
  266       mem_map[T].mem_phys = kinfo.bootdev_base >> CLICK_SHIFT;
  267       mem_map[T].mem_len = 0;
  268       mem_map[D].mem_len = (kinfo.bootdev_size+CLICK_SIZE-1) >> CLICK_SHIFT;
  269       patch_mem_chunks(mem_chunks, mem_map);
  270   }
  271 #endif /* ENABLE_BOOTDEV */
  272 
  273   /* Initialize tables to all physical memory and print memory information. */
  274   printf("Physical memory:");
  275   mem_init(mem_chunks, &free_clicks);
  276   total_clicks = minix_clicks + free_clicks;
  277   printf(" total %u KB,", click_to_round_k(total_clicks));
  278   printf(" system %u KB,", click_to_round_k(minix_clicks));
  279   printf(" free %u KB.\n", click_to_round_k(free_clicks));
  280 }
  281 
  282 /*===========================================================================*
  283  *                              get_nice_value                               *
  284  *===========================================================================*/
  285 PRIVATE int get_nice_value(queue)
  286 int queue;                              /* store mem chunks here */
  287 {
  288 /* Processes in the boot image have a priority assigned. The PM doesn't know
  289  * about priorities, but uses 'nice' values instead. The priority is between 
  290  * MIN_USER_Q and MAX_USER_Q. We have to scale between PRIO_MIN and PRIO_MAX.
  291  */ 
  292   int nice_val = (queue - USER_Q) * (PRIO_MAX-PRIO_MIN+1) / 
  293       (MIN_USER_Q-MAX_USER_Q+1);
  294   if (nice_val > PRIO_MAX) nice_val = PRIO_MAX; /* shouldn't happen */
  295   if (nice_val < PRIO_MIN) nice_val = PRIO_MIN; /* shouldn't happen */
  296   return nice_val;
  297 }
  298 
  299 #if _WORD_SIZE == 2
  300 /* In real mode only 1M can be addressed, and in 16-bit protected we can go
  301  * no further than we can count in clicks.  (The 286 is further limited by
  302  * its 24 bit address bus, but we can assume in that case that no more than
  303  * 16M memory is reported by the BIOS.)
  304  */
  305 #define MAX_REAL        0x00100000L
  306 #define MAX_16BIT       (0xFFF0L << CLICK_SHIFT)
  307 #endif
  308 
  309 /*===========================================================================*
  310  *                              get_mem_chunks                               *
  311  *===========================================================================*/
  312 PRIVATE void get_mem_chunks(mem_chunks)
  313 struct memory *mem_chunks;                      /* store mem chunks here */
  314 {
  315 /* Initialize the free memory list from the 'memory' boot variable.  Translate
  316  * the byte offsets and sizes in this list to clicks, properly truncated. Also
  317  * make sure that we don't exceed the maximum address space of the 286 or the
  318  * 8086, i.e. when running in 16-bit protected mode or real mode.
  319  */
  320   long base, size, limit;
  321   char *s, *end;                        /* use to parse boot variable */ 
  322   int i, done = 0;
  323   struct memory *memp;
  324 #if _WORD_SIZE == 2
  325   unsigned long max_address;
  326   struct machine machine;
  327   if (OK != (i=sys_getmachine(&machine)))
  328         panic(__FILE__, "sys_getmachine failed", i);
  329 #endif
  330 
  331   /* Initialize everything to zero. */
  332   for (i = 0; i < NR_MEMS; i++) {
  333         memp = &mem_chunks[i];          /* next mem chunk is stored here */
  334         memp->base = memp->size = 0;
  335   }
  336   
  337   /* The available memory is determined by MINIX' boot loader as a list of 
  338    * (base:size)-pairs in boothead.s. The 'memory' boot variable is set in
  339    * in boot.s.  The format is "b0:s0,b1:s1,b2:s2", where b0:s0 is low mem,
  340    * b1:s1 is mem between 1M and 16M, b2:s2 is mem above 16M. Pairs b1:s1 
  341    * and b2:s2 are combined if the memory is adjacent. 
  342    */
  343   s = find_param("memory");             /* get memory boot variable */
  344   for (i = 0; i < NR_MEMS && !done; i++) {
  345         memp = &mem_chunks[i];          /* next mem chunk is stored here */
  346         base = size = 0;                /* initialize next base:size pair */
  347         if (*s != 0) {                  /* get fresh data, unless at end */     
  348 
  349             /* Read fresh base and expect colon as next char. */ 
  350             base = strtoul(s, &end, 0x10);              /* get number */
  351             if (end != s && *end == ':') s = ++end;     /* skip ':' */ 
  352             else *s=0;                  /* terminate, should not happen */
  353 
  354             /* Read fresh size and expect comma or assume end. */ 
  355             size = strtoul(s, &end, 0x10);              /* get number */
  356             if (end != s && *end == ',') s = ++end;     /* skip ',' */
  357             else done = 1;
  358         }
  359         limit = base + size;    
  360 #if _WORD_SIZE == 2
  361         max_address = machine.protected ? MAX_16BIT : MAX_REAL;
  362         if (limit > max_address) limit = max_address;
  363 #endif
  364         base = (base + CLICK_SIZE-1) & ~(long)(CLICK_SIZE-1);
  365         limit &= ~(long)(CLICK_SIZE-1);
  366         if (limit <= base) continue;
  367         memp->base = base >> CLICK_SHIFT;
  368         memp->size = (limit - base) >> CLICK_SHIFT;
  369   }
  370 }
  371 
  372 /*===========================================================================*
  373  *                              patch_mem_chunks                             *
  374  *===========================================================================*/
  375 PRIVATE void patch_mem_chunks(mem_chunks, map_ptr)
  376 struct memory *mem_chunks;                      /* store mem chunks here */
  377 struct mem_map *map_ptr;                        /* memory to remove */
  378 {
  379 /* Remove server memory from the free memory list. The boot monitor
  380  * promises to put processes at the start of memory chunks. The 
  381  * tasks all use same base address, so only the first task changes
  382  * the memory lists. The servers and init have their own memory
  383  * spaces and their memory will be removed from the list. 
  384  */
  385   struct memory *memp;
  386   for (memp = mem_chunks; memp < &mem_chunks[NR_MEMS]; memp++) {
  387         if (memp->base == map_ptr[T].mem_phys) {
  388                 memp->base += map_ptr[T].mem_len + map_ptr[D].mem_len;
  389                 memp->size -= map_ptr[T].mem_len + map_ptr[D].mem_len;
  390         }
  391   }
  392 }
  393 

Cache object: c4c877f734c2ae6e4cc7fa716ba92e95


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.