Commit 05a45599 authored by Neal Norwitz's avatar Neal Norwitz

Patch #1309579: wait3 and wait4 were added to the posix module by Chad J. Schroeder.

This was a fair amount of rework of the patch.  Refactored test_fork1 so it
could be reused by the new tests for wait3/4.  Also made them into new style
unittests (derive from unittest.TestCase).
parent 910b5eec
...@@ -1731,6 +1731,27 @@ The \function{spawn()} functions called with \constant{P_NOWAIT} ...@@ -1731,6 +1731,27 @@ The \function{spawn()} functions called with \constant{P_NOWAIT}
return suitable process handles. return suitable process handles.
\end{funcdesc} \end{funcdesc}
\begin{funcdesc}{wait3}{\{optional{options}}
Similar to \function{waitpid()}, except no process id argument is given and
a 3-element tuple containing the child's process id, exit status indication,
and resource usage information is returned. Refer to
\module{resource}.\function{getrusage()}
for details on resource usage information. The option argument is the same
as that provided to \function{waitpid()} and \function{wait4()}.
Availability: \UNIX.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{wait4}{pid, options}
Similar to \function{waitpid()}, except a 3-element tuple, containing the
child's process id, exit status indication, and resource usage information
is returned. Refer to \module{resource}.\function{getrusage()} for details
on resource usage information. The arguments to \function{wait4()} are
the same as those provided to \function{waitpid()}.
Availability: \UNIX.
\versionadded{2.5}
\end{funcdesc}
\begin{datadesc}{WNOHANG} \begin{datadesc}{WNOHANG}
The option for \function{waitpid()} to return immediately if no child The option for \function{waitpid()} to return immediately if no child
process status is available immediately. The function returns process status is available immediately. The function returns
......
"""This test case provides support for checking forking and wait behavior.
To test different wait behavior, overrise the wait_impl method.
We want fork1() semantics -- only the forking thread survives in the
child after a fork().
On some systems (e.g. Solaris without posix threads) we find that all
active threads survive in the child after a fork(); this is an error.
While BeOS doesn't officially support fork and native threading in
the same application, the present example should work just fine. DC
"""
import os, sys, time, thread, unittest
from test.test_support import TestSkipped
LONGSLEEP = 2
SHORTSLEEP = 0.5
NUM_THREADS = 4
class ForkWait(unittest.TestCase):
def setUp(self):
self.alive = {}
self.stop = 0
def f(self, id):
while not self.stop:
self.alive[id] = os.getpid()
try:
time.sleep(SHORTSLEEP)
except IOError:
pass
def wait_impl(self, cpid):
spid, status = os.waitpid(cpid, 0)
self.assertEquals(spid, cpid)
self.assertEquals(status, 0, "cause = %d, exit = %d" % (status&0xff, status>>8))
def test_wait(self):
for i in range(NUM_THREADS):
thread.start_new(self.f, (i,))
time.sleep(LONGSLEEP)
a = self.alive.keys()
a.sort()
self.assertEquals(a, range(NUM_THREADS))
prefork_lives = self.alive.copy()
if sys.platform in ['unixware7']:
cpid = os.fork1()
else:
cpid = os.fork()
if cpid == 0:
# Child
time.sleep(LONGSLEEP)
n = 0
for key in self.alive:
if self.alive[key] != prefork_lives[key]:
n += 1
os._exit(n)
else:
# Parent
self.wait_impl(cpid)
# Tell threads to die
self.stop = 1
time.sleep(2*SHORTSLEEP) # Wait for threads to die
"""This test checks for correct fork() behavior. """This test checks for correct fork() behavior.
We want fork1() semantics -- only the forking thread survives in the
child after a fork().
On some systems (e.g. Solaris without posix threads) we find that all
active threads survive in the child after a fork(); this is an error.
While BeOS doesn't officially support fork and native threading in
the same application, the present example should work just fine. DC
""" """
import os, sys, time, thread import os
from test.test_support import verify, verbose, TestSkipped from test.fork_wait import ForkWait
from test.test_support import TestSkipped, run_unittest
try: try:
os.fork os.fork
except AttributeError: except AttributeError:
raise TestSkipped, "os.fork not defined -- skipping test_fork1" raise TestSkipped, "os.fork not defined -- skipping test_fork1"
LONGSLEEP = 2 class ForkTest(ForkWait):
def wait_impl(self, cpid):
SHORTSLEEP = 0.5
NUM_THREADS = 4
alive = {}
stop = 0
def f(id):
while not stop:
alive[id] = os.getpid()
try:
time.sleep(SHORTSLEEP)
except IOError:
pass
def main():
for i in range(NUM_THREADS):
thread.start_new(f, (i,))
time.sleep(LONGSLEEP)
a = alive.keys()
a.sort()
verify(a == range(NUM_THREADS))
prefork_lives = alive.copy()
if sys.platform in ['unixware7']:
cpid = os.fork1()
else:
cpid = os.fork()
if cpid == 0:
# Child
time.sleep(LONGSLEEP)
n = 0
for key in alive.keys():
if alive[key] != prefork_lives[key]:
n = n+1
os._exit(n)
else:
# Parent
spid, status = os.waitpid(cpid, 0) spid, status = os.waitpid(cpid, 0)
verify(spid == cpid) self.assertEqual(spid, cpid)
verify(status == 0, self.assertEqual(status, 0, "cause = %d, exit = %d" % (status&0xff, status>>8))
"cause = %d, exit = %d" % (status&0xff, status>>8) )
global stop def test_main():
# Tell threads to die run_unittest(ForkTest)
stop = 1
time.sleep(2*SHORTSLEEP) # Wait for threads to die
main() if __name__ == "__main__":
test_main()
"""This test checks for correct wait3() behavior.
"""
import os
from test.fork_wait import ForkWait
from test.test_support import TestSkipped, run_unittest
try:
os.fork
except AttributeError:
raise TestSkipped, "os.fork not defined -- skipping test_wait3"
try:
os.wait3
except AttributeError:
raise TestSkipped, "os.wait3 not defined -- skipping test_wait3"
class Wait3Test(ForkWait):
def wait_impl(self, cpid):
while 1:
spid, status, rusage = os.wait3(0)
if spid == cpid:
break
self.assertEqual(spid, cpid)
self.assertEqual(status, 0, "cause = %d, exit = %d" % (status&0xff, status>>8))
self.assertTrue(rusage)
def test_main():
run_unittest(Wait3Test)
if __name__ == "__main__":
test_main()
"""This test checks for correct wait4() behavior.
"""
import os
from test.fork_wait import ForkWait
from test.test_support import TestSkipped, run_unittest
try:
os.fork
except AttributeError:
raise TestSkipped, "os.fork not defined -- skipping test_wait4"
try:
os.wait4
except AttributeError:
raise TestSkipped, "os.wait4 not defined -- skipping test_wait4"
class Wait4Test(ForkWait):
def wait_impl(self, cpid):
spid, status, rusage = os.wait4(cpid, 0)
self.assertEqual(spid, cpid)
self.assertEqual(status, 0, "cause = %d, exit = %d" % (status&0xff, status>>8))
self.assertTrue(rusage)
def test_main():
run_unittest(Wait4Test)
if __name__ == "__main__":
test_main()
...@@ -536,6 +536,7 @@ David Scherer ...@@ -536,6 +536,7 @@ David Scherer
Gregor Schmid Gregor Schmid
Ralf Schmitt Ralf Schmitt
Peter Schneider-Kamp Peter Schneider-Kamp
Chad J. Schroeder
Sam Schulenburg Sam Schulenburg
Stefan Schwarzer Stefan Schwarzer
Dietmar Schwertberger Dietmar Schwertberger
......
...@@ -295,6 +295,8 @@ Core and builtins ...@@ -295,6 +295,8 @@ Core and builtins
Extension Modules Extension Modules
----------------- -----------------
- Patch #1309579: wait3 and wait4 were added to the posix module.
- Patch #1231053: The audioop module now supports encoding/decoding of alaw. - Patch #1231053: The audioop module now supports encoding/decoding of alaw.
In addition, the existing ulaw code was updated. In addition, the existing ulaw code was updated.
......
...@@ -5091,6 +5091,128 @@ posix_setgroups(PyObject *self, PyObject *args) ...@@ -5091,6 +5091,128 @@ posix_setgroups(PyObject *self, PyObject *args)
} }
#endif /* HAVE_SETGROUPS */ #endif /* HAVE_SETGROUPS */
static PyObject *
wait_helper(int pid, int status, struct rusage *ru)
{
PyObject *result;
static PyObject *struct_rusage;
if (pid == -1)
return posix_error();
if (struct_rusage == NULL) {
PyObject *m = PyImport_ImportModule("resource");
if (m == NULL)
return NULL;
struct_rusage = PyObject_GetAttrString(m, "struct_rusage");
Py_DECREF(m);
if (struct_rusage == NULL)
return NULL;
}
/* XXX(nnorwitz): Copied (w/mods) from resource.c, there should be only one. */
result = PyStructSequence_New((PyTypeObject*) struct_rusage);
if (!result)
return NULL;
#ifndef doubletime
#define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001)
#endif
PyStructSequence_SET_ITEM(result, 0,
PyFloat_FromDouble(doubletime(ru->ru_utime)));
PyStructSequence_SET_ITEM(result, 1,
PyFloat_FromDouble(doubletime(ru->ru_stime)));
#define SET_INT(result, index, value)\
PyStructSequence_SET_ITEM(result, index, PyInt_FromLong(value))
SET_INT(result, 2, ru->ru_maxrss);
SET_INT(result, 3, ru->ru_ixrss);
SET_INT(result, 4, ru->ru_idrss);
SET_INT(result, 5, ru->ru_isrss);
SET_INT(result, 6, ru->ru_minflt);
SET_INT(result, 7, ru->ru_majflt);
SET_INT(result, 8, ru->ru_nswap);
SET_INT(result, 9, ru->ru_inblock);
SET_INT(result, 10, ru->ru_oublock);
SET_INT(result, 11, ru->ru_msgsnd);
SET_INT(result, 12, ru->ru_msgrcv);
SET_INT(result, 13, ru->ru_nsignals);
SET_INT(result, 14, ru->ru_nvcsw);
SET_INT(result, 15, ru->ru_nivcsw);
#undef SET_INT
if (PyErr_Occurred()) {
Py_DECREF(result);
return NULL;
}
return Py_BuildValue("iiO", pid, status, result);
}
#ifdef HAVE_WAIT3
PyDoc_STRVAR(posix_wait3__doc__,
"wait3(options) -> (pid, status, rusage)\n\n\
Wait for completion of a child process.");
static PyObject *
posix_wait3(PyObject *self, PyObject *args)
{
int pid, options;
struct rusage ru;
#ifdef UNION_WAIT
union wait status;
#define status_i (status.w_status)
#else
int status;
#define status_i status
#endif
status_i = 0;
if (!PyArg_ParseTuple(args, "i:wait3", &options))
return NULL;
Py_BEGIN_ALLOW_THREADS
pid = wait3(&status, options, &ru);
Py_END_ALLOW_THREADS
return wait_helper(pid, status_i, &ru);
#undef status_i
}
#endif /* HAVE_WAIT3 */
#ifdef HAVE_WAIT4
PyDoc_STRVAR(posix_wait4__doc__,
"wait4(pid, options) -> (pid, status, rusage)\n\n\
Wait for completion of a given child process.");
static PyObject *
posix_wait4(PyObject *self, PyObject *args)
{
int pid, options;
struct rusage ru;
#ifdef UNION_WAIT
union wait status;
#define status_i (status.w_status)
#else
int status;
#define status_i status
#endif
status_i = 0;
if (!PyArg_ParseTuple(args, "ii:wait4", &pid, &options))
return NULL;
Py_BEGIN_ALLOW_THREADS
pid = wait4(pid, &status, options, &ru);
Py_END_ALLOW_THREADS
return wait_helper(pid, status_i, &ru);
#undef status_i
}
#endif /* HAVE_WAIT4 */
#ifdef HAVE_WAITPID #ifdef HAVE_WAITPID
PyDoc_STRVAR(posix_waitpid__doc__, PyDoc_STRVAR(posix_waitpid__doc__,
"waitpid(pid, options) -> (pid, status)\n\n\ "waitpid(pid, options) -> (pid, status)\n\n\
...@@ -7696,6 +7818,12 @@ static PyMethodDef posix_methods[] = { ...@@ -7696,6 +7818,12 @@ static PyMethodDef posix_methods[] = {
#ifdef HAVE_WAIT #ifdef HAVE_WAIT
{"wait", posix_wait, METH_NOARGS, posix_wait__doc__}, {"wait", posix_wait, METH_NOARGS, posix_wait__doc__},
#endif /* HAVE_WAIT */ #endif /* HAVE_WAIT */
#ifdef HAVE_WAIT3
{"wait3", posix_wait3, METH_VARARGS, posix_wait3__doc__},
#endif /* HAVE_WAIT3 */
#ifdef HAVE_WAIT4
{"wait4", posix_wait4, METH_VARARGS, posix_wait4__doc__},
#endif /* HAVE_WAIT4 */
#if defined(HAVE_WAITPID) || defined(HAVE_CWAIT) #if defined(HAVE_WAITPID) || defined(HAVE_CWAIT)
{"waitpid", posix_waitpid, METH_VARARGS, posix_waitpid__doc__}, {"waitpid", posix_waitpid, METH_VARARGS, posix_waitpid__doc__},
#endif /* HAVE_WAITPID */ #endif /* HAVE_WAITPID */
......
#! /bin/sh #! /bin/sh
# From configure.in Revision: 42437 . # From configure.in Revision: 42563 .
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59 for python 2.5. # Generated by GNU Autoconf 2.59 for python 2.5.
# #
...@@ -14083,6 +14083,8 @@ echo "${ECHO_T}MACHDEP_OBJS" >&6 ...@@ -14083,6 +14083,8 @@ echo "${ECHO_T}MACHDEP_OBJS" >&6
...@@ -14097,7 +14099,7 @@ for ac_func in alarm bind_textdomain_codeset chown clock confstr ctermid \ ...@@ -14097,7 +14099,7 @@ for ac_func in alarm bind_textdomain_codeset chown clock confstr ctermid \
setlocale setregid setreuid setsid setpgid setpgrp setuid setvbuf snprintf \ setlocale setregid setreuid setsid setpgid setpgrp setuid setvbuf snprintf \
sigaction siginterrupt sigrelse strftime \ sigaction siginterrupt sigrelse strftime \
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
truncate uname unsetenv utimes waitpid wcscoll _getpty truncate uname unsetenv utimes waitpid wait3 wait4 wcscoll _getpty
do do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
echo "$as_me:$LINENO: checking for $ac_func" >&5 echo "$as_me:$LINENO: checking for $ac_func" >&5
......
...@@ -2148,7 +2148,7 @@ AC_CHECK_FUNCS(alarm bind_textdomain_codeset chown clock confstr ctermid \ ...@@ -2148,7 +2148,7 @@ AC_CHECK_FUNCS(alarm bind_textdomain_codeset chown clock confstr ctermid \
setlocale setregid setreuid setsid setpgid setpgrp setuid setvbuf snprintf \ setlocale setregid setreuid setsid setpgid setpgrp setuid setvbuf snprintf \
sigaction siginterrupt sigrelse strftime \ sigaction siginterrupt sigrelse strftime \
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
truncate uname unsetenv utimes waitpid wcscoll _getpty) truncate uname unsetenv utimes waitpid wait3 wait4 wcscoll _getpty)
# For some functions, having a definition is not sufficient, since # For some functions, having a definition is not sufficient, since
# we want to take their address. # we want to take their address.
......
...@@ -670,6 +670,12 @@ ...@@ -670,6 +670,12 @@
/* Define to 1 if you have the <utime.h> header file. */ /* Define to 1 if you have the <utime.h> header file. */
#undef HAVE_UTIME_H #undef HAVE_UTIME_H
/* Define to 1 if you have the `wait3' function. */
#undef HAVE_WAIT3
/* Define to 1 if you have the `wait4' function. */
#undef HAVE_WAIT4
/* Define to 1 if you have the `waitpid' function. */ /* Define to 1 if you have the `waitpid' function. */
#undef HAVE_WAITPID #undef HAVE_WAITPID
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment