(一):进程的概念
线程,是在进程中活动的对象。每个线程都拥有一个独立的程序计数器,进程栈和一组进程寄存器。内核调度的是线程而不是进程。在Linux中,进程和线程的区别比较微妙,一会我们通过源码来查看其两个的区别。
进程提供两种虚拟机制,虚拟处理器和虚拟内存。其中在线程之间可以共享虚拟内存,但是每个线程都拥有各自的虚拟处理器。
在linux中,创建一个进程的函数是fork(),该系统调用通过复制一个现有的进程来创建一个全新的进程。调用fork()的进程称为父进程,被创建的进程成为子进程。fork()系统调用从内核中返回两次:一次回到父进程,一次回到子进程。通常,创建新的进程都是为了立即执行新的,不同的程序,所以,在创建新的子进程之后,会接着调用exec()函数,来创建新的地址空间,并且把新的程序载入到子进程中。最终,程序通过exit()系统调用退出执行。这个函数会终结进程并将其占有的资源释放掉。父进程可以通过wait4()系统调用查询子进程是否终结,这其实使得进程拥有了等待特定进程执行完毕的能力。进程退出执行后被设置为僵死状态,直到它的父进程调用wait()或waitpid()为止。
exec函数族:
定义在int execl(const char *path, const char*arg, ...);int execlp(const char *file, const char*arg, ...);int execle(const char *path, const char*arg , ..., char * const envp[]);int execv(const char *path, char *constargv[]);int execvp(const char *file, char *constargv[]);int execve(const char *path, char *constargv[], char *const envp[]);
其中, execv()函数中的参数,第一个参数const char *path为所运行成程序的地址,char *constargv[]为传递给所运行程序的参数。
下面我们看一下一个进程的创建,执行程序和终止。
#include#include int main(){ int pid,status; pid = fork(); if(pid < 0){ printf("error!!"); }else if(pid == 0){ printf("I am the child forked!!,My pid is %d",getpid()); execv("/bin/ls","-l"); }else{ printf("I am the parent!! My pid is %d",getpid()); waitpid(pid,&status,0); printf("Child %d exit %d",pid,status); } return 0;}
这个仅仅就是一个简单的例子,通过这个例子,就可以扩展出更多的子进程,其实,在内核程序开始的时候,程序的创建都是这样进行的。
下面是程序的运行结果:(二):进程描述符以及任务结构
内核把进程的列表存放在任务队列中,该任务队列是一个双向循环链表。链表中的每一项都是类型为task_struct结构体,称之为进程描述符。该结构定义在
struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ struct thread_info *thread_info; atomic_t usage; unsigned long flags; /* per process flags, defined below */ unsigned long ptrace; int lock_depth; /* BKL lock depth */#ifdef CONFIG_SMP#ifdef __ARCH_WANT_UNLOCKED_CTXSW int oncpu;#endif#endif int load_weight; /* for niceness load balancing purposes */ int prio, static_prio, normal_prio; struct list_head run_list; struct prio_array *array; unsigned short ioprio; unsigned int btrace_seq; unsigned long sleep_avg; unsigned long long timestamp, last_ran; unsigned long long sched_time; /* sched_clock time spent running */ enum sleep_type sleep_type; unsigned long policy; cpumask_t cpus_allowed; unsigned int time_slice, first_time_slice;#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) struct sched_info sched_info;#endif struct list_head tasks; /* * ptrace_list/ptrace_children forms the list of my children * that were stolen by a ptracer. */ struct list_head ptrace_children; struct list_head ptrace_list; struct mm_struct *mm, *active_mm;/* task state */ struct linux_binfmt *binfmt; long exit_state; int exit_code, exit_signal; int pdeath_signal; /* The signal sent when the parent dies */ /* ??? */ unsigned long personality; unsigned did_exec:1; pid_t pid; pid_t tgid; /* * pointers to (original) parent process, youngest child, younger sibling, * older sibling, respectively. (p->father can be replaced with * p->parent->pid) */ struct task_struct *real_parent; /* real parent process (when being debugged) */ struct task_struct *parent; /* parent process */ /* * children/sibling forms the list of my children plus the * tasks I'm ptracing. */ struct list_head children; /* list of my children */ struct list_head sibling; /* linkage in my parent's children list */ struct task_struct *group_leader; /* threadgroup leader */ /* PID/PID hash table linkage. */ struct pid_link pids[PIDTYPE_MAX]; struct list_head thread_group; struct completion *vfork_done; /* for vfork() */ int __user *set_child_tid; /* CLONE_CHILD_SETTID */ int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */ unsigned long rt_priority; cputime_t utime, stime; unsigned long nvcsw, nivcsw; /* context switch counts */ struct timespec start_time;/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ unsigned long min_flt, maj_flt; cputime_t it_prof_expires, it_virt_expires; unsigned long long it_sched_expires; struct list_head cpu_timers[3];/* process credentials */ uid_t uid,euid,suid,fsuid; gid_t gid,egid,sgid,fsgid; struct group_info *group_info; kernel_cap_t cap_effective, cap_inheritable, cap_permitted; unsigned keep_capabilities:1; struct user_struct *user;#ifdef CONFIG_KEYS struct key *request_key_auth; /* assumed request_key authority */ struct key *thread_keyring; /* keyring private to this thread */ unsigned char jit_keyring; /* default keyring to attach requested keys to */#endif int oomkilladj; /* OOM kill score adjustment (bit shift). */ char comm[TASK_COMM_LEN]; /* executable name excluding path - access with [gs]et_task_comm (which lock it with task_lock()) - initialized normally by flush_old_exec *//* file system info */ int link_count, total_link_count;/* ipc stuff */ struct sysv_sem sysvsem;/* CPU-specific state of this task */ struct thread_struct thread;/* filesystem information */ struct fs_struct *fs;/* open file information */ struct files_struct *files;/* namespace */ struct namespace *namespace;/* signal handlers */ struct signal_struct *signal; struct sighand_struct *sighand; sigset_t blocked, real_blocked; sigset_t saved_sigmask; /* To be restored with TIF_RESTORE_SIGMASK */ struct sigpending pending; unsigned long sas_ss_sp; size_t sas_ss_size; int (*notifier)(void *priv); void *notifier_data; sigset_t *notifier_mask; void *security; struct audit_context *audit_context; seccomp_t seccomp;/* Thread group tracking */ u32 parent_exec_id; u32 self_exec_id;/* Protection of (de-)allocation: mm, files, fs, tty, keyrings */ spinlock_t alloc_lock; /* Protection of the PI data structures: */ spinlock_t pi_lock;#ifdef CONFIG_RT_MUTEXES /* PI waiters blocked on a rt_mutex held by this task */ struct plist_head pi_waiters; /* Deadlock detection and priority inheritance handling */ struct rt_mutex_waiter *pi_blocked_on;#endif#ifdef CONFIG_DEBUG_MUTEXES /* mutex deadlock detection */ struct mutex_waiter *blocked_on;#endif#ifdef CONFIG_TRACE_IRQFLAGS unsigned int irq_events; int hardirqs_enabled; unsigned long hardirq_enable_ip; unsigned int hardirq_enable_event; unsigned long hardirq_disable_ip; unsigned int hardirq_disable_event; int softirqs_enabled; unsigned long softirq_disable_ip; unsigned int softirq_disable_event; unsigned long softirq_enable_ip; unsigned int softirq_enable_event; int hardirq_context; int softirq_context;#endif#ifdef CONFIG_LOCKDEP# define MAX_LOCK_DEPTH 30UL u64 curr_chain_key; int lockdep_depth; struct held_lock held_locks[MAX_LOCK_DEPTH]; unsigned int lockdep_recursion;#endif/* journalling filesystem info */ void *journal_info;/* VM state */ struct reclaim_state *reclaim_state; struct backing_dev_info *backing_dev_info; struct io_context *io_context; unsigned long ptrace_message; siginfo_t *last_siginfo; /* For ptrace use. *//* * current io wait handle: wait queue entry to use for io waits * If this thread is processing aio, this points at the waitqueue * inside the currently handled kiocb. It may be NULL (i.e. default * to a stack based synchronous wait) if its doing sync IO. */ wait_queue_t *io_wait;/* i/o counters(bytes read/written, #syscalls */ u64 rchar, wchar, syscr, syscw;#if defined(CONFIG_BSD_PROCESS_ACCT) u64 acct_rss_mem1; /* accumulated rss usage */ u64 acct_vm_mem1; /* accumulated virtual memory usage */ clock_t acct_stimexpd; /* clock_t-converted stime since last update */#endif#ifdef CONFIG_NUMA struct mempolicy *mempolicy; short il_next;#endif#ifdef CONFIG_CPUSETS struct cpuset *cpuset; nodemask_t mems_allowed; int cpuset_mems_generation; int cpuset_mem_spread_rotor;#endif struct robust_list_head __user *robust_list;#ifdef CONFIG_COMPAT struct compat_robust_list_head __user *compat_robust_list;#endif struct list_head pi_state_list; struct futex_pi_state *pi_state_cache; atomic_t fs_excl; /* holding fs exclusive resources */ struct rcu_head rcu; /* * cache last used pipe for splice */ struct pipe_inode_info *splice_pipe;#ifdef CONFIG_TASK_DELAY_ACCT struct task_delay_info *delays;#endif};