Unverified Commit 1f50bc0b authored by David Boucher's avatar David Boucher Committed by GitHub
Browse files

fix(process/process_manager): process_manager does not need anymore to lock processes.



* enh(process_manager): code reordered to remove several mutexes locks
* enh(process_manager): _update is better atomic
* enh(process_manager): stop condition simplified
* cleanup(various): Unused headers removed.
* enh(process): set_cloexec can be private
* enh(compilation) add compilation for Raspbian (raspberry pi3)

REFS: MON-5939 MON-6521

Co-authored-by: default avatarGres Remi <rgres@centreon.com>
parent d9d33b5b
......@@ -53,11 +53,14 @@ This paragraph is only a quickstart guide for the compilation of
Centreon Clib. For a more in-depth guide with build options you should
refer to the [online documentation](https://documentation.centreon.com/docs/centreon-clib/en/latest/).
**For Centos 7 :**
First of all, check if you have these packages installed (Note that packages names come from Centos 7 distribution, so if some packages names don't match on your distribution try to find their equivalent names) :
git, make, cmake, gcc-c++.
If they are not installed, please intall them.
$> yum install git make cmake gcc-c++
If you are on Centos 7 distribution, follow these steps:
......@@ -66,11 +69,37 @@ If you are on Centos 7 distribution, follow these steps:
$> cd build
$> make & make install
You're done !
**For Raspbian :**
First of all, check if you have these packages installed :
git, make, cmake.
If they are not installed, please install them.
$> apt install git make cmake
Then you will be able to resume the following steps :
$> git clone https://github.com/centreon/centreon-clib.git
$> cd centreon-clib
$> ./cmake.sh
To speed up the compilation you can use make
$> cd build/ && make && make install
You're done !
**For other distributions :**
If you are on an other distribution, then follow the steps bellow.
First of all, check if you have these packages installed :
git, make, cmake.
Once the sources of Centreon Clib extracted, create the *build/*
directory and from that directory launch the CMake command as proposed below:
$> git clone https://github.com/centreon/centreon-clib.git
$> cd centreon-clib
$> mkdir build && cd build
$> cmake -DWITH_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DWITH_PREFIX_LIB=/usr/lib64 -DWITH_TESTING=On ..
......
......@@ -82,6 +82,40 @@ elif [ -r /etc/issue ] ; then
fi
fi
done
elif [ $maj = "Raspbian" ] ; then
if [ $version = "9" ] ; then
dpkg="dpkg"
else
dpkg="dpkg --no-pager"
fi
if $dpkg -l --no-pager cmake ; then
echo "Bad version of cmake..."
exit 1
else
if [ $my_id -eq 0 ] ; then
apt install -y cmake
cmake='cmake'
else
echo -e "cmake is not installed, you could enter, as root:\n\tapt install -y cmake\n\n"
exit 1
fi
fi
pkgs=(
gcc
g++
ninja-build
pkg-config
)
for i in "${pkgs[@]}"; do
if ! $dpkg -l --no-pager $i | grep "^ii" ; then
if [ $my_id -eq 0 ] ; then
apt install -y $i
else
echo -e "The package \"$i\" is not installed, you can install it, as root, with the command:\n\tapt install -y $i\n\n"
exit 1
fi
fi
done
else
echo "Bad version of cmake..."
exit 1
......@@ -93,7 +127,11 @@ if [ ! -d build ] ; then
fi
cd build
CXXFLAGS="-Wall -Wextra" $cmake -DWITH_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DWITH_PREFIX_LIB=/usr/lib64 -DWITH_TESTING=On $* ..
if [ $maj = "Raspbian" ] ; then
CXXFLAGS="-Wall -Wextra" $cmake -DWITH_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DWITH_PREFIX_LIB=/usr/lib -DWITH_TESTING=On $* ..
else
CXXFLAGS="-Wall -Wextra" $cmake -DWITH_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DWITH_PREFIX_LIB=/usr/lib64 -DWITH_TESTING=On $* ..
fi
#CXX=/usr/bin/clang++ CC=/usr/bin/clang CXXFLAGS="-Wall -Wextra" cmake -DWITH_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DWITH_PREFIX_LIB=/usr/lib64 -DWITH_TESTING=On $* ..
......
package main
import (
"bufio"
"fmt"
"log"
"os"
"path/filepath"
"regexp"
"strings"
)
// MaxDepth Max depth in search tree
const MaxDepth = 3
func findIncludes(file string, treated *[]string, edges *[]string, depth int) {
var myList []string
file1 := file
f, err := os.Open(file1)
if err != nil {
file1 = strings.TrimPrefix(file, "inc/")
for _, pref := range []string{
"/usr/local/include/",
"inc/",
"modules/external_commands/inc/" } {
f, err = os.Open(pref + file1)
if err == nil {
file1 = pref + file1
*treated = append(*treated, file1)
break
}
}
} else {
*treated = append(*treated, file1)
}
defer f.Close()
depth++
if depth > MaxDepth {
return
}
scanner := bufio.NewScanner(f)
r, _ := regexp.Compile("^#\\s*include\\s*([<\"])(.*)[>\"]")
for scanner.Scan() {
line := scanner.Text()
match := r.FindStringSubmatch(line)
if len(match) > 0 {
/* match[0] is the global match, match[1] is '<' or '"' and match[2] is the file to include */
if match[1] == "\"" {
*edges = append(*edges, fmt.Sprintf(" \"%s\" -> \"%s\";\n", file, match[2]))
myList = append(myList, match[2])
} else {
*edges = append(*edges, fmt.Sprintf(" \"%s\" -> \"%s\";\n", file, match[2]))
}
}
}
if err := scanner.Err(); err != nil {
log.Print(file, " --- ", err)
}
for _, file2 := range myList {
found := false
for _, ff := range *treated {
if ff == file2 {
found = true
break
}
}
if !found {
findIncludes(file2, treated, edges, depth)
}
}
}
func unique(edges []string) []string {
keys := make(map[string]bool)
list := []string{}
for _, entry := range edges {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}
func main() {
args := os.Args[1:]
var fileList []string
var edges []string
if len(args) == 0 {
for _, searchDir := range []string{"src", "inc"} {
filepath.Walk(searchDir, func(path string, f os.FileInfo, err error) error {
if strings.HasSuffix(path, ".cc") || strings.HasSuffix(path, ".hh") {
fileList = append(fileList, path)
}
return nil
})
}
} else {
fileList = append(fileList, args[0])
}
fmt.Println("digraph deps {")
var treated []string
for _, file := range fileList {
findIncludes(file, &treated, &edges, 0)
}
edges = unique(edges)
for _, l := range edges {
fmt.Println(l)
}
fmt.Println("}")
}
#!/bin/bash
go run deps.go "$*" > /tmp/deps.dot
dot -Tpng /tmp/deps.dot -o deps.png
if [ -x /usr/bin/eog ] ; then
eog deps.png&
elif [ -x /usr/bin/lximage-qt ] ; then
lximage-qt deps.png&
else
echo "No image viewer defined..."
exit 1
fi
......@@ -19,7 +19,6 @@
#ifndef CC_CLIB_HH
#define CC_CLIB_HH
#include "com/centreon/namespace.hh"
#include "com/centreon/logging/engine.hh"
#include "com/centreon/process_manager.hh"
......
......@@ -43,9 +43,7 @@ class delayed_delete : public task {
*
* @param[in] dd Object to copy.
*/
void _internal_copy(delayed_delete const& dd) {
_ptr = dd._ptr;
}
void _internal_copy(delayed_delete const& dd) { _ptr = dd._ptr; }
public:
/**
......
......@@ -20,8 +20,6 @@
#define CC_EXCEPTIONS_BASIC_HH
#include <exception>
#include <string>
#include "com/centreon/namespace.hh"
#include "com/centreon/misc/stringifier.hh"
CC_BEGIN()
......
......@@ -20,7 +20,6 @@
#define CC_HANDLE_ACTION_HH
#include <atomic>
#include "com/centreon/namespace.hh"
#include "com/centreon/task.hh"
CC_BEGIN()
......
......@@ -20,7 +20,6 @@
#define CC_HANDLE_LISTENER_HH
#include "com/centreon/handle.hh"
#include "com/centreon/namespace.hh"
CC_BEGIN()
......
......@@ -17,58 +17,51 @@
*/
#ifndef CC_HANDLE_MANAGER_POSIX_HH
# define CC_HANDLE_MANAGER_POSIX_HH
#define CC_HANDLE_MANAGER_POSIX_HH
# include <map>
# include <mutex>
# include <poll.h>
# include <utility>
# include "com/centreon/namespace.hh"
# include "com/centreon/handle.hh"
#include <poll.h>
#include <map>
#include <mutex>
#include <utility>
#include "com/centreon/handle.hh"
CC_BEGIN()
// Forward declarations.
class handle_action;
class handle_listener;
class task_manager;
class handle_action;
class handle_listener;
class task_manager;
/**
* @class handle_manager handle_manager_posix.hh "com/centreon/handle_manager.hh"
* @class handle_manager handle_manager_posix.hh
* "com/centreon/handle_manager.hh"
* @brief Multiplex I/O from multiple handles.
*
* Listen handles and notifies listeners accordingly.
*/
class handle_manager {
public:
handle_manager(task_manager* tm = nullptr);
handle_manager(handle_manager const& right) = delete;
virtual ~handle_manager() throw ();
class handle_manager {
public:
handle_manager(task_manager* tm = nullptr);
handle_manager(handle_manager const& right) = delete;
virtual ~handle_manager() throw();
handle_manager& operator=(handle_manager const& right) = delete;
void add(
handle* h,
handle_listener* hl,
bool is_threadable = false);
void link(task_manager* tm);
void multiplex();
bool remove(handle* h);
unsigned int remove(handle_listener* hl);
void add(handle* h, handle_listener* hl, bool is_threadable = false);
void link(task_manager* tm);
void multiplex();
bool remove(handle* h);
unsigned int remove(handle_listener* hl);
private:
//void _internal_copy(handle_manager const& right);
static int _poll(
pollfd *fds,
nfds_t nfds,
int timeout) throw ();
void _setup_array();
private:
// void _internal_copy(handle_manager const& right);
static int _poll(pollfd* fds, nfds_t nfds, int timeout) throw();
void _setup_array();
pollfd* _array;
std::map<native_handle, handle_action*>
_handles;
bool _recreate_array;
task_manager* _task_manager;
pollfd* _array;
std::map<native_handle, handle_action*> _handles;
bool _recreate_array;
task_manager* _task_manager;
};
CC_END()
#endif // !CC_HANDLE_MANAGER_POSIX_HH
#endif // !CC_HANDLE_MANAGER_POSIX_HH
......@@ -19,9 +19,7 @@
#ifndef CC_LOGGING_LOGGER_HH
#define CC_LOGGING_LOGGER_HH
#include "com/centreon/logging/engine.hh"
#include "com/centreon/logging/temp_logger.hh"
#include "com/centreon/namespace.hh"
CC_BEGIN()
......
/*
** Copyright 2012-2013,2019 Centreon
** Copyright 2012-2013,2019-2021 Centreon
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
......@@ -19,11 +19,10 @@
#ifndef CC_PROCESS_POSIX_HH
#define CC_PROCESS_POSIX_HH
#include <sys/types.h>
#include <condition_variable>
#include <mutex>
#include <string>
#include <sys/types.h>
#include "com/centreon/namespace.hh"
#include "com/centreon/timestamp.hh"
CC_BEGIN()
......@@ -41,20 +40,49 @@ class process {
friend class process_manager;
public:
enum status {
normal = 0,
crash = 1,
timeout = 2
};
enum stream {
in = 0,
out = 1,
err = 2
};
enum status { normal = 0, crash = 1, timeout = 2 };
enum stream { in = 0, out = 1, err = 2 };
private:
std::string _buffer_err;
std::string _buffer_out;
pid_t (*_create_process)(char**, char**);
mutable std::condition_variable _cv_buffer_err;
mutable std::condition_variable _cv_buffer_out;
mutable std::condition_variable _cv_process_running;
const std::array<bool, 3> _enable_stream;
std::array<int, 3> _stream;
timestamp _end_time;
bool _is_timeout;
process_listener* _listener;
mutable std::mutex _lock_process;
pid_t _process;
timestamp _start_time;
int _status;
uint32_t _timeout;
static void _close(int& fd) noexcept;
static pid_t _create_process_with_setpgid(char** args, char** env);
static pid_t _create_process_without_setpgid(char** args, char** env);
static void _dev_null(int fd, int flags);
static int _dup(int oldfd);
static void _dup2(int oldfd, int newfd);
bool _is_running() const noexcept;
void _kill(int sig);
static void _pipe(int fds[2]);
ssize_t do_read(int fd);
void do_close(int fd);
static void _set_cloexec(int fd);
process(process_listener* l = NULL);
public:
process(process_listener* l = nullptr,
bool in_stream = true,
bool out_stream = true,
bool err_stream = true);
virtual ~process() noexcept;
void enable_stream(stream s, bool enable);
process(const process&) = delete;
process& operator=(const process&) = delete;
// void enable_stream(stream s, bool enable);
timestamp const& end_time() const noexcept;
void exec(char const* cmd, char** env = nullptr, uint32_t timeout = 0);
void exec(std::string const& cmd, uint32_t timeout = 0);
......@@ -72,39 +100,6 @@ class process {
void update_ending_process(int status);
uint32_t write(std::string const& data);
uint32_t write(void const* data, uint32_t size);
private:
process(process const& p);
process& operator=(process const& p);
static void _close(int& fd) noexcept;
static pid_t _create_process_with_setpgid(char** args, char** env);
static pid_t _create_process_without_setpgid(char** args, char** env);
static void _dev_null(int fd, int flags);
static int _dup(int oldfd);
static void _dup2(int oldfd, int newfd);
bool _is_running() const noexcept;
void _kill(int sig);
static void _pipe(int fds[2]);
ssize_t do_read(int fd);
void do_close(int fd);
static void _set_cloexec(int fd);
std::string _buffer_err;
std::string _buffer_out;
pid_t (*_create_process)(char**, char**);
mutable std::condition_variable _cv_buffer_err;
mutable std::condition_variable _cv_buffer_out;
mutable std::condition_variable _cv_process_running;
bool _enable_stream[3];
timestamp _end_time;
bool _is_timeout;
process_listener* _listener;
mutable std::mutex _lock_process;
pid_t _process;
timestamp _start_time;
int _status;
int _stream[3];
uint32_t _timeout;
};
CC_END()
......
......@@ -19,12 +19,14 @@
#ifndef CC_PROCESS_MANAGER_POSIX_HH
#define CC_PROCESS_MANAGER_POSIX_HH
#include <poll.h>
#include <atomic>
#include <deque>
#include <map>
#include <mutex>
#include <poll.h>
#include <thread>
#include <unordered_map>
#include <vector>
#include "com/centreon/namespace.hh"
CC_BEGIN()
......@@ -46,16 +48,16 @@ class process_manager {
int status;
};
std::thread* _thread;
pollfd* _fds;
std::vector<pollfd> _fds;
uint32_t _fds_capacity;
int _fds_exit[2];
uint32_t _fds_size;
mutable std::mutex _lock_processes;
std::deque<orphan> _orphans_pid;
std::unordered_map<int, process*> _processes_fd;
std::unordered_map<int32_t, process*> _processes_fd;
std::unordered_map<pid_t, process*> _processes_pid;
std::multimap<uint32_t, process*> _processes_timeout;
bool _update;
std::atomic_bool _update;
std::atomic_bool _running;
process_manager();
~process_manager() noexcept;
......
......@@ -20,8 +20,8 @@
#define CC_TASK_MANAGER_HH
#include <condition_variable>
#include <map>
#include <deque>
#include <map>
#include <mutex>
#include <thread>
#include <vector>
......@@ -38,7 +38,7 @@ class task_manager {
uint64_t id;
bool is_runnable;
bool should_delete;
uint32_t interval; // When 0, this task is in auto_delete
uint32_t interval; // When 0, this task is in auto_delete
task* tsk;
internal_task(task* tsk,
......
......@@ -19,6 +19,7 @@
#ifndef CC_TIMESTAMP_HH
#define CC_TIMESTAMP_HH
#include <cstdint>
#include <ctime>
#include "com/centreon/namespace.hh"
......@@ -31,41 +32,38 @@ CC_BEGIN()
* Allow to manage time easily.
*/
class timestamp {
public:
timestamp(time_t secs = 0, int usecs = 0);
timestamp(timestamp const& right);
~timestamp() throw();
timestamp& operator=(timestamp const& right);
bool operator==(timestamp const& right) const throw();
bool operator!=(timestamp const& right) const throw();
bool operator<(timestamp const& right) const throw();
bool operator<=(timestamp const& right) const throw();
bool operator>(timestamp const& right) const throw();
bool operator>=(timestamp const& right) const throw();
timestamp operator+(timestamp const& right) const;
timestamp operator-(timestamp const& right) const;
timestamp& operator+=(timestamp const& right);
timestamp& operator-=(timestamp const& right);
void add_mseconds(long msecs);
void add_seconds(time_t secs);
void add_useconds(long usecs);
void clear() throw();
static timestamp max_time() throw();
static timestamp min_time() throw();
static timestamp now() throw();
void sub_mseconds(long msecs);
void sub_seconds(time_t secs);
void sub_useconds(long usecs);
long long to_mseconds() const throw();
time_t to_seconds() const throw();
long long to_useconds() const throw();
private:
void _internal_copy(timestamp const& right);
static void _transfer(time_t* secs, unsigned int* usecs);
time_t _secs;
unsigned int _usecs;
uint32_t _usecs;
public:
timestamp(time_t secs = 0, int32_t usecs = 0);
timestamp(const timestamp& right);
~timestamp() noexcept = default;
timestamp& operator=(const timestamp& right);
bool operator==(const timestamp& right) const noexcept;
bool operator!=(const timestamp& right) const noexcept;
bool operator<(const timestamp& right) const noexcept;
bool operator<=(const timestamp& right) const noexcept;