Stop threads at the start of their object's destruction in all Job cases.
[dcpomatic.git] / src / lib / job.cc
index 7539a50703faa2074375bbf17ff7639509a7ddc5..a83249e798feba99abafc2a09f1393eb8cf5dc18 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -28,6 +28,7 @@
 #include "exceptions.h"
 #include "film.h"
 #include "log.h"
+#include "dcpomatic_log.h"
 #include "compose.hpp"
 #include <dcp/exceptions.h>
 #include <sub/exceptions.h>
@@ -45,14 +46,11 @@ using std::cout;
 using boost::shared_ptr;
 using boost::optional;
 using boost::function;
-
-#define LOG_ERROR_NC(...) if (_film) { _film->log()->log (__VA_ARGS__, LogEntry::TYPE_ERROR); }
-#define LOG_GENERAL(...) if (_film) { _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL); }
+using namespace dcpomatic;
 
 /** @param film Associated film, or 0 */
 Job::Job (shared_ptr<const Film> film)
        : _film (film)
-       , _thread (0)
        , _state (NEW)
        , _start_time (0)
        , _sub_start_time (0)
@@ -64,19 +62,25 @@ Job::Job (shared_ptr<const Film> film)
 
 Job::~Job ()
 {
-       if (_thread) {
-               _thread->interrupt ();
-               /* We can't use DCPOMATIC_ASSERT here as it may throw an exception */
-               if (_thread->joinable ()) {
-                       try {
-                               _thread->join ();
-                       } catch (...) {
-                               /* Too late to do anything about this */
-                       }
-               }
+#ifdef DCPOMATIC_DEBUG
+       /* Any subclass should have called stop_thread in its destructor */
+       assert (!_thread.joinable());
+#endif
+}
+
+void
+Job::stop_thread ()
+{
+       if (!_thread.joinable()) {
+               return;
        }
 
-       delete _thread;
+       _thread.interrupt ();
+       try {
+               _thread.join ();
+       } catch (...) {
+               /* Too late to do anything about this */
+       }
 }
 
 /** Start the job in a separate thread, returning immediately */
@@ -86,9 +90,9 @@ Job::start ()
        set_state (RUNNING);
        _start_time = time (0);
        _sub_start_time = time (0);
-       _thread = new boost::thread (boost::bind (&Job::run_wrapper, this));
+       _thread = boost::thread (boost::bind(&Job::run_wrapper, this));
 #ifdef DCPOMATIC_LINUX
-       pthread_setname_np (_thread->native_handle(), "job-wrapper");
+       pthread_setname_np (_thread.native_handle(), "job-wrapper");
 #endif
 }
 
@@ -186,6 +190,12 @@ Job::run_wrapper ()
                set_progress (1);
                set_state (FINISHED_ERROR);
 
+       } catch (FileError& e) {
+
+               set_error (e.what(), e.what());
+               set_progress (1);
+               set_state (FINISHED_ERROR);
+
        } catch (std::exception& e) {
 
                set_error (
@@ -290,6 +300,7 @@ Job::set_state (State s)
 
        if (finished) {
                emit (boost::bind (boost::ref (Finished)));
+               FinishedImmediate ();
        }
 }
 
@@ -444,7 +455,7 @@ Job::status () const
                        if (now.date() != finish.date()) {
                                /// TRANSLATORS: the %1 in this string will be filled in with a day of the week
                                /// to say what day a job will finish.
-                               day = String::compose (_(" on %1"), finish.date().day_of_week().as_long_string());
+                               day = String::compose (_(" on %1"), day_of_week_to_string(finish.date().day_of_week()));
                        }
                        /// TRANSLATORS: "remaining; finishing at" here follows an amount of time that is remaining
                        /// on an operation; after it is an estimated wall-clock completion time.
@@ -502,7 +513,7 @@ Job::remaining_time () const
 void
 Job::cancel ()
 {
-       if (!_thread) {
+       if (!_thread.joinable()) {
                return;
        }
 
@@ -510,11 +521,8 @@ Job::cancel ()
                resume ();
        }
 
-       _thread->interrupt ();
-       DCPOMATIC_ASSERT (_thread->joinable ());
-       _thread->join ();
-       delete _thread;
-       _thread = 0;
+       _thread.interrupt ();
+       _thread.join ();
 }
 
 /** @return true if the job was paused, false if it was not running */