~ubuntu-branches/ubuntu/natty/moin/natty-updates

« back to all changes in this revision

Viewing changes to MoinMoin/util/thread_monitor.py

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2008-06-22 21:17:13 UTC
  • mfrom: (0.9.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080622211713-fpo2zrq3s5dfecxg
Tags: 1.7.0-3
Simplify /etc/moin/wikilist format: "USER URL" (drop unneeded middle
CONFIG_DIR that was wrongly advertised as DATA_DIR).  Make
moin-mass-migrate handle both formats and warn about deprecation of
the old one.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# -*- coding: ascii -*-
2
2
"""
3
 
Thread monitor - Check the state of all threads.
4
 
 
5
 
Just call activate_hook() as early as possible in program execution.
6
 
Then you can trigger the output of tracebacks of all threads
7
 
by calling trigger_dump().
8
 
 
9
 
@copyright: 2006 Alexander Schremmer <alex AT alexanderweb DOT de>
10
 
@license: GNU GPL Version 2
 
3
    Thread monitor - Check the state of all threads.
 
4
 
 
5
    Just call activate_hook() as early as possible in program execution.
 
6
    Then you can trigger the output of tracebacks of all threads
 
7
    by calling trigger_dump().
 
8
 
 
9
    Usage of Python 2.5 is recommended because it allows for a much safer
 
10
    and faster frame extraction.
 
11
 
 
12
    @copyright: 2006 Alexander Schremmer <alex AT alexanderweb DOT de>
 
13
    @license: GNU GPL Version 2
11
14
"""
12
15
 
 
16
 
 
17
__all__ = "activate_hook trigger_dump dump_regularly".split()
 
18
 
 
19
 
13
20
import sys
14
21
import threading
15
22
import traceback
16
23
from time import sleep
17
24
from StringIO import StringIO
18
25
 
19
 
try:
20
 
    set
21
 
except:
22
 
    from sets import Set as set
23
 
 
24
 
# global state
25
 
dumping = False
26
 
dump_file = None
27
 
dumped = set()
28
 
to_dump = set()
29
 
hook_enabled = False
30
 
 
31
 
def dump(label):
32
 
    df = dump_file or sys.stderr
33
 
    s = StringIO()
34
 
    print >>s, "\nDumping thread %s:" % (label, )
35
 
    try:
36
 
        raise ZeroDivisionError
37
 
    except ZeroDivisionError:
38
 
        f = sys.exc_info()[2].tb_frame.f_back.f_back
39
 
    traceback.print_list(traceback.extract_stack(f, None), s)
40
 
    df.write(s.getvalue())
41
 
 
42
 
def dump_hook(a, b, c): # arguments are ignored
43
 
    global dumping
44
 
    
45
 
    if dumping and sys.exc_info()[0] is None:
46
 
        thread = threading.currentThread()
47
 
        if thread in to_dump:
48
 
            dump(repr(thread))
49
 
            to_dump.discard(thread)
50
 
            dumped.add(thread)
51
 
            if not to_dump:
52
 
                dumping = False
53
 
 
54
 
def trigger_dump(dumpfile=None):
55
 
    """ Triggers the dump of the tracebacks of all threads.
56
 
        If dumpfile is specified, it is used as the output file. """
57
 
    global dumping, dump_file, to_dump
58
 
 
59
 
    to_dump = set(threading.enumerate())
60
 
    if dumpfile is not None:
61
 
        dump_file = dumpfile
62
 
    dumping = True
63
 
 
64
 
def activate_hook():
65
 
    """ Activates the thread monitor hook. Note that this interferes
66
 
    with any kind of profiler and some debugging extensions. """
67
 
    global hook_enabled
68
 
    
69
 
    sys.setprofile(dump_hook)
70
 
    threading.setprofile(dump_hook)
71
 
    hook_enabled = True
 
26
from MoinMoin.support.python_compatibility import set
 
27
 
 
28
 
 
29
class AbstractMonitor(object):
 
30
    def activate_hook(self):
 
31
        """ Activates the thread monitor hook. Note that this might interfere
 
32
        with any kind of profiler and some debugging extensions. """
 
33
        raise NotImplementedError
 
34
 
 
35
    def trigger_dump(self, dumpfile=None):
 
36
        """ Triggers the dump of the tracebacks of all threads.
 
37
            If dumpfile is specified, it is used as the output file. """
 
38
        raise NotImplementedError
 
39
 
 
40
    def hook_enabled(self):
 
41
        """ Returns true if the thread_monitor hook is enabled. """
 
42
        raise NotImplementedError
 
43
 
 
44
class LegacyMonitor(AbstractMonitor):
 
45
    # global state
 
46
    dumping = False
 
47
    dump_file = None
 
48
    dumped = set()
 
49
    to_dump = set()
 
50
    hook_enabled = False
 
51
 
 
52
    def dump(cls, label):
 
53
        df = cls.dump_file or sys.stderr
 
54
        s = StringIO()
 
55
        print >>s, "\nDumping thread %s:" % (label, )
 
56
        try:
 
57
            raise ZeroDivisionError
 
58
        except ZeroDivisionError:
 
59
            f = sys.exc_info()[2].tb_frame.f_back.f_back
 
60
        traceback.print_list(traceback.extract_stack(f, None), s)
 
61
        df.write(s.getvalue())
 
62
    dump = classmethod(dump)
 
63
 
 
64
    def dump_hook(cls, a, b, c): # arguments are ignored
 
65
        if cls.dumping and sys.exc_info()[0] is None:
 
66
            thread = threading.currentThread()
 
67
            if thread in cls.to_dump:
 
68
                cls.dump(repr(thread))
 
69
                cls.to_dump.discard(thread)
 
70
                cls.dumped.add(thread)
 
71
                if not cls.to_dump:
 
72
                    cls.dumping = False
 
73
    dump_hook = classmethod(dump_hook)
 
74
 
 
75
    def trigger_dump(cls, dumpfile=None):
 
76
        cls.to_dump = set(threading.enumerate())
 
77
        if dumpfile is not None:
 
78
            cls.dump_file = dumpfile
 
79
        cls.dumping = True
 
80
    trigger_dump = classmethod(trigger_dump)
 
81
 
 
82
    def activate_hook(cls):
 
83
        sys.setprofile(cls.dump_hook)
 
84
        threading.setprofile(cls.dump_hook)
 
85
        cls.hook_enabled = True
 
86
    activate_hook = classmethod(activate_hook)
 
87
 
 
88
    def hook_enabled(cls):
 
89
        return cls.hook_enabled
 
90
    hook_enabled = classmethod(hook_enabled)
 
91
 
 
92
 
 
93
class DirectMonitor(AbstractMonitor):
 
94
    def __init__(self):
 
95
        self.enabled = False
 
96
        assert hasattr(sys, "_current_frames")
 
97
 
 
98
    def activate_hook(self):
 
99
        self.enabled = True
 
100
 
 
101
    def trigger_dump(self, dumpfile=None):
 
102
        if not self.enabled:
 
103
            return
 
104
        dumpfile = dumpfile or sys.stderr
 
105
        cur_frames = sys._current_frames()
 
106
        for i in cur_frames:
 
107
            s = StringIO()
 
108
            print >>s, "\nDumping thread (id %s):" % (i, )
 
109
            traceback.print_stack(cur_frames[i], file=s)
 
110
            dumpfile.write(s.getvalue())
 
111
 
 
112
    def hook_enabled(self):
 
113
        return self.enabled
 
114
 
72
115
 
73
116
def dump_regularly(seconds):
74
117
    """ Dumps the tracebacks every 'seconds' seconds. """
78
121
        while 1:
79
122
            sleep(seconds)
80
123
            trigger_dump()
81
 
    
 
124
 
82
125
    threading.Thread(target=background_dumper, args=(seconds, )).start()
83
126
 
 
127
 
 
128
# Python 2.5 provides an optimised version
 
129
if hasattr(sys, "_current_frames"):
 
130
    mon = DirectMonitor()
 
131
else:
 
132
    mon = LegacyMonitor()
 
133
 
 
134
activate_hook = mon.activate_hook
 
135
trigger_dump = mon.trigger_dump
 
136
hook_enabled = mon.hook_enabled