diff options
author | Oleg Nesterov <oleg@redhat.com> | 2009-06-17 19:27:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-18 16:03:52 -0400 |
commit | 9e8ae01d1c86dcaa6443c897662545d088036e4c (patch) | |
tree | d9465ffe404d318e0038d3133f76550faa3ce3c3 /kernel/exit.c | |
parent | 47918025efdabd34e96b13b26eb2cf2fd6fd1f7c (diff) |
introduce "struct wait_opts" to simplify do_wait() patches
Introduce "struct wait_opts" which holds the parameters for misc helpers
in do_wait() pathes.
This adds 13 lines to kernel/exit.c, but saves 256 bytes from .o and imho
makes the code much more readable.
This patch temporary uglifies rusage/siginfo code a little bit, will be
addressed by further cleanups.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Reviewed-by: Ingo Molnar <mingo@elte.hu>
Acked-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 207 |
1 files changed, 110 insertions, 97 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index fd781b56401d..29622e468b7f 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -1080,6 +1080,18 @@ SYSCALL_DEFINE1(exit_group, int, error_code) | |||
1080 | return 0; | 1080 | return 0; |
1081 | } | 1081 | } |
1082 | 1082 | ||
1083 | struct wait_opts { | ||
1084 | enum pid_type wo_type; | ||
1085 | struct pid *wo_pid; | ||
1086 | int wo_flags; | ||
1087 | |||
1088 | struct siginfo __user *wo_info; | ||
1089 | int __user *wo_stat; | ||
1090 | struct rusage __user *wo_rusage; | ||
1091 | |||
1092 | int notask_error; | ||
1093 | }; | ||
1094 | |||
1083 | static struct pid *task_pid_type(struct task_struct *task, enum pid_type type) | 1095 | static struct pid *task_pid_type(struct task_struct *task, enum pid_type type) |
1084 | { | 1096 | { |
1085 | struct pid *pid = NULL; | 1097 | struct pid *pid = NULL; |
@@ -1090,13 +1102,12 @@ static struct pid *task_pid_type(struct task_struct *task, enum pid_type type) | |||
1090 | return pid; | 1102 | return pid; |
1091 | } | 1103 | } |
1092 | 1104 | ||
1093 | static int eligible_child(enum pid_type type, struct pid *pid, int options, | 1105 | static int eligible_child(struct wait_opts *wo, struct task_struct *p) |
1094 | struct task_struct *p) | ||
1095 | { | 1106 | { |
1096 | int err; | 1107 | int err; |
1097 | 1108 | ||
1098 | if (type < PIDTYPE_MAX) { | 1109 | if (wo->wo_type < PIDTYPE_MAX) { |
1099 | if (task_pid_type(p, type) != pid) | 1110 | if (task_pid_type(p, wo->wo_type) != wo->wo_pid) |
1100 | return 0; | 1111 | return 0; |
1101 | } | 1112 | } |
1102 | 1113 | ||
@@ -1105,8 +1116,8 @@ static int eligible_child(enum pid_type type, struct pid *pid, int options, | |||
1105 | * set; otherwise, wait for non-clone children *only*. (Note: | 1116 | * set; otherwise, wait for non-clone children *only*. (Note: |
1106 | * A "clone" child here is one that reports to its parent | 1117 | * A "clone" child here is one that reports to its parent |
1107 | * using a signal other than SIGCHLD.) */ | 1118 | * using a signal other than SIGCHLD.) */ |
1108 | if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) | 1119 | if (((p->exit_signal != SIGCHLD) ^ !!(wo->wo_flags & __WCLONE)) |
1109 | && !(options & __WALL)) | 1120 | && !(wo->wo_flags & __WALL)) |
1110 | return 0; | 1121 | return 0; |
1111 | 1122 | ||
1112 | err = security_task_wait(p); | 1123 | err = security_task_wait(p); |
@@ -1116,14 +1127,15 @@ static int eligible_child(enum pid_type type, struct pid *pid, int options, | |||
1116 | return 1; | 1127 | return 1; |
1117 | } | 1128 | } |
1118 | 1129 | ||
1119 | static int wait_noreap_copyout(struct task_struct *p, pid_t pid, uid_t uid, | 1130 | static int wait_noreap_copyout(struct wait_opts *wo, struct task_struct *p, |
1120 | int why, int status, | 1131 | pid_t pid, uid_t uid, int why, int status) |
1121 | struct siginfo __user *infop, | ||
1122 | struct rusage __user *rusagep) | ||
1123 | { | 1132 | { |
1124 | int retval = rusagep ? getrusage(p, RUSAGE_BOTH, rusagep) : 0; | 1133 | struct siginfo __user *infop; |
1134 | int retval = wo->wo_rusage | ||
1135 | ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; | ||
1125 | 1136 | ||
1126 | put_task_struct(p); | 1137 | put_task_struct(p); |
1138 | infop = wo->wo_info; | ||
1127 | if (!retval) | 1139 | if (!retval) |
1128 | retval = put_user(SIGCHLD, &infop->si_signo); | 1140 | retval = put_user(SIGCHLD, &infop->si_signo); |
1129 | if (!retval) | 1141 | if (!retval) |
@@ -1147,19 +1159,18 @@ static int wait_noreap_copyout(struct task_struct *p, pid_t pid, uid_t uid, | |||
1147 | * the lock and this task is uninteresting. If we return nonzero, we have | 1159 | * the lock and this task is uninteresting. If we return nonzero, we have |
1148 | * released the lock and the system call should return. | 1160 | * released the lock and the system call should return. |
1149 | */ | 1161 | */ |
1150 | static int wait_task_zombie(struct task_struct *p, int options, | 1162 | static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) |
1151 | struct siginfo __user *infop, | ||
1152 | int __user *stat_addr, struct rusage __user *ru) | ||
1153 | { | 1163 | { |
1154 | unsigned long state; | 1164 | unsigned long state; |
1155 | int retval, status, traced; | 1165 | int retval, status, traced; |
1156 | pid_t pid = task_pid_vnr(p); | 1166 | pid_t pid = task_pid_vnr(p); |
1157 | uid_t uid = __task_cred(p)->uid; | 1167 | uid_t uid = __task_cred(p)->uid; |
1168 | struct siginfo __user *infop; | ||
1158 | 1169 | ||
1159 | if (!likely(options & WEXITED)) | 1170 | if (!likely(wo->wo_flags & WEXITED)) |
1160 | return 0; | 1171 | return 0; |
1161 | 1172 | ||
1162 | if (unlikely(options & WNOWAIT)) { | 1173 | if (unlikely(wo->wo_flags & WNOWAIT)) { |
1163 | int exit_code = p->exit_code; | 1174 | int exit_code = p->exit_code; |
1164 | int why, status; | 1175 | int why, status; |
1165 | 1176 | ||
@@ -1172,8 +1183,7 @@ static int wait_task_zombie(struct task_struct *p, int options, | |||
1172 | why = (exit_code & 0x80) ? CLD_DUMPED : CLD_KILLED; | 1183 | why = (exit_code & 0x80) ? CLD_DUMPED : CLD_KILLED; |
1173 | status = exit_code & 0x7f; | 1184 | status = exit_code & 0x7f; |
1174 | } | 1185 | } |
1175 | return wait_noreap_copyout(p, pid, uid, why, | 1186 | return wait_noreap_copyout(wo, p, pid, uid, why, status); |
1176 | status, infop, ru); | ||
1177 | } | 1187 | } |
1178 | 1188 | ||
1179 | /* | 1189 | /* |
@@ -1250,11 +1260,14 @@ static int wait_task_zombie(struct task_struct *p, int options, | |||
1250 | */ | 1260 | */ |
1251 | read_unlock(&tasklist_lock); | 1261 | read_unlock(&tasklist_lock); |
1252 | 1262 | ||
1253 | retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; | 1263 | retval = wo->wo_rusage |
1264 | ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; | ||
1254 | status = (p->signal->flags & SIGNAL_GROUP_EXIT) | 1265 | status = (p->signal->flags & SIGNAL_GROUP_EXIT) |
1255 | ? p->signal->group_exit_code : p->exit_code; | 1266 | ? p->signal->group_exit_code : p->exit_code; |
1256 | if (!retval && stat_addr) | 1267 | if (!retval && wo->wo_stat) |
1257 | retval = put_user(status, stat_addr); | 1268 | retval = put_user(status, wo->wo_stat); |
1269 | |||
1270 | infop = wo->wo_info; | ||
1258 | if (!retval && infop) | 1271 | if (!retval && infop) |
1259 | retval = put_user(SIGCHLD, &infop->si_signo); | 1272 | retval = put_user(SIGCHLD, &infop->si_signo); |
1260 | if (!retval && infop) | 1273 | if (!retval && infop) |
@@ -1322,10 +1335,10 @@ static int *task_stopped_code(struct task_struct *p, bool ptrace) | |||
1322 | * the lock and this task is uninteresting. If we return nonzero, we have | 1335 | * the lock and this task is uninteresting. If we return nonzero, we have |
1323 | * released the lock and the system call should return. | 1336 | * released the lock and the system call should return. |
1324 | */ | 1337 | */ |
1325 | static int wait_task_stopped(int ptrace, struct task_struct *p, | 1338 | static int wait_task_stopped(struct wait_opts *wo, |
1326 | int options, struct siginfo __user *infop, | 1339 | int ptrace, struct task_struct *p) |
1327 | int __user *stat_addr, struct rusage __user *ru) | ||
1328 | { | 1340 | { |
1341 | struct siginfo __user *infop; | ||
1329 | int retval, exit_code, *p_code, why; | 1342 | int retval, exit_code, *p_code, why; |
1330 | uid_t uid = 0; /* unneeded, required by compiler */ | 1343 | uid_t uid = 0; /* unneeded, required by compiler */ |
1331 | pid_t pid; | 1344 | pid_t pid; |
@@ -1333,7 +1346,7 @@ static int wait_task_stopped(int ptrace, struct task_struct *p, | |||
1333 | /* | 1346 | /* |
1334 | * Traditionally we see ptrace'd stopped tasks regardless of options. | 1347 | * Traditionally we see ptrace'd stopped tasks regardless of options. |
1335 | */ | 1348 | */ |
1336 | if (!ptrace && !(options & WUNTRACED)) | 1349 | if (!ptrace && !(wo->wo_flags & WUNTRACED)) |
1337 | return 0; | 1350 | return 0; |
1338 | 1351 | ||
1339 | exit_code = 0; | 1352 | exit_code = 0; |
@@ -1347,7 +1360,7 @@ static int wait_task_stopped(int ptrace, struct task_struct *p, | |||
1347 | if (!exit_code) | 1360 | if (!exit_code) |
1348 | goto unlock_sig; | 1361 | goto unlock_sig; |
1349 | 1362 | ||
1350 | if (!unlikely(options & WNOWAIT)) | 1363 | if (!unlikely(wo->wo_flags & WNOWAIT)) |
1351 | *p_code = 0; | 1364 | *p_code = 0; |
1352 | 1365 | ||
1353 | /* don't need the RCU readlock here as we're holding a spinlock */ | 1366 | /* don't need the RCU readlock here as we're holding a spinlock */ |
@@ -1369,14 +1382,15 @@ unlock_sig: | |||
1369 | why = ptrace ? CLD_TRAPPED : CLD_STOPPED; | 1382 | why = ptrace ? CLD_TRAPPED : CLD_STOPPED; |
1370 | read_unlock(&tasklist_lock); | 1383 | read_unlock(&tasklist_lock); |
1371 | 1384 | ||
1372 | if (unlikely(options & WNOWAIT)) | 1385 | if (unlikely(wo->wo_flags & WNOWAIT)) |
1373 | return wait_noreap_copyout(p, pid, uid, | 1386 | return wait_noreap_copyout(wo, p, pid, uid, why, exit_code); |
1374 | why, exit_code, | 1387 | |
1375 | infop, ru); | 1388 | retval = wo->wo_rusage |
1389 | ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; | ||
1390 | if (!retval && wo->wo_stat) | ||
1391 | retval = put_user((exit_code << 8) | 0x7f, wo->wo_stat); | ||
1376 | 1392 | ||
1377 | retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; | 1393 | infop = wo->wo_info; |
1378 | if (!retval && stat_addr) | ||
1379 | retval = put_user((exit_code << 8) | 0x7f, stat_addr); | ||
1380 | if (!retval && infop) | 1394 | if (!retval && infop) |
1381 | retval = put_user(SIGCHLD, &infop->si_signo); | 1395 | retval = put_user(SIGCHLD, &infop->si_signo); |
1382 | if (!retval && infop) | 1396 | if (!retval && infop) |
@@ -1403,15 +1417,13 @@ unlock_sig: | |||
1403 | * the lock and this task is uninteresting. If we return nonzero, we have | 1417 | * the lock and this task is uninteresting. If we return nonzero, we have |
1404 | * released the lock and the system call should return. | 1418 | * released the lock and the system call should return. |
1405 | */ | 1419 | */ |
1406 | static int wait_task_continued(struct task_struct *p, int options, | 1420 | static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) |
1407 | struct siginfo __user *infop, | ||
1408 | int __user *stat_addr, struct rusage __user *ru) | ||
1409 | { | 1421 | { |
1410 | int retval; | 1422 | int retval; |
1411 | pid_t pid; | 1423 | pid_t pid; |
1412 | uid_t uid; | 1424 | uid_t uid; |
1413 | 1425 | ||
1414 | if (!unlikely(options & WCONTINUED)) | 1426 | if (!unlikely(wo->wo_flags & WCONTINUED)) |
1415 | return 0; | 1427 | return 0; |
1416 | 1428 | ||
1417 | if (!(p->signal->flags & SIGNAL_STOP_CONTINUED)) | 1429 | if (!(p->signal->flags & SIGNAL_STOP_CONTINUED)) |
@@ -1423,7 +1435,7 @@ static int wait_task_continued(struct task_struct *p, int options, | |||
1423 | spin_unlock_irq(&p->sighand->siglock); | 1435 | spin_unlock_irq(&p->sighand->siglock); |
1424 | return 0; | 1436 | return 0; |
1425 | } | 1437 | } |
1426 | if (!unlikely(options & WNOWAIT)) | 1438 | if (!unlikely(wo->wo_flags & WNOWAIT)) |
1427 | p->signal->flags &= ~SIGNAL_STOP_CONTINUED; | 1439 | p->signal->flags &= ~SIGNAL_STOP_CONTINUED; |
1428 | uid = __task_cred(p)->uid; | 1440 | uid = __task_cred(p)->uid; |
1429 | spin_unlock_irq(&p->sighand->siglock); | 1441 | spin_unlock_irq(&p->sighand->siglock); |
@@ -1432,17 +1444,17 @@ static int wait_task_continued(struct task_struct *p, int options, | |||
1432 | get_task_struct(p); | 1444 | get_task_struct(p); |
1433 | read_unlock(&tasklist_lock); | 1445 | read_unlock(&tasklist_lock); |
1434 | 1446 | ||
1435 | if (!infop) { | 1447 | if (!wo->wo_info) { |
1436 | retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; | 1448 | retval = wo->wo_rusage |
1449 | ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; | ||
1437 | put_task_struct(p); | 1450 | put_task_struct(p); |
1438 | if (!retval && stat_addr) | 1451 | if (!retval && wo->wo_stat) |
1439 | retval = put_user(0xffff, stat_addr); | 1452 | retval = put_user(0xffff, wo->wo_stat); |
1440 | if (!retval) | 1453 | if (!retval) |
1441 | retval = pid; | 1454 | retval = pid; |
1442 | } else { | 1455 | } else { |
1443 | retval = wait_noreap_copyout(p, pid, uid, | 1456 | retval = wait_noreap_copyout(wo, p, pid, uid, |
1444 | CLD_CONTINUED, SIGCONT, | 1457 | CLD_CONTINUED, SIGCONT); |
1445 | infop, ru); | ||
1446 | BUG_ON(retval == 0); | 1458 | BUG_ON(retval == 0); |
1447 | } | 1459 | } |
1448 | 1460 | ||
@@ -1452,19 +1464,16 @@ static int wait_task_continued(struct task_struct *p, int options, | |||
1452 | /* | 1464 | /* |
1453 | * Consider @p for a wait by @parent. | 1465 | * Consider @p for a wait by @parent. |
1454 | * | 1466 | * |
1455 | * -ECHILD should be in *@notask_error before the first call. | 1467 | * -ECHILD should be in ->notask_error before the first call. |
1456 | * Returns nonzero for a final return, when we have unlocked tasklist_lock. | 1468 | * Returns nonzero for a final return, when we have unlocked tasklist_lock. |
1457 | * Returns zero if the search for a child should continue; | 1469 | * Returns zero if the search for a child should continue; |
1458 | * then *@notask_error is 0 if @p is an eligible child, | 1470 | * then ->notask_error is 0 if @p is an eligible child, |
1459 | * or another error from security_task_wait(), or still -ECHILD. | 1471 | * or another error from security_task_wait(), or still -ECHILD. |
1460 | */ | 1472 | */ |
1461 | static int wait_consider_task(struct task_struct *parent, int ptrace, | 1473 | static int wait_consider_task(struct wait_opts *wo, struct task_struct *parent, |
1462 | struct task_struct *p, int *notask_error, | 1474 | int ptrace, struct task_struct *p) |
1463 | enum pid_type type, struct pid *pid, int options, | ||
1464 | struct siginfo __user *infop, | ||
1465 | int __user *stat_addr, struct rusage __user *ru) | ||
1466 | { | 1475 | { |
1467 | int ret = eligible_child(type, pid, options, p); | 1476 | int ret = eligible_child(wo, p); |
1468 | if (!ret) | 1477 | if (!ret) |
1469 | return ret; | 1478 | return ret; |
1470 | 1479 | ||
@@ -1476,8 +1485,8 @@ static int wait_consider_task(struct task_struct *parent, int ptrace, | |||
1476 | * to look for security policy problems, rather | 1485 | * to look for security policy problems, rather |
1477 | * than for mysterious wait bugs. | 1486 | * than for mysterious wait bugs. |
1478 | */ | 1487 | */ |
1479 | if (*notask_error) | 1488 | if (wo->notask_error) |
1480 | *notask_error = ret; | 1489 | wo->notask_error = ret; |
1481 | return 0; | 1490 | return 0; |
1482 | } | 1491 | } |
1483 | 1492 | ||
@@ -1486,7 +1495,7 @@ static int wait_consider_task(struct task_struct *parent, int ptrace, | |||
1486 | * This child is hidden by ptrace. | 1495 | * This child is hidden by ptrace. |
1487 | * We aren't allowed to see it now, but eventually we will. | 1496 | * We aren't allowed to see it now, but eventually we will. |
1488 | */ | 1497 | */ |
1489 | *notask_error = 0; | 1498 | wo->notask_error = 0; |
1490 | return 0; | 1499 | return 0; |
1491 | } | 1500 | } |
1492 | 1501 | ||
@@ -1497,34 +1506,30 @@ static int wait_consider_task(struct task_struct *parent, int ptrace, | |||
1497 | * We don't reap group leaders with subthreads. | 1506 | * We don't reap group leaders with subthreads. |
1498 | */ | 1507 | */ |
1499 | if (p->exit_state == EXIT_ZOMBIE && !delay_group_leader(p)) | 1508 | if (p->exit_state == EXIT_ZOMBIE && !delay_group_leader(p)) |
1500 | return wait_task_zombie(p, options, infop, stat_addr, ru); | 1509 | return wait_task_zombie(wo, p); |
1501 | 1510 | ||
1502 | /* | 1511 | /* |
1503 | * It's stopped or running now, so it might | 1512 | * It's stopped or running now, so it might |
1504 | * later continue, exit, or stop again. | 1513 | * later continue, exit, or stop again. |
1505 | */ | 1514 | */ |
1506 | *notask_error = 0; | 1515 | wo->notask_error = 0; |
1507 | 1516 | ||
1508 | if (task_stopped_code(p, ptrace)) | 1517 | if (task_stopped_code(p, ptrace)) |
1509 | return wait_task_stopped(ptrace, p, options, | 1518 | return wait_task_stopped(wo, ptrace, p); |
1510 | infop, stat_addr, ru); | ||
1511 | 1519 | ||
1512 | return wait_task_continued(p, options, infop, stat_addr, ru); | 1520 | return wait_task_continued(wo, p); |
1513 | } | 1521 | } |
1514 | 1522 | ||
1515 | /* | 1523 | /* |
1516 | * Do the work of do_wait() for one thread in the group, @tsk. | 1524 | * Do the work of do_wait() for one thread in the group, @tsk. |
1517 | * | 1525 | * |
1518 | * -ECHILD should be in *@notask_error before the first call. | 1526 | * -ECHILD should be in ->notask_error before the first call. |
1519 | * Returns nonzero for a final return, when we have unlocked tasklist_lock. | 1527 | * Returns nonzero for a final return, when we have unlocked tasklist_lock. |
1520 | * Returns zero if the search for a child should continue; then | 1528 | * Returns zero if the search for a child should continue; then |
1521 | * *@notask_error is 0 if there were any eligible children, | 1529 | * ->notask_error is 0 if there were any eligible children, |
1522 | * or another error from security_task_wait(), or still -ECHILD. | 1530 | * or another error from security_task_wait(), or still -ECHILD. |
1523 | */ | 1531 | */ |
1524 | static int do_wait_thread(struct task_struct *tsk, int *notask_error, | 1532 | static int do_wait_thread(struct wait_opts *wo, struct task_struct *tsk) |
1525 | enum pid_type type, struct pid *pid, int options, | ||
1526 | struct siginfo __user *infop, int __user *stat_addr, | ||
1527 | struct rusage __user *ru) | ||
1528 | { | 1533 | { |
1529 | struct task_struct *p; | 1534 | struct task_struct *p; |
1530 | 1535 | ||
@@ -1533,9 +1538,7 @@ static int do_wait_thread(struct task_struct *tsk, int *notask_error, | |||
1533 | * Do not consider detached threads. | 1538 | * Do not consider detached threads. |
1534 | */ | 1539 | */ |
1535 | if (!task_detached(p)) { | 1540 | if (!task_detached(p)) { |
1536 | int ret = wait_consider_task(tsk, 0, p, notask_error, | 1541 | int ret = wait_consider_task(wo, tsk, 0, p); |
1537 | type, pid, options, | ||
1538 | infop, stat_addr, ru); | ||
1539 | if (ret) | 1542 | if (ret) |
1540 | return ret; | 1543 | return ret; |
1541 | } | 1544 | } |
@@ -1544,17 +1547,12 @@ static int do_wait_thread(struct task_struct *tsk, int *notask_error, | |||
1544 | return 0; | 1547 | return 0; |
1545 | } | 1548 | } |
1546 | 1549 | ||
1547 | static int ptrace_do_wait(struct task_struct *tsk, int *notask_error, | 1550 | static int ptrace_do_wait(struct wait_opts *wo, struct task_struct *tsk) |
1548 | enum pid_type type, struct pid *pid, int options, | ||
1549 | struct siginfo __user *infop, int __user *stat_addr, | ||
1550 | struct rusage __user *ru) | ||
1551 | { | 1551 | { |
1552 | struct task_struct *p; | 1552 | struct task_struct *p; |
1553 | 1553 | ||
1554 | list_for_each_entry(p, &tsk->ptraced, ptrace_entry) { | 1554 | list_for_each_entry(p, &tsk->ptraced, ptrace_entry) { |
1555 | int ret = wait_consider_task(tsk, 1, p, notask_error, | 1555 | int ret = wait_consider_task(wo, tsk, 1, p); |
1556 | type, pid, options, | ||
1557 | infop, stat_addr, ru); | ||
1558 | if (ret) | 1556 | if (ret) |
1559 | return ret; | 1557 | return ret; |
1560 | } | 1558 | } |
@@ -1562,38 +1560,36 @@ static int ptrace_do_wait(struct task_struct *tsk, int *notask_error, | |||
1562 | return 0; | 1560 | return 0; |
1563 | } | 1561 | } |
1564 | 1562 | ||
1565 | static long do_wait(enum pid_type type, struct pid *pid, int options, | 1563 | static long do_wait(struct wait_opts *wo) |
1566 | struct siginfo __user *infop, int __user *stat_addr, | ||
1567 | struct rusage __user *ru) | ||
1568 | { | 1564 | { |
1569 | DECLARE_WAITQUEUE(wait, current); | 1565 | DECLARE_WAITQUEUE(wait, current); |
1570 | struct task_struct *tsk; | 1566 | struct task_struct *tsk; |
1571 | int retval; | 1567 | int retval; |
1572 | 1568 | ||
1573 | trace_sched_process_wait(pid); | 1569 | trace_sched_process_wait(wo->wo_pid); |
1574 | 1570 | ||
1575 | add_wait_queue(¤t->signal->wait_chldexit,&wait); | 1571 | add_wait_queue(¤t->signal->wait_chldexit,&wait); |
1576 | repeat: | 1572 | repeat: |
1577 | /* | 1573 | /* |
1578 | * If there is nothing that can match our critiera just get out. | 1574 | * If there is nothing that can match our critiera just get out. |
1579 | * We will clear @retval to zero if we see any child that might later | 1575 | * We will clear ->notask_error to zero if we see any child that |
1580 | * match our criteria, even if we are not able to reap it yet. | 1576 | * might later match our criteria, even if we are not able to reap |
1577 | * it yet. | ||
1581 | */ | 1578 | */ |
1582 | retval = -ECHILD; | 1579 | retval = wo->notask_error = -ECHILD; |
1583 | if ((type < PIDTYPE_MAX) && (!pid || hlist_empty(&pid->tasks[type]))) | 1580 | if ((wo->wo_type < PIDTYPE_MAX) && |
1581 | (!wo->wo_pid || hlist_empty(&wo->wo_pid->tasks[wo->wo_type]))) | ||
1584 | goto end; | 1582 | goto end; |
1585 | 1583 | ||
1586 | current->state = TASK_INTERRUPTIBLE; | 1584 | current->state = TASK_INTERRUPTIBLE; |
1587 | read_lock(&tasklist_lock); | 1585 | read_lock(&tasklist_lock); |
1588 | tsk = current; | 1586 | tsk = current; |
1589 | do { | 1587 | do { |
1590 | int tsk_result = do_wait_thread(tsk, &retval, | 1588 | int tsk_result = do_wait_thread(wo, tsk); |
1591 | type, pid, options, | 1589 | |
1592 | infop, stat_addr, ru); | ||
1593 | if (!tsk_result) | 1590 | if (!tsk_result) |
1594 | tsk_result = ptrace_do_wait(tsk, &retval, | 1591 | tsk_result = ptrace_do_wait(wo, tsk); |
1595 | type, pid, options, | 1592 | |
1596 | infop, stat_addr, ru); | ||
1597 | if (tsk_result) { | 1593 | if (tsk_result) { |
1598 | /* | 1594 | /* |
1599 | * tasklist_lock is unlocked and we have a final result. | 1595 | * tasklist_lock is unlocked and we have a final result. |
@@ -1602,25 +1598,27 @@ repeat: | |||
1602 | goto end; | 1598 | goto end; |
1603 | } | 1599 | } |
1604 | 1600 | ||
1605 | if (options & __WNOTHREAD) | 1601 | if (wo->wo_flags & __WNOTHREAD) |
1606 | break; | 1602 | break; |
1607 | tsk = next_thread(tsk); | 1603 | tsk = next_thread(tsk); |
1608 | BUG_ON(tsk->signal != current->signal); | 1604 | BUG_ON(tsk->signal != current->signal); |
1609 | } while (tsk != current); | 1605 | } while (tsk != current); |
1610 | read_unlock(&tasklist_lock); | 1606 | read_unlock(&tasklist_lock); |
1611 | 1607 | ||
1612 | if (!retval && !(options & WNOHANG)) { | 1608 | retval = wo->notask_error; |
1609 | if (!retval && !(wo->wo_flags & WNOHANG)) { | ||
1613 | retval = -ERESTARTSYS; | 1610 | retval = -ERESTARTSYS; |
1614 | if (!signal_pending(current)) { | 1611 | if (!signal_pending(current)) { |
1615 | schedule(); | 1612 | schedule(); |
1616 | goto repeat; | 1613 | goto repeat; |
1617 | } | 1614 | } |
1618 | } | 1615 | } |
1619 | |||
1620 | end: | 1616 | end: |
1621 | current->state = TASK_RUNNING; | 1617 | current->state = TASK_RUNNING; |
1622 | remove_wait_queue(¤t->signal->wait_chldexit,&wait); | 1618 | remove_wait_queue(¤t->signal->wait_chldexit,&wait); |
1623 | if (infop) { | 1619 | if (wo->wo_info) { |
1620 | struct siginfo __user *infop = wo->wo_info; | ||
1621 | |||
1624 | if (retval > 0) | 1622 | if (retval > 0) |
1625 | retval = 0; | 1623 | retval = 0; |
1626 | else { | 1624 | else { |
@@ -1649,6 +1647,7 @@ end: | |||
1649 | SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, | 1647 | SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, |
1650 | infop, int, options, struct rusage __user *, ru) | 1648 | infop, int, options, struct rusage __user *, ru) |
1651 | { | 1649 | { |
1650 | struct wait_opts wo; | ||
1652 | struct pid *pid = NULL; | 1651 | struct pid *pid = NULL; |
1653 | enum pid_type type; | 1652 | enum pid_type type; |
1654 | long ret; | 1653 | long ret; |
@@ -1678,7 +1677,14 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, | |||
1678 | 1677 | ||
1679 | if (type < PIDTYPE_MAX) | 1678 | if (type < PIDTYPE_MAX) |
1680 | pid = find_get_pid(upid); | 1679 | pid = find_get_pid(upid); |
1681 | ret = do_wait(type, pid, options, infop, NULL, ru); | 1680 | |
1681 | wo.wo_type = type; | ||
1682 | wo.wo_pid = pid; | ||
1683 | wo.wo_flags = options; | ||
1684 | wo.wo_info = infop; | ||
1685 | wo.wo_stat = NULL; | ||
1686 | wo.wo_rusage = ru; | ||
1687 | ret = do_wait(&wo); | ||
1682 | put_pid(pid); | 1688 | put_pid(pid); |
1683 | 1689 | ||
1684 | /* avoid REGPARM breakage on x86: */ | 1690 | /* avoid REGPARM breakage on x86: */ |
@@ -1689,6 +1695,7 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, | |||
1689 | SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr, | 1695 | SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr, |
1690 | int, options, struct rusage __user *, ru) | 1696 | int, options, struct rusage __user *, ru) |
1691 | { | 1697 | { |
1698 | struct wait_opts wo; | ||
1692 | struct pid *pid = NULL; | 1699 | struct pid *pid = NULL; |
1693 | enum pid_type type; | 1700 | enum pid_type type; |
1694 | long ret; | 1701 | long ret; |
@@ -1710,7 +1717,13 @@ SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr, | |||
1710 | pid = find_get_pid(upid); | 1717 | pid = find_get_pid(upid); |
1711 | } | 1718 | } |
1712 | 1719 | ||
1713 | ret = do_wait(type, pid, options | WEXITED, NULL, stat_addr, ru); | 1720 | wo.wo_type = type; |
1721 | wo.wo_pid = pid; | ||
1722 | wo.wo_flags = options | WEXITED; | ||
1723 | wo.wo_info = NULL; | ||
1724 | wo.wo_stat = stat_addr; | ||
1725 | wo.wo_rusage = ru; | ||
1726 | ret = do_wait(&wo); | ||
1714 | put_pid(pid); | 1727 | put_pid(pid); |
1715 | 1728 | ||
1716 | /* avoid REGPARM breakage on x86: */ | 1729 | /* avoid REGPARM breakage on x86: */ |