Skip to content
Snippets Groups Projects
fork.c 41.6 KiB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
/*
 *  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/slab.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/completion.h>
#include <linux/mnt_namespace.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/personality.h>
#include <linux/mempolicy.h>
#include <linux/sem.h>
#include <linux/file.h>
Al Viro's avatar
Al Viro committed
#include <linux/fdtable.h>
#include <linux/iocontext.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/key.h>
#include <linux/binfmts.h>
#include <linux/mman.h>
Andrea Arcangeli's avatar
Andrea Arcangeli committed
#include <linux/mmu_notifier.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/fs.h>
#include <linux/nsproxy.h>
#include <linux/capability.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/cpu.h>
#include <linux/cgroup.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/security.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/swap.h>
#include <linux/syscalls.h>
#include <linux/jiffies.h>
Roland McGrath's avatar
Roland McGrath committed
#include <linux/tracehook.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/futex.h>
#include <linux/compat.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/rcupdate.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/ptrace.h>
#include <linux/mount.h>
#include <linux/audit.h>
#include <linux/memcontrol.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/profile.h>
#include <linux/rmap.h>
#include <linux/acct.h>
#include <linux/tsacct_kern.h>
#include <linux/cn_proc.h>
#include <linux/freezer.h>
#include <linux/delayacct.h>
#include <linux/taskstats_kern.h>
#include <linux/tty.h>
#include <linux/proc_fs.h>
#include <linux/blkdev.h>
#include <linux/fs_struct.h>
Linus Torvalds's avatar
Linus Torvalds committed

#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>

Linus Torvalds's avatar
Linus Torvalds committed
/*
 * Protected counters by write_lock_irq(&tasklist_lock)
 */
unsigned long total_forks;	/* Handle normal Linux uptimes. */
int nr_threads; 		/* The idle threads do not count.. */

int max_threads;		/* tunable limit on nr_threads */

DEFINE_PER_CPU(unsigned long, process_counts) = 0;

__cacheline_aligned DEFINE_RWLOCK(tasklist_lock);  /* outer */
Linus Torvalds's avatar
Linus Torvalds committed

int nr_processes(void)
{
	int cpu;
	int total = 0;

	for_each_online_cpu(cpu)
		total += per_cpu(process_counts, cpu);

	return total;
}

#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR
# define alloc_task_struct()	kmem_cache_alloc(task_struct_cachep, GFP_KERNEL)
# define free_task_struct(tsk)	kmem_cache_free(task_struct_cachep, (tsk))
static struct kmem_cache *task_struct_cachep;
Linus Torvalds's avatar
Linus Torvalds committed
#endif

#ifndef __HAVE_ARCH_THREAD_INFO_ALLOCATOR
static inline struct thread_info *alloc_thread_info(struct task_struct *tsk)
{
#ifdef CONFIG_DEBUG_STACK_USAGE
	gfp_t mask = GFP_KERNEL | __GFP_ZERO;
#else
	gfp_t mask = GFP_KERNEL;
#endif
	return (struct thread_info *)__get_free_pages(mask, THREAD_SIZE_ORDER);
}

static inline void free_thread_info(struct thread_info *ti)
{
	free_pages((unsigned long)ti, THREAD_SIZE_ORDER);
}
#endif

Linus Torvalds's avatar
Linus Torvalds committed
/* SLAB cache for signal_struct structures (tsk->signal) */
static struct kmem_cache *signal_cachep;
Linus Torvalds's avatar
Linus Torvalds committed

/* SLAB cache for sighand_struct structures (tsk->sighand) */
struct kmem_cache *sighand_cachep;
Linus Torvalds's avatar
Linus Torvalds committed

/* SLAB cache for files_struct structures (tsk->files) */
struct kmem_cache *files_cachep;
Linus Torvalds's avatar
Linus Torvalds committed

/* SLAB cache for fs_struct structures (tsk->fs) */
struct kmem_cache *fs_cachep;
Linus Torvalds's avatar
Linus Torvalds committed

/* SLAB cache for vm_area_struct structures */
struct kmem_cache *vm_area_cachep;
Linus Torvalds's avatar
Linus Torvalds committed

/* SLAB cache for mm_struct structures (tsk->mm) */
static struct kmem_cache *mm_cachep;
Linus Torvalds's avatar
Linus Torvalds committed

void free_task(struct task_struct *tsk)
{
	prop_local_destroy_single(&tsk->dirties);
	free_thread_info(tsk->stack);
	rt_mutex_debug_task_free(tsk);
Linus Torvalds's avatar
Linus Torvalds committed
	free_task_struct(tsk);
}
EXPORT_SYMBOL(free_task);

void __put_task_struct(struct task_struct *tsk)
Linus Torvalds's avatar
Linus Torvalds committed
{
Eugene Teo's avatar
Eugene Teo committed
	WARN_ON(!tsk->exit_state);
Linus Torvalds's avatar
Linus Torvalds committed
	WARN_ON(atomic_read(&tsk->usage));
	WARN_ON(tsk == current);

	put_cred(tsk->cred);
	delayacct_tsk_free(tsk);
Linus Torvalds's avatar
Linus Torvalds committed

	if (!profile_handoff_task(tsk))
		free_task(tsk);
}

Suresh Siddha's avatar
Suresh Siddha committed
/*
 * macro override instead of weak attribute alias, to workaround
 * gcc 4.1.0 and 4.1.1 bugs with weak attribute and empty functions.
 */
#ifndef arch_task_cache_init
#define arch_task_cache_init()
#endif
Linus Torvalds's avatar
Linus Torvalds committed
void __init fork_init(unsigned long mempages)
{
#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR
#ifndef ARCH_MIN_TASKALIGN
#define ARCH_MIN_TASKALIGN	L1_CACHE_BYTES
#endif
	/* create a slab on which task_structs can be allocated */
	task_struct_cachep =
		kmem_cache_create("task_struct", sizeof(struct task_struct),
			ARCH_MIN_TASKALIGN, SLAB_PANIC, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
#endif

	/* do the arch specific task caches init */
	arch_task_cache_init();

Linus Torvalds's avatar
Linus Torvalds committed
	/*
	 * 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 / (8 * THREAD_SIZE / PAGE_SIZE);

	/*
	 * we need to allow at least 20 threads to boot a system
	 */
	if(max_threads < 20)
		max_threads = 20;

	init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
Loading
Loading full blame...