|
|
Silberschatz: page 87 page 114A process is an execution stream in the context of a particular process state.
Key concept: Processes are separated; no process can directly affect the state of another process.
Typical example: DOS.
Problem: Users often wish to perform more than one activity at a time (load a remote file while editing a program, for example), and uniprogramming does not allow this.
Modern OS run on multiprocessor platforms!
Standard solution is to use preemptive multitasking -
OS runs one process for a while,
then takes the CPU away from that process and lets another
process run.
Problem:
Must save and restore process state.
Key issue: fairness.
Must ensure that all processes get their fair share of the CPU.
The question is: what does fair mean?
We are looking for the answers!
Question: Which kind of OS ((single|multi) process) would you develop for a HP SureStore E Disk Array XP512.
A process is a an executing program, including the
pseudo parallelism.
A ----- ----- B ----- ----- C ----- ----- D ----- ----- E ----- ----
1. no scheduling 2. priority scheduling 3. shortest job first 4. biggest job first 5. round robin
be a set of process.
is the state of the process
where
The amount of time a process needs to be in the running state before it is completed.
The amount of time a process spend in the ready state before its first transition to the running state.
The amount of time between the process first enters the ready state and the moment the process exits the running state the last time.
An operating system that supports the process concept must provide one way to create all the processes needed.
In UNIX processes are created by the fork() system call, which creates an identical copy of the calling process.
After the fork()-call the parent continues to run in parallel with the child. The child can also call fork() and so on ...
A process can overlays a new process image on its process with a exec systemcall. File descriptors open in the calling process remain open in the new process, except for those whose close-on-exec flag is set; (see fcntl(2)). For those file descriptors that remain open, the file pointer is unchanged. Signals that are being caught by the calling process are set to the default disposition in the new process image (see signal(3C)). Otherwise, the new process image inherits the signal dispositions of the calling process.
A process can be killed with kill() from another process, or a process may kill itself with exit() or _exit().
We have the following situation under UNIX:
1. Parent <-> child hierarchie -> process tree 2. Time invariable (invariant) 3. process groups
1 /*
2 * Module: zombie.c
3 * Description: a zombie is born
4 * fork fork
5 * init ---> P1 ---> P2
6 */
7
8 #include <stdio.h>
9
10 int main(void)
11 {
12 switch ( fork() ) {
13 case -1: perror("fork failed");
14 exit(1);
15 case 0: printf("Son RIP (%d)\n", getpid());
16 exit(0);
17 default: sleep(2);
18 printf("Father RIP.\n");
19 printf("Find the zombie.\n");
20 system("ps -edf | fgrep defunct");
21 exit(0);
22 }
23 }
Source Code: Src/5/zombie.c
Question: Where does the first process come from? Question: How does popen(...) works?
1 FILE * popen(const char *cmdstring, const char *type)
2 {
3 ...
4 if ( pipe(pfd) ) < 0 )
5 return(NULL);
6
7 if ( (pid = fork()) < 0)
8 return(NULL);
9 else if (pid == 0) { /* child */
10 if (*type == 'r') {
11 close(pfd[0]);
12 dup(pfd[1], 1);
13 ...
14 } else {
15 ...
16 }
17 execl(SHELL, "sh", "-c", cmdstring, (char *) 0);
18 _exit(127);
19 }
20 if (*type == 'r') { /* parent */
21 close(pfd[1]);
22 if ( (fp = fdopen(pfd[0], type)) == NULL)
23 return(NULL);
24 } else {
25 ...
26 }
27 return(fp);
28 }
Source Code: Src/5/popen.c
Fork:
Fork/Exec:
Please explain the following program:
1 #include <stdio.h>
2 #include <signal.h>
3 #include <sys/wait.h>
4
5 void catch(int sig)
6 {
7 signal(sig, SIG_IGN);
8 printf("%d: Got signal %d\n", getpid(), sig);
9 }
10
11 int main(int argc, char ** argv)
12 { FILE * fp;
13 char buffer[1024];
14 signal( 8 , catch );
15 signal( 9 , catch );
16 signal( 10 , catch );
17 if ( ( fp = fopen("signal_fork.c", "r" ) ) == -1 )
18 exit(1);
19 fscanf(fp, "%s", buffer); printf("buffer = %s\n", buffer );
20
21 switch ( fork() ) {
22 case -1: perror("fork failed");
23 exit(1);
24 case 0: fscanf(fp, "%s", buffer);
25 printf("Son: buffer = %s\n", buffer );
26 break;
27 default: fscanf(fp, "%s", buffer);
28 printf("Parent: buffer = %s\n", buffer );
29 }
30 exit(0);
31 }
Source Code: Src/5/signal_fork.c
Please explain the following program:
1 #include <stdio.h>
2 #include <signal.h>
3 #include <sys/wait.h>
4
5 void catch(int sig)
6 {
7 signal(sig, SIG_IGN);
8 printf("%d: Got signal %d\n", getpid(), sig);
9 }
10
11 int main(int argc, char ** argv)
12 { signal( 8 , catch );
13 signal( 9 , catch );
14 signal( 10 , catch );
15
16 switch ( fork() ) {
17 case -1: perror("fork failed");
18 exit(1);
19 case 0:
20 printf("Son: exec ...\n");
21 execl("/bin/sh", "sh", "-c",
22 "/usr/bin/sleep 1234", (char *) 0);
23 default: printf("Parent: .... \n");
24 sleep(12345);
25 }
26 exit(0);
27 }
Source Code: Src/5/signal_exec.c
Each process is an indepedent entity, with its own program counter and internal state. Let's take a look to the following commands:
% cd /usr/share/lib/dict/ % ls -l words -r--r--r-- 1 bin bin 206662 May 2 1996 words % cat words | grep 'whale' | tr 'a-z' 'A-Z' WHALE
Depending on the relative speed of the two processes, it may happen that grep is ready to run, but there is no input for it. It must then block until some input is available.
When a process is using the CPU, it is actually running and doing some work. However, it will not always stay in that state.
If a process does I/O and the device is not ready or just slow, the process will become blocked and be unable to do any more work until the I/O is complete.
In a multitasking environment, a process is not allowed to use the CPU all the time. At intervals (maybe signalled by a timer interrupt) it will be stopped by the OS so that another process can run. In this state it is not running, but it is runnable.
A process is in one of the following states:
1. running 2. ready/runnable 3. blocked
The process states and transitions are
1. process blocks for input 2. scheduler picks another process 3. scheduler picks this process 4. input is available
Here are some reasons for possible transition:
Fundamental Scheduling Law: A process cannot run if there is a ready process of higher priority. We will see this later.
Silberschatz: page 135 page 171
1. Fairness: make sure each gets its fair share of CPU. 2. Efficency: keep the CPU busy 100% of the time. 3. Response time: minimize response time for interactive users. 4. Turnaround: minimize the time batch users must wait for the output. 5. Throughput: maximize the number of processes per hour.
Possible ideas:
Think about: it takes time to pick another process!
i T(p of i) -------------- 0 350 1 150 2 100 3 200 4 900
Please draw the Gantt charts!
Each process will be assigned a time interval, quantum, which it is allowed to run or until it blocks.
ADD a few more things here ....
Round robind scheduling makes the implicit assumption that all processes are equally important.
Is this a good or bad assumption?
How long will it take 3 processes, each needs 3 time slices, to complete? Let's say the context switch takes 1 time slice.
+------+-----+---------------+------+ |Slice | Job | consumed time | done | +------+-----+---------------+------+ |1: | | | | +------+-----+---------------+------+ |2: | | | | +------+-----+---------------+------+ |4: | | | | +------+-----+---------------+------+ |4: | | | | +------+-----+---------------+------+ |5: | | | | +------+-----+---------------+------+ |6: | | | | +------+-----+---------------+------+ |7: | | | | +------+-----+---------------+------+ |8: | | | | +------+-----+---------------+------+ |9: | | | | +------+-----+---------------+------+ |10: | | | | +------+-----+---------------+------+ |11: | | | | +------+-----+---------------+------+ |12: | | | | +------+-----+---------------+------+ |13: | | | | +------+-----+---------------+------+ |14: | | | | +------+-----+---------------+------+ |15: | | | | +------+-----+---------------+------+ |16: | | | | +------+-----+---------------+------+ |17: | | | | +------+-----+---------------+------+ |18: | | | | +------+-----+---------------+------+ |19: | | | | +------+-----+---------------+------+
The basic idea is straightforward: each process is assigned a priority, and the process with the highest priority is allowed to run.
Priorities can be assigned by a process
Statically:
Dynamically:
A simple algorithm for giving a good service to an I/O bound process is to set the priority to
where f is the fraction of the last quantum of time that a process used.
How long will it take 3 processes, each need 3 time slices, to complete? Process 1 uses only 25% of each time slice, it needs 1 time slice. Process 2 uses only 50% of each time slice, it needs 2 time slice. Process 3 uses only 100% of each time slice, it needs 3 time slices. The initial priority for each process is 1. Use round robin if two or more processes have the same priority. Let's say the context switch takes 1 time slice.
+------+-----+----------+---------------+------+ |slice | job | priority | consumed time | done | +------+-----+----------+---------------+------+ |1: | | | | | +------+-----+----------+---------------+------+ |2: | | | | | +------+-----+----------+---------------+------+ |4: | | | | | +------+-----+----------+---------------+------+ |4: | | | | | +------+-----+----------+---------------+------+ |5: | | | | | +------+-----+----------+---------------+------+ |6: | | | | | +------+-----+----------+---------------+------+ |7: | | | | | +------+-----+----------+---------------+------+ |8: | | | | | +------+-----+----------+---------------+------+ |9: | | | | | +------+-----+----------+---------------+------+ |10: | | | | | +------+-----+----------+---------------+------+ |11: | | | | | +------+-----+----------+---------------+------+ |12: | | | | | +------+-----+----------+---------------+------+ |13: | | | | | +------+-----+----------+---------------+------+ |14: | | | | | +------+-----+----------+---------------+------+ |15: | | | | | +------+-----+----------+---------------+------+ |16: | | | | | +------+-----+----------+---------------+------+ |17: | | | | | +------+-----+----------+---------------+------+ |18: | | | | | +------+-----+----------+---------------+------+ |19: | | | | | +------+-----+----------+---------------+------+
Lets do the same with this algorithm:
where f is the fraction of the last quatum of time that a process used.
How long will it take 3 processes, each need 3 time slices, to complete?
+------+-----+----------+---------------+------+ | | 1 | 1 | 0 | | +------+-----+----------+---------------+------+ | | 2 | 1 | 0 | | +------+-----+----------+---------------+------+ | | 3 | 1 | 0 | | +------+-----+----------+---------------+------+ |slice | job | priority | consumed time | done | +------+-----+----------+---------------+------+ |1: | | | | | +------+-----+----------+---------------+------+ |2: | | | | | +------+-----+----------+---------------+------+ |4: | | | | | +------+-----+----------+---------------+------+ |4: | | | | | +------+-----+----------+---------------+------+ |5: | | | | | +------+-----+----------+---------------+------+ |6: | | | | | +------+-----+----------+---------------+------+ |7: | | | | | +------+-----+----------+---------------+------+ |8: | | | | | +------+-----+----------+---------------+------+ |9: | | | | | +------+-----+----------+---------------+------+ |10: | | | | | +------+-----+----------+---------------+------+ |11: | | | | | +------+-----+----------+---------------+------+ |12: | | | | | +------+-----+----------+---------------+------+ |13: | | | | | +------+-----+----------+---------------+------+ |14: | | | | | +------+-----+----------+---------------+------+ |15: | | | | | +------+-----+----------+---------------+------+ |16: | | | | | +------+-----+----------+---------------+------+ |17: | | | | | +------+-----+----------+---------------+------+ |18: | | | | | +------+-----+----------+---------------+------+ |19: | | | | | +------+-----+----------+---------------+------+
Priorities must be adjusted from time to time.
Use priorities to disfavor long running processes. One example of adaptive scheduler schemes:
Multi-Level Feedback Queues (or Exponential Queue)
CTSS (MIT, early 1960's) was the first to use exponential queues.
{ a - z }
1: a 1 time slice 2: write 0.5 time slice then will be blocked 0.5 time slices 3: b 1 time slice 4: c 1 time slice 5: exit
1: write 0.5 time slice then will be blocked 0.5 time slices 2: b 1 time slice 3: c 0.5 time slice 4: exit
1: a 1 time slice 2: b 0.5 time slice 3: c 1 time slice 4: c 0.5 time slice 5: c 1 time slice 6: c 0.5 time slice 7: exit
Note: added to the notes: Mon Dec 18 14:17:40 EST 2000
{ a - z }
1: a 1 Time slice 2: write 0.5 time slice then will be blocked 0.5 time slices 3: b 2.5 time slice 4: c 0.5 time slice 5: d 0.5 time slice 6: e 0.5 time slice 7: f 0.5 time slice 8: exitProcess 2:
1: a 1 Time slice 2: write 0.5 time slice then will be blocked 0.5 time slices 3: b 0.5 time slice 4: c 1.5 time slice 5: d 1.5 time slice 6: e 0.5 time slice 7: exit
Note: added to the notes: Mon Dec 18 14:17:40 EST 2000
{ a - z }
1: a 1 Time slice 2: write 0.5 time slice then will be blocked 0.5 time slices 3: b 2.5 time slice 4: write 0.5 time slice then will be blocked 0.5 time slices 5: c 0.5 time slice 6: d 0.5 time slice 7: e 0.5 time slice 8: f 0.5 time slice 9: exitProcess 2:
1: a 1 Time slice 2: write 0.5 time slice then will be blocked 0.5 time slices 3: b 0.5 time slice 4: c 1.5 time slice 5: d 1.5 time slice 6: e 0.5 time slice 7: exitProcess 3:
1: a 1 Time slice 2: write 0.5 time slice then will be blocked 0.5 time slices 3: b 0.5 time slice 4: write 0.5 time slice then will be blocked 0.5 time slices 5: d 1.5 time slice 6: e 0.5 time slice 7: exit
The OS maintains a table (an array of structures), called the process table, with one entry per process.
Why is the data structure for the process table an array?
What is a possible data structure for a process?
Entries in this table are often called process control blocks and must contain the information needed so that the process can be loaded into memory and run. This includes
-- process state -- memory state -- resource state -- the value of each register -- the program counter -- the stack pointer
for each process.
Information about the state that the process is (running, runnable, blocked) and is need to restore the process.
In addition it may contain extra fields such as:
-- process ID of itself, its parent, etc.
-- elapsed time.
-- pending signals that have not yet been dealt with
(eg signal arrived while the process was asleep).
Pointers to the various memory areas used by the program need to be kept, so that they can be relocated back as needed.
The process will generally have files open, be in particular directory, have a certain user ID, etc. The information about these will need to be stored also.
For example, in Unix each process has a file table. The first entry in this (file descriptor zero) is for the processes' standard input, the second entry is for standard output, the third for standard error. Additional entries are made when the process opens more files.
Let's take a look what happens with the process table, if we let the following run:
% example 1 % ps PID TTY TIME CMD 24245 pts/10 0:01 bash % date Wed Sep 3 15:41:21 EDT 1997 % echo $? 0 % example 2 % ps PID TTY TIME CMD 24245 pts/10 0:01 bash % date & [1] 26208 % Wed Sep 3 15:47:10 EDT 1997 [1]+ Done date % echo $?
Problems:
1. How does the process table now look?
2. What happend, if a signal is sent to blocked process?
3. What happens if a new signal arrived,
when the process is in a signal handling procedure?
4. How many signals can be sent to a blocked process?
5. Is it possible to use signals for process communication?
6. Is it possible to use signals for a stable process communication?
Here are some notes about a Unix process [version xyz???]. The reference for this is the Stevens book (Advanced Programming in the Unix Environment). Maybe you would like to read Tannenbaum chapter 7.
The following figure (from Stevens page 168) describes the layout of the address space (virtual) of a process. This space is essentially divided in two parts, a top part with the stack, and a bottom part with the heap etc. Between the two is empty space. The stack area is usually terminated by a guard, i.e. an area to which the program does not have access rights, so that an exception will be raised when running out of stack.
many user threads)
one user threads)
many user threads)
1 % ps -edf | grep bischof | sed 6q 2 UID PID PPID C STIME TTY TIME CMD 3 bischof 332 1 0 Sep 01 console 0:01 /opt/gnu/bin/bash 4 bischof 8661 8658 0 15:54:26 pts/4 0:02 bash 5 bischof 850 849 0 Sep 01 ? 0:01 (dns helper) 6 bischof 8563 4442 0 15:46:29 pts/5 0:00 vi c.04 7 bischof 342 332 0 Sep 01 console 0:00 /bin/sh 8 % 9 % # processes bound on this terminal 10 % tty 11 /dev/pts/4 12 % ps 13 PID TTY TIME CMD 14 8661 pts/4 0:02 bash 15 8658 pts/4 0:00 vi 16 8568 pts/4 0:01 bash 17 % 18 % # create a new process 19 % sleep 1000 & 20 [1] 8875 21 % ps -l | egrep '(sleep|UID)' 22 F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 23 8 S 22008 8875 8661 0 71 20 f6086320 182 f60864f0 pts/4 0:00 sleep 24 % 25 % # kill a process 26 % kill 8875 27 % ps 28 PID TTY TIME CMD 29 8661 pts/4 0:03 bash 30 8658 pts/4 0:00 vi 31 8568 pts/4 0:01 bash 32 [1]+ Terminated sleep 1000 33 % 34 % # stop a process 35 % sleep 1000 36 ^Z 37 [1]+ Stopped sleep 1000 38 % # wake up! 39 % fg 40 sleep 1000 41 ^C 42 % # take a look at 43 # http://www.cs.oswego.edu/~bischof/Man/ \ 44 # _Man_Solaris_2.5_html/html5/signal.5.html 45 % 46 % # process synchronization via pipes 47 % 48 % niscat passwd.org_dir | sed 's/Bischof/HP/' | grep HP 49 bischof:z03l03sqb2OD.:22008:7000:Hans-Peter HP:... 50 % niscat passwd.org_dir | grep HP 51 % niscat passwd.org_dir | grep bischof 52 bischof:z03l03sqb2OD.:22008:7000:Hans-Peter Bischof:... 53 % 54 55 % # process synchronization via fifos 56 % 57 % mkfifo myFifo 58 % ls -l myFifo 59 prw-r--r-- 1 bischof cs 0 Sep 2 17:00 myFifo 60 % echo 'I like it' > myFifo & 61 9390 62 % cat myFifo 63 I like it
Source Code: Src/5/unix_process
Get some information (getpid(), (getppid(), (getuid(), (geteuid():
Signals are software interrupts and can be generated with a variety of causes (divide by 0, send via signal(), control C etc). The signal causes the process temporarily to suspend whatever it was doing, save its registers on the stack and start running a special signal handling procedure. When the signal handler is done, the running process is restarted in the state it was just before.
An example:
Write the signal number of each arrived signal.
1 /*
2 * Module: 4_signal.c
3 * Description: print the name of each arrived signal.
4 */
5 #include <stdio.h>
6 #include <signal.h>
7 #include <sys/wait.h>
8
9 /*
10 * The signal handling function.
11 */
12 void catch(int sig)
13 {
14 signal(sig, SIG_IGN);
15 printf("%d: Got signal %d\n", getpid(), sig);
16 }
17
18 int main(int argc, char ** argv)
19 { int i;
20 for ( i = SIGHUP; i < SIGCANCEL; i++ )
21 signal( i , catch );
22
23 while ( 1 ) ;
24 exit(0);
25 }
Source Code: Src/5/signal.c
Compilation and a test run:
% gcc -o 5/signal 5/signal.c % 5/signal ^C3577: Got signal 2 ^C^C^C^C^C^C^C ^Z3577: Got signal 24 ^Z^Z^Z^Z^Z^Z^Z^Z
Try kill -9 from an other window:
% ps -edf | grep 5/signal bischof 3584 1629 1 12:09:22 pts/2 0:00 grep 5/signal bischof 3577 3058 92 12:07:21 pts/6 1:52 5/signal % kill -9 3577
The following figure derived from Stevens shows how
exit()
and
_exit()
are related.
Let's take a look into the Linux 2.7 kernel source code.
1 struct task_struct {
2 /* these are hardcoded - don't touch */
3 volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
4 long counter;
5 long priority;
6 unsigned long signal;
7 unsigned long blocked; /* bitmap of masked signals */
8 unsigned long flags; /* per process flags, defined below */
9 int errno;
10 long debugreg[8]; /* Hardware debugging registers */
11 struct exec_domain *exec_domain;
12 /* various fields */
13 struct linux_binfmt *binfmt;
14 struct task_struct *next_task, *prev_task;
15 struct task_struct *next_run, *prev_run;
16 unsigned long saved_kernel_stack;
17 unsigned long kernel_stack_page;
18 int exit_code, exit_signal;
19 /* ??? */
20 unsigned long personality;
21 int dumpable:1;
22 int did_exec:1;
23 /* shouldn't this be pid_t? */
24 int pid;
25 int pgrp;
26 int tty_old_pgrp;
27 int session;
28 /* boolean value for session group leader */
29 int leader;
30 int groups[NGROUPS];
31 /*
32 * pointers to (original) parent process, youngest child, younger sibling,
33 * older sibling, respectively. (p->father can be replaced with
34 * p->p_pptr->pid)
35 */
36 struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
37 struct wait_queue *wait_chldexit; /* for wait4() */
38 unsigned short uid,euid,suid,fsuid;
39 unsigned short gid,egid,sgid,fsgid;
40 unsigned long timeout, policy, rt_priority;
41 unsigned long it_real_value, it_prof_value, it_virt_value;
42 unsigned long it_real_incr, it_prof_incr, it_virt_incr;
43 struct timer_list real_timer;
44 long utime, stime, cutime, cstime, start_time;
45 /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
46 unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
47 int swappable:1;
48 unsigned long swap_address;
49 unsigned long old_maj_flt; /* old value of maj_flt */
50 unsigned long dec_flt; /* page fault count of the last time */
51 unsigned long swap_cnt; /* number of pages to swap on next pass */
52 /* limits */
53 struct rlimit rlim[RLIM_NLIMITS];
54 unsigned short used_math;
55 char comm[16];
56 /* file system info */
57 int link_count;
58 struct tty_struct *tty; /* NULL if no tty */
59 /* ipc stuff */
60 struct sem_undo *semundo;
61 struct sem_queue *semsleeping;
62 /* ldt for this task - used by Wine. If NULL, default_ldt is used */
63 struct desc_struct *ldt;
64 /* tss for this task */
65 struct thread_struct tss;
66 /* filesystem information */
67 struct fs_struct *fs;
68 /* open file information */
69 struct files_struct *files;
70 /* memory management info */
71 struct mm_struct *mm;
72 /* signal handlers */
73 struct signal_struct *sig;
74 #ifdef __SMP__
75 int processor;
76 int last_processor;
77 int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */
78 #endif
79 };
Source Code: Src/5/task_struct
struct task_struct * task[NR_TASKS] = {&init_task, };
1 /*
2 * Ok, this is the main fork-routine. It copies the system process
3 * information (task[nr]) and sets up the necessary registers. It
4 * also copies the data segment in its entirety.
5 */
6 int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
7 {
8 int nr;
9 int error = -ENOMEM;
10 unsigned long new_stack;
11 struct task_struct *p;
12
13 p = (struct task_struct *) kmalloc(sizeof(*p), GFP_KERNEL);
14 if (!p)
15 goto bad_fork;
16 new_stack = alloc_kernel_stack();
17 if (!new_stack)
18 goto bad_fork_free_p;
19 error = -EAGAIN;
20 nr = find_empty_process();
21 if (nr < 0)
22 goto bad_fork_free_stack;
23
24 *p = *current;
25
26 if (p->exec_domain && p->exec_domain->use_count)
27 (*p->exec_domain->use_count)++;
28 if (p->binfmt && p->binfmt->use_count)
29 (*p->binfmt->use_count)++;
30
31 p->did_exec = 0;
32 p->swappable = 0;
33 p->kernel_stack_page = new_stack;
34 *(unsigned long *) p->kernel_stack_page = STACK_MAGIC;
35 p->state = TASK_UNINTERRUPTIBLE;
36 p->flags &= ~(PF_PTRACED|PF_TRACESYS|PF_SUPERPRIV);
37 p->flags |= PF_FORKNOEXEC;
38 p->pid = get_pid(clone_flags);
39 p->next_run = NULL;
40 p->prev_run = NULL;
41 p->p_pptr = p->p_opptr = current;
42 p->p_cptr = NULL;
43 init_waitqueue(&p->wait_chldexit);
44 p->signal = 0;
45 p->it_real_value = p->it_virt_value = p->it_prof_value = 0;
46 p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0;
47 init_timer(&p->real_timer);
48 p->real_timer.data = (unsigned long) p;
49 p->leader = 0; /* session leadership doesn't inherit */
50 p->tty_old_pgrp = 0;
51 p->utime = p->stime = 0;
52 p->cutime = p->cstime = 0;
53 #ifdef __SMP__
54 p->processor = NO_PROC_ID;
55 p->lock_depth = 1;
56 #endif
57 p->start_time = jiffies;
58 task[nr] = p;
59 SET_LINKS(p);
60 nr_tasks++;
61
62 error = -ENOMEM;
63 /* copy all the process information */
64 if (copy_files(clone_flags, p))
65 goto bad_fork_cleanup;
66 if (copy_fs(clone_flags, p))
67 goto bad_fork_cleanup_files;
68 if (copy_sighand(clone_flags, p))
69 goto bad_fork_cleanup_fs;
70 if (copy_mm(clone_flags, p))
71 goto bad_fork_cleanup_sighand;
72 copy_thread(nr, clone_flags, usp, p, regs);
73 p->semundo = NULL;
74
75 /* ok, now we should be set up.. */
76 p->swappable = 1;
77 p->exit_signal = clone_flags & CSIGNAL;
78 p->counter = current->counter >> 1;
79 wake_up_process(p); /* do this last, just in case */
80 ++total_forks;
81 return p->pid;
82
83 bad_fork_cleanup_sighand:
84 exit_sighand(p);
85 bad_fork_cleanup_fs:
86 exit_fs(p);
87 bad_fork_cleanup_files:
88 exit_files(p);
89 bad_fork_cleanup:
90 if (p->exec_domain && p->exec_domain->use_count)
91 (*p->exec_domain->use_count)--;
92 if (p->binfmt && p->binfmt->use_count)
93 (*p->binfmt->use_count)--;
94 task[nr] = NULL;
95 REMOVE_LINKS(p);
96 nr_tasks--;
97 bad_fork_free_stack:
98 free_kernel_stack(new_stack);
99 bad_fork_free_p:
100 kfree(p);
101 bad_fork:
102 return error;
103 }
Source Code: Src/5/do_fork
i T(p of i) 0 150 1 150 2 100 3 200 4 300
p1 1 time slice
1 time slice
1/2 time slice then blocked untill the alarm goes off
1 time slice
1 time slice then blocked untill the alarm goes off
p2 1 time slice
1/2 time slice then blocked untill the alarm goes off
1 time slice
1/2 time slice then blocked untill the alarm goes off
p3 1 time slice
1 time slice
1 time slice
1/2 time slice then blocked untill the alarm goes off
1/2 time slice
1/2 time slice then blocked untill the alarm goes off
p4 1 time slice
1 time slice
1 time slice
1 time slice
1 time slice
1 time slice
1 time slice
0.5 0.5 0.5 1p1:
2 0.25 0.5
|
|