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