⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fork.c

📁 中科院徐志伟老师一书《操作系统 原理·技术与编程》的源代码和习题接
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/kernel/fork.c * *  Copyright (C) 1991, 1992  Linus Torvalds *//* *  'fork.c' contains the help-routines for the 'fork' system call * (see also entry.S and others). * Fork is rather simple, once you get the hang of it, but the memory * management can be a bitch. See 'mm/memory.c': 'copy_page_range()' */#include <linux/config.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/unistd.h>#include <linux/smp_lock.h>#include <linux/module.h>#include <linux/vmalloc.h>#include <linux/completion.h>#include <linux/personality.h>#include <asm/pgtable.h>#include <asm/pgalloc.h>#include <asm/uaccess.h>#include <asm/mmu_context.h>/* The idle threads do not count.. */int nr_threads;int nr_running;int max_threads;unsigned long total_forks;	/* Handle normal Linux uptimes. */int last_pid;struct task_struct *pidhash[PIDHASH_SZ];void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait){	unsigned long flags;	wait->flags &= ~WQ_FLAG_EXCLUSIVE;	wq_write_lock_irqsave(&q->lock, flags);	__add_wait_queue(q, wait);	wq_write_unlock_irqrestore(&q->lock, flags);}void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait){	unsigned long flags;	wait->flags |= WQ_FLAG_EXCLUSIVE;	wq_write_lock_irqsave(&q->lock, flags);	__add_wait_queue_tail(q, wait);	wq_write_unlock_irqrestore(&q->lock, flags);}void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait){	unsigned long flags;	wq_write_lock_irqsave(&q->lock, flags);	__remove_wait_queue(q, wait);	wq_write_unlock_irqrestore(&q->lock, flags);}void __init fork_init(unsigned long mempages){	/*	 * The default maximum number of threads is set to a safe	 * value: the thread structures can take up at most half	 * of memory.	 */	max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 8;	init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;	init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2;}/* Protects next_safe and last_pid. */spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED;static int get_pid(unsigned long flags){	static int next_safe = PID_MAX;	struct task_struct *p;	int pid;	if (flags & CLONE_PID)		return current->pid;	spin_lock(&lastpid_lock);	if((++last_pid) & 0xffff8000) {		last_pid = 300;		/* Skip daemons etc. */		goto inside;	}	if(last_pid >= next_safe) {inside:		next_safe = PID_MAX;		read_lock(&tasklist_lock);	repeat:		for_each_task(p) {			if(p->pid == last_pid	||			   p->pgrp == last_pid	||			   p->tgid == last_pid	||			   p->session == last_pid) {				if(++last_pid >= next_safe) {					if(last_pid & 0xffff8000)						last_pid = 300;					next_safe = PID_MAX;				}				goto repeat;			}			if(p->pid > last_pid && next_safe > p->pid)				next_safe = p->pid;			if(p->pgrp > last_pid && next_safe > p->pgrp)				next_safe = p->pgrp;			if(p->session > last_pid && next_safe > p->session)				next_safe = p->session;		}		read_unlock(&tasklist_lock);	}	pid = last_pid;	spin_unlock(&lastpid_lock);	return pid;}static inline int dup_mmap(struct mm_struct * mm){	struct vm_area_struct * mpnt, *tmp, **pprev;	int retval;	flush_cache_mm(current->mm);	mm->locked_vm = 0;	mm->mmap = NULL;	mm->mmap_cache = NULL;	mm->map_count = 0;	mm->rss = 0;	mm->cpu_vm_mask = 0;	mm->swap_address = 0;	pprev = &mm->mmap;	/*	 * Add it to the mmlist after the parent.	 * Doing it this way means that we can order the list,	 * and fork() won't mess up the ordering significantly.	 * Add it first so that swapoff can see any swap entries.	 */	spin_lock(&mmlist_lock);	list_add(&mm->mmlist, &current->mm->mmlist);	mmlist_nr++;	spin_unlock(&mmlist_lock);	for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {		struct file *file;		retval = -ENOMEM;		if(mpnt->vm_flags & VM_DONTCOPY)			continue;		tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);		if (!tmp)			goto fail_nomem;		*tmp = *mpnt;		tmp->vm_flags &= ~VM_LOCKED;		tmp->vm_mm = mm;		tmp->vm_next = NULL;		file = tmp->vm_file;		if (file) {			struct inode *inode = file->f_dentry->d_inode;			get_file(file);			if (tmp->vm_flags & VM_DENYWRITE)				atomic_dec(&inode->i_writecount);      			/* insert tmp into the share list, just after mpnt */			spin_lock(&inode->i_mapping->i_shared_lock);			if((tmp->vm_next_share = mpnt->vm_next_share) != NULL)				mpnt->vm_next_share->vm_pprev_share =					&tmp->vm_next_share;			mpnt->vm_next_share = tmp;			tmp->vm_pprev_share = &mpnt->vm_next_share;			spin_unlock(&inode->i_mapping->i_shared_lock);		}		/*		 * Link in the new vma and copy the page table entries:		 * link in first so that swapoff can see swap entries.		 */		spin_lock(&mm->page_table_lock);		*pprev = tmp;		pprev = &tmp->vm_next;		mm->map_count++;		retval = copy_page_range(mm, current->mm, tmp);		spin_unlock(&mm->page_table_lock);		if (tmp->vm_ops && tmp->vm_ops->open)			tmp->vm_ops->open(tmp);		if (retval)			goto fail_nomem;	}	retval = 0;	build_mmap_rb(mm);fail_nomem:	flush_tlb_mm(current->mm);	return retval;}spinlock_t mmlist_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;int mmlist_nr;#define allocate_mm()	(kmem_cache_alloc(mm_cachep, SLAB_KERNEL))#define free_mm(mm)	(kmem_cache_free(mm_cachep, (mm)))static struct mm_struct * mm_init(struct mm_struct * mm){	atomic_set(&mm->mm_users, 1);	atomic_set(&mm->mm_count, 1);	init_rwsem(&mm->mmap_sem);	mm->page_table_lock = SPIN_LOCK_UNLOCKED;	mm->pgd = pgd_alloc(mm);	mm->def_flags = 0;	if (mm->pgd)		return mm;	free_mm(mm);	return NULL;}	/* * Allocate and initialize an mm_struct. */struct mm_struct * mm_alloc(void){	struct mm_struct * mm;	mm = allocate_mm();	if (mm) {		memset(mm, 0, sizeof(*mm));		return mm_init(mm);	}	return NULL;}/* * Called when the last reference to the mm * is dropped: either by a lazy thread or by * mmput. Free the page directory and the mm. */inline void __mmdrop(struct mm_struct *mm){	if (mm == &init_mm) BUG();	pgd_free(mm->pgd);	destroy_context(mm);	free_mm(mm);}/* * Decrement the use count and release all resources for an mm. */void mmput(struct mm_struct *mm){	if (atomic_dec_and_lock(&mm->mm_users, &mmlist_lock)) {		extern struct mm_struct *swap_mm;		if (swap_mm == mm)			swap_mm = list_entry(mm->mmlist.next, struct mm_struct, mmlist);		list_del(&mm->mmlist);		mmlist_nr--;		spin_unlock(&mmlist_lock);		exit_mmap(mm);		mmdrop(mm);	}}/* Please note the differences between mmput and mm_release. * mmput is called whenever we stop holding onto a mm_struct, * error success whatever. * * mm_release is called after a mm_struct has been removed * from the current process. * * This difference is important for error handling, when we * only half set up a mm_struct for a new process and need to restore * the old one.  Because we mmput the new mm_struct before * restoring the old one. . . * Eric Biederman 10 January 1998 */void mm_release(void){	struct task_struct *tsk = current;	struct completion *vfork_done = tsk->vfork_done;	/* notify parent sleeping on vfork() */	if (vfork_done) {		tsk->vfork_done = NULL;		complete(vfork_done);	}}static int copy_mm(unsigned long clone_flags, struct task_struct * tsk){	struct mm_struct * mm, *oldmm;	int retval;	tsk->min_flt = tsk->maj_flt = 0;	tsk->cmin_flt = tsk->cmaj_flt = 0;	tsk->nswap = tsk->cnswap = 0;	tsk->mm = NULL;	tsk->active_mm = NULL;	/*	 * Are we cloning a kernel thread?	 *	 * We need to steal a active VM for that..	 */	oldmm = current->mm;	if (!oldmm)		return 0;	if (clone_flags & CLONE_VM) {		atomic_inc(&oldmm->mm_users);		mm = oldmm;		goto good_mm;	}	retval = -ENOMEM;	mm = allocate_mm();	if (!mm)		goto fail_nomem;	/* Copy the current MM stuff.. */	memcpy(mm, oldmm, sizeof(*mm));	if (!mm_init(mm))		goto fail_nomem;	down_write(&oldmm->mmap_sem);	retval = dup_mmap(mm);	up_write(&oldmm->mmap_sem);	if (retval)		goto free_pt;	/*	 * child gets a private LDT (if there was an LDT in the parent)	 */	copy_segments(tsk, mm);	if (init_new_context(tsk,mm))		goto free_pt;good_mm:	tsk->mm = mm;	tsk->active_mm = mm;	return 0;free_pt:	mmput(mm);fail_nomem:	return retval;}static inline struct fs_struct *__copy_fs_struct(struct fs_struct *old){	struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL);	/* We don't need to lock fs - think why ;-) */	if (fs) {		atomic_set(&fs->count, 1);		fs->lock = RW_LOCK_UNLOCKED;		fs->umask = old->umask;		read_lock(&old->lock);		fs->rootmnt = mntget(old->rootmnt);		fs->root = dget(old->root);		fs->pwdmnt = mntget(old->pwdmnt);		fs->pwd = dget(old->pwd);		if (old->altroot) {			fs->altrootmnt = mntget(old->altrootmnt);			fs->altroot = dget(old->altroot);		} else {			fs->altrootmnt = NULL;			fs->altroot = NULL;		}			read_unlock(&old->lock);	}	return fs;}struct fs_struct *copy_fs_struct(struct fs_struct *old){	return __copy_fs_struct(old);}static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk){	if (clone_flags & CLONE_FS) {		atomic_inc(&current->fs->count);		return 0;	}	tsk->fs = __copy_fs_struct(current->fs);	if (!tsk->fs)		return -1;	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -