@ -26,7 +26,6 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# POSSIBILITY OF SUCH DAMAGE.
import Queue
import cPickle
import cPickle
import cStringIO
import cStringIO
import collections
import collections
@ -41,6 +40,7 @@ import signal
import socket
import socket
import struct
import struct
import sys
import sys
import thread
import threading
import threading
import time
import time
import traceback
import traceback
@ -1039,14 +1039,19 @@ class Latch(object):
class Waker ( BasicStream ) :
class Waker ( BasicStream ) :
"""
"""
: py : class : ` BasicStream ` subclass implementing the
: py : class : ` BasicStream ` subclass implementing the ` UNIX self - pipe trick ` _ .
` UNIX self - pipe trick ` _ . Used internally to wake the IO multiplexer when
Used to wake the multiplexer when another thread needs to modify its state
some of its state has been changed by another thread .
( via a cross - thread function call ) .
. . _UNIX self - pipe trick : https : / / cr . yp . to / docs / selfpipe . html
. . _UNIX self - pipe trick : https : / / cr . yp . to / docs / selfpipe . html
"""
"""
broker_ident = None
def __init__ ( self , broker ) :
def __init__ ( self , broker ) :
self . _broker = broker
self . _broker = broker
self . _lock = threading . Lock ( )
self . _deferred = [ ]
rfd , wfd = os . pipe ( )
rfd , wfd = os . pipe ( )
self . receive_side = Side ( self , rfd )
self . receive_side = Side ( self , rfd )
self . transmit_side = Side ( self , wfd )
self . transmit_side = Side ( self , wfd )
@ -1058,24 +1063,63 @@ class Waker(BasicStream):
self . transmit_side . fd ,
self . transmit_side . fd ,
)
)
def on_receive ( self , broker ) :
@property
def keep_alive ( self ) :
"""
"""
Read a byte from the self - pipe .
Prevent immediate Broker shutdown while deferred functions remain .
"""
"""
self . receive_side . read ( 256 )
self . _lock . acquire ( )
try :
return len ( self . _deferred )
finally :
self . _lock . release ( )
def wake ( self ) :
def on_receive( self , broker ) :
"""
"""
Write a byte to the self - pipe , causing the IO multiplexer to wake up .
Drain the pipe and fire callbacks . Reading multiple bytes is safe since
Nothing is written if the current thread is the IO multiplexer thread .
new bytes corresponding to future . defer ( ) calls are written only after
. defer ( ) takes _lock : either a byte we read corresponds to something
already on the queue by the time we take _lock , or a byte remains
buffered , causing another wake up , because it was written after we
released _lock .
"""
"""
_vv and IOLOG . debug ( ' %r .wake() [fd= %r ] ' , self , self . transmit_side . fd )
_vv and IOLOG . debug ( ' %r .on_receive() ' , self )
if threading . currentThread ( ) != self . _broker . _thread :
self . receive_side . read ( 128 )
self . _lock . acquire ( )
try :
deferred = self . _deferred
self . _deferred = [ ]
finally :
self . _lock . release ( )
for func , args , kwargs in deferred :
try :
try :
self . transmit_side . write ( ' ' )
func ( * args , * * kwargs )
except OSError , e :
except Exception :
if e [ 0 ] != errno . EBADF :
LOG . exception ( ' defer() crashed: %r (* %r , ** %r ) ' ,
raise
func , args , kwargs )
self . _broker . shutdown ( )
def defer ( self , func , * args , * * kwargs ) :
if thread . get_ident ( ) == self . broker_ident :
_vv and IOLOG . debug ( ' %r .defer() [immediate] ' , self )
return func ( * args , * * kwargs )
_vv and IOLOG . debug ( ' %r .defer() [fd= %r ] ' , self , self . transmit_side . fd )
self . _lock . acquire ( )
try :
self . _deferred . append ( ( func , args , kwargs ) )
finally :
self . _lock . release ( )
# Wake the multiplexer by writing a byte. If the broker is in the midst
# of tearing itself down, the waker fd may already have been closed, so
# ignore EBADF here.
try :
self . transmit_side . write ( ' ' )
except OSError , e :
if e [ 0 ] != errno . EBADF :
raise
class IoLogger ( BasicStream ) :
class IoLogger ( BasicStream ) :
@ -1242,24 +1286,17 @@ class Broker(object):
def __init__ ( self ) :
def __init__ ( self ) :
self . _alive = True
self . _alive = True
self . _queue = Queue . Queue ( )
self . _readers = [ ]
self . _writers = [ ]
self . _waker = Waker ( self )
self . _waker = Waker ( self )
self . start_receive ( self . _waker )
self . defer = self . _waker . defer
self . _readers = [ self . _waker . receive_side ]
self . _writers = [ ]
self . _thread = threading . Thread (
self . _thread = threading . Thread (
target = _profile_hook ,
target = _profile_hook ,
args = ( ' broker ' , self . _broker_main ) ,
args = ( ' broker ' , self . _broker_main ) ,
name = ' mitogen-broker '
name = ' mitogen-broker '
)
)
self . _thread . start ( )
self . _thread . start ( )
self . _waker . broker_ident = self . _thread . ident
def defer ( self , func , * args , * * kwargs ) :
if threading . currentThread ( ) == self . _thread :
func ( * args , * * kwargs )
else :
self . _queue . put ( ( func , args , kwargs ) )
self . _waker . wake ( )
def _list_discard ( self , lst , value ) :
def _list_discard ( self , lst , value ) :
try :
try :
@ -1296,19 +1333,8 @@ class Broker(object):
LOG . exception ( ' %r crashed ' , stream )
LOG . exception ( ' %r crashed ' , stream )
stream . on_disconnect ( self )
stream . on_disconnect ( self )
def _run_defer ( self ) :
while not self . _queue . empty ( ) :
func , args , kwargs = self . _queue . get ( )
try :
func ( * args , * * kwargs )
except Exception :
LOG . exception ( ' defer() crashed: %r (* %r , ** %r ) ' ,
func , args , kwargs )
self . shutdown ( )
def _loop_once ( self , timeout = None ) :
def _loop_once ( self , timeout = None ) :
_vv and IOLOG . debug ( ' %r ._loop_once( %r ) ' , self , timeout )
_vv and IOLOG . debug ( ' %r ._loop_once( %r ) ' , self , timeout )
self . _run_defer ( )
#IOLOG.debug('readers = %r', self._readers)
#IOLOG.debug('readers = %r', self._readers)
#IOLOG.debug('writers = %r', self._writers)
#IOLOG.debug('writers = %r', self._writers)
@ -1327,15 +1353,13 @@ class Broker(object):
self . _call ( side . stream , side . stream . on_transmit )
self . _call ( side . stream , side . stream . on_transmit )
def keep_alive ( self ) :
def keep_alive ( self ) :
return ( sum ( ( side . keep_alive for side in self . _readers ) , 0 ) +
return sum ( ( side . keep_alive for side in self . _readers ) , 0 )
( not self . _queue . empty ( ) ) )
def _broker_main ( self ) :
def _broker_main ( self ) :
try :
try :
while self . _alive :
while self . _alive :
self . _loop_once ( )
self . _loop_once ( )
self . _run_defer ( )
fire ( self , ' shutdown ' )
fire ( self , ' shutdown ' )
for side in set ( self . _readers ) . union ( self . _writers ) :
for side in set ( self . _readers ) . union ( self . _writers ) :
@ -1361,8 +1385,9 @@ class Broker(object):
def shutdown ( self ) :
def shutdown ( self ) :
_v and LOG . debug ( ' %r .shutdown() ' , self )
_v and LOG . debug ( ' %r .shutdown() ' , self )
self . _alive = False
def _shutdown ( ) :
self . _waker . wake ( )
self . _alive = False
self . defer ( _shutdown )
def join ( self ) :
def join ( self ) :
self . _thread . join ( )
self . _thread . join ( )