Unnamed Fossil Project

Check-in [453a9abb8f]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:First pass, dealing with multiple threads
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:453a9abb8f62ec64e53bffe124a94735d39a5f31cd86290a5a618400b6e646ae
User & Date: vandys 2018-11-14 18:33:06
Context
2018-11-14
21:08
Let us switch between stopped threads with "fg" command check-in: c2fd6aa60a user: vandys tags: trunk
18:33
First pass, dealing with multiple threads check-in: 453a9abb8f user: vandys tags: trunk
16:01
Initial snapshot, thread aware pdb check-in: 63dbaf89d6 user: vandys tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to pdb.py.

9
10
11
12
13
14
15

16




17
18
19
20
21
22
23
...
650
651
652
653
654
655
656

657
658
659
660
661

662
663
664
665
666

667
668
669
670
671
672
673

674
675
676
677
678
679
680
681
682
683

684
685
686
687
688

689
690
691
692
693
694
695
....
1227
1228
1229
1230
1231
1232
1233
























































































1234
1235
1236
1237
1238
1239
1240
import cmd
import bdb
from repr import Repr
import os
import re
import pprint
import traceback







class Restart(Exception):
    """Causes a debugger to be restarted for the debugged python program."""
    pass

# Create a custom safe Repr instance and increase its maxstring.
# The default of 30 truncates error messages too easily.
................................................................................
            self.curframe = self.stack[self.curindex][0]
            self.curframe_locals = self.curframe.f_locals
            self.print_stack_entry(self.stack[self.curindex])
            self.lineno = None
    do_d = do_down

    def do_until(self, arg):

        self.set_until(self.curframe)
        return 1
    do_unt = do_until

    def do_step(self, arg):

        self.set_step()
        return 1
    do_s = do_step

    def do_next(self, arg):

        self.set_next(self.curframe)
        return 1
    do_n = do_next

    def do_run(self, arg):
        """Restart program by raising an exception to be caught in the main
        debugger loop.  If arguments were given, set them in sys.argv."""

        if arg:
            import shlex
            argv0 = sys.argv[0:1]
            sys.argv = shlex.split(arg)
            sys.argv[:0] = argv0
        raise Restart

    do_restart = do_run

    def do_return(self, arg):

        self.set_return(self.curframe)
        return 1
    do_r = do_return

    def do_continue(self, arg):

        self.set_continue()
        return 1
    do_c = do_cont = do_continue

    def do_jump(self, arg):
        if self.curindex + 1 != len(self.stack):
            print >>self.stdout, "*** You can only jump within the bottom frame"
................................................................................
        # avoid stopping before we reach the main script (see user_line and
        # user_call for details).
        self._wait_for_mainpyfile = 1
        self.mainpyfile = self.canonic(filename)
        self._user_requested_quit = 0
        statement = 'execfile(%r)' % filename
        self.run(statement)

























































































# Simplified interface

def run(statement, globals=None, locals=None):
    Pdb().run(statement, globals, locals)

def runeval(expression, globals=None, locals=None):







>

>
>
>
>







 







>





>





>







>










>





>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
....
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
import cmd
import bdb
from repr import Repr
import os
import re
import pprint
import traceback
import threading

# Coordinate who's talking with the user
# Thread -> (Pdb instance, state, paused-mutex)
Jobs = {}
Jobnum = 0

class Restart(Exception):
    """Causes a debugger to be restarted for the debugged python program."""
    pass

