2009年12月22日 情報科学類 オペレーティングシステム II 筑波大学 システム情報工学研究科 コンピュータサイエンス専攻, 電子・情報工学系 新城 靖 <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/literacy-2009/2009-12-22
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
vfork() は、直後に execve() を行う時にコピーの一部をさぼるような fork()。copy-on-write が一般的な時代は、普通の fork() もコピーをさぼる ので、存在意義が薄くなった。
`http://www.ibm.com/developerworks/jp/linux/library/l-gcc-hacks/',M. Tim Jones、Linux カーネルのなかに入り込む GCC、IBM Developer Works、2008年 11月 18日
arch/x86/kernel/process.c 232: int sys_fork(struct pt_regs *regs) 233: { 234: return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); 235: }
arch/
の下にある。
kernel/fork.c 1339: long do_fork(unsigned long clone_flags, 1340: unsigned long stack_start, 1341: struct pt_regs *regs, 1342: unsigned long stack_size, 1343: int __user *parent_tidptr, 1344: int __user *child_tidptr) 1345: { 1346: struct task_struct *p; ... 1388: p = copy_process(clone_flags, stack_start, regs, stack_size, 1389: child_tidptr, NULL, trace); ... 1394: if (!IS_ERR(p)) { 1395: struct completion vfork; ... 1399: nr = task_pid_vnr(p); ... 1428: wake_up_new_task(p, clone_flags); ... 1440: } else { 1441: nr = PTR_ERR(p); 1442: } 1443: return nr; 1444: } 938: static struct task_struct *copy_process(unsigned long clone_flags, 939: unsigned long stack_start, 940: struct pt_regs *regs, 941: unsigned long stack_size, 942: int __user *child_tidptr, 943: struct pid *pid, 944: int trace) 945: { ... 972: retval = -ENOMEM; 973: p = dup_task_struct(current); 974: if (!p) 975: goto fork_out; ... 985: retval = -EAGAIN; ... 1015: INIT_LIST_HEAD(&p->children); 1016: INIT_LIST_HEAD(&p->sibling); ... 1089: sched_fork(p, clone_flags); .. 1100: if ((retval = copy_files(clone_flags, p))) 1101: goto bad_fork_cleanup_semundo; 1102: if ((retval = copy_fs(clone_flags, p))) 1103: goto bad_fork_cleanup_files; 1104: if ((retval = copy_sighand(clone_flags, p))) 1105: goto bad_fork_cleanup_fs; 1106: if ((retval = copy_signal(clone_flags, p))) 1107: goto bad_fork_cleanup_sighand; 1108: if ((retval = copy_mm(clone_flags, p))) 1109: goto bad_fork_cleanup_signal; 1110: if ((retval = copy_namespaces(clone_flags, p))) 1111: goto bad_fork_cleanup_mm; ... 1118: if (pid != &init_struct_pid) { 1119: retval = -ENOMEM; 1120: pid = alloc_pid(p->nsproxy->pid_ns); ... 1129: } 1130: 1131: p->pid = pid_nr(pid); 1132: p->tgid = p->pid; ... 1174: p->exit_state = 0; ... 1212: p->real_parent = current; ... 1241: if (likely(p->pid)) { 1242: list_add_tail(&p->sibling, &p->real_parent->children); ... 1259: } ... 1267: return p; ... 1310: fork_out: 1311: return ERR_PTR(retval); 1312: } 212: static struct task_struct *dup_task_struct(struct task_struct *orig) 213: { 214: struct task_struct *tsk; 216: unsigned long *stackend; ... 222: tsk = alloc_task_struct(); ... 232: err = arch_dup_task_struct(tsk, orig); ... 257: return tsk; ... 263: } ... 205: int __attribute__((weak)) arch_dup_task_struct(struct task_struct *dst, 206: struct task_struct *src) 207: { 208: *dst = *src; 209: return 0; 210: }
1: /* 2: fork-pid-ppid.c -- 画面に pid と ppid を表示するプログラム 3: ~yas/syspro/proc/fork-pid-ppid.c 4: Created on: 2009/12/08 00:50:25 5: */ 6: 7: #include <sys/types.h> /* getpid(), getppid() */ 8: #include <unistd.h> /* getpid(), getppid() */ 9: #include <stdio.h> 10: 11: main() 12: { 13: pid_t pid, ppid; 14: fork(); 15: pid = getpid(); 16: ppid = getppid(); 17: printf("pid=%d, ppid=%d\n", pid, ppid ); 18: } 19:
% cc fork-pid-ppid.c -o fork-pid-ppid
% echo $$
11080
% ./fork-pid-ppid
pid=11650, ppid=11080
pid=11651, ppid=11650
% ./fork-pid-ppid
pid=11652, ppid=11080
pid=11653, ppid=11652
% ./fork-pid-ppid
pid=11654, ppid=11080
pid=11655, ppid=11654
% ./fork-pid-ppid
pid=11658, ppid=11657
pid=11657, ppid=11080
%
図? 親プロセスと子プロセスの実行(非同期)
親プロセスに対して、exit status という小さな値(0..254)を返す事ができる。 シェルでは、直前のコマンドの exit status を $? という変数で調べることができる。
% tcsh
[yas@viola01 proc]$ exit 300
exit
% echo $?
44
% tcsh
[yas@viola01 proc]$ exit 254
exit
% echo $?
254
%
Unix のコマンドの多くは、成功すると exit( 0 )し、失敗すると 0 以外を返す(C言語の true/false とは逆)。
% ls /bin/ls
/bin/ls
% echo $?
0
% ls /bin/nocommand
ls: /bin/nocommand: No such file or directory
% echo $?
2
%
exit status は、シェルの if 文で使うことができる。
tcsh, csh の場合
% /bin/true
% echo $?
0
% /bin/false
% echo $?
1
% if ( { /bin/true } ) echo ok
ok
% if ( { /bin/false } ) echo ok
%
sh, bash の場合
$ if /bin/true; then echo ok; fi
ok
$ if /bin/false; then echo ok; fi
$
1: /* 2: fork-pid-ppid-wait.c -- 画面に pid と ppid を表示するプログラム(wait付) 3: ~yas/syspro/proc/fork-pid-ppid-wait.c 4: Created on: 2009/12/20 16:04:41 5: */ 6: 7: #include <sys/types.h> /* getpid(), getppid() */ 8: #include <unistd.h> /* getpid(), getppid() */ 9: #include <sys/wait.h> /* wait() */ 10: #include <stdlib.h> /* exit() */ 11: #include <stdio.h> 12: 13: main() 14: { 15: pid_t pid, ppid, child_pid; 16: int status; 17: child_pid = fork(); 18: if( child_pid > 0 ) 19: { 20: /* parent process */ 21: if( wait( &status ) < 0 ) 22: { 23: perror("wait"); 24: } 25: printf("child exited with %d (%d)\n", 26: WEXITSTATUS(status),status ); 27: } 28: else if( child_pid == 0 ) 29: { 30: /* child process */ 31: /* fall through */ 32: } 33: else 34: { 35: perror("fork"); 36: exit( 1 ); 37: } 38: pid = getpid(); 39: ppid = getppid(); 40: printf("pid=%d, ppid=%d\n", pid, ppid ); 41: exit( 100 ); 42: }
% cc fork-pid-ppid-wait.c -o fork-pid-ppid-wait
% ./fork-pid-ppid-wait
pid=32423, ppid=32422
child exited with 100 (25600)
pid=32422, ppid=11080
% ./fork-pid-ppid-wait
pid=32425, ppid=32424
child exited with 100 (25600)
pid=32424, ppid=11080
% ./fork-pid-ppid-wait
pid=32427, ppid=32426
child exited with 100 (25600)
pid=32426, ppid=11080
% echo $?
100
%
WEXITSTATUS()
マクロを使って
得られる値が exit status 。
図? 親プロセスと子プロセスの実行(waitシステム・コールによる同期付き)
# ifdef __USE_BSD ... # else /* Don't use BSD. */ # define __WAIT_INT(status) (status) # define __WAIT_STATUS int * # define __WAIT_STATUS_DEFN int * # endif /* Use BSD. */ # include <bits/waitstatus.h> # define WEXITSTATUS(status) __WEXITSTATUS(__WAIT_INT(status)) # define WTERMSIG(status) __WTERMSIG(__WAIT_INT(status)) # define WSTOPSIG(status) __WSTOPSIG(__WAIT_INT(status)) # define WIFEXITED(status) __WIFEXITED(__WAIT_INT(status)) #endif /* <stdlib.h> not included. *//usr/include/bits/waitstatus.h
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8) #define __WTERMSIG(status) ((status) & 0x7f) #define __WSTOPSIG(status) __WEXITSTATUS(status) #define __WIFEXITED(status) (__WTERMSIG(status) == 0)
kernel/exit.c 1032: SYSCALL_DEFINE1(exit, int, error_code) 1033: { 1034: do_exit((error_code&0xff)<<8); 1035: }
kernel/exit.c 888: NORET_TYPE void do_exit(long code) 889: { ... 953: tsk->exit_code = code; ... 956: exit_mm(tsk); ... 963: exit_files(tsk); 964: exit_fs(tsk); ... 984: exit_notify(tsk, group_dead); .. 1012: tsk->state = TASK_DEAD; 1013: schedule(); 1014: BUG(); ... 1018: } 803: static void exit_notify(struct task_struct *tsk, int group_dead) 804: { ... 843: if (signal >= 0) 844: signal = do_notify_parent(tsk, signal); 846: tsk->exit_state = signal == DEATH_REAP ? EXIT_DEAD : EXIT_ZOMBIE; 859: if (signal == DEATH_REAP) 860: release_task(tsk); 861: }
pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options); int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); pid_t wait3(int *status, int options, struct rusage *rusage); pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);最終的には、すべて wait4() を呼ぶ。
kernel/exit.c 1689: SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr, 1690: int, options, struct rusage __user *, ru) 1691: { 1692: struct wait_opts wo; 1693: struct pid *pid = NULL; 1694: enum pid_type type; 1695: long ret; 1696: 1697: if (options & ~(WNOHANG|WUNTRACED|WCONTINUED| 1698: __WNOTHREAD|__WCLONE|__WALL)) 1699: return -EINVAL; 1700: 1701: if (upid == -1) 1702: type = PIDTYPE_MAX; 1703: else if (upid < 0) { 1704: type = PIDTYPE_PGID; 1705: pid = find_get_pid(-upid); 1706: } else if (upid == 0) { 1707: type = PIDTYPE_PGID; 1708: pid = get_task_pid(current, PIDTYPE_PGID); 1709: } else /* upid > 0 */ { 1710: type = PIDTYPE_PID; 1711: pid = find_get_pid(upid); 1712: } 1713: 1714: wo.wo_type = type; 1715: wo.wo_pid = pid; 1716: wo.wo_flags = options | WEXITED; 1717: wo.wo_info = NULL; 1718: wo.wo_stat = stat_addr; 1719: wo.wo_rusage = ru; 1720: ret = do_wait(&wo); ... 1725: return ret; 1726: }
kernel/exit.c 1563: static long do_wait(struct wait_opts *wo) 1564: { 1565: DECLARE_WAITQUEUE(wait, current); 1566: struct task_struct *tsk; 1567: int retval; ... 1571: add_wait_queue(¤t->signal->wait_chldexit,&wait); 1572: repeat: ... 1584: set_current_state(TASK_INTERRUPTIBLE); 1586: tsk = current; ... 1588: retval = do_wait_thread(wo, tsk); 1589: if (retval) 1590: goto end; ... 1601: notask: 1602: retval = wo->notask_error; 1603: if (!retval && !(wo->wo_flags & WNOHANG)) { 1604: retval = -ERESTARTSYS; 1605: if (!signal_pending(current)) { 1606: schedule(); 1607: goto repeat; 1608: } 1609: } 1610: end: 1611: __set_current_state(TASK_RUNNING); 1612: remove_wait_queue(¤t->signal->wait_chldexit,&wait); ... 1638: return retval; 1639: }
kernel/exit.c 1532: static int do_wait_thread(struct wait_opts *wo, struct task_struct *tsk) 1533: { 1534: struct task_struct *p; 1536: list_for_each_entry(p, &tsk->children, sibling) { ... 1541: int ret = wait_consider_task(wo, tsk, 0, p); 1542: if (ret) 1543: return ret; .. 1545: } 1547: return 0; 1548: } 1473: static int wait_consider_task(struct wait_opts *wo, struct task_struct *parent, 1474: int ptrace, struct task_struct *p) 1475: { ... 1508: if (p->exit_state == EXIT_ZOMBIE && !delay_group_leader(p)) 1509: return wait_task_zombie(wo, p); ... 1521: }
kernel/exit.c 1159: static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) 1160: { ... 1201: if (likely(!traced) && likely(!task_detached(p))) { ... 1221: psig = p->real_parent->signal; 1222: sig = p->signal; 1223: psig->cutime = 1224: cputime_add(psig->cutime, 1225: cputime_add(p->utime, 1226: cputime_add(sig->utime, 1227: sig->cutime))); ... 1255: } ... 1263: retval = wo->wo_rusage 1264: ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; 1265: status = (p->signal->flags & SIGNAL_GROUP_EXIT) 1266: ? p->signal->group_exit_code : p->exit_code; 1267: if (!retval && wo->wo_stat) 1268: retval = put_user(status, wo->wo_stat); ... 1314: if (p != NULL) 1315: release_task(p); 1317: return retval; 1318: }