Python-checkins
Threads by month
- ----- 2025 -----
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
August 2006
- 23 participants
- 662 discussions
Aug. 21, 2006
Author: neal.norwitz
Date: Mon Aug 21 20:20:10 2006
New Revision: 51434
Modified:
python/trunk/Modules/mmapmodule.c
python/trunk/Objects/fileobject.c
Log:
Fix a couple of ssize-t issues reported by Alexander Belopolsky on python-dev
Modified: python/trunk/Modules/mmapmodule.c
==============================================================================
--- python/trunk/Modules/mmapmodule.c (original)
+++ python/trunk/Modules/mmapmodule.c Mon Aug 21 20:20:10 2006
@@ -470,7 +470,7 @@
mmap_tell_method(mmap_object *self, PyObject *unused)
{
CHECK_VALID(NULL);
- return PyInt_FromLong((long) self->pos);
+ return PyInt_FromSsize_t(self->pos);
}
static PyObject *
Modified: python/trunk/Objects/fileobject.c
==============================================================================
--- python/trunk/Objects/fileobject.c (original)
+++ python/trunk/Objects/fileobject.c Mon Aug 21 20:20:10 2006
@@ -922,7 +922,7 @@
ndone += nnow;
ntodo -= nnow;
}
- return PyInt_FromLong((long)ndone);
+ return PyInt_FromSsize_t(ndone);
}
/**************************************************************************
1
0
Author: neal.norwitz
Date: Mon Aug 21 20:01:30 2006
New Revision: 51433
Modified:
python/trunk/Python/compile.c
Log:
Add assert to make Klocwork happy (#276)
Modified: python/trunk/Python/compile.c
==============================================================================
--- python/trunk/Python/compile.c (original)
+++ python/trunk/Python/compile.c Mon Aug 21 20:01:30 2006
@@ -568,6 +568,7 @@
if (n >= 0) {
wrapper = PyList_GET_ITEM(c->c_stack, n);
c->u = (struct compiler_unit *)PyCObject_AsVoidPtr(wrapper);
+ assert(c->u);
/* we are deleting from a list so this really shouldn't fail */
if (PySequence_DelItem(c->c_stack, n) < 0)
Py_FatalError("compiler_exit_scope()");
1
0
Aug. 21, 2006
Author: neal.norwitz
Date: Mon Aug 21 19:59:46 2006
New Revision: 51432
Modified:
python/trunk/Lib/tarfile.py
python/trunk/Lib/test/test_tarfile.py
Log:
Fix bug #1543303, tarfile adds padding that breaks gunzip.
Patch # 1543897.
Will backport to 2.5
Modified: python/trunk/Lib/tarfile.py
==============================================================================
--- python/trunk/Lib/tarfile.py (original)
+++ python/trunk/Lib/tarfile.py Mon Aug 21 19:59:46 2006
@@ -411,9 +411,6 @@
self.buf += self.cmp.flush()
if self.mode == "w" and self.buf:
- blocks, remainder = divmod(len(self.buf), self.bufsize)
- if remainder > 0:
- self.buf += NUL * (self.bufsize - remainder)
self.fileobj.write(self.buf)
self.buf = ""
if self.comptype == "gz":
Modified: python/trunk/Lib/test/test_tarfile.py
==============================================================================
--- python/trunk/Lib/test/test_tarfile.py (original)
+++ python/trunk/Lib/test/test_tarfile.py Mon Aug 21 19:59:46 2006
@@ -324,6 +324,27 @@
class WriteStreamTest(WriteTest):
sep = '|'
+ def test_padding(self):
+ self.dst.close()
+
+ if self.comp == "gz":
+ f = gzip.GzipFile(self.dstname)
+ s = f.read()
+ f.close()
+ elif self.comp == "bz2":
+ f = bz2.BZ2Decompressor()
+ s = file(self.dstname).read()
+ s = f.decompress(s)
+ self.assertEqual(len(f.unused_data), 0, "trailing data")
+ else:
+ f = file(self.dstname)
+ s = f.read()
+ f.close()
+
+ self.assertEqual(s.count("\0"), tarfile.RECORDSIZE,
+ "incorrect zero padding")
+
+
class WriteGNULongTest(unittest.TestCase):
"""This testcase checks for correct creation of GNU Longname
and Longlink extensions.
1
0
The Buildbot has detected a new failure of x86 XP-2 trunk.
Full details are available at:
http://www.python.org/dev/buildbot/all/x86%2520XP-2%2520trunk/builds/892
Buildbot URL: http://www.python.org/dev/buildbot/all/
Build Reason:
Build Source Stamp: [branch trunk] HEAD
Blamelist: jeremy.hylton
BUILD FAILED: failed compile
sincerely,
-The Buildbot
1
0
The Buildbot has detected a new failure of alpha Tru64 5.1 trunk.
Full details are available at:
http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%2520trunk/bu…
Buildbot URL: http://www.python.org/dev/buildbot/all/
Build Reason:
Build Source Stamp: [branch trunk] HEAD
Blamelist: jeremy.hylton
Build Had Warnings: warnings test
sincerely,
-The Buildbot
1
0
The Buildbot has detected a new failure of hppa Ubuntu dapper trunk.
Full details are available at:
http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk…
Buildbot URL: http://www.python.org/dev/buildbot/all/
Build Reason:
Build Source Stamp: [branch trunk] HEAD
Blamelist: jeremy.hylton
Build Had Warnings: warnings test
sincerely,
-The Buildbot
1
0
Author: jeremy.hylton
Date: Mon Aug 21 18:20:29 2006
New Revision: 51429
Modified:
python/trunk/Include/code.h
Log:
Move peephole optimizer to separate file. (Forgot .h in previous checkin.)
Modified: python/trunk/Include/code.h
==============================================================================
--- python/trunk/Include/code.h (original)
+++ python/trunk/Include/code.h Mon Aug 21 18:20:29 2006
@@ -88,6 +88,9 @@
PyAPI_FUNC(int) PyCode_CheckLineNumber(PyCodeObject* co,
int lasti, PyAddrPair *bounds);
+PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts,
+ PyObject *names, PyObject *lineno_obj);
+
#ifdef __cplusplus
}
#endif
1
0
r51428 - in python/trunk: Makefile.pre.in Python/compile.c Python/peephole.c
by jeremy.hylton Aug. 21, 2006
by jeremy.hylton Aug. 21, 2006
Aug. 21, 2006
Author: jeremy.hylton
Date: Mon Aug 21 18:19:37 2006
New Revision: 51428
Added:
python/trunk/Python/peephole.c
Modified:
python/trunk/Makefile.pre.in
python/trunk/Python/compile.c
Log:
Move peephole optimizer to separate file.
Modified: python/trunk/Makefile.pre.in
==============================================================================
--- python/trunk/Makefile.pre.in (original)
+++ python/trunk/Makefile.pre.in Mon Aug 21 18:19:37 2006
@@ -260,6 +260,7 @@
Python/modsupport.o \
Python/mystrtoul.o \
Python/mysnprintf.o \
+ Python/peephole.o \
Python/pyarena.o \
Python/pyfpe.o \
Python/pystate.o \
Modified: python/trunk/Python/compile.c
==============================================================================
--- python/trunk/Python/compile.c (original)
+++ python/trunk/Python/compile.c Mon Aug 21 18:19:37 2006
@@ -394,613 +394,6 @@
return dest;
}
-/* Begin: Peephole optimizations ----------------------------------------- */
-
-#define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1]))
-#define UNCONDITIONAL_JUMP(op) (op==JUMP_ABSOLUTE || op==JUMP_FORWARD)
-#define ABSOLUTE_JUMP(op) (op==JUMP_ABSOLUTE || op==CONTINUE_LOOP)
-#define GETJUMPTGT(arr, i) (GETARG(arr,i) + (ABSOLUTE_JUMP(arr[i]) ? 0 : i+3))
-#define SETARG(arr, i, val) arr[i+2] = val>>8; arr[i+1] = val & 255
-#define CODESIZE(op) (HAS_ARG(op) ? 3 : 1)
-#define ISBASICBLOCK(blocks, start, bytes) \
- (blocks[start]==blocks[start+bytes-1])
-
-/* Replace LOAD_CONST c1. LOAD_CONST c2 ... LOAD_CONST cn BUILD_TUPLE n
- with LOAD_CONST (c1, c2, ... cn).
- The consts table must still be in list form so that the
- new constant (c1, c2, ... cn) can be appended.
- Called with codestr pointing to the first LOAD_CONST.
- Bails out with no change if one or more of the LOAD_CONSTs is missing.
- Also works for BUILD_LIST when followed by an "in" or "not in" test.
-*/
-static int
-tuple_of_constants(unsigned char *codestr, int n, PyObject *consts)
-{
- PyObject *newconst, *constant;
- Py_ssize_t i, arg, len_consts;
-
- /* Pre-conditions */
- assert(PyList_CheckExact(consts));
- assert(codestr[n*3] == BUILD_TUPLE || codestr[n*3] == BUILD_LIST);
- assert(GETARG(codestr, (n*3)) == n);
- for (i=0 ; i<n ; i++)
- assert(codestr[i*3] == LOAD_CONST);
-
- /* Buildup new tuple of constants */
- newconst = PyTuple_New(n);
- if (newconst == NULL)
- return 0;
- len_consts = PyList_GET_SIZE(consts);
- for (i=0 ; i<n ; i++) {
- arg = GETARG(codestr, (i*3));
- assert(arg < len_consts);
- constant = PyList_GET_ITEM(consts, arg);
- Py_INCREF(constant);
- PyTuple_SET_ITEM(newconst, i, constant);
- }
-
- /* Append folded constant onto consts */
- if (PyList_Append(consts, newconst)) {
- Py_DECREF(newconst);
- return 0;
- }
- Py_DECREF(newconst);
-
- /* Write NOPs over old LOAD_CONSTS and
- add a new LOAD_CONST newconst on top of the BUILD_TUPLE n */
- memset(codestr, NOP, n*3);
- codestr[n*3] = LOAD_CONST;
- SETARG(codestr, (n*3), len_consts);
- return 1;
-}
-
-/* Replace LOAD_CONST c1. LOAD_CONST c2 BINOP
- with LOAD_CONST binop(c1,c2)
- The consts table must still be in list form so that the
- new constant can be appended.
- Called with codestr pointing to the first LOAD_CONST.
- Abandons the transformation if the folding fails (i.e. 1+'a').
- If the new constant is a sequence, only folds when the size
- is below a threshold value. That keeps pyc files from
- becoming large in the presence of code like: (None,)*1000.
-*/
-static int
-fold_binops_on_constants(unsigned char *codestr, PyObject *consts)
-{
- PyObject *newconst, *v, *w;
- Py_ssize_t len_consts, size;
- int opcode;
-
- /* Pre-conditions */
- assert(PyList_CheckExact(consts));
- assert(codestr[0] == LOAD_CONST);
- assert(codestr[3] == LOAD_CONST);
-
- /* Create new constant */
- v = PyList_GET_ITEM(consts, GETARG(codestr, 0));
- w = PyList_GET_ITEM(consts, GETARG(codestr, 3));
- opcode = codestr[6];
- switch (opcode) {
- case BINARY_POWER:
- newconst = PyNumber_Power(v, w, Py_None);
- break;
- case BINARY_MULTIPLY:
- newconst = PyNumber_Multiply(v, w);
- break;
- case BINARY_DIVIDE:
- /* Cannot fold this operation statically since
- the result can depend on the run-time presence
- of the -Qnew flag */
- return 0;
- case BINARY_TRUE_DIVIDE:
- newconst = PyNumber_TrueDivide(v, w);
- break;
- case BINARY_FLOOR_DIVIDE:
- newconst = PyNumber_FloorDivide(v, w);
- break;
- case BINARY_MODULO:
- newconst = PyNumber_Remainder(v, w);
- break;
- case BINARY_ADD:
- newconst = PyNumber_Add(v, w);
- break;
- case BINARY_SUBTRACT:
- newconst = PyNumber_Subtract(v, w);
- break;
- case BINARY_SUBSCR:
- newconst = PyObject_GetItem(v, w);
- break;
- case BINARY_LSHIFT:
- newconst = PyNumber_Lshift(v, w);
- break;
- case BINARY_RSHIFT:
- newconst = PyNumber_Rshift(v, w);
- break;
- case BINARY_AND:
- newconst = PyNumber_And(v, w);
- break;
- case BINARY_XOR:
- newconst = PyNumber_Xor(v, w);
- break;
- case BINARY_OR:
- newconst = PyNumber_Or(v, w);
- break;
- default:
- /* Called with an unknown opcode */
- PyErr_Format(PyExc_SystemError,
- "unexpected binary operation %d on a constant",
- opcode);
- return 0;
- }
- if (newconst == NULL) {
- PyErr_Clear();
- return 0;
- }
- size = PyObject_Size(newconst);
- if (size == -1)
- PyErr_Clear();
- else if (size > 20) {
- Py_DECREF(newconst);
- return 0;
- }
-
- /* Append folded constant into consts table */
- len_consts = PyList_GET_SIZE(consts);
- if (PyList_Append(consts, newconst)) {
- Py_DECREF(newconst);
- return 0;
- }
- Py_DECREF(newconst);
-
- /* Write NOP NOP NOP NOP LOAD_CONST newconst */
- memset(codestr, NOP, 4);
- codestr[4] = LOAD_CONST;
- SETARG(codestr, 4, len_consts);
- return 1;
-}
-
-static int
-fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts)
-{
- PyObject *newconst=NULL, *v;
- Py_ssize_t len_consts;
- int opcode;
-
- /* Pre-conditions */
- assert(PyList_CheckExact(consts));
- assert(codestr[0] == LOAD_CONST);
-
- /* Create new constant */
- v = PyList_GET_ITEM(consts, GETARG(codestr, 0));
- opcode = codestr[3];
- switch (opcode) {
- case UNARY_NEGATIVE:
- /* Preserve the sign of -0.0 */
- if (PyObject_IsTrue(v) == 1)
- newconst = PyNumber_Negative(v);
- break;
- case UNARY_CONVERT:
- newconst = PyObject_Repr(v);
- break;
- case UNARY_INVERT:
- newconst = PyNumber_Invert(v);
- break;
- default:
- /* Called with an unknown opcode */
- PyErr_Format(PyExc_SystemError,
- "unexpected unary operation %d on a constant",
- opcode);
- return 0;
- }
- if (newconst == NULL) {
- PyErr_Clear();
- return 0;
- }
-
- /* Append folded constant into consts table */
- len_consts = PyList_GET_SIZE(consts);
- if (PyList_Append(consts, newconst)) {
- Py_DECREF(newconst);
- return 0;
- }
- Py_DECREF(newconst);
-
- /* Write NOP LOAD_CONST newconst */
- codestr[0] = NOP;
- codestr[1] = LOAD_CONST;
- SETARG(codestr, 1, len_consts);
- return 1;
-}
-
-static unsigned int *
-markblocks(unsigned char *code, int len)
-{
- unsigned int *blocks = (unsigned int *)PyMem_Malloc(len*sizeof(int));
- int i,j, opcode, blockcnt = 0;
-
- if (blocks == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
- memset(blocks, 0, len*sizeof(int));
-
- /* Mark labels in the first pass */
- for (i=0 ; i<len ; i+=CODESIZE(opcode)) {
- opcode = code[i];
- switch (opcode) {
- case FOR_ITER:
- case JUMP_FORWARD:
- case JUMP_IF_FALSE:
- case JUMP_IF_TRUE:
- case JUMP_ABSOLUTE:
- case CONTINUE_LOOP:
- case SETUP_LOOP:
- case SETUP_EXCEPT:
- case SETUP_FINALLY:
- j = GETJUMPTGT(code, i);
- blocks[j] = 1;
- break;
- }
- }
- /* Build block numbers in the second pass */
- for (i=0 ; i<len ; i++) {
- blockcnt += blocks[i]; /* increment blockcnt over labels */
- blocks[i] = blockcnt;
- }
- return blocks;
-}
-
-/* Perform basic peephole optimizations to components of a code object.
- The consts object should still be in list form to allow new constants
- to be appended.
-
- To keep the optimizer simple, it bails out (does nothing) for code
- containing extended arguments or that has a length over 32,700. That
- allows us to avoid overflow and sign issues. Likewise, it bails when
- the lineno table has complex encoding for gaps >= 255.
-
- Optimizations are restricted to simple transformations occuring within a
- single basic block. All transformations keep the code size the same or
- smaller. For those that reduce size, the gaps are initially filled with
- NOPs. Later those NOPs are removed and the jump addresses retargeted in
- a single pass. Line numbering is adjusted accordingly. */
-
-static PyObject *
-optimize_code(PyObject *code, PyObject* consts, PyObject *names,
- PyObject *lineno_obj)
-{
- Py_ssize_t i, j, codelen;
- int nops, h, adj;
- int tgt, tgttgt, opcode;
- unsigned char *codestr = NULL;
- unsigned char *lineno;
- int *addrmap = NULL;
- int new_line, cum_orig_line, last_line, tabsiz;
- int cumlc=0, lastlc=0; /* Count runs of consecutive LOAD_CONSTs */
- unsigned int *blocks = NULL;
- char *name;
-
- /* Bail out if an exception is set */
- if (PyErr_Occurred())
- goto exitUnchanged;
-
- /* Bypass optimization when the lineno table is too complex */
- assert(PyString_Check(lineno_obj));
- lineno = (unsigned char*)PyString_AS_STRING(lineno_obj);
- tabsiz = PyString_GET_SIZE(lineno_obj);
- if (memchr(lineno, 255, tabsiz) != NULL)
- goto exitUnchanged;
-
- /* Avoid situations where jump retargeting could overflow */
- assert(PyString_Check(code));
- codelen = PyString_Size(code);
- if (codelen > 32700)
- goto exitUnchanged;
-
- /* Make a modifiable copy of the code string */
- codestr = (unsigned char *)PyMem_Malloc(codelen);
- if (codestr == NULL)
- goto exitUnchanged;
- codestr = (unsigned char *)memcpy(codestr,
- PyString_AS_STRING(code), codelen);
-
- /* Verify that RETURN_VALUE terminates the codestring. This allows
- the various transformation patterns to look ahead several
- instructions without additional checks to make sure they are not
- looking beyond the end of the code string.
- */
- if (codestr[codelen-1] != RETURN_VALUE)
- goto exitUnchanged;
-
- /* Mapping to new jump targets after NOPs are removed */
- addrmap = (int *)PyMem_Malloc(codelen * sizeof(int));
- if (addrmap == NULL)
- goto exitUnchanged;
-
- blocks = markblocks(codestr, codelen);
- if (blocks == NULL)
- goto exitUnchanged;
- assert(PyList_Check(consts));
-
- for (i=0 ; i<codelen ; i += CODESIZE(codestr[i])) {
- opcode = codestr[i];
-
- lastlc = cumlc;
- cumlc = 0;
-
- switch (opcode) {
-
- /* Replace UNARY_NOT JUMP_IF_FALSE POP_TOP with
- with JUMP_IF_TRUE POP_TOP */
- case UNARY_NOT:
- if (codestr[i+1] != JUMP_IF_FALSE ||
- codestr[i+4] != POP_TOP ||
- !ISBASICBLOCK(blocks,i,5))
- continue;
- tgt = GETJUMPTGT(codestr, (i+1));
- if (codestr[tgt] != POP_TOP)
- continue;
- j = GETARG(codestr, i+1) + 1;
- codestr[i] = JUMP_IF_TRUE;
- SETARG(codestr, i, j);
- codestr[i+3] = POP_TOP;
- codestr[i+4] = NOP;
- break;
-
- /* not a is b --> a is not b
- not a in b --> a not in b
- not a is not b --> a is b
- not a not in b --> a in b
- */
- case COMPARE_OP:
- j = GETARG(codestr, i);
- if (j < 6 || j > 9 ||
- codestr[i+3] != UNARY_NOT ||
- !ISBASICBLOCK(blocks,i,4))
- continue;
- SETARG(codestr, i, (j^1));
- codestr[i+3] = NOP;
- break;
-
- /* Replace LOAD_GLOBAL/LOAD_NAME None
- with LOAD_CONST None */
- case LOAD_NAME:
- case LOAD_GLOBAL:
- j = GETARG(codestr, i);
- name = PyString_AsString(PyTuple_GET_ITEM(names, j));
- if (name == NULL || strcmp(name, "None") != 0)
- continue;
- for (j=0 ; j < PyList_GET_SIZE(consts) ; j++) {
- if (PyList_GET_ITEM(consts, j) == Py_None) {
- codestr[i] = LOAD_CONST;
- SETARG(codestr, i, j);
- cumlc = lastlc + 1;
- break;
- }
- }
- break;
-
- /* Skip over LOAD_CONST trueconst
- JUMP_IF_FALSE xx POP_TOP */
- case LOAD_CONST:
- cumlc = lastlc + 1;
- j = GETARG(codestr, i);
- if (codestr[i+3] != JUMP_IF_FALSE ||
- codestr[i+6] != POP_TOP ||
- !ISBASICBLOCK(blocks,i,7) ||
- !PyObject_IsTrue(PyList_GET_ITEM(consts, j)))
- continue;
- memset(codestr+i, NOP, 7);
- cumlc = 0;
- break;
-
- /* Try to fold tuples of constants (includes a case for lists
- which are only used for "in" and "not in" tests).
- Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
- Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
- Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
- case BUILD_TUPLE:
- case BUILD_LIST:
- j = GETARG(codestr, i);
- h = i - 3 * j;
- if (h >= 0 &&
- j <= lastlc &&
- ((opcode == BUILD_TUPLE &&
- ISBASICBLOCK(blocks, h, 3*(j+1))) ||
- (opcode == BUILD_LIST &&
- codestr[i+3]==COMPARE_OP &&
- ISBASICBLOCK(blocks, h, 3*(j+2)) &&
- (GETARG(codestr,i+3)==6 ||
- GETARG(codestr,i+3)==7))) &&
- tuple_of_constants(&codestr[h], j, consts)) {
- assert(codestr[i] == LOAD_CONST);
- cumlc = 1;
- break;
- }
- if (codestr[i+3] != UNPACK_SEQUENCE ||
- !ISBASICBLOCK(blocks,i,6) ||
- j != GETARG(codestr, i+3))
- continue;
- if (j == 1) {
- memset(codestr+i, NOP, 6);
- } else if (j == 2) {
- codestr[i] = ROT_TWO;
- memset(codestr+i+1, NOP, 5);
- } else if (j == 3) {
- codestr[i] = ROT_THREE;
- codestr[i+1] = ROT_TWO;
- memset(codestr+i+2, NOP, 4);
- }
- break;
-
- /* Fold binary ops on constants.
- LOAD_CONST c1 LOAD_CONST c2 BINOP --> LOAD_CONST binop(c1,c2) */
- case BINARY_POWER:
- case BINARY_MULTIPLY:
- case BINARY_TRUE_DIVIDE:
- case BINARY_FLOOR_DIVIDE:
- case BINARY_MODULO:
- case BINARY_ADD:
- case BINARY_SUBTRACT:
- case BINARY_SUBSCR:
- case BINARY_LSHIFT:
- case BINARY_RSHIFT:
- case BINARY_AND:
- case BINARY_XOR:
- case BINARY_OR:
- if (lastlc >= 2 &&
- ISBASICBLOCK(blocks, i-6, 7) &&
- fold_binops_on_constants(&codestr[i-6], consts)) {
- i -= 2;
- assert(codestr[i] == LOAD_CONST);
- cumlc = 1;
- }
- break;
-
- /* Fold unary ops on constants.
- LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */
- case UNARY_NEGATIVE:
- case UNARY_CONVERT:
- case UNARY_INVERT:
- if (lastlc >= 1 &&
- ISBASICBLOCK(blocks, i-3, 4) &&
- fold_unaryops_on_constants(&codestr[i-3], consts)) {
- i -= 2;
- assert(codestr[i] == LOAD_CONST);
- cumlc = 1;
- }
- break;
-
- /* Simplify conditional jump to conditional jump where the
- result of the first test implies the success of a similar
- test or the failure of the opposite test.
- Arises in code like:
- "if a and b:"
- "if a or b:"
- "a and b or c"
- "(a and b) and c"
- x:JUMP_IF_FALSE y y:JUMP_IF_FALSE z --> x:JUMP_IF_FALSE z
- x:JUMP_IF_FALSE y y:JUMP_IF_TRUE z --> x:JUMP_IF_FALSE y+3
- where y+3 is the instruction following the second test.
- */
- case JUMP_IF_FALSE:
- case JUMP_IF_TRUE:
- tgt = GETJUMPTGT(codestr, i);
- j = codestr[tgt];
- if (j == JUMP_IF_FALSE || j == JUMP_IF_TRUE) {
- if (j == opcode) {
- tgttgt = GETJUMPTGT(codestr, tgt) - i - 3;
- SETARG(codestr, i, tgttgt);
- } else {
- tgt -= i;
- SETARG(codestr, i, tgt);
- }
- break;
- }
- /* Intentional fallthrough */
-
- /* Replace jumps to unconditional jumps */
- case FOR_ITER:
- case JUMP_FORWARD:
- case JUMP_ABSOLUTE:
- case CONTINUE_LOOP:
- case SETUP_LOOP:
- case SETUP_EXCEPT:
- case SETUP_FINALLY:
- tgt = GETJUMPTGT(codestr, i);
- if (!UNCONDITIONAL_JUMP(codestr[tgt]))
- continue;
- tgttgt = GETJUMPTGT(codestr, tgt);
- if (opcode == JUMP_FORWARD) /* JMP_ABS can go backwards */
- opcode = JUMP_ABSOLUTE;
- if (!ABSOLUTE_JUMP(opcode))
- tgttgt -= i + 3; /* Calc relative jump addr */
- if (tgttgt < 0) /* No backward relative jumps */
- continue;
- codestr[i] = opcode;
- SETARG(codestr, i, tgttgt);
- break;
-
- case EXTENDED_ARG:
- goto exitUnchanged;
-
- /* Replace RETURN LOAD_CONST None RETURN with just RETURN */
- case RETURN_VALUE:
- if (i+4 >= codelen ||
- codestr[i+4] != RETURN_VALUE ||
- !ISBASICBLOCK(blocks,i,5))
- continue;
- memset(codestr+i+1, NOP, 4);
- break;
- }
- }
-
- /* Fixup linenotab */
- for (i=0, nops=0 ; i<codelen ; i += CODESIZE(codestr[i])) {
- addrmap[i] = i - nops;
- if (codestr[i] == NOP)
- nops++;
- }
- cum_orig_line = 0;
- last_line = 0;
- for (i=0 ; i < tabsiz ; i+=2) {
- cum_orig_line += lineno[i];
- new_line = addrmap[cum_orig_line];
- assert (new_line - last_line < 255);
- lineno[i] =((unsigned char)(new_line - last_line));
- last_line = new_line;
- }
-
- /* Remove NOPs and fixup jump targets */
- for (i=0, h=0 ; i<codelen ; ) {
- opcode = codestr[i];
- switch (opcode) {
- case NOP:
- i++;
- continue;
-
- case JUMP_ABSOLUTE:
- case CONTINUE_LOOP:
- j = addrmap[GETARG(codestr, i)];
- SETARG(codestr, i, j);
- break;
-
- case FOR_ITER:
- case JUMP_FORWARD:
- case JUMP_IF_FALSE:
- case JUMP_IF_TRUE:
- case SETUP_LOOP:
- case SETUP_EXCEPT:
- case SETUP_FINALLY:
- j = addrmap[GETARG(codestr, i) + i + 3] - addrmap[i] - 3;
- SETARG(codestr, i, j);
- break;
- }
- adj = CODESIZE(opcode);
- while (adj--)
- codestr[h++] = codestr[i++];
- }
- assert(h + nops == codelen);
-
- code = PyString_FromStringAndSize((char *)codestr, h);
- PyMem_Free(addrmap);
- PyMem_Free(codestr);
- PyMem_Free(blocks);
- return code;
-
- exitUnchanged:
- if (blocks != NULL)
- PyMem_Free(blocks);
- if (addrmap != NULL)
- PyMem_Free(addrmap);
- if (codestr != NULL)
- PyMem_Free(codestr);
- Py_INCREF(code);
- return code;
-}
-
-/* End: Peephole optimizations ----------------------------------------- */
-
/*
Leave this debugging code for just a little longer.
@@ -4422,7 +3815,7 @@
if (flags < 0)
goto error;
- bytecode = optimize_code(a->a_bytecode, consts, names, a->a_lnotab);
+ bytecode = PyCode_Optimize(a->a_bytecode, consts, names, a->a_lnotab);
if (!bytecode)
goto error;
Added: python/trunk/Python/peephole.c
==============================================================================
--- (empty file)
+++ python/trunk/Python/peephole.c Mon Aug 21 18:19:37 2006
@@ -0,0 +1,615 @@
+/* Peehole optimizations for bytecode compiler. */
+
+#include "Python.h"
+
+#include "Python-ast.h"
+#include "node.h"
+#include "pyarena.h"
+#include "ast.h"
+#include "code.h"
+#include "compile.h"
+#include "symtable.h"
+#include "opcode.h"
+
+#define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1]))
+#define UNCONDITIONAL_JUMP(op) (op==JUMP_ABSOLUTE || op==JUMP_FORWARD)
+#define ABSOLUTE_JUMP(op) (op==JUMP_ABSOLUTE || op==CONTINUE_LOOP)
+#define GETJUMPTGT(arr, i) (GETARG(arr,i) + (ABSOLUTE_JUMP(arr[i]) ? 0 : i+3))
+#define SETARG(arr, i, val) arr[i+2] = val>>8; arr[i+1] = val & 255
+#define CODESIZE(op) (HAS_ARG(op) ? 3 : 1)
+#define ISBASICBLOCK(blocks, start, bytes) \
+ (blocks[start]==blocks[start+bytes-1])
+
+/* Replace LOAD_CONST c1. LOAD_CONST c2 ... LOAD_CONST cn BUILD_TUPLE n
+ with LOAD_CONST (c1, c2, ... cn).
+ The consts table must still be in list form so that the
+ new constant (c1, c2, ... cn) can be appended.
+ Called with codestr pointing to the first LOAD_CONST.
+ Bails out with no change if one or more of the LOAD_CONSTs is missing.
+ Also works for BUILD_LIST when followed by an "in" or "not in" test.
+*/
+static int
+tuple_of_constants(unsigned char *codestr, int n, PyObject *consts)
+{
+ PyObject *newconst, *constant;
+ Py_ssize_t i, arg, len_consts;
+
+ /* Pre-conditions */
+ assert(PyList_CheckExact(consts));
+ assert(codestr[n*3] == BUILD_TUPLE || codestr[n*3] == BUILD_LIST);
+ assert(GETARG(codestr, (n*3)) == n);
+ for (i=0 ; i<n ; i++)
+ assert(codestr[i*3] == LOAD_CONST);
+
+ /* Buildup new tuple of constants */
+ newconst = PyTuple_New(n);
+ if (newconst == NULL)
+ return 0;
+ len_consts = PyList_GET_SIZE(consts);
+ for (i=0 ; i<n ; i++) {
+ arg = GETARG(codestr, (i*3));
+ assert(arg < len_consts);
+ constant = PyList_GET_ITEM(consts, arg);
+ Py_INCREF(constant);
+ PyTuple_SET_ITEM(newconst, i, constant);
+ }
+
+ /* Append folded constant onto consts */
+ if (PyList_Append(consts, newconst)) {
+ Py_DECREF(newconst);
+ return 0;
+ }
+ Py_DECREF(newconst);
+
+ /* Write NOPs over old LOAD_CONSTS and
+ add a new LOAD_CONST newconst on top of the BUILD_TUPLE n */
+ memset(codestr, NOP, n*3);
+ codestr[n*3] = LOAD_CONST;
+ SETARG(codestr, (n*3), len_consts);
+ return 1;
+}
+
+/* Replace LOAD_CONST c1. LOAD_CONST c2 BINOP
+ with LOAD_CONST binop(c1,c2)
+ The consts table must still be in list form so that the
+ new constant can be appended.
+ Called with codestr pointing to the first LOAD_CONST.
+ Abandons the transformation if the folding fails (i.e. 1+'a').
+ If the new constant is a sequence, only folds when the size
+ is below a threshold value. That keeps pyc files from
+ becoming large in the presence of code like: (None,)*1000.
+*/
+static int
+fold_binops_on_constants(unsigned char *codestr, PyObject *consts)
+{
+ PyObject *newconst, *v, *w;
+ Py_ssize_t len_consts, size;
+ int opcode;
+
+ /* Pre-conditions */
+ assert(PyList_CheckExact(consts));
+ assert(codestr[0] == LOAD_CONST);
+ assert(codestr[3] == LOAD_CONST);
+
+ /* Create new constant */
+ v = PyList_GET_ITEM(consts, GETARG(codestr, 0));
+ w = PyList_GET_ITEM(consts, GETARG(codestr, 3));
+ opcode = codestr[6];
+ switch (opcode) {
+ case BINARY_POWER:
+ newconst = PyNumber_Power(v, w, Py_None);
+ break;
+ case BINARY_MULTIPLY:
+ newconst = PyNumber_Multiply(v, w);
+ break;
+ case BINARY_DIVIDE:
+ /* Cannot fold this operation statically since
+ the result can depend on the run-time presence
+ of the -Qnew flag */
+ return 0;
+ case BINARY_TRUE_DIVIDE:
+ newconst = PyNumber_TrueDivide(v, w);
+ break;
+ case BINARY_FLOOR_DIVIDE:
+ newconst = PyNumber_FloorDivide(v, w);
+ break;
+ case BINARY_MODULO:
+ newconst = PyNumber_Remainder(v, w);
+ break;
+ case BINARY_ADD:
+ newconst = PyNumber_Add(v, w);
+ break;
+ case BINARY_SUBTRACT:
+ newconst = PyNumber_Subtract(v, w);
+ break;
+ case BINARY_SUBSCR:
+ newconst = PyObject_GetItem(v, w);
+ break;
+ case BINARY_LSHIFT:
+ newconst = PyNumber_Lshift(v, w);
+ break;
+ case BINARY_RSHIFT:
+ newconst = PyNumber_Rshift(v, w);
+ break;
+ case BINARY_AND:
+ newconst = PyNumber_And(v, w);
+ break;
+ case BINARY_XOR:
+ newconst = PyNumber_Xor(v, w);
+ break;
+ case BINARY_OR:
+ newconst = PyNumber_Or(v, w);
+ break;
+ default:
+ /* Called with an unknown opcode */
+ PyErr_Format(PyExc_SystemError,
+ "unexpected binary operation %d on a constant",
+ opcode);
+ return 0;
+ }
+ if (newconst == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+ size = PyObject_Size(newconst);
+ if (size == -1)
+ PyErr_Clear();
+ else if (size > 20) {
+ Py_DECREF(newconst);
+ return 0;
+ }
+
+ /* Append folded constant into consts table */
+ len_consts = PyList_GET_SIZE(consts);
+ if (PyList_Append(consts, newconst)) {
+ Py_DECREF(newconst);
+ return 0;
+ }
+ Py_DECREF(newconst);
+
+ /* Write NOP NOP NOP NOP LOAD_CONST newconst */
+ memset(codestr, NOP, 4);
+ codestr[4] = LOAD_CONST;
+ SETARG(codestr, 4, len_consts);
+ return 1;
+}
+
+static int
+fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts)
+{
+ PyObject *newconst=NULL, *v;
+ Py_ssize_t len_consts;
+ int opcode;
+
+ /* Pre-conditions */
+ assert(PyList_CheckExact(consts));
+ assert(codestr[0] == LOAD_CONST);
+
+ /* Create new constant */
+ v = PyList_GET_ITEM(consts, GETARG(codestr, 0));
+ opcode = codestr[3];
+ switch (opcode) {
+ case UNARY_NEGATIVE:
+ /* Preserve the sign of -0.0 */
+ if (PyObject_IsTrue(v) == 1)
+ newconst = PyNumber_Negative(v);
+ break;
+ case UNARY_CONVERT:
+ newconst = PyObject_Repr(v);
+ break;
+ case UNARY_INVERT:
+ newconst = PyNumber_Invert(v);
+ break;
+ default:
+ /* Called with an unknown opcode */
+ PyErr_Format(PyExc_SystemError,
+ "unexpected unary operation %d on a constant",
+ opcode);
+ return 0;
+ }
+ if (newconst == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+
+ /* Append folded constant into consts table */
+ len_consts = PyList_GET_SIZE(consts);
+ if (PyList_Append(consts, newconst)) {
+ Py_DECREF(newconst);
+ return 0;
+ }
+ Py_DECREF(newconst);
+
+ /* Write NOP LOAD_CONST newconst */
+ codestr[0] = NOP;
+ codestr[1] = LOAD_CONST;
+ SETARG(codestr, 1, len_consts);
+ return 1;
+}
+
+static unsigned int *
+markblocks(unsigned char *code, int len)
+{
+ unsigned int *blocks = (unsigned int *)PyMem_Malloc(len*sizeof(int));
+ int i,j, opcode, blockcnt = 0;
+
+ if (blocks == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ memset(blocks, 0, len*sizeof(int));
+
+ /* Mark labels in the first pass */
+ for (i=0 ; i<len ; i+=CODESIZE(opcode)) {
+ opcode = code[i];
+ switch (opcode) {
+ case FOR_ITER:
+ case JUMP_FORWARD:
+ case JUMP_IF_FALSE:
+ case JUMP_IF_TRUE:
+ case JUMP_ABSOLUTE:
+ case CONTINUE_LOOP:
+ case SETUP_LOOP:
+ case SETUP_EXCEPT:
+ case SETUP_FINALLY:
+ j = GETJUMPTGT(code, i);
+ blocks[j] = 1;
+ break;
+ }
+ }
+ /* Build block numbers in the second pass */
+ for (i=0 ; i<len ; i++) {
+ blockcnt += blocks[i]; /* increment blockcnt over labels */
+ blocks[i] = blockcnt;
+ }
+ return blocks;
+}
+
+/* Perform basic peephole optimizations to components of a code object.
+ The consts object should still be in list form to allow new constants
+ to be appended.
+
+ To keep the optimizer simple, it bails out (does nothing) for code
+ containing extended arguments or that has a length over 32,700. That
+ allows us to avoid overflow and sign issues. Likewise, it bails when
+ the lineno table has complex encoding for gaps >= 255.
+
+ Optimizations are restricted to simple transformations occuring within a
+ single basic block. All transformations keep the code size the same or
+ smaller. For those that reduce size, the gaps are initially filled with
+ NOPs. Later those NOPs are removed and the jump addresses retargeted in
+ a single pass. Line numbering is adjusted accordingly. */
+
+PyObject *
+PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
+ PyObject *lineno_obj)
+{
+ Py_ssize_t i, j, codelen;
+ int nops, h, adj;
+ int tgt, tgttgt, opcode;
+ unsigned char *codestr = NULL;
+ unsigned char *lineno;
+ int *addrmap = NULL;
+ int new_line, cum_orig_line, last_line, tabsiz;
+ int cumlc=0, lastlc=0; /* Count runs of consecutive LOAD_CONSTs */
+ unsigned int *blocks = NULL;
+ char *name;
+
+ /* Bail out if an exception is set */
+ if (PyErr_Occurred())
+ goto exitUnchanged;
+
+ /* Bypass optimization when the lineno table is too complex */
+ assert(PyString_Check(lineno_obj));
+ lineno = (unsigned char*)PyString_AS_STRING(lineno_obj);
+ tabsiz = PyString_GET_SIZE(lineno_obj);
+ if (memchr(lineno, 255, tabsiz) != NULL)
+ goto exitUnchanged;
+
+ /* Avoid situations where jump retargeting could overflow */
+ assert(PyString_Check(code));
+ codelen = PyString_Size(code);
+ if (codelen > 32700)
+ goto exitUnchanged;
+
+ /* Make a modifiable copy of the code string */
+ codestr = (unsigned char *)PyMem_Malloc(codelen);
+ if (codestr == NULL)
+ goto exitUnchanged;
+ codestr = (unsigned char *)memcpy(codestr,
+ PyString_AS_STRING(code), codelen);
+
+ /* Verify that RETURN_VALUE terminates the codestring. This allows
+ the various transformation patterns to look ahead several
+ instructions without additional checks to make sure they are not
+ looking beyond the end of the code string.
+ */
+ if (codestr[codelen-1] != RETURN_VALUE)
+ goto exitUnchanged;
+
+ /* Mapping to new jump targets after NOPs are removed */
+ addrmap = (int *)PyMem_Malloc(codelen * sizeof(int));
+ if (addrmap == NULL)
+ goto exitUnchanged;
+
+ blocks = markblocks(codestr, codelen);
+ if (blocks == NULL)
+ goto exitUnchanged;
+ assert(PyList_Check(consts));
+
+ for (i=0 ; i<codelen ; i += CODESIZE(codestr[i])) {
+ opcode = codestr[i];
+
+ lastlc = cumlc;
+ cumlc = 0;
+
+ switch (opcode) {
+
+ /* Replace UNARY_NOT JUMP_IF_FALSE POP_TOP with
+ with JUMP_IF_TRUE POP_TOP */
+ case UNARY_NOT:
+ if (codestr[i+1] != JUMP_IF_FALSE ||
+ codestr[i+4] != POP_TOP ||
+ !ISBASICBLOCK(blocks,i,5))
+ continue;
+ tgt = GETJUMPTGT(codestr, (i+1));
+ if (codestr[tgt] != POP_TOP)
+ continue;
+ j = GETARG(codestr, i+1) + 1;
+ codestr[i] = JUMP_IF_TRUE;
+ SETARG(codestr, i, j);
+ codestr[i+3] = POP_TOP;
+ codestr[i+4] = NOP;
+ break;
+
+ /* not a is b --> a is not b
+ not a in b --> a not in b
+ not a is not b --> a is b
+ not a not in b --> a in b
+ */
+ case COMPARE_OP:
+ j = GETARG(codestr, i);
+ if (j < 6 || j > 9 ||
+ codestr[i+3] != UNARY_NOT ||
+ !ISBASICBLOCK(blocks,i,4))
+ continue;
+ SETARG(codestr, i, (j^1));
+ codestr[i+3] = NOP;
+ break;
+
+ /* Replace LOAD_GLOBAL/LOAD_NAME None
+ with LOAD_CONST None */
+ case LOAD_NAME:
+ case LOAD_GLOBAL:
+ j = GETARG(codestr, i);
+ name = PyString_AsString(PyTuple_GET_ITEM(names, j));
+ if (name == NULL || strcmp(name, "None") != 0)
+ continue;
+ for (j=0 ; j < PyList_GET_SIZE(consts) ; j++) {
+ if (PyList_GET_ITEM(consts, j) == Py_None) {
+ codestr[i] = LOAD_CONST;
+ SETARG(codestr, i, j);
+ cumlc = lastlc + 1;
+ break;
+ }
+ }
+ break;
+
+ /* Skip over LOAD_CONST trueconst
+ JUMP_IF_FALSE xx POP_TOP */
+ case LOAD_CONST:
+ cumlc = lastlc + 1;
+ j = GETARG(codestr, i);
+ if (codestr[i+3] != JUMP_IF_FALSE ||
+ codestr[i+6] != POP_TOP ||
+ !ISBASICBLOCK(blocks,i,7) ||
+ !PyObject_IsTrue(PyList_GET_ITEM(consts, j)))
+ continue;
+ memset(codestr+i, NOP, 7);
+ cumlc = 0;
+ break;
+
+ /* Try to fold tuples of constants (includes a case for lists
+ which are only used for "in" and "not in" tests).
+ Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
+ Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
+ Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
+ case BUILD_TUPLE:
+ case BUILD_LIST:
+ j = GETARG(codestr, i);
+ h = i - 3 * j;
+ if (h >= 0 &&
+ j <= lastlc &&
+ ((opcode == BUILD_TUPLE &&
+ ISBASICBLOCK(blocks, h, 3*(j+1))) ||
+ (opcode == BUILD_LIST &&
+ codestr[i+3]==COMPARE_OP &&
+ ISBASICBLOCK(blocks, h, 3*(j+2)) &&
+ (GETARG(codestr,i+3)==6 ||
+ GETARG(codestr,i+3)==7))) &&
+ tuple_of_constants(&codestr[h], j, consts)) {
+ assert(codestr[i] == LOAD_CONST);
+ cumlc = 1;
+ break;
+ }
+ if (codestr[i+3] != UNPACK_SEQUENCE ||
+ !ISBASICBLOCK(blocks,i,6) ||
+ j != GETARG(codestr, i+3))
+ continue;
+ if (j == 1) {
+ memset(codestr+i, NOP, 6);
+ } else if (j == 2) {
+ codestr[i] = ROT_TWO;
+ memset(codestr+i+1, NOP, 5);
+ } else if (j == 3) {
+ codestr[i] = ROT_THREE;
+ codestr[i+1] = ROT_TWO;
+ memset(codestr+i+2, NOP, 4);
+ }
+ break;
+
+ /* Fold binary ops on constants.
+ LOAD_CONST c1 LOAD_CONST c2 BINOP --> LOAD_CONST binop(c1,c2) */
+ case BINARY_POWER:
+ case BINARY_MULTIPLY:
+ case BINARY_TRUE_DIVIDE:
+ case BINARY_FLOOR_DIVIDE:
+ case BINARY_MODULO:
+ case BINARY_ADD:
+ case BINARY_SUBTRACT:
+ case BINARY_SUBSCR:
+ case BINARY_LSHIFT:
+ case BINARY_RSHIFT:
+ case BINARY_AND:
+ case BINARY_XOR:
+ case BINARY_OR:
+ if (lastlc >= 2 &&
+ ISBASICBLOCK(blocks, i-6, 7) &&
+ fold_binops_on_constants(&codestr[i-6], consts)) {
+ i -= 2;
+ assert(codestr[i] == LOAD_CONST);
+ cumlc = 1;
+ }
+ break;
+
+ /* Fold unary ops on constants.
+ LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */
+ case UNARY_NEGATIVE:
+ case UNARY_CONVERT:
+ case UNARY_INVERT:
+ if (lastlc >= 1 &&
+ ISBASICBLOCK(blocks, i-3, 4) &&
+ fold_unaryops_on_constants(&codestr[i-3], consts)) {
+ i -= 2;
+ assert(codestr[i] == LOAD_CONST);
+ cumlc = 1;
+ }
+ break;
+
+ /* Simplify conditional jump to conditional jump where the
+ result of the first test implies the success of a similar
+ test or the failure of the opposite test.
+ Arises in code like:
+ "if a and b:"
+ "if a or b:"
+ "a and b or c"
+ "(a and b) and c"
+ x:JUMP_IF_FALSE y y:JUMP_IF_FALSE z --> x:JUMP_IF_FALSE z
+ x:JUMP_IF_FALSE y y:JUMP_IF_TRUE z --> x:JUMP_IF_FALSE y+3
+ where y+3 is the instruction following the second test.
+ */
+ case JUMP_IF_FALSE:
+ case JUMP_IF_TRUE:
+ tgt = GETJUMPTGT(codestr, i);
+ j = codestr[tgt];
+ if (j == JUMP_IF_FALSE || j == JUMP_IF_TRUE) {
+ if (j == opcode) {
+ tgttgt = GETJUMPTGT(codestr, tgt) - i - 3;
+ SETARG(codestr, i, tgttgt);
+ } else {
+ tgt -= i;
+ SETARG(codestr, i, tgt);
+ }
+ break;
+ }
+ /* Intentional fallthrough */
+
+ /* Replace jumps to unconditional jumps */
+ case FOR_ITER:
+ case JUMP_FORWARD:
+ case JUMP_ABSOLUTE:
+ case CONTINUE_LOOP:
+ case SETUP_LOOP:
+ case SETUP_EXCEPT:
+ case SETUP_FINALLY:
+ tgt = GETJUMPTGT(codestr, i);
+ if (!UNCONDITIONAL_JUMP(codestr[tgt]))
+ continue;
+ tgttgt = GETJUMPTGT(codestr, tgt);
+ if (opcode == JUMP_FORWARD) /* JMP_ABS can go backwards */
+ opcode = JUMP_ABSOLUTE;
+ if (!ABSOLUTE_JUMP(opcode))
+ tgttgt -= i + 3; /* Calc relative jump addr */
+ if (tgttgt < 0) /* No backward relative jumps */
+ continue;
+ codestr[i] = opcode;
+ SETARG(codestr, i, tgttgt);
+ break;
+
+ case EXTENDED_ARG:
+ goto exitUnchanged;
+
+ /* Replace RETURN LOAD_CONST None RETURN with just RETURN */
+ case RETURN_VALUE:
+ if (i+4 >= codelen ||
+ codestr[i+4] != RETURN_VALUE ||
+ !ISBASICBLOCK(blocks,i,5))
+ continue;
+ memset(codestr+i+1, NOP, 4);
+ break;
+ }
+ }
+
+ /* Fixup linenotab */
+ for (i=0, nops=0 ; i<codelen ; i += CODESIZE(codestr[i])) {
+ addrmap[i] = i - nops;
+ if (codestr[i] == NOP)
+ nops++;
+ }
+ cum_orig_line = 0;
+ last_line = 0;
+ for (i=0 ; i < tabsiz ; i+=2) {
+ cum_orig_line += lineno[i];
+ new_line = addrmap[cum_orig_line];
+ assert (new_line - last_line < 255);
+ lineno[i] =((unsigned char)(new_line - last_line));
+ last_line = new_line;
+ }
+
+ /* Remove NOPs and fixup jump targets */
+ for (i=0, h=0 ; i<codelen ; ) {
+ opcode = codestr[i];
+ switch (opcode) {
+ case NOP:
+ i++;
+ continue;
+
+ case JUMP_ABSOLUTE:
+ case CONTINUE_LOOP:
+ j = addrmap[GETARG(codestr, i)];
+ SETARG(codestr, i, j);
+ break;
+
+ case FOR_ITER:
+ case JUMP_FORWARD:
+ case JUMP_IF_FALSE:
+ case JUMP_IF_TRUE:
+ case SETUP_LOOP:
+ case SETUP_EXCEPT:
+ case SETUP_FINALLY:
+ j = addrmap[GETARG(codestr, i) + i + 3] - addrmap[i] - 3;
+ SETARG(codestr, i, j);
+ break;
+ }
+ adj = CODESIZE(opcode);
+ while (adj--)
+ codestr[h++] = codestr[i++];
+ }
+ assert(h + nops == codelen);
+
+ code = PyString_FromStringAndSize((char *)codestr, h);
+ PyMem_Free(addrmap);
+ PyMem_Free(codestr);
+ PyMem_Free(blocks);
+ return code;
+
+ exitUnchanged:
+ if (blocks != NULL)
+ PyMem_Free(blocks);
+ if (addrmap != NULL)
+ PyMem_Free(addrmap);
+ if (codestr != NULL)
+ PyMem_Free(codestr);
+ Py_INCREF(code);
+ return code;
+}
1
0
Author: matt.fleming
Date: Mon Aug 21 17:49:31 2006
New Revision: 51427
Added:
sandbox/trunk/pdb/patches/
sandbox/trunk/pdb/patches/01-08-06-pydb.diff
sandbox/trunk/pdb/patches/01-08-06-pydb.diff2
sandbox/trunk/pdb/patches/01-08-06-sighandler.cmd
sandbox/trunk/pdb/patches/01-08-06-sighandler.right
sandbox/trunk/pdb/patches/04-07-06-patch.diff
sandbox/trunk/pdb/patches/06-08-06-pydb.diff
sandbox/trunk/pdb/patches/06-08-06-sighandler.cmd
sandbox/trunk/pdb/patches/06-08-06-sighandler.right
sandbox/trunk/pdb/patches/10-07-06-opts.diff
sandbox/trunk/pdb/patches/11-08-06-pydb.diff
sandbox/trunk/pdb/patches/11-08-06-sigtest.py.in
sandbox/trunk/pdb/patches/11-08-06-sigtestexample.py
sandbox/trunk/pdb/patches/20-08-06-threaddbg.patch
sandbox/trunk/pdb/patches/24-07-06-pydb.diff
sandbox/trunk/pdb/patches/24-07-06-pydb2.diff
sandbox/trunk/pdb/patches/27-07-06-pydb.diff
sandbox/trunk/pdb/patches/27-07-06-sighandler.py
sandbox/trunk/pdb/patches/30-05-06-pdb.py
sandbox/trunk/pdb/patches/31-07-06-fns.diff
sandbox/trunk/pdb/patches/31-07-06-pydb.diff
sandbox/trunk/pdb/patches/31-07-06-sig.diff
sandbox/trunk/pdb/patches/31-07-06-sighandler.cmd
sandbox/trunk/pdb/patches/31-07-06-sighandler.py
sandbox/trunk/pdb/patches/31-07-06-sighandler.right
sandbox/trunk/pdb/patches/31-07-06-test.py
Log:
Add the patches that I've produced over the summer, both
for pydb and my mpdb code, just so the Google Gods can see
all the stuff I've worked on for this project.
Added: sandbox/trunk/pdb/patches/01-08-06-pydb.diff
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/01-08-06-pydb.diff Mon Aug 21 17:49:31 2006
@@ -0,0 +1,237 @@
+? t.py
+? thread_script2.py
+? tpdb.py
+? tpdb2.py
+? test/sighandler.cmd
+? test/sighandler.right
+Index: pydb/sighandler.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/sighandler.py,v
+retrieving revision 1.4
+diff -u -r1.4 sighandler.py
+--- pydb/sighandler.py 1 Aug 2006 15:10:04 -0000 1.4
++++ pydb/sighandler.py 1 Aug 2006 16:53:53 -0000
+@@ -32,62 +32,24 @@
+ """
+ def __init__(self, pydb):
+ self.pydb = pydb
+- # This list contains tuples made up of four items, one tuple for
+- # every signal handler we've created. The tuples contain
+- # (signal_num, stop, print, pass)
+- self._sig_attr = []
+- self._sig_stop = []
+- self._sig_print = []
+- self._sig_pass = []
+-
+- for sig in signal.__dict__.keys():
+- if sig.startswith('SIG') and '_' not in sig:
+- self._sig_attr.append(sig)
++ self._sigs = {}
+
+ # set up signal handling for some known signals
+- # SIGKILL is non-maskable. Should we *really* include it here?
+- fatal = ['SIGINT', 'SIGTRAP', 'SIGTERM', 'SIGQUIT', 'SIGILL', \
+- 'SIGKILL', 'SIGSTOP']
++ fatal = ['SIGKILL', 'SIGSTOP']
+ ignore= ['SIGALRM', 'SIGCHLD', 'SIGURG', 'SIGIO', 'SIGVTALRM'
+ 'SIGPROF', 'SIGWINCH', 'SIGPOLL', 'SIGWAITING', 'SIGLWP',
+- 'SIGCANCEL']
+- for sig in self._sig_attr:
+- if str(sig) not in fatal:
+- num = lookup_signum(sig)
+- if num:
+- if str(sig) in ignore:
+- self._set_sig(sig, (False, False, True))
+- else:
+- self._set_sig(sig, (True, True, True))
+- signal.signal(num, self.handle)
+- else:
+- self._set_sig(sig, (False, False, True))
+-
+- def _get_sig(self, name):
+- st = name in self._sig_stop
+- pr = name in self._sig_print
+- pa = name in self._sig_pass
+- return (st, pr, pa)
+-
+- def _set_sig(self, name, (st, pr, pa)):
+- """Set the actions to be taken when a signal, specified by
+- 'name', is received.
+- """
+- if st:
+- if name not in self._sig_stop:
+- self._sig_stop.append(name)
+- elif name in self._sig_stop:
+- self._sig_stop.pop(self._sig_stop.index(name))
+- if pr:
+- if name not in self._sig_print:
+- self._sig_print.append(name)
+- elif name in self._sig_print:
+- self._sig_print.pop(self._sig_print.index(name))
+- if pa:
+- if name not in self._sig_pass:
+- self._sig_pass.append(name)
+- elif name in self._sig_pass:
+- self._sig_pass.pop(self._sig_pass.index(name))
++ 'SIGCANCEL', 'SIGTRAP', 'SIGTERM', 'SIGQUIT', 'SIGILL', \
++ 'SIGINT']
++ for sig in signal.__dict__.keys():
++ if sig.startswith('SIG') and '_' not in sig:
++ if str(sig) not in fatal:
++ num = lookup_signum(sig)
++ if num:
++ if str(sig) in ignore:
++ self._sigs[sig] = (False, False, True)
++ else:
++ self._sigs[sig] = (True, True, True)
++ signal.signal(num, self.handle)
+
+ def info_signal(self, signame):
+ """Print information about a signal"""
+@@ -98,18 +60,14 @@
+ # This has come from pydb's info command
+ if len(signame) == 1:
+ self.pydb.msg(header)
+- for sig in self._sig_attr:
+- s = sig in self._sig_stop
+- pr = sig in self._sig_print
+- pa = sig in self._sig_pass
+- self.pydb.msg(fmt % (sig,s,pr,pa))
++ for sig in self._sigs.keys():
++ st, pr, pa = self._sigs[sig]
++ self.pydb.msg(fmt % (sig, st, pr, pa))
+ else:
+ self.info_signal(signame[1])
+ return
+
+- s = signame in self._sig_stop
+- pr = signame in self._sig_print
+- pa = signame in self._sig_pass
++ s, pr, pa = self._sigs[signame]
+ self.pydb.msg(header)
+ self.pydb.msg(fmt % (signame, s, pr, pa))
+
+@@ -121,74 +79,77 @@
+ self.info_signal(['handle'])
+ return
+ args = arg.split()
+- if args[0] in self._sig_attr:
+- if len(args) == 1:
+- self.info_signal(args[0])
+- return
+- # multiple commands might be specified, i.e. 'nopass nostop'
+- for attr in args[1:]:
+- if attr.startswith('no'):
+- on = False
+- attr = attr[2:]
+- else:
+- on = True
+- if attr.startswith('stop'):
+- self.handle_stop(args[0], on)
+- elif attr.startswith('print'):
+- self.handle_print(args[0], on)
+- elif attr.startswith('pass'):
+- self.handle_pass(args[0], on)
+- else:
+- self.pydb.errmsg('Invalid arguments')
++ try:
++ self._sigs[args[0]]
++ except KeyError:
++ return
++ if len(args) == 1:
++ self.info_signal(args[0])
++ return
++ # multiple commands might be specified, i.e. 'nopass nostop'
++ for attr in args[1:]:
++ if attr.startswith('no'):
++ on = False
++ attr = attr[2:]
++ else:
++ on = True
++ if attr.startswith('stop'):
++ self.handle_stop(args[0], on)
++ elif attr.startswith('print'):
++ self.handle_print(args[0], on)
++ elif attr.startswith('pass'):
++ self.handle_pass(args[0], on)
++ else:
++ self.pydb.errmsg('Invalid arguments')
+
+- def handle_stop(self, signum, change):
++ def handle_stop(self, signame, change):
+ """Change whether we stop or not when this signal is caught.
+ If 'change' is True your program will stop when this signal
+ happens."""
+ if not isinstance(change, bool):
+ return
+- old_attr = self._get_sig(signum)
++ old_attr = self._sigs[signame]
+ st, pr, pa = change, old_attr[1], old_attr[2]
+ if st:
+ pr = True
+- self._set_sig(signum, (st, pr, pa))
++ self._sigs[signame] = (st, pr, pa)
+ return change
+
+- def handle_pass(self, signum, change):
++ def handle_pass(self, signame, change):
+ """Change whether we pass this signal to the program (or not)
+ when this signal is caught. If change is True, Pydb should allow
+ your program to see this signal.
+ """
+ if not isinstance(change, bool):
+ return
+- old_attr = self._get_sig(signum)
++ old_attr = self._sigs[signame]
+ st, pr, pa = old_attr[0], old_attr[1], change
+- self._set_sig(signum, (st, pr, pa))
++ self._sigs[signame] = (st, pr, pa)
+ return change
+
+ # ignore is a synonym for nopass and noignore is a synonym for pass
+- def handle_ignore(self, signum, change):
++ def handle_ignore(self, signame, change):
+ if not isinstance(change, bool):
+ return
+ self.handle_pass(not change)
+ return change
+
+- def handle_print(self, signum, change):
++ def handle_print(self, signame, change):
+ """Change whether we print or not when this signal is caught."""
+ if not isinstance(change, bool):
+ return
+- old_attr = self._get_sig(signum)
++ old_attr = self._sigs[signame]
+ st, pr, pa = old_attr[0], change, old_attr[2]
+ if not change:
+ # noprint implies nostop
+ st = False
+- self._set_sig(signum, (st, pr, pa))
++ self._sigs[signame] = (st, pr, pa)
+ return change
+
+ def handle(self, signum, frame):
+ """This method is called when a signal is received."""
+ sig = lookup_signame(signum)
+- st, pa, pr = self._get_sig(sig)
++ st, pa, pr = self._sigs[sig]
+ if pr:
+ self.pydb.msg('Program received signal %s' % sig)
+ if st:
+Index: test/Makefile.am
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/test/Makefile.am,v
+retrieving revision 1.17
+diff -u -r1.17 Makefile.am
+--- test/Makefile.am 28 Jul 2006 00:47:47 -0000 1.17
++++ test/Makefile.am 1 Aug 2006 16:53:53 -0000
+@@ -28,6 +28,8 @@
+ run.right \
+ run2.cmd \
+ run2.right \
++ sighandler.cmd \
++ sighandle.right \
+ test.py \
+ trace-2.5.right \
+ trace.py \
Added: sandbox/trunk/pdb/patches/01-08-06-pydb.diff2
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/01-08-06-pydb.diff2 Mon Aug 21 17:49:31 2006
@@ -0,0 +1,255 @@
+? t.py
+? thread_script2.py
+? tpdb.py
+? tpdb2.py
+? test/sighandler.cmd
+? test/sighandler.right
+Index: pydb/sighandler.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/sighandler.py,v
+retrieving revision 1.4
+diff -u -r1.4 sighandler.py
+--- pydb/sighandler.py 1 Aug 2006 15:10:04 -0000 1.4
++++ pydb/sighandler.py 1 Aug 2006 18:08:56 -0000
+@@ -18,6 +18,8 @@
+ else:
+ return None
+
++fatal_signals = ['SIGKILL', 'SIGSTOP']
++
+ class SigHandler:
+
+ """Store information about what we do when we handle a signal,
+@@ -32,62 +34,27 @@
+ """
+ def __init__(self, pydb):
+ self.pydb = pydb
+- # This list contains tuples made up of four items, one tuple for
+- # every signal handler we've created. The tuples contain
+- # (signal_num, stop, print, pass)
+- self._sig_attr = []
+- self._sig_stop = []
+- self._sig_print = []
+- self._sig_pass = []
+-
+- for sig in signal.__dict__.keys():
+- if sig.startswith('SIG') and '_' not in sig:
+- self._sig_attr.append(sig)
++ self._sigs = {}
+
+ # set up signal handling for some known signals
+- # SIGKILL is non-maskable. Should we *really* include it here?
+- fatal = ['SIGINT', 'SIGTRAP', 'SIGTERM', 'SIGQUIT', 'SIGILL', \
+- 'SIGKILL', 'SIGSTOP']
+ ignore= ['SIGALRM', 'SIGCHLD', 'SIGURG', 'SIGIO', 'SIGVTALRM'
+ 'SIGPROF', 'SIGWINCH', 'SIGPOLL', 'SIGWAITING', 'SIGLWP',
+- 'SIGCANCEL']
+- for sig in self._sig_attr:
+- if str(sig) not in fatal:
+- num = lookup_signum(sig)
+- if num:
+- if str(sig) in ignore:
+- self._set_sig(sig, (False, False, True))
+- else:
+- self._set_sig(sig, (True, True, True))
+- signal.signal(num, self.handle)
+- else:
+- self._set_sig(sig, (False, False, True))
+-
+- def _get_sig(self, name):
+- st = name in self._sig_stop
+- pr = name in self._sig_print
+- pa = name in self._sig_pass
+- return (st, pr, pa)
+-
+- def _set_sig(self, name, (st, pr, pa)):
+- """Set the actions to be taken when a signal, specified by
+- 'name', is received.
+- """
+- if st:
+- if name not in self._sig_stop:
+- self._sig_stop.append(name)
+- elif name in self._sig_stop:
+- self._sig_stop.pop(self._sig_stop.index(name))
+- if pr:
+- if name not in self._sig_print:
+- self._sig_print.append(name)
+- elif name in self._sig_print:
+- self._sig_print.pop(self._sig_print.index(name))
+- if pa:
+- if name not in self._sig_pass:
+- self._sig_pass.append(name)
+- elif name in self._sig_pass:
+- self._sig_pass.pop(self._sig_pass.index(name))
++ 'SIGCANCEL', 'SIGTRAP', 'SIGTERM', 'SIGQUIT', 'SIGILL', \
++ 'SIGINT']
++ for sig in signal.__dict__.keys():
++ if sig.startswith('SIG') and '_' not in sig:
++ if str(sig) not in fatal_signals:
++ num = lookup_signum(sig)
++ if num:
++ if str(sig) in ignore:
++ self._sigs[sig] = (False, False, True)
++ else:
++ self._sigs[sig] = (True, True, True)
++ signal.signal(num, self.handle)
++ else:
++ # Make an entry in the _sig dict for these signals
++ # even though they cannot be ignored or caught.
++ self._sigs[sig] = (False, False, True)
+
+ def info_signal(self, signame):
+ """Print information about a signal"""
+@@ -98,18 +65,14 @@
+ # This has come from pydb's info command
+ if len(signame) == 1:
+ self.pydb.msg(header)
+- for sig in self._sig_attr:
+- s = sig in self._sig_stop
+- pr = sig in self._sig_print
+- pa = sig in self._sig_pass
+- self.pydb.msg(fmt % (sig,s,pr,pa))
++ for sig in self._sigs.keys():
++ st, pr, pa = self._sigs[sig]
++ self.pydb.msg(fmt % (sig, st, pr, pa))
+ else:
+ self.info_signal(signame[1])
+ return
+
+- s = signame in self._sig_stop
+- pr = signame in self._sig_print
+- pa = signame in self._sig_pass
++ s, pr, pa = self._sigs[signame]
+ self.pydb.msg(header)
+ self.pydb.msg(fmt % (signame, s, pr, pa))
+
+@@ -121,74 +84,83 @@
+ self.info_signal(['handle'])
+ return
+ args = arg.split()
+- if args[0] in self._sig_attr:
+- if len(args) == 1:
+- self.info_signal(args[0])
+- return
+- # multiple commands might be specified, i.e. 'nopass nostop'
+- for attr in args[1:]:
+- if attr.startswith('no'):
+- on = False
+- attr = attr[2:]
+- else:
+- on = True
+- if attr.startswith('stop'):
+- self.handle_stop(args[0], on)
+- elif attr.startswith('print'):
+- self.handle_print(args[0], on)
+- elif attr.startswith('pass'):
+- self.handle_pass(args[0], on)
+- else:
+- self.pydb.errmsg('Invalid arguments')
++ try:
++ self._sigs[args[0]]
++ except KeyError:
++ return
++ if len(args) == 1:
++ self.info_signal(args[0])
++ return
++
++ # We can display information about 'fatal' signals, but not
++ # change their actions.
++ if args[0] in fatal_signals:
++ return
++
++ # multiple commands might be specified, i.e. 'nopass nostop'
++ for attr in args[1:]:
++ if attr.startswith('no'):
++ on = False
++ attr = attr[2:]
++ else:
++ on = True
++ if attr.startswith('stop'):
++ self.handle_stop(args[0], on)
++ elif attr.startswith('print'):
++ self.handle_print(args[0], on)
++ elif attr.startswith('pass'):
++ self.handle_pass(args[0], on)
++ else:
++ self.pydb.errmsg('Invalid arguments')
+
+- def handle_stop(self, signum, change):
++ def handle_stop(self, signame, change):
+ """Change whether we stop or not when this signal is caught.
+ If 'change' is True your program will stop when this signal
+ happens."""
+ if not isinstance(change, bool):
+ return
+- old_attr = self._get_sig(signum)
++ old_attr = self._sigs[signame]
+ st, pr, pa = change, old_attr[1], old_attr[2]
+ if st:
+ pr = True
+- self._set_sig(signum, (st, pr, pa))
++ self._sigs[signame] = (st, pr, pa)
+ return change
+
+- def handle_pass(self, signum, change):
++ def handle_pass(self, signame, change):
+ """Change whether we pass this signal to the program (or not)
+ when this signal is caught. If change is True, Pydb should allow
+ your program to see this signal.
+ """
+ if not isinstance(change, bool):
+ return
+- old_attr = self._get_sig(signum)
++ old_attr = self._sigs[signame]
+ st, pr, pa = old_attr[0], old_attr[1], change
+- self._set_sig(signum, (st, pr, pa))
++ self._sigs[signame] = (st, pr, pa)
+ return change
+
+ # ignore is a synonym for nopass and noignore is a synonym for pass
+- def handle_ignore(self, signum, change):
++ def handle_ignore(self, signame, change):
+ if not isinstance(change, bool):
+ return
+ self.handle_pass(not change)
+ return change
+
+- def handle_print(self, signum, change):
++ def handle_print(self, signame, change):
+ """Change whether we print or not when this signal is caught."""
+ if not isinstance(change, bool):
+ return
+- old_attr = self._get_sig(signum)
++ old_attr = self._sigs[signame]
+ st, pr, pa = old_attr[0], change, old_attr[2]
+ if not change:
+ # noprint implies nostop
+ st = False
+- self._set_sig(signum, (st, pr, pa))
++ self._sigs[signame] = (st, pr, pa)
+ return change
+
+ def handle(self, signum, frame):
+ """This method is called when a signal is received."""
+ sig = lookup_signame(signum)
+- st, pa, pr = self._get_sig(sig)
++ st, pa, pr = self._sigs[sig]
+ if pr:
+ self.pydb.msg('Program received signal %s' % sig)
+ if st:
+Index: test/Makefile.am
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/test/Makefile.am,v
+retrieving revision 1.17
+diff -u -r1.17 Makefile.am
+--- test/Makefile.am 28 Jul 2006 00:47:47 -0000 1.17
++++ test/Makefile.am 1 Aug 2006 18:08:56 -0000
+@@ -28,6 +28,8 @@
+ run.right \
+ run2.cmd \
+ run2.right \
++ sighandler.cmd \
++ sighandle.right \
+ test.py \
+ trace-2.5.right \
+ trace.py \
Added: sandbox/trunk/pdb/patches/01-08-06-sighandler.cmd
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/01-08-06-sighandler.cmd Mon Aug 21 17:49:31 2006
@@ -0,0 +1,16 @@
+info signal
+info handle
+handle SIGINT
+handle SIGINT stop pass noprint
+handle SIGINT
+handle SIGINT print
+handle SIGINT
+handle SIGINT nopass noprint nostop
+handle SIGINT
+info signal SIGINT
+# try changing fatal signal handlers (which are unchangable)
+handle SIGKILL stop
+handle SIGKILL
+handle SIGSTOP print
+handle SIGSTOP
+quit
Added: sandbox/trunk/pdb/patches/01-08-06-sighandler.right
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/01-08-06-sighandler.right Mon Aug 21 17:49:31 2006
@@ -0,0 +1,91 @@
+Signal Stop Print Pass to program
+
+SIGHUP True True True
+SIGSYS True True True
+SIGQUIT False False True
+SIGUSR1 True True True
+SIGFPE True True True
+SIGTSTP True True True
+SIGWINCH False False True
+SIGIOT True True True
+SIGBUS True True True
+SIGXCPU True True True
+SIGCONT True True True
+SIGPROF True True True
+SIGKILL False False True
+SIGSEGV True True True
+SIGINT False False True
+SIGIO False False True
+SIGTRAP False False True
+SIGILL False False True
+SIGEMT True True True
+SIGUSR2 True True True
+SIGABRT True True True
+SIGALRM False False True
+SIGXFSZ True True True
+SIGCHLD False False True
+SIGPIPE True True True
+SIGTERM False False True
+SIGVTALRM True True True
+SIGINFO True True True
+SIGURG False False True
+SIGPWR True True True
+SIGSTOP False False True
+SIGTTOU True True True
+SIGTTIN True True True
+Signal Stop Print Pass to program
+
+SIGHUP True True True
+SIGSYS True True True
+SIGQUIT False False True
+SIGUSR1 True True True
+SIGFPE True True True
+SIGTSTP True True True
+SIGWINCH False False True
+SIGIOT True True True
+SIGBUS True True True
+SIGXCPU True True True
+SIGCONT True True True
+SIGPROF True True True
+SIGKILL False False True
+SIGSEGV True True True
+SIGINT False False True
+SIGIO False False True
+SIGTRAP False False True
+SIGILL False False True
+SIGEMT True True True
+SIGUSR2 True True True
+SIGABRT True True True
+SIGALRM False False True
+SIGXFSZ True True True
+SIGCHLD False False True
+SIGPIPE True True True
+SIGTERM False False True
+SIGVTALRM True True True
+SIGINFO True True True
+SIGURG False False True
+SIGPWR True True True
+SIGSTOP False False True
+SIGTTOU True True True
+SIGTTIN True True True
+Signal Stop Print Pass to program
+
+SIGINT False False True
+Signal Stop Print Pass to program
+
+SIGINT False False True
+Signal Stop Print Pass to program
+
+SIGINT False True True
+Signal Stop Print Pass to program
+
+SIGINT False False False
+Signal Stop Print Pass to program
+
+SIGINT False False False
+Signal Stop Print Pass to program
+
+SIGKILL False False True
+Signal Stop Print Pass to program
+
+SIGSTOP False False True
Added: sandbox/trunk/pdb/patches/04-07-06-patch.diff
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/04-07-06-patch.diff Mon Aug 21 17:49:31 2006
@@ -0,0 +1,36 @@
+? configure.lineno
+? patch.diff
+Index: pydb/fns.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/fns.py,v
+retrieving revision 1.8
+diff -u -r1.8 fns.py
+--- pydb/fns.py 26 Jun 2006 12:30:18 -0000 1.8
++++ pydb/fns.py 3 Jul 2006 23:41:40 -0000
+@@ -228,7 +228,9 @@
+
+ if opts.output:
+ try:
+- sys.stdout = open(opts.output, 'w')
++ pydb.stdout = open(opts.output, 'w')
++ # XXX Redirecting sys.stdout is fine for debugging purposes
++ sys.stdout = pydb.stdout
+ except IOError, (errno, strerror):
+ print "I/O in opening debugger output file %s" % opts.output
+ print "error(%s): %s" % (errno, strerror)
+Index: pydb/pydbcmd.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/pydbcmd.py,v
+retrieving revision 1.20
+diff -u -r1.20 pydbcmd.py
+--- pydb/pydbcmd.py 18 Jun 2006 22:40:10 -0000 1.20
++++ pydb/pydbcmd.py 3 Jul 2006 23:41:40 -0000
+@@ -285,7 +285,7 @@
+ do_print = not self.logging_redirect
+ if do_print:
+ if out is None:
+- out = sys.stdout
++ out = self.stdout
+ print >> out, msg,
+
+ def precmd(self, line):
Added: sandbox/trunk/pdb/patches/06-08-06-pydb.diff
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/06-08-06-pydb.diff Mon Aug 21 17:49:31 2006
@@ -0,0 +1,255 @@
+? t.py
+? thread_script2.py
+? tpdb.py
+? tpdb2.py
+? test/sighandler.cmd
+? test/sighandler.right
+Index: pydb/sighandler.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/sighandler.py,v
+retrieving revision 1.4
+diff -u -r1.4 sighandler.py
+--- pydb/sighandler.py 1 Aug 2006 15:10:04 -0000 1.4
++++ pydb/sighandler.py 1 Aug 2006 18:08:56 -0000
+@@ -18,6 +18,8 @@
+ else:
+ return None
+
++fatal_signals = ['SIGKILL', 'SIGSTOP']
++
+ class SigHandler:
+
+ """Store information about what we do when we handle a signal,
+@@ -32,62 +34,27 @@
+ """
+ def __init__(self, pydb):
+ self.pydb = pydb
+- # This list contains tuples made up of four items, one tuple for
+- # every signal handler we've created. The tuples contain
+- # (signal_num, stop, print, pass)
+- self._sig_attr = []
+- self._sig_stop = []
+- self._sig_print = []
+- self._sig_pass = []
+-
+- for sig in signal.__dict__.keys():
+- if sig.startswith('SIG') and '_' not in sig:
+- self._sig_attr.append(sig)
++ self._sigs = {}
+
+ # set up signal handling for some known signals
+- # SIGKILL is non-maskable. Should we *really* include it here?
+- fatal = ['SIGINT', 'SIGTRAP', 'SIGTERM', 'SIGQUIT', 'SIGILL', \
+- 'SIGKILL', 'SIGSTOP']
+ ignore= ['SIGALRM', 'SIGCHLD', 'SIGURG', 'SIGIO', 'SIGVTALRM'
+ 'SIGPROF', 'SIGWINCH', 'SIGPOLL', 'SIGWAITING', 'SIGLWP',
+- 'SIGCANCEL']
+- for sig in self._sig_attr:
+- if str(sig) not in fatal:
+- num = lookup_signum(sig)
+- if num:
+- if str(sig) in ignore:
+- self._set_sig(sig, (False, False, True))
+- else:
+- self._set_sig(sig, (True, True, True))
+- signal.signal(num, self.handle)
+- else:
+- self._set_sig(sig, (False, False, True))
+-
+- def _get_sig(self, name):
+- st = name in self._sig_stop
+- pr = name in self._sig_print
+- pa = name in self._sig_pass
+- return (st, pr, pa)
+-
+- def _set_sig(self, name, (st, pr, pa)):
+- """Set the actions to be taken when a signal, specified by
+- 'name', is received.
+- """
+- if st:
+- if name not in self._sig_stop:
+- self._sig_stop.append(name)
+- elif name in self._sig_stop:
+- self._sig_stop.pop(self._sig_stop.index(name))
+- if pr:
+- if name not in self._sig_print:
+- self._sig_print.append(name)
+- elif name in self._sig_print:
+- self._sig_print.pop(self._sig_print.index(name))
+- if pa:
+- if name not in self._sig_pass:
+- self._sig_pass.append(name)
+- elif name in self._sig_pass:
+- self._sig_pass.pop(self._sig_pass.index(name))
++ 'SIGCANCEL', 'SIGTRAP', 'SIGTERM', 'SIGQUIT', 'SIGILL', \
++ 'SIGINT']
++ for sig in signal.__dict__.keys():
++ if sig.startswith('SIG') and '_' not in sig:
++ if str(sig) not in fatal_signals:
++ num = lookup_signum(sig)
++ if num:
++ if str(sig) in ignore:
++ self._sigs[sig] = (False, False, True)
++ else:
++ self._sigs[sig] = (True, True, True)
++ signal.signal(num, self.handle)
++ else:
++ # Make an entry in the _sig dict for these signals
++ # even though they cannot be ignored or caught.
++ self._sigs[sig] = (False, False, True)
+
+ def info_signal(self, signame):
+ """Print information about a signal"""
+@@ -98,18 +65,14 @@
+ # This has come from pydb's info command
+ if len(signame) == 1:
+ self.pydb.msg(header)
+- for sig in self._sig_attr:
+- s = sig in self._sig_stop
+- pr = sig in self._sig_print
+- pa = sig in self._sig_pass
+- self.pydb.msg(fmt % (sig,s,pr,pa))
++ for sig in self._sigs.keys():
++ st, pr, pa = self._sigs[sig]
++ self.pydb.msg(fmt % (sig, st, pr, pa))
+ else:
+ self.info_signal(signame[1])
+ return
+
+- s = signame in self._sig_stop
+- pr = signame in self._sig_print
+- pa = signame in self._sig_pass
++ s, pr, pa = self._sigs[signame]
+ self.pydb.msg(header)
+ self.pydb.msg(fmt % (signame, s, pr, pa))
+
+@@ -121,74 +84,83 @@
+ self.info_signal(['handle'])
+ return
+ args = arg.split()
+- if args[0] in self._sig_attr:
+- if len(args) == 1:
+- self.info_signal(args[0])
+- return
+- # multiple commands might be specified, i.e. 'nopass nostop'
+- for attr in args[1:]:
+- if attr.startswith('no'):
+- on = False
+- attr = attr[2:]
+- else:
+- on = True
+- if attr.startswith('stop'):
+- self.handle_stop(args[0], on)
+- elif attr.startswith('print'):
+- self.handle_print(args[0], on)
+- elif attr.startswith('pass'):
+- self.handle_pass(args[0], on)
+- else:
+- self.pydb.errmsg('Invalid arguments')
++ try:
++ self._sigs[args[0]]
++ except KeyError:
++ return
++ if len(args) == 1:
++ self.info_signal(args[0])
++ return
++
++ # We can display information about 'fatal' signals, but not
++ # change their actions.
++ if args[0] in fatal_signals:
++ return
++
++ # multiple commands might be specified, i.e. 'nopass nostop'
++ for attr in args[1:]:
++ if attr.startswith('no'):
++ on = False
++ attr = attr[2:]
++ else:
++ on = True
++ if attr.startswith('stop'):
++ self.handle_stop(args[0], on)
++ elif attr.startswith('print'):
++ self.handle_print(args[0], on)
++ elif attr.startswith('pass'):
++ self.handle_pass(args[0], on)
++ else:
++ self.pydb.errmsg('Invalid arguments')
+
+- def handle_stop(self, signum, change):
++ def handle_stop(self, signame, change):
+ """Change whether we stop or not when this signal is caught.
+ If 'change' is True your program will stop when this signal
+ happens."""
+ if not isinstance(change, bool):
+ return
+- old_attr = self._get_sig(signum)
++ old_attr = self._sigs[signame]
+ st, pr, pa = change, old_attr[1], old_attr[2]
+ if st:
+ pr = True
+- self._set_sig(signum, (st, pr, pa))
++ self._sigs[signame] = (st, pr, pa)
+ return change
+
+- def handle_pass(self, signum, change):
++ def handle_pass(self, signame, change):
+ """Change whether we pass this signal to the program (or not)
+ when this signal is caught. If change is True, Pydb should allow
+ your program to see this signal.
+ """
+ if not isinstance(change, bool):
+ return
+- old_attr = self._get_sig(signum)
++ old_attr = self._sigs[signame]
+ st, pr, pa = old_attr[0], old_attr[1], change
+- self._set_sig(signum, (st, pr, pa))
++ self._sigs[signame] = (st, pr, pa)
+ return change
+
+ # ignore is a synonym for nopass and noignore is a synonym for pass
+- def handle_ignore(self, signum, change):
++ def handle_ignore(self, signame, change):
+ if not isinstance(change, bool):
+ return
+ self.handle_pass(not change)
+ return change
+
+- def handle_print(self, signum, change):
++ def handle_print(self, signame, change):
+ """Change whether we print or not when this signal is caught."""
+ if not isinstance(change, bool):
+ return
+- old_attr = self._get_sig(signum)
++ old_attr = self._sigs[signame]
+ st, pr, pa = old_attr[0], change, old_attr[2]
+ if not change:
+ # noprint implies nostop
+ st = False
+- self._set_sig(signum, (st, pr, pa))
++ self._sigs[signame] = (st, pr, pa)
+ return change
+
+ def handle(self, signum, frame):
+ """This method is called when a signal is received."""
+ sig = lookup_signame(signum)
+- st, pa, pr = self._get_sig(sig)
++ st, pa, pr = self._sigs[sig]
+ if pr:
+ self.pydb.msg('Program received signal %s' % sig)
+ if st:
+Index: test/Makefile.am
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/test/Makefile.am,v
+retrieving revision 1.17
+diff -u -r1.17 Makefile.am
+--- test/Makefile.am 28 Jul 2006 00:47:47 -0000 1.17
++++ test/Makefile.am 1 Aug 2006 18:08:56 -0000
+@@ -28,6 +28,8 @@
+ run.right \
+ run2.cmd \
+ run2.right \
++ sighandler.cmd \
++ sighandle.right \
+ test.py \
+ trace-2.5.right \
+ trace.py \
Added: sandbox/trunk/pdb/patches/06-08-06-sighandler.cmd
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/06-08-06-sighandler.cmd Mon Aug 21 17:49:31 2006
@@ -0,0 +1,16 @@
+info signal
+info handle
+handle SIGINT
+handle SIGINT stop pass noprint
+handle SIGINT
+handle SIGINT print
+handle SIGINT
+handle SIGINT nopass noprint nostop
+handle SIGINT
+info signal SIGINT
+# try changing fatal signal handlers (which are unchangable)
+handle SIGKILL stop
+handle SIGKILL
+handle SIGSTOP print
+handle SIGSTOP
+quit
Added: sandbox/trunk/pdb/patches/06-08-06-sighandler.right
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/06-08-06-sighandler.right Mon Aug 21 17:49:31 2006
@@ -0,0 +1,91 @@
+Signal Stop Print Pass to program
+
+SIGHUP True True True
+SIGSYS True True True
+SIGQUIT False False True
+SIGUSR1 True True True
+SIGFPE True True True
+SIGTSTP True True True
+SIGWINCH False False True
+SIGIOT True True True
+SIGBUS True True True
+SIGXCPU True True True
+SIGCONT True True True
+SIGPROF True True True
+SIGKILL False False True
+SIGSEGV True True True
+SIGINT False False True
+SIGIO False False True
+SIGTRAP False False True
+SIGILL False False True
+SIGEMT True True True
+SIGUSR2 True True True
+SIGABRT True True True
+SIGALRM False False True
+SIGXFSZ True True True
+SIGCHLD False False True
+SIGPIPE True True True
+SIGTERM False False True
+SIGVTALRM True True True
+SIGINFO True True True
+SIGURG False False True
+SIGPWR True True True
+SIGSTOP False False True
+SIGTTOU True True True
+SIGTTIN True True True
+Signal Stop Print Pass to program
+
+SIGHUP True True True
+SIGSYS True True True
+SIGQUIT False False True
+SIGUSR1 True True True
+SIGFPE True True True
+SIGTSTP True True True
+SIGWINCH False False True
+SIGIOT True True True
+SIGBUS True True True
+SIGXCPU True True True
+SIGCONT True True True
+SIGPROF True True True
+SIGKILL False False True
+SIGSEGV True True True
+SIGINT False False True
+SIGIO False False True
+SIGTRAP False False True
+SIGILL False False True
+SIGEMT True True True
+SIGUSR2 True True True
+SIGABRT True True True
+SIGALRM False False True
+SIGXFSZ True True True
+SIGCHLD False False True
+SIGPIPE True True True
+SIGTERM False False True
+SIGVTALRM True True True
+SIGINFO True True True
+SIGURG False False True
+SIGPWR True True True
+SIGSTOP False False True
+SIGTTOU True True True
+SIGTTIN True True True
+Signal Stop Print Pass to program
+
+SIGINT False False True
+Signal Stop Print Pass to program
+
+SIGINT False False True
+Signal Stop Print Pass to program
+
+SIGINT False True True
+Signal Stop Print Pass to program
+
+SIGINT False False False
+Signal Stop Print Pass to program
+
+SIGINT False False False
+Signal Stop Print Pass to program
+
+SIGKILL False False True
+Signal Stop Print Pass to program
+
+SIGSTOP False False True
Added: sandbox/trunk/pdb/patches/10-07-06-opts.diff
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/10-07-06-opts.diff Mon Aug 21 17:49:31 2006
@@ -0,0 +1,31 @@
+? configure.lineno
+Index: pydb/fns.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/fns.py,v
+retrieving revision 1.11
+diff -u -r1.11 fns.py
+--- pydb/fns.py 4 Jul 2006 06:02:46 -0000 1.11
++++ pydb/fns.py 10 Jul 2006 00:20:59 -0000
+@@ -147,12 +147,12 @@
+ except KeyboardInterrupt:
+ pass
+
+-def process_options(pydb, debugger_name, program, pkg_version):
++def process_options(pydb, debugger_name, program, pkg_version, option_list):
+ usage_str="""%s [debugger-options] python-script [script-options...]
+
+ Runs the extended python debugger""" % (program)
+
+- optparser = OptionParser(usage=usage_str,
++ optparser = OptionParser(usage=usage_str, option_list=option_list,
+ version="%%prog version %s" % pkg_version)
+
+ optparser.add_option("-X", "--trace", dest="linetrace",
+@@ -254,6 +254,7 @@
+ opts.errors
+ print sys.exc_info()[0]
+ sys.exit(2)
++ return opts
+
+ def search_file(filename, path, cdir):
+ """Return a full pathname for filename if we can find one. path
Added: sandbox/trunk/pdb/patches/11-08-06-pydb.diff
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/11-08-06-pydb.diff Mon Aug 21 17:49:31 2006
@@ -0,0 +1,196 @@
+? pydb.diff
+? pydb/.gdb.py.in.swp
+? test/sigtest.py.in
+? test/sigtestexample.py
+Index: Makefile.am
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/Makefile.am,v
+retrieving revision 1.33
+diff -u -r1.33 Makefile.am
+--- Makefile.am 1 Aug 2006 14:46:19 -0000 1.33
++++ Makefile.am 11 Aug 2006 15:36:47 -0000
+@@ -66,7 +66,7 @@
+ -rm $(top_builddir)/pydb/*.pyc
+
+ test: check
+-check: pydb/pydb.py pydb/gdb.py test/test.py test/pm.py
++check: pydb/pydb.py pydb/gdb.py test/test.py test/pm.py test/sigtest.py
+
+ #
+ # For the executable, we make a symbolic link to the python program,
+Index: configure.ac
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/configure.ac,v
+retrieving revision 1.35
+diff -u -r1.35 configure.ac
+--- configure.ac 29 Jul 2006 08:09:31 -0000 1.35
++++ configure.ac 11 Aug 2006 15:36:47 -0000
+@@ -126,6 +126,7 @@
+ AC_CONFIG_FILES([test/except.py],[chmod +x test/except.py])
+ AC_CONFIG_FILES([test/pm.py],[chmod +x test/pm.py])
+ AC_CONFIG_FILES([test/settrace.py],[chmod +x test/settrace.py])
++AC_CONFIG_FILES([test/sigtest.py], [chmod +x test/sigtest.py])
+ AC_CONFIG_FILES([test/test.py],[chmod +x test/test.py])
+ AC_CONFIG_FILES([test/trace.py],[chmod +x test/trace.py])
+
+Index: pydb/gdb.py.in
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/gdb.py.in,v
+retrieving revision 1.51
+diff -u -r1.51 gdb.py.in
+--- pydb/gdb.py.in 8 Aug 2006 01:34:05 -0000 1.51
++++ pydb/gdb.py.in 11 Aug 2006 15:36:49 -0000
+@@ -21,7 +21,7 @@
+ from pydbcmd import Cmd
+ from pydbbdb import Bdb
+
+-from sighandler import SigHandler
++from sighandler import SigHandler, lookup_signame, lookup_signum
+
+ class Restart(Exception):
+ """Causes a debugger to be restarted for the debugged Python program."""
+@@ -41,6 +41,7 @@
+
+ # set up signal handling
+ self._sig_handler = SigHandler(self)
++ self._reset_handler = None
+
+ self.__init_info()
+ self.__init_set()
+@@ -118,6 +119,23 @@
+ except ImportError:
+ self.histfile = None
+
++ def trace_dispatch(self, frame, event, arg):
++ for sig in self._sig_handler._sigs.keys():
++ if self._sig_handler._sigs[sig][0] == True:
++ import signal
++ sig_num = lookup_signum(sig)
++ old_handler = signal.getsignal(sig_num)
++ if old_handler != self._sig_handler.handle:
++ # save the program's signal handler
++ self._sig_handler.old_handlers[sig_num] = old_handler
++
++ # restore _our_ signal handler
++ signal.signal(sig_num, self._sig_handler.handle)
++
++ Bdb.trace_dispatch(self, frame, event, arg)
++ return self.trace_dispatch
++
++
+ def __adjust_frame(self, pos, absolute_pos):
+ """Adjust stack frame by pos positions. If absolute_pos then
+ pos is an absolute number. Otherwise it is a relative number.
+Index: pydb/sighandler.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/sighandler.py,v
+retrieving revision 1.6
+diff -u -r1.6 sighandler.py
+--- pydb/sighandler.py 8 Aug 2006 02:04:25 -0000 1.6
++++ pydb/sighandler.py 11 Aug 2006 15:36:49 -0000
+@@ -7,9 +7,8 @@
+ # - remove pychecker errors.
+ # - can remove signal handler altogether when
+ # ignore=True, print=False, pass=True
+-# - write real regression tests.
+-#
+ #
++#
+ import signal
+
+ def lookup_signame(num):
+@@ -44,6 +43,8 @@
+ def __init__(self, pydb):
+ self.pydb = pydb
+ self._sigs = {}
++
++ self.old_handlers = {}
+
+ # set up signal handling for some known signals
+ ignore= ['SIGALRM', 'SIGCHLD', 'SIGURG', 'SIGIO', 'SIGVTALRM'
+@@ -59,7 +60,8 @@
+ self._sigs[sig] = (False, False, True)
+ else:
+ self._sigs[sig] = (True, True, True)
+- signal.signal(num, self.handle)
++ old_handler = signal.signal(num, self.handle)
++ self.old_handlers[num] = old_handler
+ else:
+ # Make an entry in the _sig dict for these signals
+ # even though they cannot be ignored or caught.
+@@ -93,9 +95,7 @@
+ self.info_signal(['handle'])
+ return
+ args = arg.split()
+- try:
+- self._sigs[args[0]]
+- except KeyError:
++ if not self._sigs.has_key(args[0]):
+ return
+ if len(args) == 1:
+ self.info_signal(args[0])
+@@ -131,6 +131,7 @@
+ old_attr = self._sigs[signame]
+ st, pr, pa = change, old_attr[1], old_attr[2]
+ if st:
++ # stop keyword implies print
+ pr = True
+ self._sigs[signame] = (st, pr, pa)
+ return change
+@@ -151,7 +152,7 @@
+ def handle_ignore(self, signame, change):
+ if not isinstance(change, bool):
+ return
+- self.handle_pass(not change)
++ self.handle_pass(signame, not change)
+ return change
+
+ def handle_print(self, signame, change):
+@@ -169,10 +170,17 @@
+ def handle(self, signum, frame):
+ """This method is called when a signal is received."""
+ sig = lookup_signame(signum)
+- st, pa, pr = self._sigs[sig]
++ st, pr, pa = self._sigs[sig]
+ if pr:
+ self.pydb.msg('Program received signal %s' % sig)
+ if st:
+- # XXX Rocky what's the best way to handle this?
+ self.pydb.use_rawinput = False
++ self.pydb.step_ignore = 1
+ self.pydb.interaction(self.pydb.curframe, None)
++ if pa:
++ # pass the signal to the program by reinstating the old signal
++ # handler and send the signal to this process again
++ old_handler = self.old_handlers[signum]
++ signal.signal(signum, old_handler)
++ import os
++ os.kill(os.getpid(), signum)
+Index: test/Makefile.am
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/test/Makefile.am,v
+retrieving revision 1.18
+diff -u -r1.18 Makefile.am
+--- test/Makefile.am 8 Aug 2006 01:34:06 -0000 1.18
++++ test/Makefile.am 11 Aug 2006 15:36:49 -0000
+@@ -28,16 +28,16 @@
+ run.right \
+ run2.cmd \
+ run2.right \
+- sighandler.cmd \
+- sighandle.right \
++ sigtest.py \
++ sigtestexample.py \
+ test.py \
+ trace-2.5.right \
+ trace.py \
+ trace.right
+
+-TESTS = test.py pm.py trace.py
++TESTS = test.py pm.py trace.py sigtest.py
+
+ EXTRA_DIST = $(check_DATA) except.py.in pm.py.in \
+- settrace.py.in test.py.in trace.py.in
++ settrace.py.in test.py.in trace.py.in sigtest.py.in
+
+ test: check
Added: sandbox/trunk/pdb/patches/11-08-06-sigtest.py.in
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/11-08-06-sigtest.py.in Mon Aug 21 17:49:31 2006
@@ -0,0 +1,101 @@
+#!@PYTHON@ -t
+# $Id$
+"Unit test for Extended Python debugger's signal handling commands "
+import os, time, sys, unittest, signal
+
+top_builddir = "@top_builddir@"
+if top_builddir[-1] != os.path.sep:
+ top_builddir += os.path.sep
+sys.path.insert(0, os.path.join(top_builddir, 'pydb'))
+top_srcdir = "@top_srcdir@"
+if top_srcdir[-1] != os.path.sep:
+ top_srcdir += os.path.sep
+sys.path.insert(0, os.path.join(top_srcdir, 'pydb'))
+
+import pydb
+
+builddir = "@builddir@"
+if builddir[-1] != os.path.sep:
+ builddir += os.path.sep
+
+top_builddir = "@top_builddir@"
+if top_builddir[-1] != os.path.sep:
+ top_builddir += os.path.sep
+
+srcdir = "@srcdir@"
+if srcdir[-1] != os.path.sep:
+ srcdir += os.path.sep
+
+pydir = os.path.join(top_builddir, "pydb")
+pydb_short = "pydb.py"
+pydb_path = os.path.join(pydir, pydb_short)
+outfile = 'sighandler.out'
+program = 'sigtestexample.py'
+
+class SigTests(unittest.TestCase):
+ def tearDown(self):
+ try:
+ os.unlink(outfile)
+ except OSError:
+ pass
+
+ def create_proc(self, cmds):
+ pid = os.spawnlp(os.P_NOWAIT, pydb_path, pydb_path, '-o',
+ outfile, '-e', '%s' % cmds, program)
+ time.sleep(1.0)
+ return pid
+
+ def test_pass(self):
+ # Run pydb and turn on passing SIGUSR1 signal to the test programs'
+ # signal handler.
+ cmds = 'handle SIGUSR1 nostop;;step;;step'
+
+ pid = self.create_proc(cmds)
+
+ os.kill(pid, signal.SIGUSR1)
+ os.waitpid(pid, 0)
+
+
+ f = open('log', 'r')
+ line = f.readline()
+ f.close()
+ self.assertEqual(line, 'signal received\n')
+ os.unlink('log')
+
+ f = open(outfile, 'r')
+ lines = f.readlines()
+ f.close()
+ self.assertFalse('Program received signal' in lines)
+
+ def test_nopass(self):
+ # Run pydb and intercept the signal SIGUSR1 instead of passing it
+ # to the program.
+ cmds = 'handle SIGUSR1 nopass nostop'
+
+ pid = self.create_proc(cmds)
+
+ os.kill(pid, signal.SIGUSR1)
+ os.waitpid(pid, 0)
+
+ f = open(outfile, 'r')
+ lines = f.readlines()
+ f.close()
+
+ self.assertEqual(lines[1], 'Program received signal SIGUSR1\n')
+
+ def test_noprint(self):
+ cmds = "handle SIGUSR1 noprint nopass"
+ pid = self.create_proc(cmds)
+
+ os.kill(pid, signal.SIGUSR1)
+ os.waitpid(pid, 0)
+
+ f = open(outfile, 'r')
+ lines = f.readlines()
+ f.close()
+
+ self.assertFalse('Program received signal SIGUSR1\n' in lines)
+ self.assertRaises(IOError, open, 'log', 'r')
+
+if __name__ == '__main__':
+ unittest.main()
Added: sandbox/trunk/pdb/patches/11-08-06-sigtestexample.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/11-08-06-sigtestexample.py Mon Aug 21 17:49:31 2006
@@ -0,0 +1,9 @@
+def func(num, f):
+ f = open('log', 'w+')
+ f.write('signal received\n')
+ f.close()
+
+import signal
+signal.signal(signal.SIGUSR1, func)
+
+x = 2
Added: sandbox/trunk/pdb/patches/20-08-06-threaddbg.patch
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/20-08-06-threaddbg.patch Mon Aug 21 17:49:31 2006
@@ -0,0 +1,306 @@
+--- threaddbg.py 2006/08/07 02:25:13 1.3
++++ threaddbg.py 2006/08/19 20:57:38
+@@ -9,9 +9,23 @@
+ ### -
+
+ import bdb, inspect, os, pydb, sys
+-
++from bdb import Breakpoint, checkfuncname
++from pydb.pydbbdb import checkline
+ import thread, threading
+
++class TBreakpoint(Breakpoint):
++
++ """Per-thread Breakpoint class."""
++
++ next = 1
++ bplist = {}
++ bpbynumber = [None]
++
++ def __init__(self, file, line, temporary=0, cond=None, funcname=None,
++ threadname=None):
++ Breakpoint.__init__(self, file, line, temporary, cond, funcname)
++ self.threadname = threadname
++
+ class threadDbg(pydb.Pdb):
+
+ def __init__(self, completekey='tab', stdin=None, stdout=None):
+@@ -20,6 +34,8 @@
+ self.add_hook()
+ self.stack = self.curframe = self.botframe = None
+
++ self.t_breaks = {'MainThread': {}}
++
+ # desired_thread is the thread we want to switch to after issuing
+ # a "thread <thread-name>" command.
+ self.desired_thread=None
+@@ -193,6 +209,7 @@
+ # Record in my own table a list of thread names
+ if not thread_name in self.traced.keys():
+ self.traced[thread_name] = thread.get_ident()
++ self.t_breaks[thread_name] = {}
+
+ # See if there was a request to switch to a specific thread
+ while self.desired_thread not in (None,
+@@ -205,11 +222,9 @@
+ self.threading_lock.acquire()
+
+ if self.desired_thread != None:
+- print "Hey we just did a switch to %s!" % self.desired_thread
+ self.threading_cond.acquire()
+ self.threading_cond.notifyAll()
+ self.threading_cond.release()
+- print "notify done from %s" % threading.currentThread().getName()
+
+ self.desired_thread = None
+
+@@ -256,3 +271,249 @@
+ statement = 'execfile( "%s")' % filename
+ self.run(statement, globals=globals_, locals=locals_)
+
++ def info_breakpoints(self, arg):
++ threadname = threading.currentThread().getName()
++ if not self.breaks and not self.t_breaks[threadname]:
++ self.msg('No breakpoints')
++ return
++
++ have_breaks = False
++ if self.breaks:
++ pydb.Pdb.info_breakpoints(self, arg)
++ have_breaks = True
++ if self.t_breaks[threadname]:
++ self.msg("\nThread-specific breakpoints:")
++ self.msg("Num Type Disp Enb Where Thread")
++ for bp in TBreakpoint.bpbynumber:
++ if bp:
++ self.tbpprint(bp)
++ else:
++ if not have_breaks: self.msg("No breakpoints.")
++
++ info_breakpoints.__doc__ = pydb.Pdb.info_breakpoints.__doc__
++
++ def set_break(self, filename, lineno, temporary=0, cond=None, funcname=None,
++ threadname=None):
++ if threadname is None:
++ pydb.Pdb.set_break(self, filename, lineno, temporary, cond, funcname)
++ else:
++ filename = self.canonic(filename)
++ import linecache
++ line = linecache.getline(filename, lineno)
++ if not line:
++ return 'Line %s:%d does not exist' % (filename, lineno)
++
++ if not filename in self.t_breaks:
++ self.t_breaks[threadname][filename] = []
++ blist = self.t_breaks[threadname][filename]
++ if not lineno in blist:
++ blist.append(lineno)
++ bp = TBreakpoint(filename, lineno, temporary, cond, funcname, threadname)
++
++ def do_break(self, arg, temporary=0):
++ if 'thread' not in arg:
++ # We only deal with thread-spefic breakpoints. pydb handles
++ # all others.
++ pydb.Pdb.do_break(self, arg)
++ return
++
++ if not self.curframe:
++ self.msg("No stack.")
++ return
++ # Pull the 'thread' command and threadname out of the args
++ threadname = arg[arg.find('thread')+7:]
++ print threadname.__repr__()
++ arg = arg[:arg.find('thread')-1]
++ cond = None
++ funcname = None
++ if not arg:
++ if self.lineno is None:
++ lineno = max(1, inspect.getlineno(self.curframe))
++ else:
++ lineno = self.lineno + 1
++ filename = self.curframe.f_code.co_filename
++ else:
++ filename = None
++ lineno = None
++ comma = arg.find(',')
++ if comma > 0:
++ cond = arg[comma+1:].lstrip()
++ arg = arg[:comma].rstrip()
++ (funcname, filename, lineno) = self.parse_fileops(arg)
++
++ if not filename:
++ filename = self.defaultFile()
++
++ line = checkline(self, filename, lineno)
++ if line:
++ try:
++ err = self.set_break(filename, line, temporary, cond, funcname, threadname)
++ except TypeError:
++ err = self.set_break(filename, line, temporary, cond, threadname)
++
++ if err: self.errmsg(err)
++ else:
++ bp = self.get_breaks(filename, line, threadname)[-1]
++ self.msg("Breakpoint %d set in file %s, line %d, thread %s."
++ % (bp.number, self.filename(bp.file), bp.line, bp.threadname))
++
++ do_break.__doc__ = pydb.Pdb.do_break.__doc__
++
++ # XXX This is an _exact_ copy of __parse_fileops from gdb.py
++ # It's only included because of the name mangling
++ def parse_fileops(self, arg):
++ colon = arg.find(':')
++ if colon >= 0:
++ filename = arg[:colon].rstrip()
++ f = self.lookupmodule(filename)
++ if not f:
++ self.errmsg("%s not found on sys.path" %
++ self.saferepr(filename))
++ return (None, None, None)
++ else:
++ filename = f
++ arg = arg[colon+1:].lstrip()
++ try:
++ lineno = int(arg)
++ except TypeError:
++ self.errmsg("Bad lineno: %s", str(arg))
++ return (None, filename, None)
++ return (None, filename, lineno)
++ else:
++ # no colon: can be lineno or function
++ return self.get_brkpt_lineno(arg)
++
++ # Likewise, this method is only included because of the namespace mangling
++ def get_brkpt_lineno(self, arg):
++ funcname, filename = (None, None)
++ try:
++ lineno = int(arg)
++ filename = self.curframe.f_code.co_filename
++ except ValueError:
++ try:
++ func = eval(arg, self.curframe.f_globals,
++ self.curframe.f_locals)
++ except:
++ func = arg
++ try:
++ if hasattr(func, 'im_func'):
++ func = func.im_func
++ code = func.func_code
++ lineno = code.co_firstlineno
++ filename = code.co_filename
++ except:
++ (ok, filename, ln) = self.lineinfo(arg)
++ if not ok:
++ self.errmsg(('The specified object %s is not'
++ +' a fucntion, or not found'
++ +' along sys.path or not line given.')
++ % str(repr(arg)))
++ return (None, None, None)
++ funcname = ok
++ lineno = int(ln)
++ return (funcname, filename, lineno)
++
++ def get_breaks(self, filename, lineno, threadname=None):
++ if threadname is None:
++ return pydb.Pdb.get_breaks(self, filename, lineno)
++ filename = self.canonic(filename)
++ return filename in self.t_breaks[threadname] and \
++ lineno in self.t_breaks[threadname][filename] and \
++ TBreakpoint.bplist[filename, lineno] or []
++
++ def tbpprint(self, bp, out=None):
++ if bp.temporary:
++ disp = 'del '
++ else:
++ disp = 'keep '
++ if bp.enabled:
++ disp = disp + 'y '
++ else:
++ disp = disp + 'n '
++ self.msg('%-4dbreakpoint %s at %s:%d in %s' %
++ (bp.number, disp, self.filename(bp.file), bp.line, bp.threadname), out)
++ if bp.cond:
++ self.msg('\tstop only if %s' % (bp.cond))
++ if bp.ignore:
++ self.msg('\tignore next %d hits' % (bp.ignore), out)
++ if (bp.hits):
++ if (bp.hits > 1): ss = 's'
++ else: ss = ''
++ self.msg('\tbreakpoint already hit %d time%s' %
++ (bp.hits, ss), out)
++
++ def break_here(self, frame):
++ if pydb.Pdb.break_here(self, frame):
++ return True
++
++ threadname = threading.currentThread().getName()
++ filename = self.canonic(frame.f_code.co_filename)
++ if not filename in self.t_breaks[threadname]:
++ return False
++ lineno = frame.f_lineno
++ if not lineno in self.t_breaks[threadname][filename]:
++ # The line itself has no breakpoint, but maybe the line is the
++ # first line of a function with breakpoint set by function name.
++ lineno = frame.f_code.co_firstlineno
++ if not lineno in self.t_breaks[threadname][filename]:
++ return False
++
++ # flag says ok to delete temp. bp
++ (bp, flag) = effective(filename, lineno, frame)
++ if bp:
++ self.currentbp = bp.number
++ if (flag and bp.temporary):
++ self.do_clear(str(bp.number))
++ return True
++ else:
++ return False
++
++def effective(file, line, frame):
++ """Determine which breakpoint for this file:line is to be acted upon.
++
++ Called only if we know there is a bpt at this
++ location. Returns breakpoint that was triggered and a flag
++ that indicates if it is ok to delete a temporary bp.
++
++ """
++ possibles = TBreakpoint.bplist[file,line]
++ for i in range(0, len(possibles)):
++ b = possibles[i]
++ if b.enabled == 0:
++ continue
++ if not checkfuncname(b, frame):
++ continue
++ # Count every hit when bp is enabled
++ b.hits = b.hits + 1
++ if not b.cond:
++ # If unconditional, and ignoring,
++ # go on to next, else break
++ if b.ignore > 0:
++ b.ignore = b.ignore -1
++ continue
++ else:
++ # breakpoint and marker that's ok
++ # to delete if temporary
++ return (b,1)
++ else:
++ # Conditional bp.
++ # Ignore count applies only to those bpt hits where the
++ # condition evaluates to true.
++ try:
++ val = eval(b.cond, frame.f_globals,
++ frame.f_locals)
++ if val:
++ if b.ignore > 0:
++ b.ignore = b.ignore -1
++ # continue
++ else:
++ return (b,1)
++ except:
++ # if eval fails, most conservative
++ # thing is to stop on breakpoint
++ # regardless of ignore count.
++ # Don't delete temporary,
++ # as another hint to user.
++ return (b,0)
++ return (None, None)
++
Added: sandbox/trunk/pdb/patches/24-07-06-pydb.diff
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/24-07-06-pydb.diff Mon Aug 21 17:49:31 2006
@@ -0,0 +1,221 @@
+? configure.lineno
+Index: pydb/gdb.py.in
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/gdb.py.in,v
+retrieving revision 1.41
+diff -u -r1.41 gdb.py.in
+--- pydb/gdb.py.in 22 Jul 2006 22:39:18 -0000 1.41
++++ pydb/gdb.py.in 24 Jul 2006 14:36:15 -0000
+@@ -258,7 +258,7 @@
+ self.showcmds.add('args', self.show_args)
+ self.showcmds.add('basename', self.show_basename)
+ self.showcmds.add('cmdtrace', self.show_cmdtrace, 2)
+- self.showcmds.add('commands', self.show_commands, 2)
++ self.showcmds.add('commands', self.show_commands, 2, False)
+ self.showcmds.add('history', self.show_history)
+ self.showcmds.add('interactive', self.show_interactive)
+ self.showcmds.add('linetrace', self.show_linetrace, 3)
+@@ -1096,87 +1096,14 @@
+ get info about just that subcommand."""
+
+ if not arg:
+- self.help_info([])
++ for subcommand in self.infocmds.list():
++ self.msg_nocr("%s: " % subcommand)
++ self.do_info(subcommand)
+ return
+
+- arglist = arg.split()
+- arg = arglist[0]
+- frame=self.curframe
+- if "args".startswith(arg):
+- if not self.curframe:
+- self.msg("No stack.")
+- return
+- self.info_args(None)
+- elif "break".startswith(arg):
+- # FIXME: Should split out the "info" part in args
+- self.do_L(None)
+- elif 'display'.startswith(arg):
+- if not self.display.displayAll():
+- self.msg('There are no auto-display expressions now.')
+- elif "globals".startswith(arg):
+- if not frame:
+- self.msg("No frame selected.")
+- return
+- self.msg("\n".join(["%s = %s"
+- % (l, pprint.pformat(self.getval(l)))
+- for l in frame.f_globals]))
+- elif "line".startswith(arg) and len(arg) > 1:
+- #info line identifier
+- if not frame:
+- self.msg("No line number information available.")
+- return
+- if len(arglist) == 2:
+- # lineinfo returns (item, file, lineno) or (None,)
+- answer = self.lineinfo(arglist[1])
+- if answer[0]:
+- item, file, lineno = answer
+- if not os.path.isfile(file):
+- file = search_file(file, self.search_path,
+- self.main_dirname)
+- self.msg('Line %s of "%s" <%s>' %
+- (lineno, file, item))
+- return
+- #info line
+- file=self.canonic_filename(frame)
+- if not os.path.isfile(file):
+- file = search_file(file, self.search_path, self.main_dirname)
+-
+- self.msg('Line %d of \"%s\" at instruction %d' %
+- (inspect.getlineno(frame),
+- self.filename(self.canonic_filename(frame)),
+- self.curframe.f_lasti))
+- elif "locals".startswith(arg) and len(arg) > 1:
+- if not frame:
+- self.msg("No frame selected.")
+- return
+- self.msg("\n".join(["%s = %s"
+- % (l, pprint.pformat(self.getval(l)))
+- for l in frame.f_locals]))
+- elif 'program'.startswith(arg):
+- if not frame:
+- self.msg("The program being debugged is not being run.")
+- return
+- if self.is_running():
+- self.msg('Program stopped.')
+- if self.currentbp:
+- self.msg('It stopped at breakpoint %d.' % self.currentbp)
+- elif self.stop_reason == 'call':
+- self.msg('It stopped at a call.')
+- elif self.stop_reason == 'exception':
+- self.msg('It stopped as a result of an exception.')
+- elif self.stop_reason == 'return':
+- self.msg('It stopped at a return.')
+- else:
+- self.msg("It stopped after stepping, next'ing or initial start.")
+- return
+- elif "source".startswith(arg):
+- if not frame:
+- self.msg("No current source file.")
+- return
+- self.msg('Current Python file is %s' %
+- self.filename(self.canonic_filename(frame)))
+ else:
+- self.undefined_cmd("info", arg)
++ args = arg.split()
++ self.infocmds.do(self, args[0], args)
+
+ def info_break(self, arg):
+ """info break
+Index: pydb/pydbcmd.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/pydbcmd.py,v
+retrieving revision 1.23
+diff -u -r1.23 pydbcmd.py
+--- pydb/pydbcmd.py 22 Jul 2006 22:39:18 -0000 1.23
++++ pydb/pydbcmd.py 24 Jul 2006 14:36:15 -0000
+@@ -6,7 +6,7 @@
+ of more oriented towards any gdb-like debugger. Also routines that need to
+ be changed from cmd are here.
+ """
+-import cmd, linecache, os, sys, types
++import cmd, linecache, os, pprint, sys, types
+ from fns import *
+
+ # Interaction prompt line will separate file and call info from code
+@@ -274,7 +274,7 @@
+ self.commands_doprompt[self.commands_bnum] = False
+ self.cmdqueue = []
+ return 1
+- return
++ return
+
+ def info_args(self, arg):
+ """Argument variables of current stack frame"""
+@@ -318,9 +318,9 @@
+ if not self.curframe:
+ self.msg("No line number information available.")
+ return
+- if len(arglist) == 2:
++ if len(arg) == 2:
+ # lineinfo returns (item, file, lineno) or (None,)
+- answer = self.lineinfo(arglist[1])
++ answer = self.lineinfo(arg[1])
+ if answer[0]:
+ item, file, lineno = answer
+ if not os.path.isfile(file):
+@@ -329,6 +329,14 @@
+ self.msg('Line %s of "%s" <%s>' %
+ (lineno, file, item))
+ return
++ file=self.canonic_filename(self.curframe)
++ if not os.path.isfile(file):
++ file = search_file(file, self.search_path, self.main_dirname)
++
++ self.msg('Line %d of \"%s\" at instruction %d' %
++ (inspect.getlineno(self.curframe),
++ self.filename(self.canonic_filename(self.curframe)),
++ self.curframe.f_lasti))
+
+ def info_locals(self, arg):
+ """Local variables of current stack frame"""
+@@ -362,7 +370,7 @@
+ self.msg("No current source file.")
+ return
+ self.msg('Current Python file is %s' %
+- self.filename(self.canonic_filename(frame)))
++ self.filename(self.canonic_filename(self.curframe)))
+
+ def msg(self, msg, out=None):
+ """Common routine for reporting messages.
+Index: pydb/subcmd.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/subcmd.py,v
+retrieving revision 1.1
+diff -u -r1.1 subcmd.py
+--- pydb/subcmd.py 22 Jul 2006 22:39:18 -0000 1.1
++++ pydb/subcmd.py 24 Jul 2006 14:36:15 -0000
+@@ -24,7 +24,11 @@
+
+ entry=self.lookup(subcmd_name)
+ if entry:
+- obj.msg(entry['doc'])
++ d = entry['doc']
++ # Only print one line of the docstring, stopping at the full-stop.
++ if '.' in d:
++ d = d[:d.find('.')]
++ obj.msg(d)
+ return
+ obj.undefined_cmd("help", subcmd_name)
+
+@@ -75,6 +79,10 @@
+
+ def list(self):
+ l=self.subcmds.keys()
++ for i in l:
++ # Remove subcmd if we don't want it displayed in the list
++ if not self.subcmds[i]['in_list']:
++ l.pop(l.index(i))
+ l.sort()
+ return l
+
+Index: test/cmdparse.right
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/test/cmdparse.right,v
+retrieving revision 1.19
+diff -u -r1.19 cmdparse.right
+--- test/cmdparse.right 22 Jul 2006 22:39:18 -0000 1.19
++++ test/cmdparse.right 24 Jul 2006 14:36:15 -0000
+@@ -295,10 +295,9 @@
+ show args -- Show argument list to give debugged program on start
+ show basename -- Show if we are to show short of long filenames
+ show cmdtrace -- Show if we are to show debugger commands before running
+-show commands -- Show the history of commands you typed
+ show history -- Generic command for showing command history parameters
+ show interactive -- Show whether we are interactive
+-show linetrace -- Show the line tracing status. Can also add 'delay'
++show linetrace -- Show the line tracing status
+ show listsize -- Show number of source lines the debugger will list by default
+ show logging -- Show logging options
+ show prompt -- Show debugger's prompt
Added: sandbox/trunk/pdb/patches/24-07-06-pydb2.diff
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/24-07-06-pydb2.diff Mon Aug 21 17:49:31 2006
@@ -0,0 +1,269 @@
+Index: pydb/gdb.py.in
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/gdb.py.in,v
+retrieving revision 1.41
+diff -u -r1.41 gdb.py.in
+--- pydb/gdb.py.in 22 Jul 2006 22:39:18 -0000 1.41
++++ pydb/gdb.py.in 24 Jul 2006 16:53:11 -0000
+@@ -258,7 +258,7 @@
+ self.showcmds.add('args', self.show_args)
+ self.showcmds.add('basename', self.show_basename)
+ self.showcmds.add('cmdtrace', self.show_cmdtrace, 2)
+- self.showcmds.add('commands', self.show_commands, 2)
++ self.showcmds.add('commands', self.show_commands, 2, False)
+ self.showcmds.add('history', self.show_history)
+ self.showcmds.add('interactive', self.show_interactive)
+ self.showcmds.add('linetrace', self.show_linetrace, 3)
+@@ -1096,87 +1096,14 @@
+ get info about just that subcommand."""
+
+ if not arg:
+- self.help_info([])
++ for subcommand in self.infocmds.list():
++ self.msg_nocr("%s: " % subcommand)
++ self.do_info(subcommand)
+ return
+
+- arglist = arg.split()
+- arg = arglist[0]
+- frame=self.curframe
+- if "args".startswith(arg):
+- if not self.curframe:
+- self.msg("No stack.")
+- return
+- self.info_args(None)
+- elif "break".startswith(arg):
+- # FIXME: Should split out the "info" part in args
+- self.do_L(None)
+- elif 'display'.startswith(arg):
+- if not self.display.displayAll():
+- self.msg('There are no auto-display expressions now.')
+- elif "globals".startswith(arg):
+- if not frame:
+- self.msg("No frame selected.")
+- return
+- self.msg("\n".join(["%s = %s"
+- % (l, pprint.pformat(self.getval(l)))
+- for l in frame.f_globals]))
+- elif "line".startswith(arg) and len(arg) > 1:
+- #info line identifier
+- if not frame:
+- self.msg("No line number information available.")
+- return
+- if len(arglist) == 2:
+- # lineinfo returns (item, file, lineno) or (None,)
+- answer = self.lineinfo(arglist[1])
+- if answer[0]:
+- item, file, lineno = answer
+- if not os.path.isfile(file):
+- file = search_file(file, self.search_path,
+- self.main_dirname)
+- self.msg('Line %s of "%s" <%s>' %
+- (lineno, file, item))
+- return
+- #info line
+- file=self.canonic_filename(frame)
+- if not os.path.isfile(file):
+- file = search_file(file, self.search_path, self.main_dirname)
+-
+- self.msg('Line %d of \"%s\" at instruction %d' %
+- (inspect.getlineno(frame),
+- self.filename(self.canonic_filename(frame)),
+- self.curframe.f_lasti))
+- elif "locals".startswith(arg) and len(arg) > 1:
+- if not frame:
+- self.msg("No frame selected.")
+- return
+- self.msg("\n".join(["%s = %s"
+- % (l, pprint.pformat(self.getval(l)))
+- for l in frame.f_locals]))
+- elif 'program'.startswith(arg):
+- if not frame:
+- self.msg("The program being debugged is not being run.")
+- return
+- if self.is_running():
+- self.msg('Program stopped.')
+- if self.currentbp:
+- self.msg('It stopped at breakpoint %d.' % self.currentbp)
+- elif self.stop_reason == 'call':
+- self.msg('It stopped at a call.')
+- elif self.stop_reason == 'exception':
+- self.msg('It stopped as a result of an exception.')
+- elif self.stop_reason == 'return':
+- self.msg('It stopped at a return.')
+- else:
+- self.msg("It stopped after stepping, next'ing or initial start.")
+- return
+- elif "source".startswith(arg):
+- if not frame:
+- self.msg("No current source file.")
+- return
+- self.msg('Current Python file is %s' %
+- self.filename(self.canonic_filename(frame)))
+ else:
+- self.undefined_cmd("info", arg)
++ args = arg.split()
++ self.infocmds.do(self, args[0], args)
+
+ def info_break(self, arg):
+ """info break
+@@ -1468,8 +1395,10 @@
+
+ if not arg:
+ for subcommand in self.showcmds.list():
+- self.msg_nocr("%s: " % subcommand)
+- self.do_show(subcommand)
++ # Only display commands that are 'in_list'
++ if self.showcmds.subcmds[subcommand]['in_list']:
++ self.msg_nocr("%s: " % subcommand)
++ self.do_show(subcommand)
+ return
+
+ if self._re_linetrace_delay.match(arg):
+Index: pydb/pydbcmd.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/pydbcmd.py,v
+retrieving revision 1.23
+diff -u -r1.23 pydbcmd.py
+--- pydb/pydbcmd.py 22 Jul 2006 22:39:18 -0000 1.23
++++ pydb/pydbcmd.py 24 Jul 2006 16:53:11 -0000
+@@ -6,7 +6,7 @@
+ of more oriented towards any gdb-like debugger. Also routines that need to
+ be changed from cmd are here.
+ """
+-import cmd, linecache, os, sys, types
++import cmd, linecache, os, pprint, sys, types
+ from fns import *
+
+ # Interaction prompt line will separate file and call info from code
+@@ -104,6 +104,10 @@
+ try:
+ doc=getattr(self, 'do_' + first_arg).__doc__
+ if doc:
++ # We only print the first line, removing any periods
++ # if they are the last character on the line
++ doc = doc[:doc.find('\n')]
++ if doc[-1] == '.': doc = doc[:-1]
+ self.msg("%s\n" % str(doc))
+ return
+ except AttributeError:
+@@ -274,7 +278,7 @@
+ self.commands_doprompt[self.commands_bnum] = False
+ self.cmdqueue = []
+ return 1
+- return
++ return
+
+ def info_args(self, arg):
+ """Argument variables of current stack frame"""
+@@ -318,9 +322,9 @@
+ if not self.curframe:
+ self.msg("No line number information available.")
+ return
+- if len(arglist) == 2:
++ if len(arg) == 2:
+ # lineinfo returns (item, file, lineno) or (None,)
+- answer = self.lineinfo(arglist[1])
++ answer = self.lineinfo(arg[1])
+ if answer[0]:
+ item, file, lineno = answer
+ if not os.path.isfile(file):
+@@ -329,6 +333,14 @@
+ self.msg('Line %s of "%s" <%s>' %
+ (lineno, file, item))
+ return
++ file=self.canonic_filename(self.curframe)
++ if not os.path.isfile(file):
++ file = search_file(file, self.search_path, self.main_dirname)
++
++ self.msg('Line %d of \"%s\" at instruction %d' %
++ (inspect.getlineno(self.curframe),
++ self.filename(self.canonic_filename(self.curframe)),
++ self.curframe.f_lasti))
+
+ def info_locals(self, arg):
+ """Local variables of current stack frame"""
+@@ -362,7 +374,7 @@
+ self.msg("No current source file.")
+ return
+ self.msg('Current Python file is %s' %
+- self.filename(self.canonic_filename(frame)))
++ self.filename(self.canonic_filename(self.curframe)))
+
+ def msg(self, msg, out=None):
+ """Common routine for reporting messages.
+Index: pydb/subcmd.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/subcmd.py,v
+retrieving revision 1.1
+diff -u -r1.1 subcmd.py
+--- pydb/subcmd.py 22 Jul 2006 22:39:18 -0000 1.1
++++ pydb/subcmd.py 24 Jul 2006 16:53:12 -0000
+@@ -17,14 +17,21 @@
+ return self.subcmds[subcmd_name]
+ return None
+
+- def _subcmd_helper(self, subcmd_name, obj, label=False):
++ def _subcmd_helper(self, subcmd_name, obj, label=False, strip=False):
+ """Show help for a single subcommand"""
+ if label:
+ obj.msg_nocr("%s %s --" % (self.name, subcmd_name))
+
+ entry=self.lookup(subcmd_name)
+ if entry:
+- obj.msg(entry['doc'])
++ d = entry['doc']
++ if strip:
++ # Limit the help message to one line (delimited by '\n')
++ if '\n' in d:
++ d = d[:d.find('\n')]
++ # If the last character is a period, remove it.
++ if d[-1] == '.': d = d[:d.find('.')]
++ obj.msg(d)
+ return
+ obj.undefined_cmd("help", subcmd_name)
+
+@@ -54,7 +61,7 @@
+
+ # Note: format of help is compatible with ddd.
+ def help(self, obj, *args):
+- """help for subcommands"""
++ """help for subcommands."""
+
+ subcmd_prefix=args[0]
+ if not subcmd_prefix or len(subcmd_prefix) == 0:
+@@ -63,7 +70,7 @@
+ List of %s subcommands:
+ """ % (self.name))
+ for subcmd_name in self.list():
+- self._subcmd_helper(subcmd_name, obj, True)
++ self._subcmd_helper(subcmd_name, obj, True, True)
+ return
+
+ entry=self.lookup(subcmd_prefix)
+@@ -75,6 +82,10 @@
+
+ def list(self):
+ l=self.subcmds.keys()
++ for i in l:
++ # Remove subcmd if we don't want it displayed in the list
++ if not self.subcmds[i]['in_list']:
++ l.pop(l.index(i))
+ l.sort()
+ return l
+
+Index: test/cmdparse.right
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/test/cmdparse.right,v
+retrieving revision 1.19
+diff -u -r1.19 cmdparse.right
+--- test/cmdparse.right 22 Jul 2006 22:39:18 -0000 1.19
++++ test/cmdparse.right 24 Jul 2006 16:53:12 -0000
+@@ -295,7 +295,6 @@
+ show args -- Show argument list to give debugged program on start
+ show basename -- Show if we are to show short of long filenames
+ show cmdtrace -- Show if we are to show debugger commands before running
+-show commands -- Show the history of commands you typed
+ show history -- Generic command for showing command history parameters
+ show interactive -- Show whether we are interactive
+ show linetrace -- Show the line tracing status. Can also add 'delay'
Added: sandbox/trunk/pdb/patches/27-07-06-pydb.diff
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/27-07-06-pydb.diff Mon Aug 21 17:49:31 2006
@@ -0,0 +1,27 @@
+Index: pydb/fns.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/fns.py,v
+retrieving revision 1.17
+diff -u -r1.17 fns.py
+--- pydb/fns.py 13 Jul 2006 07:45:09 -0000 1.17
++++ pydb/fns.py 27 Jul 2006 17:48:29 -0000
+@@ -256,6 +256,9 @@
+ action="store", type='string',
+ help="Write debugger's error output "
+ + "(stderr) to FILE")
++ optparser.add_option("-e", "--exec", dest="execute", type="string",
++ help="A comma-separate list of commands to " +
++ "execute.")
+
+ # Set up to stop on the first non-option because that's the name
+ # of the script to be debugged on arguments following that are
+@@ -297,6 +300,9 @@
+ if opts.command:
+ pydb.setup_source(os.path.expanduser(opts.command), True);
+
++ if opts.execute:
++ pydb.cmdqueue = list(opts.execute.split(','))
++
+ if opts.output:
+ try:
+ pydb.stdout = open(opts.output, 'w')
Added: sandbox/trunk/pdb/patches/27-07-06-sighandler.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/27-07-06-sighandler.py Mon Aug 21 17:49:31 2006
@@ -0,0 +1,112 @@
+"""$Id $
+Handles signal handlers within Pydb.
+"""
+import signal
+
+def lookup_signum(name):
+ """Find the corresponding signal number for 'name'."""
+ try:
+ exec 'from signal import %s' % name
+ except ImportError:
+ return
+ return eval(name)
+
+# XXX Rocky, do you think the do_* methods are confusing? I.e. that someone
+# will think they work the same way as the do_* method from cmd.Cmd?
+# I used it because print and pass are keywords and trying to strip out the
+# 'i' and 'a' from print and pass respectively, when this code is used in
+# another file is just.. mad.. 'do' made sense to me.
+
+class SigHandler:
+
+ """Store information about what we do when we handle a signal,
+
+ - Do we print/not print when signal is caught
+ - Do we pass/not pass the signal to the program
+ - Do we stop/not stop when signal is caught
+
+ All the methods to change these attributes return None on error, or
+ True or False if we have set the action (pass/print/stop) for a signal
+ handler.
+ """
+ def __init__(self, signum):
+
+ # This list contains tuples made up of four items, one tuple for
+ # every available signal number on this system. The tuples contain
+ # (signal_num, stop, print, pass)
+ self._sig_attr = []
+
+ for i in range(1, NSIG):
+ try:
+ d_handler = signal.getsignal(i)
+ self._sig_nums.append((i, True, True, True))
+ except RuntimeError:
+ # A runtime exception can be raised if we ask for the signal
+ # handler for a signal that doesn't exist.
+ continue
+
+ def _get_sig(self, num):
+ for i in self._sig_attr:
+ if i[0] == num:
+ return i[1:]
+
+ def _set_sig(self, num, (st, pr, pa)):
+ for i in self._sig_attr:
+ if i[0] == num:
+ self._sig_attr.pop(self._sig_attr.index(i))
+ self._sig_attr.append((num, st, pr, pa))
+
+ def do_stop(self, signum, change):
+ """Change whether we stop or not when this signal is caught.
+ If 'change' is True your program will stop when this signal
+ happens."""
+ if not isinstance(change, bool):
+ return
+ old_attr = self._get_sig(signum)
+ st, pr, pa = change, old_attr[1], old_attr[2]
+ if st:
+ pr = True
+ self._set_sig(signum, (st, pr, pa))
+ return change
+
+ def do_pass(self, signum, change):
+ """Change whether we pass this signal to the program (or not)
+ when this signal is caught. If change is True, Pydb should allow
+ your program to see this signal.
+ """
+ if not isinstance(change, bool):
+ return
+ old_attr = self._get_sig(signum)
+ st, pr, pa = old_attr[0], old_attr[1], change
+ self._set_sig(signum, (st, pr, pa))
+ return change
+
+ # ignore is a synonym for nopass and noignore is a synonym for pass
+ def do_ignore(self, signum, change):
+ if not isinstance(change, bool):
+ return
+ self.do_pass(not change)
+ return change
+
+ def do_print(self, signum, change):
+ """Change whether we print or not when this signal is caught."""
+ if not isinstance(change, bool):
+ return
+ old_attr = self._get_sig(signum)
+ st, pr, pa = old_attr[0], change, old_attr[2]
+ if not change:
+ # noprint implies nostop
+ st = False
+ self._set_sig(signum, (st, pr, pa))
+ return change
+
+ def handle(self, signum, frame):
+ """This method is called when a signal is received."""
+ st, pa, pr = self._get_sig(signum)
+ if pr:
+ print 'Signal %d received' % self._signum
+ if pa:
+ # pass signal to program and stop
+ pass
+
+
Added: sandbox/trunk/pdb/patches/30-05-06-pdb.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/30-05-06-pdb.py Mon Aug 21 17:49:31 2006
@@ -0,0 +1,116 @@
+# Use the version of Pdb that's in svn trunk because the constructor
+# from Pdb needs to take a stdin and stdout argument.
+class MPdb(pdb.Pdb):
+ def __init__(self, sys.stdin, sys.stdout):
+ """ Use sys.stdin and sys.stdout for our input
+ and output streams respectively.
+ """
+
+ def do_list(self, args):
+ """ Override pdb's implementation of the list command """"
+
+ def do_info(self, args):
+ """ Provide information about [args] like the gdb info
+ command.
+ """
+
+ def do_thread(self, thread_no):
+ """ Use this command to switch between threads or to apply
+ a command to all threads.
+ """
+
+ def do_attach(self, location):
+ """ fork a new MXXXConsole object and close this one. """
+
+class MSocketConsole(MPdb):
+ """ A debugging console that connects to a debugging
+ server on a socket. We leave stdin and stdout in tact
+ """
+ def __init__(self, stdin, stdout)
+
+ def do_attach(self, args):
+ """ Attach to a debugging server. """
+
+ def write(self, cmd):
+ """ Send a command to the debugging server. """
+
+ def read(self):
+ """ Receive output from a debugging server. """
+
+ def cmdloop(self):
+ """ Loop until we exit sending and receiving commands
+ and output from the debugging server.
+ """
+
+# SERVER CLASSES
+
+# What I'm think would be cool here is allowing a design where a
+# programmer can combine MPdb and a server class to produce a working
+# debugging server. Below are some samples
+
+# It is possible for someone to write a wrapper for this class to allow
+# XMLRPC communication over SSL. See,
+# http://www.shipyard.com.au/articles/webdevelopment/sslxmlrpc.py
+class MXMLRPCServer(MPdb, SimpleXMLRPCServer):
+ def __init__(self, stdin, stdout, host, port):
+ """ A XMLRPC server. """
+
+ def _register_functions(Self):
+ """ Register all MPdb functions with the XMLRPC
+ server.
+ """
+
+ def do_list(self, args):
+ """ This is an example of a method that one may wish to override
+ in order to provide the debugging console (which may end up being
+ a GUI front-end) with more structured information than that which
+ is available in the inherited methods.
+
+ For example, one may wish to return the contents of an entire file
+ for the GUIs parsing plus a tag indicating where we currently
+ are in the file.
+ """
+
+# It is possible to provide a wrapper class for this to enable SSL
+# See above for more info (url link above MXMLRPCServer class)
+class MTCPSocketServer(MPdb, SocketServer.TCPServer):
+ def __init__(self, stdin, stdout, host, port):
+ """ A socket server implementation of a debugging
+ server.
+ """
+
+ def handle_request(self):
+ """ Override the method from TCPServer.
+ Handle requests coming in on the socket.
+
+ Most of the work of this entire class will be done in
+ this method. For instance,
+
+ - redirecting self.stdin and self.stdout to the connected
+ sockets
+ - providing any authentication methods
+ """
+
+class MSerialServer(MPdb):
+ """ A class that sets up a debugging server for use with serial
+ communication, such as that through a serial port.
+ """
+ def __init__(self, stdin, stdout, device):
+ """ Specify the serial device on the computer as a file from
+ /dev to read and write serial information from and to.
+ """
+
+ def listen(self):
+ """ Listen on the serial device for connecting debugging
+ consoles.
+ """
+
+ def accept(self):
+ """ Accept a debugging console connection through the serial
+ device.
+ """
+
+
+
+
+
Added: sandbox/trunk/pdb/patches/31-07-06-fns.diff
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/31-07-06-fns.diff Mon Aug 21 17:49:31 2006
@@ -0,0 +1,26 @@
+Index: pydb/fns.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/fns.py,v
+retrieving revision 1.15
+diff -u -r1.15 fns.py
+--- pydb/fns.py 10 Jul 2006 07:21:32 -0000 1.15
++++ pydb/fns.py 11 Jul 2006 20:41:11 -0000
+@@ -55,12 +55,12 @@
+ except EOFError:
+ reply = 'no'
+ reply = reply.strip().lower()
+- if reply in ('y', 'yes'):
+- return True
+- elif reply in ('n', 'no'):
+- return False
+- else:
+- self.msg("Please answer y or n.")
++ if reply in ('y', 'yes'):
++ return True
++ elif reply in ('n', 'no'):
++ return False
++ else:
++ self.msg("Please answer y or n.")
+ return False
+
+
Added: sandbox/trunk/pdb/patches/31-07-06-pydb.diff
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/31-07-06-pydb.diff Mon Aug 21 17:49:31 2006
@@ -0,0 +1,33 @@
+Index: pydb/sighandler.py
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/sighandler.py,v
+retrieving revision 1.3
+diff -u -r1.3 sighandler.py
+--- pydb/sighandler.py 31 Jul 2006 00:14:54 -0000 1.3
++++ pydb/sighandler.py 31 Jul 2006 10:02:20 -0000
+@@ -32,9 +32,6 @@
+ """
+ def __init__(self, pydb):
+ self.pydb = pydb
+- # This list contains tuples made up of four items, one tuple for
+- # every signal handler we've created. The tuples contain
+- # (signal_num, stop, print, pass)
+ self._sig_attr = []
+ self._sig_stop = []
+ self._sig_print = []
+Index: test/Makefile.am
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/test/Makefile.am,v
+retrieving revision 1.17
+diff -u -r1.17 Makefile.am
+--- test/Makefile.am 28 Jul 2006 00:47:47 -0000 1.17
++++ test/Makefile.am 31 Jul 2006 10:02:20 -0000
+@@ -28,6 +28,8 @@
+ run.right \
+ run2.cmd \
+ run2.right \
++ sighandler.cmd \
++ sighandle.right \
+ test.py \
+ trace-2.5.right \
+ trace.py \
Added: sandbox/trunk/pdb/patches/31-07-06-sig.diff
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/31-07-06-sig.diff Mon Aug 21 17:49:31 2006
@@ -0,0 +1,66 @@
+? sig.diff
+? t.py
+? thread_script2.py
+? tpdb.py
+? tpdb2.py
+? pydb/.gdb.py.in.swp
+? pydb/sighandler.py
+Index: pydb/gdb.py.in
+===================================================================
+RCS file: /cvsroot/bashdb/pydb/pydb/gdb.py.in,v
+retrieving revision 1.49
+diff -u -r1.49 gdb.py.in
+--- pydb/gdb.py.in 29 Jul 2006 08:09:32 -0000 1.49
++++ pydb/gdb.py.in 30 Jul 2006 23:17:40 -0000
+@@ -21,6 +21,8 @@
+ from pydbcmd import Cmd
+ from pydbbdb import Bdb
+
++from sighandler import SigHandler
++
+ class Restart(Exception):
+ """Causes a debugger to be restarted for the debugged Python program."""
+ pass
+@@ -37,6 +39,9 @@
+ self._re_linetrace_delay = re.compile(r'\s*linetrace\s+delay')
+ self._wait_for_mainpyfile = False
+
++ # set up signal handling
++ self._sig_handler = SigHandler(self)
++
+ self.__init_info()
+ self.__init_set()
+ self.__init_show()
+@@ -236,10 +241,12 @@
+ self.infocmds.add('args', self.info_args)
+ self.infocmds.add('breakpoints', self.info_breakpoints)
+ self.infocmds.add('display', self.info_display)
++ self.infocmds.add('handle', self._sig_handler.info_signal)
+ self.infocmds.add('globals', self.info_globals, 1, False)
+ self.infocmds.add('line', self.info_line)
+ self.infocmds.add('locals', self.info_locals, 1, False)
+ self.infocmds.add('program', self.info_program)
++ self.infocmds.add('signal', self._sig_handler.info_signal)
+ self.infocmds.add('source', self.info_source)
+
+ def __init_set(self):
+@@ -1043,6 +1050,19 @@
+ else:
+ self.__adjust_frame(pos=arg, absolute_pos=True)
+
++ def do_handle(self, arg):
++ """Specify how to handle a signal.
++ Args are signals and actions to apply to those signals.
++ Recognized actions include "stop", "nostop", "print", "noprint",
++ "pass", "nopass", "ignore", or "noignore".
++ Stop means reenter debugger if this signal happens (implies print).
++ Print means print a message if this signal happens.
++ Pass means let program see this signal; otherwise program doesn't know.
++ Ignore is a synonym for nopass and noignore is a synonym for pass.
++ Pass and Stop may be combined.
++ """
++ self._sig_handler.action(arg)
++
+ def do_ignore(self,arg):
+ """ignore bpnumber count
+
Added: sandbox/trunk/pdb/patches/31-07-06-sighandler.cmd
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/31-07-06-sighandler.cmd Mon Aug 21 17:49:31 2006
@@ -0,0 +1,11 @@
+info signal
+info handle
+handle SIGINT
+handle SIGINT stop pass noprint
+handle SIGINT
+handle SIGINT print
+handle SIGINT
+handle SIGINT nopass noprint nostop
+handle SIGINT
+info signal SIGINT
+quit
Added: sandbox/trunk/pdb/patches/31-07-06-sighandler.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/31-07-06-sighandler.py Mon Aug 21 17:49:31 2006
@@ -0,0 +1,190 @@
+"""$Id $
+Handles signal handlers within Pydb.
+"""
+import signal
+
+def lookup_signame(num):
+ """Find the corresponding signal name for 'num'. Return None
+ if 'num' is invalid."""
+ for signame in signal.__dict__.keys():
+ if signal.__dict__[signame] == num:
+ return signame
+
+def lookup_signum(name):
+ """Find the corresponding signal number for 'name'. Return None
+ if 'name' is invalid."""
+ if hasattr(signal, name):
+ return getattr(signal, name)
+ else:
+ return None
+
+class SigHandler:
+
+ """Store information about what we do when we handle a signal,
+
+ - Do we print/not print when signal is caught
+ - Do we pass/not pass the signal to the program
+ - Do we stop/not stop when signal is caught
+
+ All the methods to change these attributes return None on error, or
+ True or False if we have set the action (pass/print/stop) for a signal
+ handler.
+ """
+ def __init__(self, pydb):
+ self.pydb = pydb
+ # This list contains tuples made up of four items, one tuple for
+ # every signal handler we've created. The tuples contain
+ # (signal_num, stop, print, pass)
+ self._sig_attr = []
+ self._sig_stop = []
+ self._sig_print = []
+ self._sig_pass = []
+
+ for sig in signal.__dict__.keys():
+ if sig.startswith('SIG') and '_' not in sig:
+ self._sig_attr.append(sig)
+
+ # set up signal handling for some known signals
+ fatal = ['SIGINT', 'SIGTRAP', 'SIGTERM', 'SIGQUIT', 'SIGILL', \
+ 'SIGKILL', 'SIGSTOP']
+ for sig in self._sig_attr:
+ if str(sig) not in fatal:
+ num = lookup_signum(sig)
+ if num:
+ self._set_sig(sig, (True, True, True))
+ signal.signal(num, self.handle)
+ else:
+ self._set_sig(sig, (False, False, True))
+
+ def _get_sig(self, name):
+ st = name in self._sig_stop
+ pr = name in self._sig_print
+ pa = name in self._sig_pass
+ return (st, pr, pa)
+
+ def _set_sig(self, name, (st, pr, pa)):
+ """Set the actions to be taken when a signal, specified by
+ 'name', is received.
+ """
+ if st:
+ if name not in self._sig_stop:
+ self._sig_stop.append(name)
+ else:
+ if name in self._sig_stop:
+ self._sig_stop.pop(self._sig_stop.index(name))
+ if pr:
+ if name not in self._sig_print:
+ self._sig_print.append(name)
+ else:
+ if name in self._sig_print:
+ self._sig_print.pop(self._sig_print.index(name))
+ if pa:
+ if name not in self._sig_pass:
+ self._sig_pass.append(name)
+ else:
+ if name in self._sig_pass:
+ self._sig_pass.pop(self._sig_pass.index(name))
+
+ def info_signal(self, signame):
+ """Print information about a signal"""
+ if 'handle' in signame or 'signal' in signame:
+ # This has come from pydb's info command
+ if len(signame) == 1:
+ self.pydb.msg('NAME\t\tSTOP\tPRINT\tPASS')
+ for sig in self._sig_attr:
+ s = sig in self._sig_stop
+ pr = sig in self._sig_print
+ pa = sig in self._sig_pass
+ self.pydb.msg('%s\t\t%s\t%s\t%s' % (sig,s,pr,pa))
+ else:
+ self.info_signal(signame[1])
+ return
+
+ s = signame in self._sig_stop
+ pr = signame in self._sig_print
+ pa = signame in self._sig_pass
+ self.pydb.msg('NAME\t\tSTOP\tPRINT\tPASS')
+ self.pydb.msg('%s\t\t%s\t%s\t%s' % (signame, s, pr, pa))
+
+ def action(self, arg):
+ """Delegate the actions specified in 'arg' to another
+ method.
+ """
+ if not arg:
+ self.info_signal(['handle'])
+ return
+ args = arg.split()
+ if args[0] in self._sig_attr:
+ if len(args) == 1:
+ self.info_signal(args[0])
+ return
+ # multiple commands might be specified, i.e. 'nopass nostop'
+ for attr in args[1:]:
+ if attr.startswith('no'):
+ on = False
+ attr = attr[2:]
+ else:
+ on = True
+ if attr.startswith('stop'):
+ self.handle_stop(args[0], on)
+ elif attr.startswith('print'):
+ self.handle_print(args[0], on)
+ elif attr.startswith('pass'):
+ self.handle_pass(args[0], on)
+ else:
+ self.pydb.errmsg('Invalid arguments')
+
+ def handle_stop(self, signum, change):
+ """Change whether we stop or not when this signal is caught.
+ If 'change' is True your program will stop when this signal
+ happens."""
+ if not isinstance(change, bool):
+ return
+ old_attr = self._get_sig(signum)
+ st, pr, pa = change, old_attr[1], old_attr[2]
+ if st:
+ pr = True
+ self._set_sig(signum, (st, pr, pa))
+ return change
+
+ def handle_pass(self, signum, change):
+ """Change whether we pass this signal to the program (or not)
+ when this signal is caught. If change is True, Pydb should allow
+ your program to see this signal.
+ """
+ if not isinstance(change, bool):
+ return
+ old_attr = self._get_sig(signum)
+ st, pr, pa = old_attr[0], old_attr[1], change
+ self._set_sig(signum, (st, pr, pa))
+ return change
+
+ # ignore is a synonym for nopass and noignore is a synonym for pass
+ def handle_ignore(self, signum, change):
+ if not isinstance(change, bool):
+ return
+ self.handle_pass(not change)
+ return change
+
+ def handle_print(self, signum, change):
+ """Change whether we print or not when this signal is caught."""
+ if not isinstance(change, bool):
+ return
+ old_attr = self._get_sig(signum)
+ st, pr, pa = old_attr[0], change, old_attr[2]
+ if not change:
+ # noprint implies nostop
+ st = False
+ self._set_sig(signum, (st, pr, pa))
+ return change
+
+ def handle(self, signum, frame):
+ """This method is called when a signal is received."""
+ sig = lookup_signame(signum)
+ st, pa, pr = self._get_sig(sig)
+ if pr:
+ self.pydb.msg('Program received signal %s' % sig)
+ if st:
+ # XXX Rocky what's the best way to handle this?
+ self.pydb.use_rawinput = False
+ self.pydb.interaction(self.pydb.curframe, None)
Added: sandbox/trunk/pdb/patches/31-07-06-sighandler.right
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/31-07-06-sighandler.right Mon Aug 21 17:49:31 2006
@@ -0,0 +1,85 @@
+Signal Stop Print Pass to program
+
+SIGHUP True True True
+SIGSYS True True True
+SIGQUIT False False True
+SIGUSR1 True True True
+SIGFPE True True True
+SIGTSTP True True True
+SIGCHLD True True True
+SIGIOT True True True
+SIGBUS True True True
+SIGXCPU True True True
+SIGPROF True True True
+SIGCONT True True True
+SIGUSR2 True True True
+SIGKILL False False True
+SIGSEGV True True True
+SIGINT False False True
+SIGIO True True True
+SIGTRAP False False True
+SIGILL False False True
+SIGEMT True True True
+SIGABRT True True True
+SIGALRM True True True
+SIGPIPE True True True
+SIGWINCH True True True
+SIGTERM False False True
+SIGVTALRM True True True
+SIGINFO True True True
+SIGURG True True True
+SIGPWR True True True
+SIGXFSZ True True True
+SIGTTIN True True True
+SIGSTOP False False True
+SIGTTOU True True True
+Signal Stop Print Pass to program
+
+SIGHUP True True True
+SIGSYS True True True
+SIGQUIT False False True
+SIGUSR1 True True True
+SIGFPE True True True
+SIGTSTP True True True
+SIGCHLD True True True
+SIGIOT True True True
+SIGBUS True True True
+SIGXCPU True True True
+SIGPROF True True True
+SIGCONT True True True
+SIGUSR2 True True True
+SIGKILL False False True
+SIGSEGV True True True
+SIGINT False False True
+SIGIO True True True
+SIGTRAP False False True
+SIGILL False False True
+SIGEMT True True True
+SIGABRT True True True
+SIGALRM True True True
+SIGPIPE True True True
+SIGWINCH True True True
+SIGTERM False False True
+SIGVTALRM True True True
+SIGINFO True True True
+SIGURG True True True
+SIGPWR True True True
+SIGXFSZ True True True
+SIGTTIN True True True
+SIGSTOP False False True
+SIGTTOU True True True
+Signal Stop Print Pass to program
+
+SIGINT False False True
+Signal Stop Print Pass to program
+
+SIGINT False False True
+Signal Stop Print Pass to program
+
+SIGINT False True True
+Signal Stop Print Pass to program
+
+SIGINT False False False
+Signal Stop Print Pass to program
+
+SIGINT False False False
Added: sandbox/trunk/pdb/patches/31-07-06-test.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/pdb/patches/31-07-06-test.py Mon Aug 21 17:49:31 2006
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+"""Run a bunch of threading programs with line tracing
+to make sure we don't hang tracing them."""
+
+import os, time
+
+def run_test(test, wait_period):
+ """Run the test 'test' in a separate process and sleep for 'wait_period'
+ seconds. 'wait_period' should specify an optimal amount of time for
+ 'test' to finish. If the process hasn't finished by the time
+ 'wait_period' seconds have passed, we assume that the test is hung.
+ If the test has hung False is returned, otherwise True is returned.
+ """
+ pid = os.spawnlp(os.P_NOWAIT, 'python', 'python', 'tpdb.py', '--trace',
+ test)
+ time.sleep(wait_period)
+ ret = os.waitpid(pid, os.WNOHANG)
+ if ret == (0,0):
+ import signal
+ os.kill(pid, signal.SIGKILL)
+ return False
+ else:
+ return True
+
+def main():
+ # The way that I got the times below was by timing each file on
+ # my AMD64 machine and adding 5 seconds on to it. We may find that
+ # these times are way too short.
+ tests = [('t2.py', 5.0), ('q.py', 15.0), ('thread1.py',10.0)]
+ failed_tests = []
+
+ # Construct a test command suitable for passing to run_test
+ for test in tests:
+ filename = os.path.realpath(test[0])
+ result = run_test(filename, test[1])
+ if not result:
+ failed_tests.append(test)
+
+ if failed_tests:
+ print '=' * 60
+ print 'Failed Tests:\n'
+ for failed in failed_tests:
+ print failed[0]
+ print '=' * 60
+ else:
+ print '=' * 60
+ print 'All tests passed\n'
+ print '=' * 60
+
+if __name__ == '__main__':
+ main()
1
0