LCOV - code coverage report
Current view: top level - cppthread - thread.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 231 0.4 %
Date: 2021-08-21 09:27:22 Functions: 2 31 6.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2013-2021  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/cppthread
       4             : // contact@m2osw.com
       5             : //
       6             : // This program is free software; you can redistribute it and/or modify
       7             : // it under the terms of the GNU General Public License as published by
       8             : // the Free Software Foundation; either version 2 of the License, or
       9             : // (at your option) any later version.
      10             : //
      11             : // This program is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : //
      16             : // You should have received a copy of the GNU General Public License along
      17             : // with this program; if not, write to the Free Software Foundation, Inc.,
      18             : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19             : 
      20             : /** \file
      21             :  * \brief Implementation of the Thread Runner and Managers.
      22             :  *
      23             :  * This file includes the implementation used by the cppthread environment.
      24             :  */
      25             : 
      26             : 
      27             : // self
      28             : //
      29             : #include    "cppthread/thread.h"
      30             : 
      31             : #include    "cppthread/exception.h"
      32             : #include    "cppthread/guard.h"
      33             : #include    "cppthread/log.h"
      34             : #include    "cppthread/runner.h"
      35             : 
      36             : 
      37             : // snapdev lib
      38             : //
      39             : #include    <snapdev/glob_to_list.h>
      40             : 
      41             : 
      42             : // C++ lib
      43             : //
      44             : #include    <fstream>
      45             : 
      46             : 
      47             : // C lib
      48             : //
      49             : #include    <signal.h>
      50             : #include    <sys/stat.h>
      51             : #include    <sys/syscall.h>
      52             : #include    <sys/sysinfo.h>
      53             : #include    <unistd.h>
      54             : 
      55             : 
      56             : // last include
      57             : //
      58             : #include    <snapdev/poison.h>
      59             : 
      60             : 
      61             : 
      62             : 
      63             : namespace cppthread
      64             : {
      65             : 
      66             : 
      67             : 
      68             : 
      69             : 
      70             : /** \brief Initialize the thread object.
      71             :  *
      72             :  * This function saves the name of the thread. The name is generally a
      73             :  * static string and it is used to distinguish between threads when
      74             :  * managing several at once. The function makes a copy of the name.
      75             :  *
      76             :  * The runner pointer is an object which has a run() function that will
      77             :  * be called from another thread. That object becomes the "child" of
      78             :  * this thread \em controller. However, if it is already assigned a
      79             :  * thread controller, then the initialization of the thread fails.
      80             :  * You may test whether a runner is already assigned a thread controller
      81             :  * by calling its get_thread() function and see that it is not nullptr.
      82             :  *
      83             :  * The pointer to the runner object cannot be nullptr.
      84             :  *
      85             :  * \param[in] name  The name of the process.
      86             :  * \param[in] runner  The runner (the actual thread) to handle.
      87             :  */
      88           0 : thread::thread(std::string const & name, runner * runner)
      89             :     : f_name(name)
      90           0 :     , f_runner(runner)
      91             : {
      92           0 :     if(f_runner == nullptr)
      93             :     {
      94           0 :         throw cppthread_invalid_error("runner missing in thread() constructor");
      95             :     }
      96           0 :     if(f_runner->f_thread != nullptr)
      97             :     {
      98           0 :         throw cppthread_in_use_error("this runner (" + name + ") is already in use");
      99             :     }
     100             : 
     101           0 :     int err(pthread_attr_init(&f_thread_attr));
     102           0 :     if(err != 0)
     103             :     {
     104           0 :         log << log_level_t::fatal
     105           0 :             << "the thread attributes could not be initialized, error #"
     106           0 :             << err
     107           0 :             << end;
     108           0 :         throw cppthread_invalid_error("pthread_attr_init() failed");
     109             :     }
     110           0 :     err = pthread_attr_setdetachstate(&f_thread_attr, PTHREAD_CREATE_JOINABLE);
     111           0 :     if(err != 0)
     112             :     {
     113           0 :         log << log_level_t::fatal
     114           0 :             << "the thread detach state could not be initialized, error #"
     115           0 :             << err
     116           0 :             << end;
     117           0 :         pthread_attr_destroy(&f_thread_attr);
     118           0 :         throw cppthread_invalid_error("pthread_attr_setdetachstate() failed");
     119             :     }
     120             : 
     121           0 :     f_runner->f_thread = this;
     122           0 : }
     123             : 
     124             : 
     125             : /** \brief Delete a thread object.
     126             :  *
     127             :  * The destructor of a Snap! C++ thread object ensures that the thread stops
     128             :  * running before actually deleting the runner object.
     129             :  *
     130             :  * Then it destroys the thread attributes and returns.
     131             :  *
     132             :  * The destructor also removes the thread from the runner so the runner
     133             :  * can create another thread controller and run again.
     134             :  */
     135           0 : thread::~thread()
     136             : {
     137             :     try
     138             :     {
     139           0 :         stop();
     140             :     }
     141           0 :     catch(...)
     142             :     {
     143             :         // stop() may rethrow any user exception which we have to ignore in
     144             :         // a destructor...
     145             :     }
     146           0 :     f_runner->f_thread = nullptr;
     147             : 
     148           0 :     int const err(pthread_attr_destroy(&f_thread_attr));
     149           0 :     if(err != 0)
     150             :     {
     151           0 :         log << log_level_t::error
     152           0 :             << "the thread attributes could not be destroyed, error #"
     153           0 :             << err
     154           0 :             << end;
     155             :     }
     156           0 : }
     157             : 
     158             : 
     159             : /** \brief Retrieve the name of this process object.
     160             :  *
     161             :  * This process object is given a name on creation. In most cases this is
     162             :  * a static name that is used to determine which process is which.
     163             :  *
     164             :  * \return The name of the process.
     165             :  */
     166           0 : std::string const & thread::get_name() const
     167             : {
     168           0 :     return f_name;
     169             : }
     170             : 
     171             : 
     172             : /** \brief Get a pointer to this thread runner.
     173             :  *
     174             :  * This function returns the pointer to the thread runner. There are cases
     175             :  * where it is quite handy to be able to use this function rather than
     176             :  * having to hold on the information in your own way.
     177             :  *
     178             :  * You will probably have to dynamic_cast<>() the result to your own
     179             :  * object type.
     180             :  *
     181             :  * \note
     182             :  * The thread constructor ensures that this pointer is never nullptr.
     183             :  * Therefore this function never returns a null pointer. However, the
     184             :  * dynamic_cast<>() function may return a nullptr.
     185             :  *
     186             :  * \return The runner object attached to this thread.
     187             :  */
     188           0 : runner * thread::get_runner() const
     189             : {
     190           0 :     return f_runner;
     191             : }
     192             : 
     193             : 
     194             : /** \brief Check whether the thread is considered to be running.
     195             :  *
     196             :  * This flag is used to know whether the thread is running.
     197             :  *
     198             :  * \todo
     199             :  * We need to save the pid of the process that creates threads.
     200             :  * This tells us whether the thread is running in this process.
     201             :  * i.e. if a fork() happens, then the child process does not
     202             :  * have any threads so is_running() has to return false. Also,
     203             :  * any other function that checks whether a thread is running
     204             :  * needs to also check the pid. We have to save the pid at
     205             :  * the time we start the thread and then when we check whether
     206             :  * the thread is running.
     207             :  *
     208             :  * \return true if the thread is still considered to be running.
     209             :  */
     210           0 : bool thread::is_running() const
     211             : {
     212           0 :     guard lock(f_mutex);
     213           0 :     return f_running;
     214             : }
     215             : 
     216             : 
     217             : /** \brief Check whether the thread was asked to stop.
     218             :  *
     219             :  * The thread is using three status flags. One of them is f_stopping which
     220             :  * is set to false (which is also the default status) when start() is called
     221             :  * and to true when stop() is called. This function is used to read that
     222             :  * flag status from the continue_running() function.
     223             :  *
     224             :  * \return true if the stop() function was called, false otherwise.
     225             :  */
     226           0 : bool thread::is_stopping() const
     227             : {
     228           0 :     guard lock(f_mutex);
     229           0 :     return f_stopping;
     230             : }
     231             : 
     232             : 
     233             : /** \brief Start the actual thread.
     234             :  *
     235             :  * This function is called when starting the thread. This is a static
     236             :  * function since pthread can only accept such a function pointer.
     237             :  *
     238             :  * The function then calls the internal_thread().
     239             :  *
     240             :  * \note
     241             :  * The function parameter is a void * instead of thread because that
     242             :  * way the function signature matches the signature the pthread_create()
     243             :  * function expects.
     244             :  *
     245             :  * \param[in] system_thread  The thread pointer.
     246             :  *
     247             :  * \return We return a null pointer, which we do not use because we expect
     248             :  *         uses to pass results in a different way (i.e. using the fifo).
     249             :  */
     250           0 : void * func_internal_start(void * system_thread)
     251             : {
     252           0 :     thread * t(reinterpret_cast<thread *>(system_thread));
     253           0 :     t->internal_thread();
     254           0 :     return nullptr; // == pthread_exit(nullptr);
     255             : }
     256             : 
     257             : 
     258             : /** \brief Run the thread process.
     259             :  *
     260             :  * This function is called by the func_internal_start() so we run from
     261             :  * within the thread class. (i.e. the func_internal_start() function
     262             :  * itself is static.)
     263             :  *
     264             :  * The function marks the thread as started which allows the parent start()
     265             :  * function to return.
     266             :  *
     267             :  * \note
     268             :  * The function catches standard exceptions thrown by any of the functions
     269             :  * called by the thread. When that happens, the thread returns early after
     270             :  * making a copy of the exception. The stop() function will then rethrow
     271             :  * that exception and it can be managed as if it had happened in the main
     272             :  * process (if a thread creates another thread, then it can be propagated
     273             :  * multiple times between all the threads up to the main process.)
     274             :  */
     275           0 : void thread::internal_thread()
     276             : {
     277             :     try
     278             :     {
     279             :         {
     280           0 :             guard lock(f_mutex);
     281           0 :             f_tid = gettid();
     282           0 :             f_started = true;
     283           0 :             f_mutex.signal();
     284             :         }
     285             : 
     286             :         // if the enter failed, do not continue
     287             :         //
     288           0 :         if(internal_enter())
     289             :         {
     290           0 :             if(internal_run())
     291             :             {
     292           0 :                 internal_leave(leave_status_t::LEAVE_STATUS_NORMAL);
     293             :             }
     294             :             else
     295             :             {
     296           0 :                 internal_leave(leave_status_t::LEAVE_STATUS_THREAD_FAILED);
     297             :             }
     298             :         }
     299             :         else
     300             :         {
     301           0 :             internal_leave(leave_status_t::LEAVE_STATUS_INITIALIZATION_FAILED);
     302             :         }
     303             : 
     304             :         // if useful (necessary) it would probably be better to call this
     305             :         // function from here; see function and read the "note" section
     306             :         // for additional info
     307             :         //
     308             :         //tcp_client_server::cleanup_on_thread_exit();
     309             :     }
     310           0 :     catch(std::exception const & e)
     311             :     {
     312             :         // keep a copy of the exception
     313             :         //
     314           0 :         f_exception = std::current_exception();
     315             : 
     316           0 :         if(f_log_all_exceptions)
     317             :         {
     318           0 :             log << log_level_t::fatal
     319           0 :                 << "thread internal_thread() got exception: \""
     320           0 :                 << e.what()
     321           0 :                 << "\", exiting thread now."
     322           0 :                 << end;
     323             :         }
     324             : 
     325           0 :         internal_leave(leave_status_t::LEAVE_STATUS_INSTRUMENTATION);
     326             :     }
     327           0 :     catch(...)
     328             :     {
     329             :         // ... any other exception terminates the whole process ...
     330             :         //
     331           0 :         log << log_level_t::fatal
     332           0 :             << "thread internal_thread() got an unknown exception (a.k.a. non-std::exception), exiting process."
     333           0 :             << end;
     334             : 
     335             :         // rethrow, our goal is not to ignore the exception, only to
     336             :         // have a log about it
     337             :         //
     338           0 :         throw;
     339             :     }
     340             : 
     341             :     // marked we are done (outside of the try/catch because if this one
     342             :     // fails, we have a big problem... (i.e. invalid mutex or more unlock
     343             :     // than locks)
     344             :     {
     345           0 :         guard lock(f_mutex);
     346           0 :         f_running = false;
     347           0 :         f_tid = PID_UNDEFINED;
     348           0 :         f_mutex.signal();
     349             :     }
     350           0 : }
     351             : 
     352             : 
     353             : /** \brief Enter the thread runner.
     354             :  *
     355             :  * This function signals that the thread runner is about to be entered.
     356             :  * This is often used as an initialization function.
     357             :  *
     358             :  * If the runner::enter() function raises an std::exception, then the
     359             :  * function saves that exception for the thread owner, emits a log,
     360             :  * and returns false.
     361             :  *
     362             :  * \note
     363             :  * The log is not emitted if set_log_all_exceptions() was called with false.
     364             :  *
     365             :  * \return true if the runner::enter() function returned as expected.
     366             :  */
     367           0 : bool thread::internal_enter()
     368             : {
     369             :     try
     370             :     {
     371           0 :         f_runner->enter();
     372           0 :         return true;
     373             :     }
     374           0 :     catch(std::exception const & e)
     375             :     {
     376             :         // keep a copy of the exception
     377             :         //
     378           0 :         f_exception = std::current_exception();
     379             : 
     380           0 :         if(f_log_all_exceptions)
     381             :         {
     382           0 :             log << log_level_t::fatal
     383           0 :                 << "thread internal_enter() got exception: \""
     384           0 :                 << e.what()
     385           0 :                 << "\", exiting thread now."
     386           0 :                 << end;
     387             :         }
     388             :     }
     389             : 
     390           0 :     return false;
     391             : }
     392             : 
     393             : 
     394             : /** \brief Execute the run() function.
     395             :  *
     396             :  * This function specifically calls the run() function in an exception
     397             :  * safe manner.
     398             :  *
     399             :  * If no exception occurs, the function returns true meaning that everything
     400             :  * worked as expected.
     401             :  *
     402             :  * When an std::exception occurs, the function returns false after saving
     403             :  * the exception so it can be reported to this thread owner. (i.e. it gets
     404             :  * re-thrown whenever the thread owner joins with the thread).
     405             :  *
     406             :  * The std::exception can be logged by calling the set_log_all_exceptions()
     407             :  * function with true, which is the default (i.e. don't call it with false
     408             :  * if you want to get the logs).
     409             :  *
     410             :  * Other exceptions are ignored (they will be caught by the internal_thread()
     411             :  * function).
     412             :  *
     413             :  * \return true if the run worked as expected; false if an exception was
     414             :  * caught.
     415             :  */
     416           0 : bool thread::internal_run()
     417             : {
     418             :     try
     419             :     {
     420           0 :         f_runner->run();
     421           0 :         return true;
     422             :     }
     423           0 :     catch(std::exception const & e)
     424             :     {
     425             :         // keep a copy of the exception
     426             :         //
     427           0 :         f_exception = std::current_exception();
     428             : 
     429           0 :         if(f_log_all_exceptions)
     430             :         {
     431           0 :             log << log_level_t::fatal
     432           0 :                 << "thread internal_run() got exception: \""
     433           0 :                 << e.what()
     434           0 :                 << "\", exiting thread now."
     435           0 :                 << end;
     436             :         }
     437             :     }
     438             : 
     439           0 :     return false;
     440             : }
     441             : 
     442             : 
     443             : /** \brief Function called when leaving the thread runner.
     444             :  *
     445             :  * Whenever the thread runner leaves, we want to send a signal to the
     446             :  * runner owner through the runner::leave() function. This is the thread
     447             :  * function which makes sure that the runner::leave() function get called.
     448             :  *
     449             :  * The function is called with a status which tells us what failed (i.e.
     450             :  * the reason for the call).
     451             :  *
     452             :  * The function is std::exception safe. Unknown exceptions are ignored here
     453             :  * since they will be caught by the internal_thread() function.
     454             :  *
     455             :  * std::exceptions are reported and either ignored (another exception occurred
     456             :  * earlier) or reported back to the thread owner after the owner joins with
     457             :  * the thread.
     458             :  *
     459             :  * \param[in] status  The status when the internal_leave() function gets called.
     460             :  */
     461           0 : void thread::internal_leave(leave_status_t status)
     462             : {
     463             :     try
     464             :     {
     465           0 :         f_runner->leave(status);
     466             :     }
     467           0 :     catch(std::exception const & e)
     468             :     {
     469             :         // keep the first exception (i.e. internal_enter() or internal_run()
     470             :         // have priority on this one)
     471             :         //
     472           0 :         if(f_exception == std::exception_ptr())
     473             :         {
     474           0 :             f_exception = std::current_exception();
     475             :         }
     476             : 
     477           0 :         log << log_level_t::fatal
     478           0 :             << "thread internal_leave() got exception: \""
     479           0 :             << e.what()
     480           0 :             << "\", exiting thread now."
     481           0 :             << end;
     482             :     }
     483           0 : }
     484             : 
     485             : 
     486             : /** \brief Attempt to start the thread.
     487             :  *
     488             :  * This function is used to start running the thread code. If the
     489             :  * thread is already running, then the function returns false.
     490             :  *
     491             :  * The function makes use of a condition to wait until the thread
     492             :  * is indeed started. The function will not return until the thread
     493             :  * is started or something failed.
     494             :  *
     495             :  * \return true if the thread successfully started, false otherwise.
     496             :  */
     497           0 : bool thread::start()
     498             : {
     499           0 :     guard lock(f_mutex);
     500             : 
     501           0 :     if(f_running || f_started)
     502             :     {
     503           0 :         log << log_level_t::warning
     504           0 :             << "the thread is already running"
     505           0 :             << end;
     506           0 :         return false;
     507             :     }
     508             : 
     509           0 :     if(!f_runner->is_ready())
     510             :     {
     511           0 :         log << log_level_t::warning
     512           0 :             << "the thread runner is not ready"
     513           0 :             << end;
     514           0 :         return false;
     515             :     }
     516             : 
     517           0 :     f_running = true;
     518           0 :     f_started = false;
     519           0 :     f_stopping = false; // make sure it is reset
     520           0 :     f_exception = std::exception_ptr();
     521             : 
     522           0 :     int const err(pthread_create(&f_thread_id, &f_thread_attr, &func_internal_start, this));
     523           0 :     if(err != 0)
     524             :     {
     525           0 :         f_running = false;
     526             : 
     527           0 :         log << log_level_t::error
     528           0 :             << "the thread could not be created, error #"
     529           0 :             << err
     530           0 :             << end;
     531           0 :         return false;
     532             :     }
     533             : 
     534           0 :     while(!f_started)
     535             :     {
     536           0 :         f_mutex.wait();
     537             :     }
     538             : 
     539           0 :     return true;
     540             : }
     541             : 
     542             : 
     543             : /** \brief Stop the thread.
     544             :  *
     545             :  * This function requests the thread to stop. Note that the function does
     546             :  * not actually forcibly stop the thread. It only turns on a flag (namely
     547             :  * it makes the is_stopping() function return true) meaning that the
     548             :  * thread should stop as soon as possible. This gives the thread the
     549             :  * time necessary to do all necessary cleanup before quitting.
     550             :  *
     551             :  * The stop function blocks until the thread is done.
     552             :  *
     553             :  * \warning
     554             :  * This function throws the thread exceptions that weren't caught in your
     555             :  * run() function. This happens after the thread has completed. The exception
     556             :  * is then removed from the thread (i.e. it won't re-throw a second time
     557             :  * and a call to get_exception() returns a null pointer).
     558             :  */
     559           0 : void thread::stop()
     560             : {
     561             :     {
     562           0 :         guard lock(f_mutex);
     563             : 
     564           0 :         if(!f_running && !f_started)
     565             :         {
     566             :             // we return immediately in this case because
     567             :             // there is nothing to join when the thread never
     568             :             // started...
     569             :             //
     570           0 :             return;
     571             :         }
     572             : 
     573             :         // request the child to stop
     574             :         //
     575           0 :         f_stopping = true;
     576             :     }
     577             : 
     578             :     // wait for the child to be stopped
     579             :     //
     580             :     // we cannot pass any results through the pthread interface so we
     581             :     // pass a nullptr for the result; instead, the user is expected to
     582             :     // add fields to his class and fill in whatever results he wants
     583             :     // there; it is going to work much better that way
     584             :     //
     585           0 :     pthread_join(f_thread_id, nullptr);
     586             : 
     587             :     // at this point the thread has fully exited
     588             : 
     589             :     // we are done now
     590             :     //
     591             :     // these flags are likely already the correct value except for
     592             :     // f_stopping which the stop() function manages here
     593             :     //
     594           0 :     f_running = false;
     595           0 :     f_started = false;
     596           0 :     f_stopping = false;
     597             : 
     598             :     // if the child died because of a standard exception, rethrow it now
     599             :     // and "lose it" at the same time
     600             :     //
     601           0 :     if(f_exception != std::exception_ptr())
     602             :     {
     603           0 :         std::exception_ptr e;
     604           0 :         e.swap(f_exception);
     605           0 :         std::rethrow_exception(e);
     606             :     }
     607             : }
     608             : 
     609             : 
     610             : /** \brief Retrieve the thread identifier of this thread.
     611             :  *
     612             :  * Under Linux, threads are tasks like any others. Each task is given a
     613             :  * `pid_t` value. This function returns that `pid_t` for this thread.
     614             :  *
     615             :  * When the thread is not running this function returns PID_UNDEFINED.
     616             :  * Note, however, that the value is set a little after the thread started
     617             :  * and cleared a little before the thread exits. This is **not** a good
     618             :  * way to know whether the thread is running. Use the is_running() function
     619             :  * instead.
     620             :  *
     621             :  * \return The thread identifier (tid) or PID_UNDEFINED if the thread is
     622             :  *         not running.
     623             :  */
     624           0 : pid_t thread::get_thread_tid() const
     625             : {
     626           0 :     guard lock(f_mutex);
     627           0 :     return f_tid;
     628             : }
     629             : 
     630             : 
     631             : /** \brief Retrieve a reference to the thread mutex.
     632             :  *
     633             :  * This function returns a reference to this thread mutex. Note that
     634             :  * the `runner` has its own mutex as well.
     635             :  *
     636             :  * \return This thread's mutex.
     637             :  */
     638           0 : mutex & thread::get_thread_mutex() const
     639             : {
     640           0 :     return f_mutex;
     641             : }
     642             : 
     643             : 
     644             : /** \brief Whether to log exceptions caught in the thread.
     645             :  *
     646             :  * We catch exceptions that happen in your threads. By default, we log them
     647             :  * with the basic cppthread log mechanism. If you do not want to have this
     648             :  * intermediate logging kick in, you can set this flag to false.
     649             :  *
     650             :  * This flag is defaulted to true because in many cases you are not joining
     651             :  * a thread when the exception occurs. That means your code would never
     652             :  * see the exception. Instead, you'd have a dangling process as it is
     653             :  * likely to expect things are happening in the thread and if not, it
     654             :  * gets stuck. At least, in this way, by default you get a message in your
     655             :  * logs.
     656             :  *
     657             :  * \note
     658             :  * Unknown exceptions (i.e. those not derived from std::exception), are
     659             :  * always logged and re-thrown (which has the effect of terminating your
     660             :  * process). Those exceptions are always logged, whatever the state of
     661             :  * this "log all exceptions" flag.
     662             :  *
     663             :  * \param[in] log_all_exceptions  Whether to log (true) all exceptions or
     664             :  * not (false).
     665             :  *
     666             :  * \sa get_log_all_exceptions()
     667             :  */
     668           0 : void thread::set_log_all_exceptions(bool log_all_exceptions)
     669             : {
     670           0 :     f_log_all_exceptions = log_all_exceptions;
     671           0 : }
     672             : 
     673             : 
     674             : /** \brief Retrieve whether all exceptions get logged or not.
     675             :  *
     676             :  * This function returns true if all exceptions are to be logged. By default
     677             :  * this flag is set to true. You can change it with the
     678             :  * set_log_all_exceptions() function.
     679             :  *
     680             :  * Internally, the flag is used to know whether we should log exceptions.
     681             :  * It is very useful to do so if you do not join your thread on a constant
     682             :  * basis (i.e. in a service where a thread runs as long as the service
     683             :  * itself--you probably will want to know when the thread runs in a problem).
     684             :  *
     685             :  * This also means you do not have to log the exception yourself unless you
     686             :  * need some special handling to indicate all the possible messages and
     687             :  * parameters found in the exception object. However, the logging doesn't
     688             :  * prevent the system from re-throwing the exception once the thread was
     689             :  * joined. In other words, whether you log the exception or not, you most
     690             :  * certainly want to catch it or your process will be terminated.
     691             :  *
     692             :  * \return true if the thread object is to log all exceptions.
     693             :  *
     694             :  * \sa set_log_all_exceptions()
     695             :  */
     696           0 : bool thread::get_log_all_exceptions() const
     697             : {
     698           0 :     return f_log_all_exceptions;
     699             : }
     700             : 
     701             : 
     702             : /** \brief Get the exception pointer.
     703             :  *
     704             :  * When the thread runner raises an exception, it gets saved in the
     705             :  * thread object. That exception can be retrieved using this get_exception()
     706             :  * function.
     707             :  *
     708             :  * If no exception occurred, then this pointer will be the nullptr. If
     709             :  * an exception did occur, then it will be a pointer to that exception.
     710             :  * It can be rethrown inside a try/catch in order to handle it.
     711             :  *
     712             :  * \code
     713             :  *     std::exception_ptr e(my_thread->get_exception());
     714             :  *     if(e != std::exception_ptr())
     715             :  *     {
     716             :  *         try
     717             :  *         {
     718             :  *             e->rethrow_exception();
     719             :  *         }
     720             :  *         catch(std::exception const & e)
     721             :  *         {
     722             :  *             std::cerr << "exception occurred: " << e.what() << std::endl;
     723             :  *         }
     724             :  *     }
     725             :  * \endcode
     726             :  *
     727             :  * \return A pointer to a standard exception (std::exception).
     728             :  */
     729           0 : std::exception_ptr thread::get_exception() const
     730             : {
     731           0 :     guard lock(f_mutex);
     732           0 :     return f_exception;
     733             : }
     734             : 
     735             : 
     736             : /** \brief Send a signal to this thread.
     737             :  *
     738             :  * This function sends a signal to a specific thread.
     739             :  *
     740             :  * You have to be particularly careful with Unix signal and threads as they
     741             :  * do not always work as expected. This is yet particularly useful if you
     742             :  * want to send a signal such as SIGUSR1 and SIGUSR2 to a thread so it
     743             :  * reacts one way or another (i.e. you are using poll() over a socket and
     744             :  * need to be stopped without using a possibly long time out, you can use
     745             :  * the signalfd() function to transform SIGUSR1 into a poll-able signal.)
     746             :  *
     747             :  * \note
     748             :  * Obviously, if the thread is not running, nothing happens.
     749             :  *
     750             :  * \param[in] sig  The signal to send to this thread.
     751             :  *
     752             :  * \return true if the signal was sent, false if the signal could not
     753             :  *         be sent (i.e. the thread was already terminated...)
     754             :  */
     755           0 : bool thread::kill(int sig)
     756             : {
     757           0 :     guard lock(f_mutex);
     758           0 :     if(f_running)
     759             :     {
     760             :         // pthread_kill() returns zero on success, otherwise it returns
     761             :         // an error code which at this point we lose
     762             :         //
     763           0 :         return pthread_kill(f_thread_id, sig) == 0;
     764             :     }
     765             : 
     766           0 :     return false;
     767             : }
     768             : 
     769             : 
     770             : 
     771             : 
     772             : 
     773             : 
     774             : 
     775             : 
     776             : /** \brief Retrieve the number of processors available on this system.
     777             :  *
     778             :  * This function returns the number of processors available on this system.
     779             :  *
     780             :  * \attention
     781             :  * Note that the OS may not be using all of the available processors. This
     782             :  * function returns the total number, including processors that are not
     783             :  * currently usable by your application. Most often, you probably want to
     784             :  * call get_number_of_available_processors() instead.
     785             :  *
     786             :  * \return The total number of processors on this system.
     787             :  *
     788             :  * \sa get_number_of_available_processors()
     789             :  */
     790           0 : int get_total_number_of_processors()
     791             : {
     792           0 :     return get_nprocs_conf();
     793             : }
     794             : 
     795             : 
     796             : /** \brief Retrieve the number of processors currently usable.
     797             :  *
     798             :  * This function returns the number of processors that are currently
     799             :  * running on this system. This is usually what you want to know about
     800             :  * to determine how many threads to run in parallel.
     801             :  *
     802             :  * This function is going to be equal or less than what the
     803             :  * get_total_number_of_processors() returns. For example, on some systems
     804             :  * a processors can be made offline. This is useful to save energy when
     805             :  * the total load decreases under a given threshold.
     806             :  *
     807             :  * \note
     808             :  * What is the right number of threads needed in a thread pool? If you
     809             :  * have worker threads that do a fairly small amount of work, then
     810             :  * having a number of threads equal to two times the number of
     811             :  * available thread is still sensible:
     812             :  *
     813             :  * \code
     814             :  *     pool_size = get_number_of_available_processors() * 2;
     815             :  * \endcode
     816             :  *
     817             :  * \par
     818             :  * This is particularly true when threads perform I/O with high latency
     819             :  * (i.e. read/write from a hard drive or a socket.)
     820             :  *
     821             :  * \par
     822             :  * If your thread does really intensive work for a while (i.e. one thread
     823             :  * working on one 4Mb image,) then the pool size should be limited to
     824             :  * one worker per CPU:
     825             :  *
     826             :  * \code
     827             :  *     pool_size = get_number_of_available_processors();
     828             :  * \endcode
     829             :  *
     830             :  * \par
     831             :  * Also, if you know that you will never get more than `n` objects at
     832             :  * a time in your input, then the maximum number of threads needed is
     833             :  * going to be `n`. In most cases `n` is going to be larger than the
     834             :  * number of processors although now that we can have machines with
     835             :  * over 100 CPUs, make sure to clamp your `pool_size` parameter to
     836             :  * `n` if known ahead of time.
     837             :  *
     838             :  * \return The number of processors currently available for your threads.
     839             :  *
     840             :  * \sa get_total_number_of_processors()
     841             :  */
     842           0 : int get_number_of_available_processors()
     843             : {
     844           0 :     return get_nprocs();
     845             : }
     846             : 
     847             : 
     848             : /** \brief Get the thread identifier of the current thread.
     849             :  *
     850             :  * This function retrieves the thread identifier of the current thread.
     851             :  * In most cases, this is only useful to print out messages to a log
     852             :  * including the thread identifier. This identifier is equivalent
     853             :  * to the `pid_t` returned by `getpid()` but specific to the running
     854             :  * thread.
     855             :  *
     856             :  * \return The thread identifier.
     857             :  */
     858           0 : pid_t gettid()
     859             : {
     860           0 :     return static_cast<pid_t>(syscall(SYS_gettid));
     861             : }
     862             : 
     863             : 
     864             : /** \brief Set the name of the currently running thread.
     865             :  *
     866             :  * This function is used to set the name of the currently running thread.
     867             :  *
     868             :  * \param[in] name  The name of the thread.
     869             :  *
     870             :  * \return 0 if the function worked, -1 on error.
     871             :  */
     872           0 : int set_current_thread_name(std::string const & name)
     873             : {
     874           0 :     return set_thread_name(gettid(), name);
     875             : }
     876             : 
     877             : 
     878             : /** \brief Set the name of the specified thread.
     879             :  *
     880             :  * This function changes the name of one of your threads. In
     881             :  * most cases, you should let the runner set the name of the thread
     882             :  * on construction.
     883             :  *
     884             :  * This function should be used only if the name somehow changes over
     885             :  * time, for example:
     886             :  *
     887             :  * The thread is a worker thread and you want the name to reflect what
     888             :  * the worker is currently doing. However, do that only if the worker
     889             :  * is going to do work for a while, otherwise it's likely going to be
     890             :  * rather useless (i.e. htop refresh rate is 1 to 2 seconds).
     891             :  *
     892             :  * \exception cppthread_invalid_error
     893             :  * This exception is raised if the name is empty.
     894             :  *
     895             :  * \exception cppthread_out_of_range
     896             :  * This exception is raised if the name is too long. Linux limits the
     897             :  * name of a thread to 15 characters (the buffer has a limit of
     898             :  * 16 characters).
     899             :  *
     900             :  * \param[in] tid  The thread identifier (its number, not pthread_t).
     901             :  * \param[in] name  The name of the thread.
     902             :  *
     903             :  * \return 0 if the function worked, -1 on error.
     904             :  */
     905           0 : int set_thread_name(pid_t tid, std::string const & name)
     906             : {
     907           0 :     if(name.empty())
     908             :     {
     909           0 :         throw cppthread_invalid_error("thread name cannot be empty.");
     910             :     }
     911           0 :     if(name.length() > 15)
     912             :     {
     913             :         throw cppthread_out_of_range(
     914             :               "thread name is limited to 15 characters, \""
     915           0 :             + name
     916           0 :             + "\" is too long.");
     917             :     }
     918             : 
     919           0 :     std::ofstream comm("/proc/" + std::to_string(tid) + "/comm");
     920           0 :     comm << name;
     921             : 
     922           0 :     return comm ? 0 : -1;
     923             : }
     924             : 
     925             : 
     926             : /** \brief Retrieve the name of the current thread.
     927             :  *
     928             :  * This function reads the name of the currently running thread by reading
     929             :  * its `/proc/\<tid>/comm` file. See the get_thread_name() for more details.
     930             :  *
     931             :  * \return The name of the current thread.
     932             :  *
     933             :  * \sa get_thread_name()
     934             :  * \sa gettid()
     935             :  */
     936           0 : std::string get_current_thread_name()
     937             : {
     938           0 :     return get_thread_name(gettid());
     939             : }
     940             : 
     941             : 
     942             : /** \brief Retrieve the name of a thread.
     943             :  *
     944             :  * This function reads the name of the \p tid thread by reading its
     945             :  * `/proc/\<tid>/comm` file.
     946             :  *
     947             :  * This function is different from the pthread_getname_np() which will
     948             :  * return the in memory name. If you have access to your runner, you
     949             :  * may instead want to use its get_name() function. Note that the name
     950             :  * of a runner cannot be changed so it may be considered more authoritative.
     951             :  *
     952             :  * \param[in] tid  The thread identifier (its number, not pthread_t).
     953             :  *
     954             :  * \return The name of the specified thread.
     955             :  *
     956             :  * \sa get_current_thread_name()
     957             :  * \sa gettid()
     958             :  */
     959           0 : std::string get_thread_name(pid_t tid)
     960             : {
     961           0 :     std::ifstream comm("/proc/" + std::to_string(tid) + "/comm");
     962           0 :     std::string name;
     963           0 :     comm >> name;
     964           0 :     return name;
     965             : }
     966             : 
     967             : 
     968             : /** \brief Retrieve the list of threads for a given process.
     969             :  *
     970             :  * This function reads the list of PID from `/proc/<pid>/task/\*` which is
     971             :  * the list of threads of a process has. If only one PID, then this is the
     972             :  * main process PID and the process has no threads currently running.
     973             :  *
     974             :  * \param[in] pid  The parent process to be searched for threads.
     975             :  *
     976             :  * \return A vector of PIDs.
     977             :  */
     978           0 : process_ids_t get_thread_ids(pid_t pid)
     979             : {
     980           0 :     process_ids_t results;
     981             : 
     982           0 :     if(pid == -1)
     983             :     {
     984           0 :         pid = getpid();
     985             :     }
     986             : 
     987           0 :     std::string pattern("/proc/");
     988           0 :     pattern += std::to_string(pid);
     989           0 :     pattern += "/task/*";
     990             : 
     991           0 :     snap::glob_to_list<std::vector<std::string>> glob;
     992           0 :     if(glob.read_path<
     993             :               snap::glob_to_list_flag_t::GLOB_FLAG_IGNORE_ERRORS
     994           0 :             , snap::glob_to_list_flag_t::GLOB_FLAG_ONLY_DIRECTORIES>(pattern))
     995             :     {
     996           0 :         for(auto s : glob)
     997             :         {
     998           0 :             pid_t id(0);
     999           0 :             std::string::size_type pos(s.rfind('/') + 1);
    1000             : 
    1001           0 :             bool valid(pos < s.length());
    1002           0 :             for(; pos < s.length(); ++pos)
    1003             :             {
    1004           0 :                 char const c(s[pos]);
    1005           0 :                 if(c >= '0' && c <= '9')
    1006             :                 {
    1007           0 :                     id = id * 10 + c - '0';
    1008             :                 }
    1009             :                 else
    1010             :                 {
    1011           0 :                     valid = false;
    1012           0 :                     break;
    1013             :                 }
    1014             :             }
    1015           0 :             if(valid)
    1016             :             {
    1017           0 :                 results.push_back(id);
    1018             :             }
    1019             :         }
    1020             :     }
    1021             : 
    1022           0 :     return results;
    1023             : }
    1024             : 
    1025             : 
    1026             : /** \brief Check whether a process is running or not.
    1027             :  *
    1028             :  * This function checks whether the `/proc/<pid>` directory exists. If so,
    1029             :  * that means that the process with \p pid is current running.
    1030             :  *
    1031             :  * \note
    1032             :  * Keep in mind that between the time this function checks whether a process
    1033             :  * is running or not and the time it returns, the given process may have
    1034             :  * stopped or a new process may have been started.
    1035             :  * \note
    1036             :  * Also, security wise, this is not safe except around the time a process
    1037             :  * quits and even though, on a very heavy system starting new processes all
    1038             :  * the time, it may re-use the same \p pid very quickly.
    1039             :  *
    1040             :  * \param[in] pid  The process identifier to check.
    1041             :  *
    1042             :  * \return true if the process is currently running.
    1043             :  */
    1044           0 : bool is_process_running(pid_t pid)
    1045             : {
    1046           0 :     if(pid == getpid())
    1047             :     {
    1048             :         // funny guy testing whether he himself is running!?
    1049             :         //
    1050           0 :         return true;
    1051             :     }
    1052             : 
    1053           0 :     std::string proc_path("/proc/");
    1054           0 :     proc_path += std::to_string(pid);
    1055             : 
    1056           0 :     struct stat st;
    1057           0 :     return stat(proc_path.c_str(), &st) == 0;
    1058             : }
    1059             : 
    1060             : 
    1061             : /** \brief Retrieve the boot UUID.
    1062             :  *
    1063             :  * The Linux kernel generates a UUID on a reboot. This allows software to
    1064             :  * determine whether the computer was rebooted since the last time it was
    1065             :  * used.
    1066             :  *
    1067             :  * On computers where there is no boot identifier, this function returns
    1068             :  * an empty string.
    1069             :  *
    1070             :  * \return The boot UUID as a string or an empty string if not available.
    1071             :  */
    1072           0 : std::string get_boot_id()
    1073             : {
    1074           0 :     std::ifstream in("/proc/sys/kernel/random/boot_id");
    1075           0 :     std::string uuid;
    1076           0 :     if(in)
    1077             :     {
    1078           0 :         std::getline(in, uuid);
    1079             :     }
    1080           0 :     return uuid;
    1081             : }
    1082             : 
    1083             : 
    1084             : 
    1085             : 
    1086             : 
    1087             : 
    1088             : 
    1089             : 
    1090             : 
    1091             : 
    1092             : 
    1093             : 
    1094             : 
    1095             : 
    1096             : 
    1097             : 
    1098             : 
    1099             : 
    1100             : 
    1101             : 
    1102             : 
    1103             : 
    1104             : 
    1105             : 
    1106             : 
    1107             : 
    1108             : 
    1109             : 
    1110             : 
    1111             : 
    1112             : 
    1113             : /** \class thread
    1114             :  * \brief A thread object that ensures proper usage of system threads.
    1115             :  *
    1116             :  * This class is used to handle threads. It should NEVER be used, however,
    1117             :  * there are some very specific cases where a thread is necessary to make
    1118             :  * sure that main process doesn't get stuck. For example, the process
    1119             :  * environment using pipes requires threads to read and write pipes
    1120             :  * because otherwise the processes could lock up.
    1121             :  */
    1122             : 
    1123             : 
    1124             : /** \fn thread::thread(thread const & rhs)
    1125             :  * \brief The copy operator is deleted.
    1126             :  *
    1127             :  * The thread object holds a pointer to a runner which is an OS thread.
    1128             :  * These would be really difficult to _copy_. Instead we prevent the
    1129             :  * operation altogether.
    1130             :  *
    1131             :  * \param[in] rhs  The right hand side.
    1132             :  */
    1133             : 
    1134             : 
    1135             : /** \fn thread::operator = (thread const & rhs)
    1136             :  * \brief The assignment operator is deleted.
    1137             :  *
    1138             :  * The thread object holds a pointer to a runner which is an OS thread.
    1139             :  * These would be really difficult to _assign_. Instead we prevent
    1140             :  * the operation altogether.
    1141             :  *
    1142             :  * \param[in] rhs  The right hand side.
    1143             :  *
    1144             :  * \return A reference to this object.
    1145             :  */
    1146             : 
    1147             : 
    1148             : /** \typedef thread::pointer_t
    1149             :  * \brief The shared pointer for a thread object.
    1150             :  *
    1151             :  * This type is used to hold a smart pointer to a thread.
    1152             :  *
    1153             :  * This smart pointer is safe. It can be used to hold a thread object and
    1154             :  * when it goes out of scope, it properly ends the corresponding thread
    1155             :  * runner (the runner) and returns.
    1156             :  *
    1157             :  * Be cautious because the smart pointer of a runner is not actually
    1158             :  * safe to delete without first stopping the thread. Make sure to manage
    1159             :  * all your threads in with two objects, making sure that the thread goes
    1160             :  * out of scope first so it can stop your thread before your thread object
    1161             :  * gets destroyed.
    1162             :  */
    1163             : 
    1164             : 
    1165             : /** \typedef thread::vector_t
    1166             :  * \brief A vector of threads.
    1167             :  *
    1168             :  * This type defines a vector of threads. Since each entry in the vector
    1169             :  * is a smart pointer, it is safe to use this type.
    1170             :  */
    1171             : 
    1172             : 
    1173             : /** \var thread::f_exception
    1174             :  * \brief An exception pointer.
    1175             :  *
    1176             :  * The exception pointer to the exception that was raised in the runner.
    1177             :  * By default this pointer is null.
    1178             :  *
    1179             :  * This pointer is reset back to a null pointer each time the start()
    1180             :  * is called.
    1181             :  *
    1182             :  * This exception must be caught by your function when calling the
    1183             :  * stop() function. If you don't catch these, then it will stop your
    1184             :  * process.
    1185             :  *
    1186             :  * \note
    1187             :  * Only standard exceptions can be caught in this way. You should
    1188             :  * derive all your exception from std::exception (or use the libexcept).
    1189             :  */
    1190             : 
    1191             : 
    1192             : /** \var thread::f_log_all_exceptions
    1193             :  * \brief Whether the runner exceptions should be logged or not.
    1194             :  *
    1195             :  * Whenever an exception occurs in a runner, the exception pointer is
    1196             :  * saved in the runner so it can be re-thrown after we join with that
    1197             :  * thread.
    1198             :  *
    1199             :  * The main problem here is that certain threads are not joined until
    1200             :  * we are done with an application. So the exception lingers and there
    1201             :  * is absolutely no trace of it, especially if you hit Ctlr-C to exit
    1202             :  * your software, the exception will 100% be lost.
    1203             :  *
    1204             :  * Instead, we have this flag to determine whether the exception should
    1205             :  * be logged at the time it gets caught instead of just saving it in
    1206             :  * the pointer. By default the flag is set to true which means we will
    1207             :  * log the exception immediately. This makes it easy to not forget.
    1208             :  *
    1209             :  * If you use threads to run a quick process and then return/join
    1210             :  * (i.e. stop()), then setting this flag to false is okay.
    1211             :  *
    1212             :  * \sa get_log_all_exceptions()
    1213             :  * \sa set_log_all_exceptions()
    1214             :  */
    1215             : 
    1216             : 
    1217             : /** \var thread::f_mutex
    1218             :  * \brief The thread mutex to guard various functions.
    1219             :  *
    1220             :  * The mutex is used whenever a variable that may be accessed by different
    1221             :  * threads is used. Especially, it makes sure that the variables do not
    1222             :  * get changed too early or too late (i.e. avoid race conditions).
    1223             :  *
    1224             :  * Also the mutex is used to send signals. For example, the thread waits
    1225             :  * on the runner to start. Once the runner is started, it signals the
    1226             :  * main thread which can then wake up and return as everything is now
    1227             :  * well defined.
    1228             :  */
    1229             : 
    1230             : 
    1231             : /** \var thread::f_name
    1232             :  * \brief The name of this thread.
    1233             :  *
    1234             :  * For debug purposes, you can give each one of your threads a different
    1235             :  * name. It gets saved in this string.
    1236             :  */
    1237             : 
    1238             : 
    1239             : /** \var thread::f_runner
    1240             :  * \brief The actual thread object.
    1241             :  *
    1242             :  * The runner is the object which holds the system thread and runs the
    1243             :  * commands. We have a separate object because that way we can make sure
    1244             :  * the runner destructor isn't called while the thread is still running.
    1245             :  * If that were to happen, then all the virtual functions would be
    1246             :  * invalid at that point and the system could crash.
    1247             :  *
    1248             :  * So the thread object holds a runner allowing the thread to be destroyed
    1249             :  * first, which calls the stop() function before the runner gets destroyed.
    1250             :  */
    1251             : 
    1252             : 
    1253             : /** \var thread::f_running
    1254             :  * \brief The thread is running.
    1255             :  *
    1256             :  * When the thread is running, this flag is set to true. The start()
    1257             :  * function sets this flag to true before starting the thread and the
    1258             :  * internal_run() function sets the flag back to false right before
    1259             :  * the thread exits.
    1260             :  *
    1261             :  * In other words, the flag is true early and false early. It's not
    1262             :  * a way to know whether the actual system thread is running or not.
    1263             :  */
    1264             : 
    1265             : 
    1266             : /** \var thread::f_started
    1267             :  * \brief The thread is started.
    1268             :  *
    1269             :  * The start() function returns only after the thread is started. To control
    1270             :  * that state, we use this flag. The caller will wait until the child
    1271             :  * thread is started (i.e. f_started is true).
    1272             :  */
    1273             : 
    1274             : 
    1275             : /** \var thread::f_stopping
    1276             :  * \brief The thread is currently in the stopping process.
    1277             :  *
    1278             :  * When the stop() function is called, the flag is set to true until after
    1279             :  * the caller joined with the thread.
    1280             :  *
    1281             :  * The is_stopping() function returns the current value of that field.
    1282             :  */
    1283             : 
    1284             : 
    1285             : /** \var thread::f_thread_attr
    1286             :  * \brief This thread attributes.
    1287             :  *
    1288             :  * When we create a thread we create attributes to assign to the thread
    1289             :  * on creation. These are the attributes.
    1290             :  *
    1291             :  * These are created once at the time the thread object is created and
    1292             :  * released when the object is destroyed. The same attributes are reused
    1293             :  * to re-start the thread over and over again (i.e. start() / stop()
    1294             :  * sequences).
    1295             :  */
    1296             : 
    1297             : 
    1298             : /** \var thread::f_thread_id
    1299             :  * \brief This thread identifier.
    1300             :  *
    1301             :  * Each thread is assigned a unique identifier by the C-library. This is
    1302             :  * that identifier. Under Linux, it is an IP address.
    1303             :  */
    1304             : 
    1305             : 
    1306             : /** \var thread::f_tid
    1307             :  * \brief This thread identifier.
    1308             :  *
    1309             :  * Each thread is assigned a unique identifier by the OS.
    1310             :  */
    1311             : 
    1312             : 
    1313             : 
    1314             : /** \var PID_UNDEFINED
    1315             :  * \brief The value a PID variable is set to when not representing a process.
    1316             :  *
    1317             :  * In many cases we want to be able to initialize a pid_t variable with some
    1318             :  * default value. This variable is generally the best choice.
    1319             :  *
    1320             :  * \code
    1321             :  *     pid_t    f_my_process = PID_UNDEFINED;
    1322             :  * \endcode
    1323             :  */
    1324             : 
    1325             : 
    1326             : /** \var THREAD_UNDEFINED
    1327             :  * \brief An invalid thread identifier for initialization.
    1328             :  *
    1329             :  * In many cases we want to be able to initialize a pthread_t variable
    1330             :  * with some default value. This variable is generally the best choice.
    1331             :  *
    1332             :  * \code
    1333             :  *     pthread_t    f_my_thread = THREAD_UNDEFINED;
    1334             :  * \endcode
    1335             :  */
    1336             : 
    1337             : 
    1338             : /** \typedef process_ids_t
    1339             :  * \brief A list of identifiers representing various processes.
    1340             :  *
    1341             :  * This type defines a vector that can hold identifiers to various
    1342             :  * processes.
    1343             :  */
    1344             : 
    1345             : 
    1346             : 
    1347           6 : } // namespace cppthread
    1348             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13