Update of /cvsroot/freevo/freevo/src
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28417

Modified Files:
        childapp.py 
Log Message:
move basic process handling from childapp to util.popen

Index: childapp.py
===================================================================
RCS file: /cvsroot/freevo/freevo/src/childapp.py,v
retrieving revision 1.71
retrieving revision 1.72
diff -C2 -d -r1.71 -r1.72
*** childapp.py 12 Dec 2004 18:02:39 -0000      1.71
--- childapp.py 18 Dec 2004 13:27:54 -0000      1.72
***************
*** 1,76 ****
  # -*- coding: iso-8859-1 -*-
! # -----------------------------------------------------------------------
! # childapp.py - Runs an application in a child process
! # -----------------------------------------------------------------------
  # $Id$
  #
! # Notes:
! # Todo:        
! #
! # -----------------------------------------------------------------------
! # $Log$
! # Revision 1.71  2004/12/12 18:02:39  dischi
! # wait longer on exit
! #
! # Revision 1.70  2004/12/05 13:01:10  dischi
! # delete old tv variables, rename some and fix detection
! #
! # Revision 1.69  2004/11/20 18:22:58  dischi
! # use python logger module for debug
! #
! # Revision 1.68  2004/11/07 16:39:21  dischi
! # create extra finish function
! #
! # Revision 1.67  2004/11/04 17:40:17  dischi
! # change to new notifier interface
! #
! # Revision 1.66  2004/11/01 20:14:04  dischi
! # fix debug
! #
! # Revision 1.65  2004/10/30 18:47:14  dischi
! # fix missing import
! #
! # Revision 1.64  2004/10/29 18:16:41  dischi
! # moved killall to this file
! #
! # Revision 1.63  2004/10/06 19:24:00  dischi
! # switch from rc.py to pyNotifier
! #
! # Revision 1.62  2004/10/06 18:44:24  dischi
! # rewrite to use pyNotifier and no threads
! #
! # Revision 1.61  2004/09/15 20:47:42  dischi
! # avoid duplicate events
! #
! # Revision 1.60  2004/08/23 20:38:56  dischi
! # fix osd stop/restart
! #
! # Revision 1.59  2004/08/23 12:39:59  dischi
! # remove osd.py dep
! #
! # Revision 1.58  2004/07/26 18:10:16  dischi
! # move global event handling to eventhandler.py
! #
! # Revision 1.57  2004/07/10 12:33:36  dischi
! # header cleanup
! #
! # Revision 1.56  2004/06/06 06:51:55  dischi
! # fix prio handling
! #
! # Revision 1.55  2004/05/31 10:40:57  dischi
! # update to new callback handling in rc
  #
! # Revision 1.54  2004/05/30 18:27:53  dischi
! # More event / main loop cleanup. rc.py has a changed interface now
  #
! # Revision 1.53  2004/05/29 19:06:46  dischi
! # register poll function to rc
  #
! # Revision 1.52  2004/05/09 14:16:16  dischi
! # let the child stdout handled by main
  #
- # -----------------------------------------------------------------------
- # Freevo - A Home Theater PC framework
- # Copyright (C) 2002 Krister Lagerstrom, et al. 
  # Please see the file freevo/Docs/CREDITS for a complete list of authors.
  #
--- 1,22 ----
  # -*- coding: iso-8859-1 -*-
! # 
-----------------------------------------------------------------------------
! # childapp.py - runs an application in a child process
! # 
-----------------------------------------------------------------------------
  # $Id$
  #
! # Run a child application inside Freevo. The class is based util.popen and
! # send events on start/stop. It is also possible to shut down the gui when
! # the child is starting.
  #
! # TODO: o remove doeslogging, debugname
! #       o better handling of stop_osd and is_video
  #
! # 
-----------------------------------------------------------------------------
! # Freevo - A Home Theater PC framework
! # Copyright (C) 2002-2004 Krister Lagerstrom, Dirk Meyer, et al.
  #
