~ubuntu-branches/ubuntu/karmic/kaa-base/karmic

« back to all changes in this revision

Viewing changes to src/notifier/__init__.py

  • Committer: Bazaar Package Importer
  • Author(s): A Mennucc1
  • Date: 2008-03-25 14:12:15 UTC
  • mfrom: (2.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080325141215-unddr7llk7aghxma
Tags: 0.4.0-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
# -----------------------------------------------------------------------------
3
3
# __init__.py - Interface to kaa.notifier
4
4
# -----------------------------------------------------------------------------
5
 
# $Id: __init__.py 2604 2007-03-28 09:21:52Z dmeyer $
 
5
# $Id: __init__.py 3208 2008-03-20 15:46:27Z dmeyer $
6
6
#
7
7
# -----------------------------------------------------------------------------
8
8
# kaa.notifier - Mainloop and callbacks
9
 
# Copyright (C) 2005, 2006 Dirk Meyer, Jason Tackaberry, et al.
 
9
# Copyright (C) 2005-2008 Dirk Meyer, Jason Tackaberry, et al.
10
10
#
11
11
# First Version: Dirk Meyer <dmeyer@tzi.de>
12
12
# Maintainer:    Dirk Meyer <dmeyer@tzi.de>
30
30
#
31
31
# -----------------------------------------------------------------------------
32
32
 
33
 
# python imports
34
 
import sys
35
 
import logging
36
 
import os
37
 
import time
38
 
import signal
39
 
import threading
40
 
import atexit
41
 
 
42
 
# kaa.notifier imports
43
 
import nf_wrapper as notifier
44
 
 
45
 
init = notifier.init
46
 
 
47
 
from popen import *
48
 
from callback import *
49
 
from thread import *
50
 
from timer import *
51
 
from sockets import *
52
 
from event import *
53
 
from yieldfunc import *
54
 
from jobserver import ThreadCallback, execute_in_thread
55
 
from jobserver import killall as kill_jobserver
56
 
from async import InProgress
57
 
 
58
 
from decorators import execute_in_timer, execute_in_mainloop
59
 
 
60
 
# get logging object
61
 
log = logging.getLogger('notifier')
62
 
 
63
 
# variable to check if the notifier is running
64
 
running = False
65
 
# Set if currently in shutdown() (to prevent reentrancy)
66
 
shutting_down = False
67
 
 
68
 
def _step_signal_changed(signal, flag):
69
 
    if flag == Signal.SIGNAL_CONNECTED and signal.count() == 1:
70
 
        notifier.dispatcher_add(signals["step"].emit)
71
 
    elif flag == Signal.SIGNAL_DISCONNECTED and signal.count() == 0:
72
 
        notifier.dispatcher_remove(signals["step"].emit)
73
 
 
74
 
 
75
 
signals = {
76
 
    "shutdown": Signal(),
77
 
    "step": Signal(changed_cb = _step_signal_changed),
78
 
}
79
 
 
80
 
 
81
 
def shutdown():
82
 
    """
83
 
    Shutdown notifier and kill all background processes.
84
 
    """
85
 
    global shutting_down
86
 
 
87
 
    # Ensure shutdown() is called from main thread.
88
 
    if not is_mainthread():
89
 
        return MainThreadCallback(shutdown)()
90
 
 
91
 
    if running:
92
 
        # notifier loop still running, send system exit
93
 
        log.info('Stop notifier loop')
94
 
        raise SystemExit
95
 
 
96
 
    if shutting_down:
97
 
        return
98
 
    shutting_down = True
99
 
 
100
 
    stop_all_processes()
101
 
    signals["shutdown"].emit()
102
 
    signals["shutdown"].disconnect_all()
103
 
    signals["step"].disconnect_all()
104
 
 
105
 
    # Kill processes _after_ shutdown emits to give callbacks a chance to
106
 
    # close them properly.
107
 
    kill_all_processes()
108
 
    kill_jobserver()
109
 
    # Collect any zombies
110
 
    try:
111
 
        os.waitpid(-1, os.WNOHANG)
112
 
    except:
113
 
        pass
114
 
 
115
 
 
116
 
def loop():
117
 
    """
118
 
    Notifier main loop function. It will loop until an exception
119
 
    is raised or sys.exit is called.
120
 
    """
121
 
    global running
122
 
    running = True
123
 
 
124
 
    set_current_as_mainthread()
125
 
    try:
126
 
        notifier.loop()
127
 
    except (KeyboardInterrupt, SystemExit):
128
 
        try:
129
 
            # This looks stupid, I know that. The problem is that if we have
130
 
            # a KeyboardInterrupt, that flag is still valid somewhere inside
131
 
            # python. The next system call will fail because of that. Since we
132
 
            # don't want a join of threads or similar fail, we use a very short
133
 
            # sleep here. In most cases we won't sleep at all because this sleep
134
 
            # fails. But after that everything is back to normal.
135
 
            time.sleep(0.001)
136
 
        except:
137
 
            pass
138
 
    except Exception, e:
139
 
        log.exception('loop')
140
 
    running = False
141
 
    shutdown()
142
 
 
143
 
 
144
 
def step(*args, **kwargs):
145
 
    """
146
 
    Notifier step function with signal support.
147
 
    """
148
 
    if not is_mainthread():
149
 
        # If step is being called from a thread, wake up the mainthread
150
 
        # instead of allowing the thread into notifier.step.
151
 
        wakeup()
152
 
        # Sleep for epsilon to prevent busy loops.
153
 
        time.sleep(0.001)
154
 
        return
155
 
 
156
 
    try:
157
 
        notifier.step(*args, **kwargs)
158
 
    except (KeyboardInterrupt, SystemExit):
159
 
        raise SystemExit
160
 
 
161
 
 
162
 
def _shutdown_check(*args):
163
 
    # Helper function to shutdown kaa on system exit
164
 
    # The problem is that pytgtk just exits python and
165
 
    # does not simply return from the main loop and kaa
166
 
    # can't call the shutdown handler. This is not a perfect
167
 
    # solution, e.g. with the generic notifier you can do
168
 
    # stuff after kaa.main() which is not possible with gtk
169
 
    global running
170
 
    if running:
171
 
        # If the kaa mainthread (i.e. thread the mainloop is running in)
172
 
        # is not the program's main thread, then is_mainthread() will be False
173
 
        # and we don't need to set running=False since shutdown() will raise a
174
 
        # SystemExit and things will exit normally.
175
 
        if is_mainthread():
176
 
            running = False
177
 
        shutdown()
178
 
 
179
 
# # catch SIGTERM if possible for a clean shutdown
180
 
if threading.enumerate()[0] == threading.currentThread():
181
 
    signal.signal(signal.SIGTERM, _shutdown_check)
182
 
else:
183
 
    log.info('kaa imported from thread, disable SIGTERM handler')
184
 
    
185
 
# check to make sure we really call our shutdown function
186
 
atexit.register(_shutdown_check)
 
33
# Import all classes, functions and decorators that are part of the API
 
34
 
 
35
# Callback classes
 
36
from callback import Callback, WeakCallback
 
37
 
 
38
# Signal and dict of Signals
 
39
from signals import Signal, Signals
 
40
 
 
41
# InProgress class
 
42
from async import TimeoutException, InProgress, InProgressCallback, InProgressSignals
 
43
 
 
44
# Thread callbacks, helper functions and decorators
 
45
from thread import MainThreadCallback, NamedThreadCallback, ThreadCallback, \
 
46
     is_mainthread, threaded, MAINTHREAD, synchronized
 
47
 
 
48
# Timer classes and decorators
 
49
from timer import Timer, WeakTimer, OneShotTimer, WeakOneShotTimer, AtTimer, \
 
50
     OneShotAtTimer, timed, POLICY_ONCE, POLICY_MANY, POLICY_RESTART
 
51
 
 
52
# IO/Socket handling
 
53
from sockets import IOMonitor, WeakIOMonitor, Socket, IO_READ, IO_WRITE
 
54
 
 
55
# Event and event handler classes
 
56
from event import Event, EventHandler, WeakEventHandler
 
57
 
 
58
# coroutine decorator and helper classes
 
59
from coroutine import NotFinished, coroutine
 
60
 
 
61
# process management
 
62
from popen import Process
 
63
 
 
64
# special gobject thread support
 
65
from gobject import GOBJECT, gobject_set_threaded