1 // libTorrent - BitTorrent library
2 // Copyright (C) 2005-2011, Jari Sundell
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 //
18 // In addition, as a special exception, the copyright holders give
19 // permission to link the code of portions of this program with the
20 // OpenSSL library under certain conditions as described in each
21 // individual source file, and distribute linked combinations
22 // including the two.
23 //
24 // You must obey the GNU General Public License in all respects for
25 // all of the code used other than OpenSSL.  If you modify file(s)
26 // with this exception, you may extend this exception to your version
27 // of the file(s), but you are not obligated to do so.  If you do not
28 // wish to do so, delete this exception statement from your version.
29 // If you delete this exception statement from all source files in the
30 // program, then also delete it here.
31 //
32 // Contact:  Jari Sundell <jaris@ifi.uio.no>
33 //
34 //           Skomakerveien 33
35 //           3185 Skoppum, NORWAY
36 
37 #ifndef LIBTORRENT_UTILS_THREAD_BASE_H
38 #define LIBTORRENT_UTILS_THREAD_BASE_H
39 
40 #include <pthread.h>
41 #include <sys/types.h>
42 #include <torrent/common.h>
43 #include <torrent/utils/signal_bitfield.h>
44 #include lt_tr1_functional
45 
46 namespace torrent {
47 
48 class Poll;
49 class thread_interrupt;
50 
51 class LIBTORRENT_EXPORT lt_cacheline_aligned thread_base {
52 public:
53   typedef void* (*pthread_func)(void*);
54   typedef std::function<void ()>     slot_void;
55   typedef std::function<uint64_t ()> slot_timer;
56   typedef class signal_bitfield           signal_type;
57 
58   enum state_type {
59     STATE_UNKNOWN,
60     STATE_INITIALIZED,
61     STATE_ACTIVE,
62     STATE_INACTIVE
63   };
64 
65   static const int flag_do_shutdown  = 0x1;
66   static const int flag_did_shutdown = 0x2;
67   static const int flag_no_timeout   = 0x4;
68   static const int flag_polling      = 0x8;
69 
70   static const int flag_main_thread  = 0x10;
71 
72   thread_base();
73   virtual ~thread_base();
74 
is_initialized()75   bool                is_initialized() const { return state() == STATE_INITIALIZED; }
is_active()76   bool                is_active()      const { return state() == STATE_ACTIVE; }
is_inactive()77   bool                is_inactive()    const { return state() == STATE_INACTIVE; }
78 
79   bool                is_polling() const;
80   bool                is_current() const;
81 
has_no_timeout()82   bool                has_no_timeout()   const { return (flags() & flag_no_timeout); }
has_do_shutdown()83   bool                has_do_shutdown()  const { return (flags() & flag_do_shutdown); }
has_did_shutdown()84   bool                has_did_shutdown() const { return (flags() & flag_did_shutdown); }
85 
86   state_type          state() const;
87   int                 flags() const;
88 
89   virtual const char* name() const = 0;
90 
poll()91   Poll*               poll()            { return m_poll; }
signal_bitfield()92   signal_type*        signal_bitfield() { return &m_signal_bitfield; }
pthread()93   pthread_t           pthread()         { return m_thread; }
94 
95   virtual void        init_thread() = 0;
96 
97   virtual void        start_thread();
98   virtual void        stop_thread();
99   void                stop_thread_wait();
100 
101   void                interrupt();
102   void                send_event_signal(unsigned int index, bool interrupt = true);
103 
slot_do_work()104   slot_void&          slot_do_work()      { return m_slot_do_work; }
slot_next_timeout()105   slot_timer&         slot_next_timeout() { return m_slot_next_timeout; }
106 
global_queue_size()107   static inline int   global_queue_size() { return m_global.waiting; }
108 
109   static inline void  acquire_global_lock();
110   static inline bool  trylock_global_lock();
111   static inline void  release_global_lock();
112   static inline void  waive_global_lock();
113 
is_main_polling()114   static inline bool  is_main_polling() { return m_global.main_polling; }
115   static inline void  entering_main_polling();
116   static inline void  leaving_main_polling();
117 
118   static bool         should_handle_sigusr1();
119 
120   static void*        event_loop(thread_base* thread);
121 
122 protected:
123   struct lt_cacheline_aligned global_lock_type {
124     int             waiting;
125     int             main_polling;
126     pthread_mutex_t lock;
127   };
128 
129   virtual void        call_events() = 0;
130   virtual int64_t     next_timeout_usec() = 0;
131 
132   static global_lock_type m_global;
133 
134   pthread_t           m_thread;
135   state_type          m_state lt_cacheline_aligned;
136   int                 m_flags lt_cacheline_aligned;
137 
138   int                 m_instrumentation_index;
139 
140   Poll*               m_poll;
141   signal_type         m_signal_bitfield;
142 
143   slot_void           m_slot_do_work;
144   slot_timer          m_slot_next_timeout;
145 
146   thread_interrupt*   m_interrupt_sender;
147   thread_interrupt*   m_interrupt_receiver;
148 };
149 
150 inline bool
is_polling()151 thread_base::is_polling() const {
152   return (flags() & flag_polling);
153 }
154 
155 inline bool
is_current()156 thread_base::is_current() const {
157   return m_thread == pthread_self();
158 }
159 
160 inline int
flags()161 thread_base::flags() const {
162   __sync_synchronize();
163   return m_flags;
164 }
165 
166 inline thread_base::state_type
state()167 thread_base::state() const {
168   __sync_synchronize();
169   return m_state;
170 }
171 
172 inline void
send_event_signal(unsigned int index,bool do_interrupt)173 thread_base::send_event_signal(unsigned int index, bool do_interrupt) {
174   m_signal_bitfield.signal(index);
175 
176   if (do_interrupt)
177     interrupt();
178 }
179 
180 inline void
acquire_global_lock()181 thread_base::acquire_global_lock() {
182   __sync_add_and_fetch(&thread_base::m_global.waiting, 1);
183   pthread_mutex_lock(&thread_base::m_global.lock);
184   __sync_sub_and_fetch(&thread_base::m_global.waiting, 1);
185 }
186 
187 inline bool
trylock_global_lock()188 thread_base::trylock_global_lock() {
189   return pthread_mutex_trylock(&thread_base::m_global.lock) == 0;
190 }
191 
192 inline void
release_global_lock()193 thread_base::release_global_lock() {
194   pthread_mutex_unlock(&thread_base::m_global.lock);
195 }
196 
197 inline void
waive_global_lock()198 thread_base::waive_global_lock() {
199   pthread_mutex_unlock(&thread_base::m_global.lock);
200 
201   // Do we need to sleep here? Make a CppUnit test for this.
202   acquire_global_lock();
203 }
204 
205 // 'entering/leaving_main_polling' is used by the main polling thread
206 // to indicate to other threads when it is safe to change the main
207 // thread's event entries.
208 //
209 // A thread should first aquire global lock, then if it needs to
210 // change poll'ed sockets on the main thread it should call
211 // 'interrupt_main_polling' unless 'is_main_polling() == false'.
212 inline void
entering_main_polling()213 thread_base::entering_main_polling() {
214   __sync_lock_test_and_set(&thread_base::m_global.main_polling, 1);
215 }
216 
217 inline void
leaving_main_polling()218 thread_base::leaving_main_polling() {
219   __sync_lock_test_and_set(&thread_base::m_global.main_polling, 0);
220 }
221 
222 }
223 
224 #endif
225