! # First edition: Krister Lagerstrom <[EMAIL PROTECTED]>
! # Maintainer:    Dirk Meyer <[EMAIL PROTECTED]>
  #
  # Please see the file freevo/Docs/CREDITS for a complete list of authors.
  #
***************
*** 89,160 ****
  # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  #
! # ----------------------------------------------------------------------- */
! import sys
! import time
! import os
! import fcntl
! import threading, thread
! import signal
! import copy
! import popen2
! import glob
! import re
  
- import notifier
  
  import config
  import eventhandler
! import cleanup
! import util
  
  from event import *
  
! import logging
! log = logging.getLogger('childapp')
! 
! watcher = None
! 
! 
! def killall(appname, sig=9):
!     """
!     kills all applications with the string <appname> in their commandline.
! 
!     The <sig> parameter indicates the signal to use.
!     This implementation uses the /proc filesystem, it might be 
Linux-dependent.
!     """
! 
!     unify_name = re.compile('[^A-Za-z0-9]').sub
!     appname = unify_name('', appname)
! 
!     cmdline_filenames = glob.glob('/proc/[0-9]*/cmdline')
! 
!     for cmdline_filename in cmdline_filenames:
!         try:
!             fd = vfs.open(cmdline_filename)
!             cmdline = fd.read()
!             fd.close()
!         except IOError:
!             continue
!         if unify_name('', cmdline).find(appname) != -1:
!             # Found one, kill it
!             pid = int(cmdline_filename.split('/')[2])
!             try:
!                 os.kill(pid, sig)
!             except:
!                 pass
!     return
! 
! 
! class Instance:
!     """
!     Base class for started child processes
!     """
!     ready = False
! 
      def __init__( self, app, debugname = None, doeslogging = 0, prio = 0,
                    stop_osd = 2 ):
!         cleanup.register( self.stop )
! 
!         self.is_video = 0                       # Be more explicit
          if stop_osd == 2: 
              self.is_video = 1
--- 35,59 ----
  # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  #
! # 
-----------------------------------------------------------------------------
  
  
+ __all__ = [ 'Instance' ]
+ 
+ # Python imports
+ import os
+ 
+ # Freevo imports
+ import sysconfig
  import config
  import eventhandler
! import util.popen
! import gui
  
  from event import *
  
! class Instance(util.popen.Process):
      def __init__( self, app, debugname = None, doeslogging = 0, prio = 0,
                    stop_osd = 2 ):
!         self.is_video = 0
          if stop_osd == 2: 
              self.is_video = 1
***************
*** 164,168 ****
          self.stop_osd = stop_osd
          if self.stop_osd:
-             import gui
              gui.display.hide()
          
--- 63,66 ----
***************
*** 170,268 ****
              eventhandler.post( Event( PLAY_START, arg = self.item ) )
  
-         # return status of the child
-         self.status = 0
- 
          if isinstance( app, unicode ):
!             app = app.encode( config.LOCALE, 'ignore' )
              
!         if isinstance(app, str):
!             # app is a string to execute. It will be executed by 'sh -c '
!             # inside the popen code
!             self.binary = app.lstrip()
!                 
!             start_str = app
!             debug_name = app[ : app.find( ' ' ) ]
!         else:
!             # app is a list
!             if app[ 0 ].startswith( '--prio' ): app = app[ 1 : ]
!             while '' in app:
!                 app.remove( '' )
  
!             self.binary = str( ' ' ).join( app )
!             start_str = app
!             
!             debug_name = app[ 0 ]
!             log.info('running %s' % self.binary)
!         
!         if debug_name.rfind('/') > 0:
!             debug_name = debug_name[ debug_name.rfind( '/' ) + 1 : ]
!         else:
!             debug_name = debug_name
  
          if debugname:
!           debug_name = debugname
!       
!       if doeslogging or config.CHILDAPP_DEBUG:
!           doeslogging = 1
        
!         self.__kill_timer = None
!         self.stopping = False
!         self.child   = popen2.Popen3( start_str, True, 100 )
!         self.outfile = self.child.fromchild 
!         self.errfile = self.child.childerr
!         self.infile  = self.child.tochild
  
-         self.__io_out = IO_Handler( 'stdout', self.outfile, self.stdout_cb,
-                                    debug_name, doeslogging )
-         self.__io_err = IO_Handler( 'stderr', self.errfile, self.stderr_cb,
-                                    debug_name, doeslogging )
-         watcher.add( self.child, self.__child_died )
-         
          if prio and config.CONF.renice:
              os.system('%s %s -p %s 2>/dev/null >/dev/null' % \
                        (config.CONF.renice, prio, self.child.pid))
              
-         self.ready = True
-         self.dead = False
          
  
-     # Write a string to the app. 
-     def write( self, line ):
-         try:
-             self.infile.write(line)
-             self.infile.flush()
-         except (IOError, ValueError):
-             pass
-         
- 
-     def isAlive( self ):
-         if not self.ready: # return true if constructor has not finished yet
-             return True
-         return not self.outfile.closed or not self.errfile.closed
-         
- 
-     def stop( self, cmd = '' ):
-         """
-         stop the child
-         """
-         if self.stopping:
-             return
- 
-         self.stopping = True
-         cleanup.unregister( self.stop )
- 
-         if self.isAlive() and not self.__kill_timer:
-             if cmd:
-                 log.info('sending exit command to app')
-                 self.write(cmd)
-                 cb = notifier.Callback( self._kill, 15 )
-                 self.__kill_timer = notifier.addTimer( 3000, cb )
-             else:
-                 cb = notifier.Callback( self._kill, 15 )
-                 self.__kill_timer = notifier.addTimer( 0, cb )
- 
-             while not self.dead:
-                 notifier.step( False, False )
- 
      def stop_event(self):
          """
--- 68,94 ----
              eventhandler.post( Event( PLAY_START, arg = self.item ) )
  
          if isinstance( app, unicode ):
!             app = String(app)
              
!         if not debugname:
!             if isinstance(app, str):
!                 debugname = app[ : app.find( ' ' ) ]
!             else:
!                 debugname = app[ 0 ]
  
!             if debugname.rfind('/') > 0:
!                 debugname = debugname[ debugname.rfind( '/' ) + 1 : ]
  
          if debugname:
!           debugname = sysconfig.logfile(debugname)
        
!         util.popen.Process.__init__(self, app, debugname)
  
          if prio and config.CONF.renice:
              os.system('%s %s -p %s 2>/dev/null >/dev/null' % \
                        (config.CONF.renice, prio, self.child.pid))
              
          
  
      def stop_event(self):
          """
***************
*** 272,327 ****
  
  
-     def _kill( self, signal ):
-         if not self.isAlive():
-             self.dead = True
-             return False
-         # child needs some assistance with dying ...
-         try:
-             os.kill( self.child.pid, signal )
-         except OSError:
-             pass
- 
-         if signal == 15:
-             cb = notifier.Callback( self._kill, 9 )
-         else:
-             cb = notifier.Callback( self._killall, 15 )
-             
-         self.__kill_timer = notifier.addTimer( 3000, cb )
-         
-         return False
- 
-     def _killall( self, signal ):
-         if not self.isAlive():
-             self.dead = True
-             return False
-         # child needs some assistance with dying ...
-         try:
-             killall( self.binary, signal )
-         except OSError:
-             pass
- 
-         log.info('kill -%d %s' % ( signal, self.binary ))
-         if signal == 15:
-             cb = notifier.Callback( self._killall, 9 )
-             self.__kill_timer = notifier.addTimer( 2000, cb )
-         else:
-             log.critical('PANIC %s' % self.binary)
-             
-         return False
- 
-     def __child_died( self, proc ):
-         self.dead = True
-         # cleanup IO handler and kill timer
-         self.__io_out.cleanup()
-         self.__io_err.cleanup()
-         if self.__kill_timer:
-             notifier.removeTimer( self.__kill_timer )
-         self.finished()
- 
-         
      def finished(self):
          # Ok, we can use the OSD again.
          if self.stop_osd:
-             import gui
              gui.display.show()
  
--- 98,104 ----
***************
*** 332,452 ****
  
          
-     # Override this method to receive stdout from the child app
-     # The function receives complete lines
-     def stdout_cb( self, line ):
-         pass
- 
- 
-     # Override this method to receive stderr from the child app
-     # The function receives complete lines
-     def stderr_cb( self, line ):
-         pass
- 
- 
- class IO_Handler:
-     """
-     reading data from socket 
-     """
-     def __init__( self, name, fp, callback, logger = None, doeslogging = 0 ):
-         self.name = name
-         self.fp = fp
-         fcntl.fcntl( self.fp.fileno(), fcntl.F_SETFL, os.O_NONBLOCK )
-         self.callback = callback
-         self.logger = None
-         self.saved = ''
-         notifier.addSocket( fp, self._handle_input )
-         if logger and doeslogging:
-             logger = os.path.join( config.LOGDIR,
-                                         '%s-%s.log' % ( logger, name ) )
-             try:
-                 try:
-                     os.unlink(logger)
-                 except:
-                     pass
-                 self.logger = open(logger, 'w')
-                 log.info('logging child to "%s"' % logger)
-             except IOError:
-                 log.warning('Error: Cannot open "%s" for logging' % logger)
-             
-     def cleanup( self ):
-         notifier.removeSocket( self.fp )
- 
-     def _handle_input( self, socket ):
-         data = self.fp.read( 100 )
-         if not data:
-             log.debug( '%s: No data, stopping (pid %s)!' % \
-                        ( self.name, os.getpid() ) )
-             notifier.removeSocket( self.fp )
-             self.fp.close()
-             if self.logger:
-                 self.logger.close()
-         else:
-             data  = data.replace('\r', '\n')
-             lines = data.split('\n')
- 
-             # Only one partial line?
-             if len(lines) == 1:
-                 self.saved += data
-             else:
-                 # Combine saved data and first line, send to app
-                 if self.logger:
-                     self.logger.write( self.saved + lines[ 0 ] + '\n' )
-                 self.callback( self.saved + lines[ 0 ] )
-                 self.saved = ''
- 
-                 # There's one or more lines + possibly a partial line
-                 if lines[ -1 ] != '':
-                     # The last line is partial, save it for the next time
-                     self.saved = lines[ -1 ]
- 
-                     # Send all lines except the last partial line to the app
-                     for line in lines[ 1 : -1 ]:
-                         if self.logger:
-                             self.logger.write( line + '\n' )
-                         self.callback( line )
-                 else:
-                     # Send all lines to the app
-                     for line in lines[ 1 : ]:
-                         if self.logger:
-                             self.logger.write( line + '\n' )
-                         self.callback( line )
-         return True
-     
- 
- class _Watcher:
-     def __init__( self ):
-         log.info('new process watcher instance')
-         self.__processes = {}
- 
- 
-     def add( self, proc, cb ):
-         self.__processes[ proc ] = cb
- 
-     def remove( self, proc ):
-         if self.__processes.has_key():
-             del self.__processes[ proc ]
-     
-     def step( self ):
-         remove_proc = []
-         for p in copy.copy( self.__processes ):
-             try:
-                 if isinstance( p, popen2.Popen3 ):
-                     pid, status = os.waitpid( p.pid, os.WNOHANG )
-                 else:
-                     pid, status = os.waitpid( p.pid, os.WNOHANG )
-             except OSError:
-                 remove_proc.append( p )
-                 continue
-             if not pid: continue
-             log.info('DEAD CHILD: %s (%s)' % ( pid, status ))
-             if status == -1:
-                 log.error('error retrieving process information from %d' % p)
-             elif os.WIFEXITED( status ) or os.WIFSIGNALED( status ) or \
-                      os.WCOREDUMP( status ):
-                 self.__processes[ p ]( p )
-                 remove_proc.append( p )
- 
-         # remove dead processes
-         for p in remove_proc: del self.__processes[ p ]
- 
- watcher = _Watcher()
--- 109,110 ----



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now. 
http://productguide.itmanagersjournal.com/
_______________________________________________
Freevo-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog

Reply via email to