static int procfs_updatedir(vnode_t * dir) { int err = 0; if (dir == vn_procfs) { PROC_LOCK(); /* * This is the procfs root. * * Now we just try to create a directory for every process in the system * regardless whether it already exist or not and try to remove * directories that should not exist anymore. */ for (int i = 0; i <= configMAXPROC; i++) { struct proc_info * proc = proc_ref_locked(i); if (proc) { err = procfs_mkentry(proc); proc_unref(proc); } else { procfs_rmentry(i); } } PROC_UNLOCK(); } return err; }
pid_t proc_fork(void) { /* * http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html */ KERROR_DBG("%s(%u)\n", __func__, curproc->pid); struct proc_info * const old_proc = curproc; struct proc_info * new_proc; pid_t retval = 0; /* Check that the old process is in valid state. */ if (!old_proc || old_proc->state == PROC_STATE_INITIAL) return -EINVAL; new_proc = clone_proc_info(old_proc); if (!new_proc) return -ENOMEM; /* Clear some things required to be zeroed at this point */ new_proc->state = PROC_STATE_INITIAL; new_proc->files = NULL; new_proc->pgrp = NULL; /* Must be NULL so we don't free the old ref. */ memset(&new_proc->tms, 0, sizeof(new_proc->tms)); /* ..and then start to fix things. */ /* * Process group. */ PROC_LOCK(); proc_pgrp_insert(old_proc->pgrp, new_proc); PROC_UNLOCK(); /* * Initialize the mm struct. */ retval = vm_mm_init(&new_proc->mm, old_proc->mm.nr_regions); if (retval) goto out; /* * Clone the master page table. * This is probably something we would like to get rid of but we are * stuck with because it's the easiest way to keep some static kernel * mappings valid between processes. */ if (mmu_ptcpy(&new_proc->mm.mpt, &old_proc->mm.mpt)) { retval = -EAGAIN; goto out; } /* * Clone L2 page tables. */ if (vm_ptlist_clone(&new_proc->mm.ptlist_head, &new_proc->mm.mpt, &old_proc->mm.ptlist_head) < 0) { retval = -ENOMEM; goto out; } retval = clone_code_region(new_proc, old_proc); if (retval) goto out; /* * Clone stack region. */ retval = clone_stack(new_proc, old_proc); if (retval) { KERROR_DBG("Cloning stack region failed.\n"); goto out; } /* * Clone other regions. */ retval = clone_regions_from(new_proc, old_proc, MM_HEAP_REGION); if (retval) goto out; /* * Set break values. */ new_proc->brk_start = (void *)( (*new_proc->mm.regions)[MM_HEAP_REGION]->b_mmu.vaddr + (*new_proc->mm.regions)[MM_HEAP_REGION]->b_bcount); new_proc->brk_stop = (void *)( (*new_proc->mm.regions)[MM_HEAP_REGION]->b_mmu.vaddr + (*new_proc->mm.regions)[MM_HEAP_REGION]->b_bufsize); /* fork() signals */ ksignal_signals_fork_reinit(&new_proc->sigs); /* * Copy file descriptors. */ KERROR_DBG("Copy file descriptors\n"); int nofile_max = old_proc->rlim[RLIMIT_NOFILE].rlim_max; if (nofile_max < 0) { #if configRLIMIT_NOFILE < 0 #error configRLIMIT_NOFILE can't be negative. #endif nofile_max = configRLIMIT_NOFILE; } new_proc->files = fs_alloc_files(nofile_max, nofile_max); if (!new_proc->files) { KERROR_DBG( "\tENOMEM when tried to allocate memory for file descriptors\n"); retval = -ENOMEM; goto out; } /* Copy and ref old file descriptors */ for (int i = 0; i < old_proc->files->count; i++) { new_proc->files->fd[i] = old_proc->files->fd[i]; fs_fildes_ref(new_proc->files, i, 1); /* null pointer safe */ } KERROR_DBG("All file descriptors copied\n"); /* * Select PID. */ if (likely(nprocs != 1)) { /* Tecnically it would be good idea to have lock * on nprocs before reading it but I think this * should work fine... */ new_proc->pid = proc_get_random_pid(); } else { /* Proc is init */ KERROR_DBG("Assuming this process to be init\n"); new_proc->pid = 1; } if (new_proc->cwd) { KERROR_DBG("Increment refcount for the cwd\n"); vref(new_proc->cwd); /* Increment refcount for the cwd */ } /* Update inheritance attributes */ set_proc_inher(old_proc, new_proc); /* Insert the new process into the process array */ procarr_insert(new_proc); /* * A process shall be created with a single thread. If a multi-threaded * process calls fork(), the new process shall contain a replica of the * calling thread. * We left main_thread null if calling process has no main thread. */ KERROR_DBG("Handle main_thread\n"); if (old_proc->main_thread) { KERROR_DBG("Call thread_fork() to get a new main thread for the fork.\n"); if (!(new_proc->main_thread = thread_fork(new_proc->pid))) { KERROR_DBG("\tthread_fork() failed\n"); retval = -EAGAIN; goto out; } KERROR_DBG("\tthread_fork() fork OK\n"); /* * We set new proc's mpt as the current mpt because the new main thread * is going to return directly to the user space. */ new_proc->main_thread->curr_mpt = &new_proc->mm.mpt; } else { KERROR_DBG("No thread to fork.\n"); new_proc->main_thread = NULL; } retval = new_proc->pid; new_proc->state = PROC_STATE_READY; #ifdef configPROCFS procfs_mkentry(new_proc); #endif if (new_proc->main_thread) { KERROR_DBG("Set the new main_thread (%d) ready\n", new_proc->main_thread->id); thread_ready(new_proc->main_thread->id); } KERROR_DBG("Fork %d -> %d created.\n", old_proc->pid, new_proc->pid); out: if (unlikely(retval < 0)) { _proc_free(new_proc); } return retval; }