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

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