问题描述
我知道这已经被问到了很多不同的方式,并且我能够在C和Python中实现我想要的功能,但是我需要在Ruby中实现。但是,我在任何文档中或Google上都没有看到对tcsetpgrp的支持。我什至尝试为posix函数创建C包装程序,但找不到.so。
- 将其自身(或更好的是,它创建的子过程)置于与其父系统不同的过程组中(例如posix setpgrp)
- 在控制终端(例如posix tcsetpgrp)中使这个新的过程组成为前台,
我将包括我的Python代码,这可能会更好地解释这一点,并说明这应该是一件多么简单的任务。我不是在寻找完整的解决方案,而是在Ruby 2.6.5中缺少tcsetpgrp beeing的解决方案...是否有其他功能或方法?如何创建包装器来调用手册页中所述的posix函数?
谢谢!
tcgetpgrp:
NAME
tcgetpgrp,tcsetpgrp - get and set terminal foreground process group
SYnopSIS
#include <unistd.h>
pid_t tcgetpgrp(int fd);
int tcsetpgrp(int fd,pid_t pgrp);
def App.become_tty_fg
'''This function,when used like:
suprocess.Popen(...,preexec_fn=become_tty_fg)
will force the child into a new process group and
also force the child process group to be the foreground process group in the
controlling terminal. The affect will be that that only the child will
receive a ctrl-c generated SIGNINT because the parent is Now backgrounded in a
different process group and the child process group is foreground. Signals
reach all memebers of a proces group but ctrl-c originates in the foreground
process group,so the child must be foreground in the terminal and in its own
process group to protect the parent from an ctrl-c generated SIGINT.
'''
# create new process group for the child and put it in it.
os.setpgrp()
# Supress handling of SIGTTOU which would otherwise stop the
# child proc when the terminal process group is changed.
# The return value is the current handler for SIGTTOU.
hdlr = signal.signal(signal.SIGTTOU,signal.SIG_IGN)
# Need the terminal handle to use tcsetpgrp()
tty = os.open('/dev/tty',os.O_RDWR)
# change the foreground process in the terminal to the child
os.tcsetpgrp(tty,os.getpgrp())
# restore handling of SIGTTOU in case the child needs to be stopped (ctrl-z)
signal.signal(signal.SIGTTOU,hdlr)
tty.close()
解决方法
这是python代码的逐行直接翻译。
由于ruby没有实现tcsetpgrp
,最简单的解决方案是使用FFI gem绑定到它,或者通过gem install ffi
或将FFI添加到项目Gemfile
require 'ffi'
# This is our FFI binding to our system libc.
module C
extend FFI::Library
ffi_lib 'c'
# 'int tcsetpgrp(int,pid_t)'.
# glibc defines pid_t as an int,apparently,so use that.
# this may be system/os dependent!
attach_function :tcsetpgrp,[:int,:int],:int
end
Process.setpgrp
prev = Signal.trap('SIGTTOU','IGNORE')
tty = File.open('/dev/tty','r')
rc = C.tcsetpgrp(tty.fileno,Process.getpgrp)
Signal.trap('SIGTTOU',prev)
tty.close
参考: