Fork me on GitHub

root/kernel/syscalls/fork.c

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

DEFINITIONS

This source file includes following definitions.
  1. sys_fork

   1 /*
   2  * fiwix/kernel/syscalls/fork.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/asm.h>
   9 #include <fiwix/kernel.h>
  10 #include <fiwix/types.h>
  11 #include <fiwix/segments.h>
  12 #include <fiwix/sigcontext.h>
  13 #include <fiwix/process.h>
  14 #include <fiwix/sched.h>
  15 #include <fiwix/sleep.h>
  16 #include <fiwix/mm.h>
  17 #include <fiwix/errno.h>
  18 #include <fiwix/stdio.h>
  19 #include <fiwix/string.h>
  20 
  21 int sys_fork(int arg1, int arg2, int arg3, int arg4, int arg5, struct sigcontext *sc)
  22 {
  23         int count, pages;
  24         unsigned int n;
  25         unsigned int *child_pgdir;
  26         struct sigcontext *stack;
  27         struct proc *child, *p;
  28         struct vma *vma;
  29         __pid_t pid;
  30 
  31 #ifdef __DEBUG__
  32         printk("(pid %d) sys_fork()\n", current->pid);
  33 #endif /*__DEBUG__ */
  34 
  35         /* check the number of processes already allocated by this UID */
  36         count = 0;
  37         FOR_EACH_PROCESS(p) {
  38                 if(p->uid == current->uid) {
  39                         count++;
  40                 }
  41                 p = p->next;
  42         }
  43         if(count > current->rlim[RLIMIT_NPROC].rlim_cur) {
  44                 printk("WARNING: %s(): RLIMIT_NPROC exceeded.\n", __FUNCTION__);
  45                 return -EAGAIN;
  46         }
  47 
  48         if(!(pid = get_unused_pid())) {
  49                 return -EAGAIN;
  50         }
  51         if(!(child = get_proc_free())) {
  52                 return -EAGAIN;
  53         }
  54 
  55         /* 
  56          * This memcpy() will overwrite the prev and next pointers, so that's
  57          * the reason why proc_slot_init() is separated from get_proc_free().
  58          */
  59         memcpy_b(child, current, sizeof(struct proc));
  60 
  61         proc_slot_init(child);
  62         child->pid = pid;
  63         memset_b(&child->tss, NULL, sizeof(struct i386tss));
  64         sprintk(child->pidstr, "%d", child->pid);
  65 
  66         if(!(child_pgdir = (void *)kmalloc())) {
  67                 release_proc(child);
  68                 return -ENOMEM;
  69         }
  70         child->rss++;
  71         memcpy_b(child_pgdir, kpage_dir, PAGE_SIZE);
  72         child->tss.cr3 = V2P((unsigned int)child_pgdir);
  73 
  74         child->ppid = current->pid;
  75         child->flags = 0;
  76         child->children = 0;
  77         child->cpu_count = child->priority;
  78         child->start_time = CURRENT_TICKS;
  79         child->sleep_address = NULL;
  80 
  81         memcpy_b(child->vma, current->vma, sizeof(child->vma));
  82         vma = child->vma;
  83         for(n = 0; n < VMA_REGIONS && vma->start; n++, vma++) {
  84                 if(vma->inode) {
  85                         vma->inode->count++;
  86                 }
  87         }
  88 
  89         child->sigpending = 0;
  90         child->sigexecuting = 0;
  91         memset_b(&child->sc, NULL, sizeof(struct sigcontext));
  92         memset_b(&child->usage, NULL, sizeof(struct rusage));
  93         memset_b(&child->cusage, NULL, sizeof(struct rusage));
  94         child->it_real_interval = 0;
  95         child->it_real_value = 0;
  96         child->it_virt_interval = 0;
  97         child->it_virt_value = 0;
  98         child->it_prof_interval = 0;
  99         child->it_prof_value = 0;
 100 
 101         if(!(child->tss.esp0 = kmalloc())) {
 102                 kfree((unsigned int)child_pgdir);
 103                 kfree((unsigned int)child->vma);
 104                 release_proc(child);
 105                 return -ENOMEM;
 106         }
 107 
 108         if(!(pages = clone_pages(child))) {
 109                 printk("WARNING: %s(): not enough memory, can't clone pages.\n", __FUNCTION__);
 110                 free_page_tables(child);
 111                 kfree((unsigned int)child_pgdir);
 112                 kfree((unsigned int)child->vma);
 113                 release_proc(child);
 114                 return -ENOMEM;
 115         }
 116         child->rss += pages;
 117         invalidate_tlb();
 118 
 119         child->tss.esp0 += PAGE_SIZE - 4;
 120         child->rss++;
 121         child->tss.ss0 = KERNEL_DS;
 122 
 123         memcpy_b((unsigned int *)(child->tss.esp0 & PAGE_MASK), (void *)((unsigned int)(sc) & PAGE_MASK), PAGE_SIZE);
 124         stack = (struct sigcontext *)((child->tss.esp0 & PAGE_MASK) + ((unsigned int)(sc) & ~PAGE_MASK));
 125 
 126         child->tss.eip = (unsigned int)return_from_syscall;
 127         child->tss.esp = (unsigned int)stack;
 128         stack->eax = 0;         /* child returns 0 */
 129 
 130         /* increase file descriptors usage */
 131         for(n = 0; n < OPEN_MAX; n++) {
 132                 if(current->fd[n]) {
 133                         fd_table[current->fd[n]].count++;
 134                 }
 135         }
 136         if(current->root) {
 137                 current->root->count++;
 138         }
 139         if(current->pwd) {
 140                 current->pwd->count++;
 141         }
 142 
 143         kstat.processes++;
 144         nr_processes++;
 145         current->children++;
 146         runnable(child);
 147 
 148         return child->pid;      /* parent returns child's PID */
 149 }

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