Fork me on GitHub

root/kernel/process.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. kill_pid
  2. kill_pgrp
  3. add_crusage
  4. get_rusage
  5. add_rusage
  6. get_next_zombie
  7. remove_zombie
  8. is_orphaned_pgrp
  9. get_proc_free
  10. release_proc
  11. get_unused_pid
  12. get_proc_by_pid
  13. get_new_user_fd
  14. release_user_fd
  15. kernel_process
  16. proc_slot_init
  17. proc_init

   1 /*
   2  * fiwix/kernel/process.c
   3  *
   4  * Copyright 2018, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/kernel.h>
   9 #include <fiwix/mm.h>
  10 #include <fiwix/errno.h>
  11 #include <fiwix/process.h>
  12 #include <fiwix/timer.h>
  13 #include <fiwix/sched.h>
  14 #include <fiwix/sleep.h>
  15 #include <fiwix/stdio.h>
  16 #include <fiwix/string.h>
  17 
  18 struct proc *proc_table;
  19 struct proc *current;
  20 
  21 struct proc *proc_pool_head;
  22 struct proc *proc_table_head;
  23 struct proc *proc_table_tail;
  24 unsigned int free_proc_slots = 0;
  25 
  26 static struct resource slot_resource = { NULL, NULL };
  27 static struct resource pid_resource = { NULL, NULL };
  28 
  29 int nr_processes = 0;
  30 __pid_t lastpid = 0;
  31 
  32 int kill_pid(__pid_t pid, __sigset_t signum)
  33 {
  34         struct proc *p;
  35 
  36         FOR_EACH_PROCESS(p) {
  37                 if(p->pid == pid && (p->state && p->state != PROC_ZOMBIE)) {
  38                         return send_sig(p, signum);
  39                 }
  40         }
  41         return -ESRCH;
  42 }
  43 
  44 int kill_pgrp(__pid_t pgid, __sigset_t signum)
  45 {
  46         struct proc *p;
  47         int found;
  48 
  49         found = 0;
  50         FOR_EACH_PROCESS(p) {
  51                 if(p->pgid == pgid && (p->state && p->state != PROC_ZOMBIE)) {
  52                         send_sig(p, signum);
  53                         found = 1;
  54                 }
  55         }
  56 
  57         if(!found) {
  58                 return -ESRCH;
  59         }
  60         return 0;
  61 }
  62 
  63 /* sum up child (and its children) statistics */
  64 void add_crusage(struct proc *p, struct rusage *cru)
  65 {
  66         cru->ru_utime.tv_sec = p->usage.ru_utime.tv_sec + p->cusage.ru_utime.tv_sec;
  67         cru->ru_utime.tv_usec = p->usage.ru_utime.tv_usec + p->cusage.ru_utime.tv_usec;
  68         if(cru->ru_utime.tv_usec >= 1000000) {
  69                 cru->ru_utime.tv_sec++;
  70                 cru->ru_utime.tv_usec -= 1000000;
  71         }
  72         cru->ru_stime.tv_sec = p->usage.ru_stime.tv_sec + p->cusage.ru_stime.tv_sec;
  73         cru->ru_stime.tv_usec = p->usage.ru_stime.tv_usec + p->cusage.ru_stime.tv_usec;
  74         if(cru->ru_stime.tv_usec >= 1000000) {
  75                 cru->ru_stime.tv_sec++;
  76                 cru->ru_stime.tv_usec -= 1000000;
  77         }
  78         cru->ru_maxrss = p->usage.ru_maxrss + p->cusage.ru_maxrss;
  79         cru->ru_ixrss = p->usage.ru_ixrss + p->cusage.ru_ixrss;
  80         cru->ru_idrss = p->usage.ru_idrss + p->cusage.ru_idrss;
  81         cru->ru_isrss = p->usage.ru_isrss + p->cusage.ru_isrss;
  82         cru->ru_minflt = p->usage.ru_minflt + p->cusage.ru_minflt;
  83         cru->ru_majflt = p->usage.ru_majflt + p->cusage.ru_majflt;
  84         cru->ru_nswap = p->usage.ru_nswap + p->cusage.ru_nswap;
  85         cru->ru_inblock = p->usage.ru_inblock + p->cusage.ru_inblock;
  86         cru->ru_oublock = p->usage.ru_oublock + p->cusage.ru_oublock;
  87         cru->ru_msgsnd = p->usage.ru_msgsnd + p->cusage.ru_msgsnd;
  88         cru->ru_msgrcv = p->usage.ru_msgrcv + p->cusage.ru_msgrcv;
  89         cru->ru_nsignals = p->usage.ru_nsignals + p->cusage.ru_nsignals;
  90         cru->ru_nvcsw = p->usage.ru_nvcsw + p->cusage.ru_nvcsw;
  91         cru->ru_nivcsw = p->usage.ru_nivcsw + p->cusage.ru_nivcsw;
  92 }
  93 
  94 void get_rusage(struct proc *p, struct rusage *ru)
  95 {
  96         struct rusage cru;
  97 
  98         /*
  99          * Conforms with SUSv3 which specifies that if SIGCHLD is being ignored
 100          * then the child statistics should not be added to the values returned
 101          * by RUSAGE_CHILDREN.
 102          */
 103         if(current->sigaction[SIGCHLD - 1].sa_handler == SIG_IGN) {
 104                 return;
 105         }
 106 
 107         add_crusage(p, &cru);
 108         memcpy_b(ru, &cru, sizeof(struct rusage));
 109 }
 110 
 111 /* add child statistics to parent */
 112 void add_rusage(struct proc *p)
 113 {
 114         struct rusage cru;
 115 
 116         add_crusage(p, &cru);
 117         current->cusage.ru_utime.tv_sec += cru.ru_utime.tv_sec;
 118         current->cusage.ru_utime.tv_usec += cru.ru_utime.tv_usec;
 119         if(current->cusage.ru_utime.tv_usec >= 1000000) {
 120                 current->cusage.ru_utime.tv_sec++;
 121                 current->cusage.ru_utime.tv_usec -= 1000000;
 122         }
 123         current->cusage.ru_stime.tv_sec += cru.ru_stime.tv_sec;
 124         current->cusage.ru_stime.tv_usec += cru.ru_stime.tv_usec;
 125         if(current->cusage.ru_stime.tv_usec >= 1000000) {
 126                 current->cusage.ru_stime.tv_sec++;
 127                 current->cusage.ru_stime.tv_usec -= 1000000;
 128         }
 129         current->cusage.ru_maxrss += cru.ru_maxrss;
 130         current->cusage.ru_ixrss += cru.ru_ixrss;
 131         current->cusage.ru_idrss += cru.ru_idrss;
 132         current->cusage.ru_isrss += cru.ru_isrss;
 133         current->cusage.ru_minflt += cru.ru_minflt;
 134         current->cusage.ru_majflt += cru.ru_majflt;
 135         current->cusage.ru_nswap += cru.ru_nswap;
 136         current->cusage.ru_inblock += cru.ru_inblock;
 137         current->cusage.ru_oublock += cru.ru_oublock;
 138         current->cusage.ru_msgsnd += cru.ru_msgsnd;
 139         current->cusage.ru_msgrcv += cru.ru_msgrcv;
 140         current->cusage.ru_nsignals += cru.ru_nsignals;
 141         current->cusage.ru_nvcsw += cru.ru_nvcsw;
 142         current->cusage.ru_nivcsw += cru.ru_nivcsw;
 143 }
 144 
 145 struct proc * get_next_zombie(struct proc *parent)
 146 {
 147         struct proc *p;
 148 
 149         if(proc_table_head == NULL) {
 150                 PANIC("process table is empty!\n");
 151         }
 152 
 153         FOR_EACH_PROCESS(p) {
 154                 if(p->ppid == parent->pid && p->state == PROC_ZOMBIE) {
 155                         return p;
 156                 }
 157         }
 158 
 159         return NULL;
 160 }
 161 
 162 __pid_t remove_zombie(struct proc *p)
 163 {
 164         __pid_t pid;
 165 
 166         pid = p->pid;
 167         kfree(p->tss.esp0);             current->rss--;
 168         kfree(P2V(p->tss.cr3));         current->rss--;
 169         release_proc(p);
 170         current->children--;
 171         return pid;
 172 }
 173 
 174 /*
 175  * An orphaned process group is a process group in which the parent of every
 176  * member is either itself a member of the group or is not a member of the
 177  * group's session.
 178  */
 179 int is_orphaned_pgrp(__pid_t pgid)
 180 {
 181         struct proc *p, *pp;
 182 
 183         FOR_EACH_PROCESS(p) {
 184                 if(p->pgid != pgid) {
 185                         continue;
 186                 }
 187                 if(p->state && p->state != PROC_ZOMBIE) {
 188                         pp = get_proc_by_pid(p->ppid);
 189                         /* return if only one is found that breaks the rule */
 190                         if(pp->pgid != pgid || pp->sid == p->sid) {
 191                                 return 0;
 192                         }
 193                 }
 194         }
 195         return 1;
 196 }
 197 
 198 struct proc * get_proc_free(void)
 199 {
 200         struct proc *p = NULL;
 201 
 202         if(free_proc_slots <= SAFE_SLOTS && !IS_SUPERUSER) {
 203                 printk("WARNING: %s(): the remaining slots are only for root user!\n", __FUNCTION__);
 204                 return NULL;
 205         }
 206 
 207         lock_resource(&slot_resource);
 208 
 209         if(proc_pool_head) {
 210 
 211                 /* get (remove) a process slot from the free list */
 212                 p = proc_pool_head;
 213                 proc_pool_head = proc_pool_head->next;
 214 
 215                 free_proc_slots--;
 216         } else {
 217                 printk("WARNING: %s(): no more slots free in proc table!\n", __FUNCTION__);
 218         }
 219 
 220         unlock_resource(&slot_resource);
 221         return p;
 222 }
 223 
 224 void release_proc(struct proc *p)
 225 {
 226         lock_resource(&slot_resource);
 227 
 228         /* remove a process from the proc_table */
 229         if(p == proc_table_tail) {
 230                 if(proc_table_head == proc_table_tail) {
 231                         proc_table_head = proc_table_tail = NULL;
 232                 } else {
 233                         proc_table_tail = proc_table_tail->prev;
 234                         proc_table_tail->next = NULL;
 235                 }
 236         } else {
 237                 p->prev->next = p->next;
 238                 p->next->prev = p->prev;
 239         }
 240 
 241         /* initialize and put a process slot back in the free list */
 242         memset_b(p, NULL, sizeof(struct proc));
 243         p->next = proc_pool_head;
 244         proc_pool_head = p;
 245         free_proc_slots++;
 246 
 247         unlock_resource(&slot_resource);
 248 }
 249 
 250 int get_unused_pid(void)
 251 {
 252         short int loop;
 253         struct proc *p;
 254 
 255         loop = 0;
 256         lock_resource(&pid_resource);
 257 
 258 loop:
 259         lastpid++;
 260         if(lastpid > MAX_PID_VALUE) {
 261                 loop++;
 262                 lastpid = INIT;
 263         }
 264         if(loop > 1) {
 265                 printk("WARNING: %s(): system ran out of PID numbers!\n");
 266                 return 0;
 267         }
 268         FOR_EACH_PROCESS(p) {
 269                 if(p->state != PROC_UNUSED) {
 270                         /*
 271                          * Make sure the kernel never reuses active pid, pgid
 272                          * or sid values.
 273                          */
 274                         if(lastpid == p->pid || lastpid == p->pgid || lastpid == p->sid) {
 275                                 goto loop;
 276                         }
 277                 }
 278         }
 279 
 280         unlock_resource(&pid_resource);
 281         return lastpid;
 282 }
 283 
 284 struct proc * get_proc_by_pid(__pid_t pid)
 285 {
 286         struct proc *p;
 287 
 288         FOR_EACH_PROCESS(p) {
 289                 if(p->state && p->pid == pid) {
 290                         return p;
 291                 }
 292         }
 293 
 294         PANIC("would return NULL! (current->pid=%d pid=%d)\n", current->pid, pid);
 295         return NULL;
 296 }
 297 
 298 int get_new_user_fd(int fd)
 299 {
 300         int n;
 301 
 302         for(n = fd; n < OPEN_MAX && n < current->rlim[RLIMIT_NOFILE].rlim_cur; n++) {
 303                 if(current->fd[n] == 0) {
 304                         current->fd[n] = -1;
 305                         current->fd_flags[n] = 0;
 306                         return n;
 307                 }
 308         }
 309 
 310         return -EMFILE;
 311 }
 312 
 313 void release_user_fd(int ufd)
 314 {
 315         current->fd[ufd] = 0;
 316 }
 317 
 318 struct proc * kernel_process(int (*fn)(void))
 319 {
 320         struct proc *p;
 321 
 322         p = get_proc_free();
 323         proc_slot_init(p);
 324         p->pid = get_unused_pid();
 325         p->ppid = 0;
 326         p->flags |= PF_KPROC;
 327         p->priority = DEF_PRIORITY;
 328         if(!(p->tss.esp0 = kmalloc())) {
 329                 release_proc(p);
 330                 return NULL;
 331         }
 332         p->tss.esp0 += PAGE_SIZE - 4;
 333         p->rss++;
 334         p->tss.cr3 = (unsigned int)kpage_dir;
 335         p->tss.eip = (unsigned int)fn;
 336         p->tss.esp = p->tss.esp0;
 337         sprintk(p->pidstr, "%d", p->pid);
 338         p->state = PROC_RUNNING;
 339         return p;
 340 }
 341 
 342 void proc_slot_init(struct proc *p)
 343 {
 344         int n;
 345 
 346         /* insert process at the end of proc_table */
 347         lock_resource(&slot_resource);
 348         if(proc_table_head == NULL) {
 349                 p->prev = NULL;
 350                 p->next = NULL;
 351                 proc_table_head = proc_table_tail = p;
 352         } else {
 353                 p->prev = proc_table_tail;
 354                 p->next = NULL;
 355                 proc_table_tail->next = p;
 356                 proc_table_tail = p;
 357         }
 358         p->sleep_prev = p->sleep_next = NULL;
 359         unlock_resource(&slot_resource);
 360 
 361         memset_b(&p->tss, NULL, sizeof(struct i386tss));
 362         p->tss.io_bitmap_addr = (unsigned int)&p->io_bitmap;
 363 
 364         /*
 365          * At the moment, all io_bitmap bits are setup to 0, which means full
 366          * access. This must be changed to 1 once we have fixed the ioperm()
 367          * system call.
 368          */
 369         for(n = 0; n < IO_BITMAP_SIZE + 1; n++) {
 370                 p->io_bitmap[n] = 0;    /* FIXME: change it to 1 */
 371         }
 372         p->state = PROC_IDLE;
 373 }
 374 
 375 void proc_init(void)
 376 {
 377         int n;
 378         struct proc *p;
 379 
 380         memset_b(proc_table, NULL, proc_table_size);
 381 
 382         /* free list initialization */
 383         proc_pool_head = NULL;
 384         n = (proc_table_size / sizeof(struct proc)) - 1;
 385         do {
 386                 p = &proc_table[n];
 387 
 388                 /* fill the free list */
 389                 p->next = proc_pool_head;
 390                 proc_pool_head = p;
 391                 free_proc_slots++;
 392         } while(n--);
 393         proc_table_head = proc_table_tail = NULL;
 394 
 395         /* slot 0 is for the IDLE process */
 396         current = get_proc_free();
 397         proc_slot_init(current);
 398 }

/* [previous][next][first][last][top][bottom][index][help] */