/* * SystemBackendPosix.cpp * * Copyright (C) 2008 Matthias Schiffer * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "SystemBackendPosix.h" #include #include #include #include #include namespace Mad { namespace Common { namespace Backends { SystemBackendPosix SystemBackendPosix::backend; std::map > SystemBackendPosix::processes; void SystemBackendPosix::setChildHandler() { struct sigaction action; action.sa_handler = childHandler; sigemptyset(&action.sa_mask); action.sa_flags = 0; sigaction(SIGCHLD, &action, 0); } SystemBackendPosix::~SystemBackendPosix() { struct sigaction action; action.sa_handler = SIG_DFL; sigemptyset(&action.sa_mask); action.sa_flags = 0; sigaction(SIGCHLD, &action, 0); } void SystemBackendPosix::childHandler(int) { int status; pid_t pid; while((pid = waitpid(-1, &status, WNOHANG)) > 0) { std::map >::iterator it = processes.find(pid); if(it != processes.end()) { it->second(status); processes.erase(it); } } setChildHandler(); } bool SystemBackendPosix::exec(sigc::slot resultHandler, const std::string &filename, const std::vector &argv, const std::vector &env) { pid_t pid; char **argvp, **envp; if(argv.empty()) { argvp = new char*[2]; argvp[0] = strdup(filename.c_str()); argvp[1] = 0; } else { argvp = new char*[argv.size() + 1]; for(size_t s = 0; s < argv.size(); ++s) { argvp[s] = strdup(argv[s].c_str()); } argvp[argv.size()] = 0; } if(env.empty()) { envp = environ; } else { envp = new char*[env.size() + 1]; for(size_t s = 0; s < env.size(); ++s) { envp[0] = strdup(env[s].c_str()); } envp[env.size()] = 0; } sigset_t set, oldset; sigemptyset(&set); sigaddset(&set, SIGCHLD); sigprocmask(SIG_BLOCK, &set, &oldset); bool ret = (posix_spawnp(&pid, filename.c_str(), 0, 0, argvp, envp) == 0); if(ret) processes.insert(std::make_pair(pid, resultHandler)); sigprocmask(SIG_SETMASK, &oldset, 0); for(char **p = argvp; *p != 0; ++p) std::free(*p); delete [] argvp; if(envp != environ) { for(char **p = envp; *p != 0; ++p) std::free(*p); delete [] envp; } return ret; } } } }