Imported Upstream version 17.23.5
[platform/upstream/libzypp.git] / zypp / base / CleanerThread.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/base/CleanerThread.cc
10  */
11
12 #include <zypp/base/CleanerThread_p.h>
13 #include <algorithm>
14 #include <thread>
15 #include <mutex>
16 #include <condition_variable>
17 #include <chrono>
18 #include <vector>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21
22 struct CleanerData
23 {
24   static CleanerData &instance ()
25   {
26     // C++11 requires that this is thread safe "magic statics"
27     // this is a intentional leak and will live until the application exits
28     static CleanerData *data( new CleanerData );
29     return *data;
30   }
31
32   CleanerData ()
33   {
34     std::thread t ( [&](){
35       this->run();
36     } );
37     t.detach(); //we will control the thread otherwise
38   }
39
40   void run ()
41   {
42     std::unique_lock<std::mutex> lk( _m );
43
44     while ( true )
45     {
46       auto filter = []( pid_t pid ){
47         int status = 0;
48         int res = waitpid( pid, &status, WNOHANG );
49          // we either got an error, or the child has exited, remove it from list
50         bool removeMe = ( res == -1 || res == pid  );
51         return removeMe;
52       };
53       _watchedPIDs.erase( std::remove_if( _watchedPIDs.begin(), _watchedPIDs.end(), filter ), _watchedPIDs.end() );
54
55       if ( _watchedPIDs.size() )
56         _cv.wait_for( lk, std::chrono::milliseconds(100) );
57       else
58         _cv.wait( lk );
59     }
60   }
61
62   std::mutex _m; // < locks all data in CleanerData, do not access it without owning the mutex
63   std::condition_variable _cv;
64
65   std::vector<pid_t> _watchedPIDs;
66 };
67
68
69 void zypp::CleanerThread::watchPID( pid_t pid_r )
70 {
71   CleanerData &data = CleanerData::instance();
72   {
73     std::lock_guard<std::mutex> guard( data._m );
74     data._watchedPIDs.push_back( pid_r );
75   }
76   //wake the thread up
77   data._cv.notify_one();
78 }