Implement a variation of the linux_common_wait() which should

be used by linuxolator itself.

Move linux_wait4() to MD path as it requires native struct
rusage translation to struct l_rusage on linux32/amd64.

MFC after:	1 Month.
This commit is contained in:
Dmitry Chagin 2011-01-28 18:47:07 +00:00
parent 53c74fc607
commit adc7ece00a
4 changed files with 113 additions and 67 deletions

View File

@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <sys/syscallsubr.h>
#include <sys/sysproto.h>
#include <sys/unistd.h>
#include <sys/wait.h>
#include <machine/frame.h>
#include <machine/pcb.h>
@ -66,6 +67,7 @@ __FBSDID("$FreeBSD$");
#include <amd64/linux32/linux.h>
#include <amd64/linux32/linux32_proto.h>
#include <compat/linux/linux_ipc.h>
#include <compat/linux/linux_misc.h>
#include <compat/linux/linux_signal.h>
#include <compat/linux/linux_util.h>
#include <compat/linux/linux_emul.h>
@ -1272,3 +1274,44 @@ linux_set_thread_area(struct thread *td,
return (0);
}
int
linux_wait4(struct thread *td, struct linux_wait4_args *args)
{
int error, options;
struct rusage ru, *rup;
struct l_rusage lru;
struct proc *p;
#ifdef DEBUG
if (ldebug(wait4))
printf(ARGS(wait4, "%d, %p, %d, %p"),
args->pid, (void *)args->status, args->options,
(void *)args->rusage);
#endif
options = (args->options & (WNOHANG | WUNTRACED));
/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
if (args->options & __WCLONE)
options |= WLINUXCLONE;
if (args->rusage != NULL)
rup = &ru;
else
rup = NULL;
error = linux_common_wait(td, args->pid, args->status, options, rup);
if (error)
return (error);
p = td->td_proc;
PROC_LOCK(p);
sigqueue_delete(&p->p_sigqueue, SIGCHLD);
PROC_UNLOCK(p);
if (args->rusage != NULL) {
bsd_to_linux_rusage(rup, &lru);
error = copyout(&lru, args->rusage, sizeof(lru));
}
return (error);
}

View File

@ -847,13 +847,35 @@ linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
}
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
#define __WCLONE 0x80000000
int
linux_common_wait(struct thread *td, int pid, int *status,
int options, struct rusage *ru)
{
int error, tmpstat;
error = kern_wait(td, pid, &tmpstat, options, ru);
if (error)
return (error);
if (status) {
tmpstat &= 0xffff;
if (WIFSIGNALED(tmpstat))
tmpstat = (tmpstat & 0xffffff80) |
BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
else if (WIFSTOPPED(tmpstat))
tmpstat = (tmpstat & 0xffff00ff) |
(BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
error = copyout(&tmpstat, status, sizeof(int));
}
return (error);
}
int
linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
{
int error, options, tmpstat;
int options;
#ifdef DEBUG
if (ldebug(waitpid))
printf(ARGS(waitpid, "%d, %p, %d"),
@ -865,77 +887,15 @@ linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
*/
if (args->options & ~(WUNTRACED | WNOHANG | WCONTINUED | __WCLONE))
return (EINVAL);
options = (args->options & (WNOHANG | WUNTRACED));
/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
if (args->options & __WCLONE)
options |= WLINUXCLONE;
error = kern_wait(td, args->pid, &tmpstat, options, NULL);
if (error)
return error;
if (args->status) {
tmpstat &= 0xffff;
if (WIFSIGNALED(tmpstat))
tmpstat = (tmpstat & 0xffffff80) |
BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
else if (WIFSTOPPED(tmpstat))
tmpstat = (tmpstat & 0xffff00ff) |
(BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
return copyout(&tmpstat, args->status, sizeof(int));
}
return (0);
return (linux_common_wait(td, args->pid, args->status, options, NULL));
}
int
linux_wait4(struct thread *td, struct linux_wait4_args *args)
{
int error, options, tmpstat;
struct rusage ru, *rup;
struct proc *p;
#ifdef DEBUG
if (ldebug(wait4))
printf(ARGS(wait4, "%d, %p, %d, %p"),
args->pid, (void *)args->status, args->options,
(void *)args->rusage);
#endif
options = (args->options & (WNOHANG | WUNTRACED));
/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
if (args->options & __WCLONE)
options |= WLINUXCLONE;
if (args->rusage != NULL)
rup = &ru;
else
rup = NULL;
error = kern_wait(td, args->pid, &tmpstat, options, rup);
if (error)
return error;
p = td->td_proc;
PROC_LOCK(p);
sigqueue_delete(&p->p_sigqueue, SIGCHLD);
PROC_UNLOCK(p);
if (args->status) {
tmpstat &= 0xffff;
if (WIFSIGNALED(tmpstat))
tmpstat = (tmpstat & 0xffffff80) |
BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
else if (WIFSTOPPED(tmpstat))
tmpstat = (tmpstat & 0xffff00ff) |
(BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
error = copyout(&tmpstat, args->status, sizeof(int));
}
if (args->rusage != NULL && error == 0)
error = copyout(&ru, args->rusage, sizeof(ru));
return (error);
}
int
linux_mknod(struct thread *td, struct linux_mknod_args *args)

View File

@ -67,4 +67,9 @@ extern const char *linux_platform;
extern int stclohz;
#define __WCLONE 0x80000000
int linux_common_wait(struct thread *td, int pid, int *status,
int options, struct rusage *ru);
#endif /* _LINUX_MISC_H_ */

View File

@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
#include <i386/linux/linux.h>
#include <i386/linux/linux_proto.h>
#include <compat/linux/linux_ipc.h>
#include <compat/linux/linux_misc.h>
#include <compat/linux/linux_signal.h>
#include <compat/linux/linux_util.h>
#include <compat/linux/linux_emul.h>
@ -1312,3 +1313,40 @@ linux_mq_getsetattr(struct thread *td, struct linux_mq_getsetattr_args *args)
#endif
}
int
linux_wait4(struct thread *td, struct linux_wait4_args *args)
{
int error, options;
struct rusage ru, *rup;
struct proc *p;
#ifdef DEBUG
if (ldebug(wait4))
printf(ARGS(wait4, "%d, %p, %d, %p"),
args->pid, (void *)args->status, args->options,
(void *)args->rusage);
#endif
options = (args->options & (WNOHANG | WUNTRACED));
/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
if (args->options & __WCLONE)
options |= WLINUXCLONE;
if (args->rusage != NULL)
rup = &ru;
else
rup = NULL;
error = linux_common_wait(td, args->pid, args->status, options, rup);
if (error)
return (error);
p = td->td_proc;
PROC_LOCK(p);
sigqueue_delete(&p->p_sigqueue, SIGCHLD);
PROC_UNLOCK(p);
if (args->rusage != NULL)
error = copyout(&ru, args->rusage, sizeof(ru));
return (error);
}