1 /*********************************************************************/
2 // dar - disk archive - a backup/restoration program
3 // Copyright (C) 2002-2052 Denis Corbin
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 //
19 // to contact the author : http://dar.linux.free.fr/email.html
20 /*********************************************************************/
21 
22     /// \file thread_cancellation.hpp
23     /// \brief to be able to cancel libdar operation while running in a given thread.
24     /// \ingroup API
25     ///
26     /// the class thread_cancellation implemented in this module
27     /// permits to define checkpoints where is looked whether the current
28     /// thread has been marked as to be canceled by the user
29     /// The advantage of this class is that it then throws a Euser_abort
30     /// exception which properly terminates the libdar operation in the thread
31     /// freeing allocated memory and release mutex properly. Note that the thread
32     /// is not canceled but libdar call in this thread returns as soon as a checkpoint
33     /// is met during the execution.
34 
35 #ifndef THREAD_CANCELLATION_HPP
36 #define THREAD_CANCELLATION_HPP
37 
38 #include "../my_config.h"
39 
40 extern "C"
41 {
42 #if MUTEX_WORKS
43 #if HAVE_PTHREAD_H
44 #include <pthread.h>
45 #endif
46 #endif
47 }
48 #include <list>
49 #include <map>
50 #include "integers.hpp"
51 
52 namespace libdar
53 {
54 
55 	/// class to be used as parent to provide checkpoints to inherited classes
56 
57 	/// the class provides a checkpoints to inherited classes and a mechanism
58 	/// that let any libdar external code to ask the termination of a libdar
59 	/// call executing in a given thread. This does not imply the termination
60 	/// of the thread itself but it implies the return of the thread execution
61 	/// to the code that called libdar
62 	/// \ingroup Private
63 
64     class thread_cancellation
65     {
66     public:
67 
68 	    /// the constructor
69 	thread_cancellation();
70 
71 	    /// the destructor
72 	virtual ~thread_cancellation() throw(Ebug);
73 
74 	    /// Checkpoint test : whether the current libdar call must abort or not
75 
76 	    /// \exception Euser_abort is thrown if the thread the checkpoint is running
77 	    /// from is marked as to be canceled.
78 	void check_self_cancellation() const;
79 
80 	    /// by default delayed (non immediate) cancellation generate a specific exception,
81 	    /// it is possible for delayed cancellation only, do block such exceptions for a certain time
82 
83 	    ///\param[in] mode can be set to true to block delayed cancellations
84 	    ///\note when unblocking delayed cancellations, if a delayed cancellation has been
85 	    ///requested during the ignore time, it will be thrown by this call
86 	void block_delayed_cancellation(bool mode);
87 
88 
89 #if MUTEX_WORKS
90 	    /// marks the thread given in argument as to be canceled
91 
92 	    //! \param[in] tid the thread ID of the thread where any libdar call must abort
93 	    //! \param[in] x_immediate whether the cancellation must be as fast as possible or can take a
94 	    //! \param[in] x_flag is a value to transmit to the Ethread_cancel exception used to cancel libdar's call stack
95 	    //! little time to make a usable archive
96 	static void cancel(pthread_t tid, bool x_immediate, U_64 x_flag);
97 
98 	    /// gives the cancellation status of the given thread ID
99 
100 	    //! \param[in] tid the thread to check
101 	    //! \return true if the given thread is under cancellation
102 	static bool cancel_status(pthread_t tid);
103 
104 	    /// abort the pending thread cancellation
105 
106 	    /// \return true if the pending thread was still running and
107 	    /// false if it has already aborted.
108 	static bool clear_pending_request(pthread_t tid);
109 
110 	    /// define association between threads: if a cancellation is requested for src, it will also be requested for dst
111 	    ///
112 	    /// \param[in] src orginal target for cancellation
113 	    /// \param[in] dst additional target for cancellation
114 	    /// \note that the propagation of cancellation request with association is transitive
115 	    /// in other word if t1 is associtated with t2 which is associated with t3,
116 	    /// requesting cancellation of t1 will also lead to signal cancellation request for t2 and t3
117 	    /// \note that association is not symmetrical, unless associating A to B *and* B to A
118 	static void associate_tid_to_tid(pthread_t src, pthread_t dst);
119 
120 	    /// remove all association from a given tid to any other thread
121 	    ///
122 	    /// \param[in] src is the thread id that has to be removed from the
123 	    /// association table (see associate_tid_to_tid() above).
124 	static void remove_association_for_tid(pthread_t src);
125 
126 	    /// remove all association for any thread to a given targetted thread
127 	    ///
128 	    /// \param[in] dst all association target at dst will be removed
129 	static void remove_association_targeted_at(pthread_t dst);
130 
131 	    /// clean class info from all related information about that thread, like associations and pending cancellations
132 	static void dead_thread(pthread_t tid);
133 #endif
134 
135 	    /// method for debugging/control purposes
count()136 	static U_I count()
137 	{
138 #if MUTEX_WORKS
139 	    return info.size();
140 #else
141 	    return 0;
142 #endif
143 	};
144 
145 #if MUTEX_WORKS
146     private:
147 
148 	    // class types
149 
150 	struct fields
151 	{
152 	    pthread_t tid;             ///< thread id of the current thread
153 	    bool block_delayed;        ///< whether we buffer any delayed cancellation requests for "this" thread
154 	    bool immediate;            ///< whether we take a few more second to make a real usable archive
155 	    bool cancellation;         ///< true if a thread has to be canceled
156 	    U_64 flag;                 ///< user defined informational field, given to the Ethread_cancel constructor
157 	};
158 
159 	    // object information
160 
161 	fields status;
162 
163 	    // class's static variables and types
164 
165 	static pthread_mutex_t access;                 //< mutex for the access to "info"
166 	static std::list<thread_cancellation *> info;  //< list of all object
167 	static std::list<fields> preborn;              //< canceled thread that still not have a thread_cancellation object to deal with cancellation
168 	static std::multimap<pthread_t, pthread_t> thread_asso; //< which other thread to propagate cancellation request to, given a initial tid
169 
170 	    // helper class routing
171 	static void set_cancellation_in_info_for(pthread_t tid,
172 						 bool cancel_status,
173 						 bool x_immediate,
174 						 U_64 x_flag,
175 						 bool & found,
176 						 bool & previous_val,
177 						 bool & bug);
178 	static void add_to_preborn(pthread_t tid, bool x_immediate, U_64 x_flag);
179 	static void remove_from_preborn(pthread_t tid, bool & found, bool & prev);
180 	static void find_asso_tid_with(pthread_t tid,
181 				       std::multimap<pthread_t, pthread_t>::iterator & begin,
182 				       std::multimap<pthread_t, pthread_t>::iterator & end);
183 
184 #endif
185     };
186 
187 } // end of namespace
188 
189 #endif
190