作为另一个ProcessGroup(Haskell)的成员生成新的shell进程

作为另一个ProcessGroup(Haskell)的成员生成新的shell进程,haskell,Haskell,问题。我正在尝试生成一个新的shell进程,并强制它成为另一个现有进程组的成员,这样,如果我的Haskell程序死掉,生成的进程将保证生存。以下投诉有关my repl中的权限: 导入系统进程 导入数据.Int createProcessWithGroup::ProcessGroupID->FilePath->[String]->可能[(String,String)]->IO ProcessID createProcessWithGroup pgid exe args env=forkProces

问题。我正在尝试生成一个新的shell进程,并强制它成为另一个现有进程组的成员,这样,如果我的Haskell程序死掉,生成的进程将保证生存。以下投诉有关my repl中的权限:

导入系统进程
导入数据.Int
createProcessWithGroup::ProcessGroupID->FilePath->[String]->可能[(String,String)]->IO ProcessID
createProcessWithGroup pgid exe args env=forkProcess$do
joinProcessGroup pgid
executeFile exe真参数环境

pidStr您只能在同一会话中将进程的进程组更改为(现有)进程组。这是操作系统的限制。有关
setpgid
调用,请参见手册页。尝试将进程组更改为其他会话中的组将导致EPERM(即使您是root)

最有可能的是,您的Haskell进程与
firefox
进程不在同一个会话中,这将解释您遇到的错误。我发现,如果我从窗口管理器启动Firefox并在终端中运行以下程序(这样Firefox属于
gnome shell
的会话,而Haskell进程属于我的
bash
shell的会话),我会得到:

另一方面,如果我完全关闭Firefox,在运行程序之前使用
Firefox&
同一终端在后台重新启动它,
joinProcessGroup
工作正常(尽管我收到了不同的错误,因为我没有安装
gvim
):

以下是我运行的测试程序:

import System.Posix
import System.Process
import Data.Int

createProcessWithGroup :: ProcessGroupID -> FilePath -> [String] -> Maybe [(String, String)] -> IO ProcessID
createProcessWithGroup pgid exe args env = forkProcess $ do
    joinProcessGroup pgid
    executeFile exe True args env

main :: IO ()
main = do
  pidStr <- readProcess "pgrep" ["firefox"] []
  let pid = CPid ((read pidStr) :: Int32)
  gpid <- getProcessGroupIDOf pid -- :: ProcessID -> IO ProcessGroupID
  putStrLn $ "gpid: " ++ (show gpid)

  pid <- createProcessWithGroup gpid "gvim" [] Nothing
  putStrLn $ "pid: " ++ (show pid)
import System.Posix
导入系统。进程
导入数据.Int
createProcessWithGroup::ProcessGroupID->FilePath->[String]->可能[(String,String)]->IO ProcessID
createProcessWithGroup pgid exe args env=forkProcess$do
joinProcessGroup pgid
executeFile exe真参数环境
main::IO()
main=do

pidStr如果您只需要将当前进程从当前进程组中分离出来,请使用
setId(2)
,或者将标准流文件描述符重定向到
/dev/null

import System.Posix.Process
导入System.Posix.IO
stdFds=[stdInput、stdOutput、stdError]
createProcessAsSessionLeader::FilePath->[String]->可能[(String,String)]->IO进程ID
createProcessAsSessionLeader exe args env=forkProcess$do
--改为使用getProcessId>>=createProcessGroupFor执行setpgid(getpid(),0)
创建会话
--此处不需要括号或结尾
--因为子进程是短暂的。
fd[String]->Maybe[(String,String)]->IO处理句柄
createProcessAsSessionLeader exe参数环境'=
fmap(\(\,p)->p)$
withBinaryFile“/dev/null”ReadWriteMode$\h->
设s=useh
在createProcess$proc exe参数中{
环境=env',标准输入=s,标准输出=s,标准错误=s,
--改为使用create_group=True执行setpgid(getpid(),0)
新会话=真
}
如果确实要加入现有流程组,请确保attacher和attachee具有相同的会话id(与登录会话不完全相同),但通常情况并非如此。否则,
setsid(2)
也被守护进程、GUI程序启动和屏幕多路复用器用于此特定目的


如果您不想完全放弃进程,那么仅屏蔽stdin就足够了,这样就不会放弃stdout和stderr。在任何情况下,子进程对终端发送的信号都没有响应,因为将进程设为会话引导程序会将其与当前控制终端断开关联(除非再次连接)。

这是运行程序的人要解决的问题,而不是程序本身。通常,你会在
screen
tmux
中运行它。我也在编译程序中得到了它?你可以尝试生成例如
sh-c'gvim&disown'
请发布一个最小的、可重复的示例。您发布的内容在顶层有一元代码,这不是合法的Haskell,因此无法按原样编译和测试。
gpid: 12125
pid: 12359
Setpgid.hs: gvim: executeFile: does not exist (No such file or directory)
import System.Posix
import System.Process
import Data.Int

createProcessWithGroup :: ProcessGroupID -> FilePath -> [String] -> Maybe [(String, String)] -> IO ProcessID
createProcessWithGroup pgid exe args env = forkProcess $ do
    joinProcessGroup pgid
    executeFile exe True args env

main :: IO ()
main = do
  pidStr <- readProcess "pgrep" ["firefox"] []
  let pid = CPid ((read pidStr) :: Int32)
  gpid <- getProcessGroupIDOf pid -- :: ProcessID -> IO ProcessGroupID
  putStrLn $ "gpid: " ++ (show gpid)

  pid <- createProcessWithGroup gpid "gvim" [] Nothing
  putStrLn $ "pid: " ++ (show pid)