2021SC@SDUSC
os-sim/www源码分析之agent/src/task.py
1、class ready
class _ready(Exception):
pass
def which(filename):
"""Find the file 'filename' in the execution path. If no executable
file is found, return None"""
for dir in os.environ['PATH'].split(os.pathsep):
fn=os.path.join(dir,filename)
if os.path.exists(fn):
if os.stat(fn)[0]&0111:
return fn
else:
return None
def Kill(self,signal=signal.SIGTERM):
"""Send a signal to the running subprocess.
optional arguments:
signal=SIGTERM: number of the signal to send.
(see os.kill)
return value:
see os.kill()
"""
if self.status is None:
# Only if it is not already finished
return os.kill(self.pid,signal)
which函数在执行路径中查找文件“filename”。如果没有可执行文件就返回None
Kill向正在运行的子进程发送信号。如果自身状态为None就执行os.kill(self.pid,signal)
os.kill()
一般用于直接Kill掉进程
2、class Task
管理异步子进程任务。
启动任务后,我们可以:
- 询问它是否已经完成了
- 等待它完成
- 在等待时执行“空闲”任务(例如Tkinter的主循环)
- 子进程终止
- 使用特定信号终止子进程
- 询问出口代码。
公共属性:None
公共方法:
- __初始化:init
- 运行: Run
- 等待:Wait
- 终止:Kill
- 完成:Done
- 状态:Status
2.1 def init
构造器
def __init__(self,command):
"""Constructor.
arguments:
command: the command to run, in the form of a string,
or a tuple or list of words.
"""
if type(command)==type(''):
self.cmd=command
self.words=command.split()
elif type(command)==type([]) or type(command)==type(()):
# Surround each word by ' '. Limitation: words cannot contain ' chars
self.cmd="'"+"' '".join(command)+"'"
self.words=tuple(command)
else:
raise error("command must be tuple, list, or string")
self.pid=None
self.status=None
2.2 def run
执行该进程。
这个方法应该只调用一次。
这个方法应该只调用一次。
可选参数:
- usesh=0:如果为1,则运行“sh-c命令”,如果为0,则拆分命令变成文字,由我们自己来执行。如果usesh=1,“Kill”方法可能不起作用你想要(它会杀死“sh”进程,而不是命令)。
- detach=0:如果为1,则运行“sh-c”命令&(不管“usesh”)。因为“sh”过程将立即终止,创建的任务将由继承“init”,这样你就可以放心地忘记它了。如果detach=1,Kill()、Done()和Status()将操作“sh”过程;没有办法知道这件事分离过程。
- stdout=None:用作子进程的stdout的文件名。如果没有,将使用父级的标准输出。
- stdin=None:用作子进程的stdin的文件名。如果没有,将使用父级的stdin。
- stderr=None:用作子进程的stderr的文件名。如果没有,将使用父级的stderr。
def Run(self,usesh=0,detach=0,stdout=None,stdin=None,stderr=None):
if self.pid!=None:
raise error("Second run on task forbidden")
self.pid=os.fork()
if not self.pid:
for fn in range(3,256): # Close all non-standard files in a safe way
try:
os.close(fn)
except os.error:
pass
if stdout: # Replace stdout by file
os.close(1)
i=os.open(stdout,os.O_CREAT|os.O_WRONLY|os.O_TRUNC,0666)
if i!=1:
sys.stderr.write("stdout not opened on 1!\n")
if stdin: # Replace stdin by file
os.close(0)
i=os.open(stdin,os.O_RDONLY)
if i!=0:
sys.stderr.write("stdin not opened on 0!\n")
if stderr: # Replace stderr by file
os.close(2)
i=os.open(stderr,os.O_CREAT|os.O_WRONLY|os.O_TRUNC,0666)
if i!=2:
sys.stdout.write("stderr not opened on 2!\n")
try:
if detach:
os.execv('/bin/sh',('sh','-c',self.cmd+'&'))
elif usesh:
os.execv('/bin/sh',('sh','-c',self.cmd))
elif self.words[0]=='/':
os.execv(self.words[0],self.words)
else:
os.execvp(self.words[0],self.words)
except:
print self.words
sys.stderr.write("Subprocess '%s' execution failed!\n"%self.cmd)
sys.exit(1)
else:
# Mother process
if detach:
# Should complete "immediately"
self.Wait()
2.3 def wait
等待子进程终止。
如果进程已终止,此函数将立即返回。
返回值:子流程的退出状态(如果成功,则为0)。
def Wait(self,idlefunc=None,interval=0.1):
if self.status!=None:
# Already finished
return self.status
if callable(idlefunc):
while 1:
try:
pid,status=os.waitpid(self.pid,os.WNOHANG)
if pid==self.pid:
self.status=status
return status
else:
idlefunc()
time.sleep(interval)
except KeyboardInterrupt:
# Send the interrupt to the inferior process.
try:
self.Kill(signal=signal.SIGINT)
except OSError:
# Apparently the process has terminated?
pass
except OSError:
# Apparently the process is unfindable?
print "WARNING: Unfindable process. Somebody else asked for my status!"
self.status=0
return 0
elif idlefunc:
raise error("Non-callable idle function")
else:
while 1:
try:
pid,status=os.waitpid(self.pid,0)
self.status=status
return status
except KeyboardInterrupt:
# Send the interrupt to the inferior process.
try:
self.Kill(signal=signal.SIGINT)
except OSError:
# Apparently the process has terminated?
pass
except OSError:
# Apparently the process is unfindable?
print "WARNING: Unfindable process. Somebody else asked for my status!"
self.status=0
return 0
2.4 def Kill
向正在运行的子进程发送信号。
参数:要发送的信号的编号。
def Kill(self,signal=signal.SIGTERM):
if self.status is None:
# Only if it is not already finished
return os.kill(self.pid,signal)
else:
print "DBG> trying to send signal to finished program"
2.5 def Done
询问进程是否已完成。
返回值:
- 1:流程已经完成了。
- 0:流程尚未完成。
def Done(self):
if self.status!=None:
return 1
else:
pid,status=os.waitpid(self.pid,os.WNOHANG)
if pid==self.pid:
#print "OK:",pid,status
self.status=status
return 1
else:
#print "NOK:",pid,status
return 0
3、class attach
class Attach:
def __init__(self,pid):
self.pid=pid
def Kill(self,signal=signal.SIGTERM):
"""Send a signal to the attached process.
optional arguments:
signal=SIGTERM: number of the signal to send.
(see os.kill)
return value:
see os.kill()
"""
return os.kill(self.pid,signal)
def Status(self):
try:
self.Kill(signal=0)
except OSError:
return 0 # Terminated (or owned by someone else)
return None # Still running
4、总结
本文件作用为对任务和任务的子进程进行监控,对任务进行执行并等待结束,在收到KILL指令时,将杀死进程。最终返回任务的执行情况。