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

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