# Create a custom safe Repr instance and increase its maxstring.
# The default of 30 truncates error messages too easily.
................................................................................
            self.curframe = self.stack[self.curindex][0]
            self.curframe_locals = self.curframe.f_locals
            self.print_stack_entry(self.stack[self.curindex])
            self.lineno = None
    do_d = do_down

    def do_until(self, arg):
	self.pdb_state("stepping")
        self.set_until(self.curframe)
        return 1
    do_unt = do_until

    def do_step(self, arg):
	self.pdb_state("stepping")
        self.set_step()
        return 1
    do_s = do_step

    def do_next(self, arg):
	self.pdb_state("stepping")
        self.set_next(self.curframe)
        return 1
    do_n = do_next

    def do_run(self, arg):
        """Restart program by raising an exception to be caught in the main
        debugger loop.  If arguments were given, set them in sys.argv."""
	self.pdb_state("running")
        if arg:
            import shlex
            argv0 = sys.argv[0:1]
            sys.argv = shlex.split(arg)
            sys.argv[:0] = argv0
        raise Restart

    do_restart = do_run

    def do_return(self, arg):
	self.pdb_state("stepping")
        self.set_return(self.curframe)
        return 1
    do_r = do_return

    def do_continue(self, arg):
	self.pdb_state("running")
        self.set_continue()
        return 1
    do_c = do_cont = do_continue

    def do_jump(self, arg):
        if self.curindex + 1 != len(self.stack):
            print >>self.stdout, "*** You can only jump within the bottom frame"
................................................................................
        # avoid stopping before we reach the main script (see user_line and
        # user_call for details).
        self._wait_for_mainpyfile = 1
        self.mainpyfile = self.canonic(filename)
        self._user_requested_quit = 0
        statement = 'execfile(%r)' % filename
        self.run(statement)

    # Interactive wants to start, wait in line if a pdb
    #  is already going
    def preloop(self):
	global Jobs, Jobnum

	me = threading.current_thread()

	# We're the only one, go ahead
	if not Jobs:
	    Jobs[me] = [self, "pdb", None, Jobnum]
	    Jobnum += 1
	    return

	# We're continuing, like from a single step
	if me in Jobs:
	    Jobs[me][1] = "pdb"
	    return

	# Wait our turn
	sys.stderr.write("[pdb: %s waiting]\n" % (me,))
	sema = threading.Semaphore(0)
	jnum = Jobnum
	l = Jobs[me] = [self, "waiting", sema, jnum]
	Jobnum += 1
	sema.acquire()
	# We've waited and now have the go-ahead
	sys.stderr.write("[pdb job %d: %s]\n" % (jnum, me))
	l[1] = "pdb"
	return

    # List any threads waiting to enter pdb
    def do_jobs(self, arg):
	global Jobs

	for t,tup in Jobs.iteritems():
	    sys.stderr.write("%5d %r: %s\n" % (tup[3], t, tup[1]))

    # Command loop finished
    def postloop(self):
	self.leave_pdb()

    # Change our pdb state value
    def pdb_state(self, s):
	global Jobs

	me = threading.current_thread()
	tup = Jobs[me]
	tup[1] = s

    # Bow out of pdb mode
    def leave_pdb(self):
	global Jobs

	me = threading.current_thread()
	tup = Jobs[me]

	# If we're planning on returning to pdb as a part
	#  of this session (single step, run to return, etc.)
	#  then don't let anybody else take over.
	if tup[1] != "running":
	    return

	# We're coming out of pdb with no (immediate)
	#  intention of continuing, relinquish the debug
	#  session.
	del Jobs[me]
	if not Jobs:
	    # Nobody else
	    return

	# Pick lowest job number and hand off
	chosen = min( tup[3] for tup in Jobs.itervalues() )
	for tup in Jobs.itervalues():
	    if tup[3] == chosen:
		tup[2].release()
		return

    # Update state to reflect we're still in PDB, but
    #  running target code
    def stepping(self):
	global Jobs
	me = threading.current_thread()
	Jobs[me][1] = "stepping"
    def unstepping(self):
	global Jobs
	me = threading.current_thread()
	Jobs[me][1] = "pdb"

# Simplified interface

def run(statement, globals=None, locals=None):
    Pdb().run(statement, globals, locals)

def runeval(expression, globals=None, locals=None):