forked from tmm1/nzbget
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Thread.cpp
279 lines (233 loc) · 5.97 KB
/
Thread.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
/*
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <[email protected]>
* Copyright (C) 2007-2010 Andrey Prygunkov <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#ifdef WIN32
#include <process.h>
#else
#include <fcntl.h>
#include <pthread.h>
#endif
#include "Log.h"
#include "Thread.h"
int Thread::m_iThreadCount = 1; // take the main program thread into account
Mutex* Thread::m_pMutexThread;
Mutex::Mutex()
{
#ifdef WIN32
m_pMutexObj = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION));
InitializeCriticalSection((CRITICAL_SECTION*)m_pMutexObj);
#else
m_pMutexObj = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
pthread_mutex_init((pthread_mutex_t*)m_pMutexObj, NULL);
#endif
}
Mutex::~ Mutex()
{
#ifdef WIN32
DeleteCriticalSection((CRITICAL_SECTION*)m_pMutexObj);
#else
pthread_mutex_destroy((pthread_mutex_t*)m_pMutexObj);
#endif
free(m_pMutexObj);
}
void Mutex::Lock()
{
#ifdef WIN32
EnterCriticalSection((CRITICAL_SECTION*)m_pMutexObj);
#ifdef DEBUG
// CriticalSections on Windows can be locked many times from the same thread,
// but we do not want this and must treat such situations as errors and detect them.
if (((CRITICAL_SECTION*)m_pMutexObj)->RecursionCount > 1)
{
error("Internal program error: inconsistent thread-lock detected");
}
#endif
#else
pthread_mutex_lock((pthread_mutex_t*)m_pMutexObj);
#endif
}
void Mutex::Unlock()
{
#ifdef WIN32
LeaveCriticalSection((CRITICAL_SECTION*)m_pMutexObj);
#else
pthread_mutex_unlock((pthread_mutex_t*)m_pMutexObj);
#endif
}
#ifdef HAVE_SPINLOCK
SpinLock::SpinLock()
{
#ifdef WIN32
m_pSpinLockObj = (CRITICAL_SECTION *)malloc(sizeof(CRITICAL_SECTION));
InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION *)m_pSpinLockObj, 0x00FFFFFF);
#else
m_pSpinLockObj = (pthread_spinlock_t *)malloc(sizeof(pthread_spinlock_t));
pthread_spin_init((pthread_spinlock_t *)m_pSpinLockObj, PTHREAD_PROCESS_PRIVATE);
#endif
}
SpinLock::~SpinLock()
{
#ifdef WIN32
DeleteCriticalSection((CRITICAL_SECTION *)m_pSpinLockObj);
#else
pthread_spin_destroy((pthread_spinlock_t *)m_pSpinLockObj);
#endif
free((void*)m_pSpinLockObj);
}
void SpinLock::Lock()
{
#ifdef WIN32
EnterCriticalSection((CRITICAL_SECTION *)m_pSpinLockObj);
#else
pthread_spin_lock((pthread_spinlock_t *)m_pSpinLockObj);
#endif
}
void SpinLock::Unlock()
{
#ifdef WIN32
LeaveCriticalSection((CRITICAL_SECTION *)m_pSpinLockObj);
#else
pthread_spin_unlock((pthread_spinlock_t *)m_pSpinLockObj);
#endif
}
#endif
void Thread::Init()
{
debug("Initializing global thread data");
m_pMutexThread = new Mutex();
}
void Thread::Final()
{
debug("Finalizing global thread data");
delete m_pMutexThread;
}
Thread::Thread()
{
debug("Creating Thread");
#ifdef WIN32
m_pThreadObj = NULL;
#else
m_pThreadObj = (pthread_t*)malloc(sizeof(pthread_t));
*((pthread_t*)m_pThreadObj) = 0;
#endif
m_bRunning = false;
m_bStopped = false;
m_bAutoDestroy = false;
}
Thread::~Thread()
{
debug("Destroying Thread");
#ifndef WIN32
free(m_pThreadObj);
#endif
}
void Thread::Start()
{
debug("Starting Thread");
m_bRunning = true;
// NOTE: we must guarantee, that in a time we set m_bRunning
// to value returned from pthread_create, the thread-object still exists.
// This is not obviously!
// pthread_create could wait long enough before returning result
// back to allow the started thread to complete its job and terminate.
// We lock mutex m_pMutexThread on calling pthread_create; the started thread
// then also try to lock the mutex (see thread_handler) and therefore
// must wait until we unlock it
m_pMutexThread->Lock();
#ifdef WIN32
m_pThreadObj = (HANDLE)_beginthread(Thread::thread_handler, 0, (void *)this);
m_bRunning = m_pThreadObj != NULL;
#else
pthread_attr_t m_Attr;
pthread_attr_init(&m_Attr);
pthread_attr_setdetachstate(&m_Attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setinheritsched(&m_Attr , PTHREAD_INHERIT_SCHED);
m_bRunning = !pthread_create((pthread_t*)m_pThreadObj, &m_Attr, Thread::thread_handler, (void *) this);
pthread_attr_destroy(&m_Attr);
#endif
m_pMutexThread->Unlock();
}
void Thread::Stop()
{
debug("Stopping Thread");
m_bStopped = true;
}
bool Thread::Kill()
{
debug("Killing Thread");
m_pMutexThread->Lock();
#ifdef WIN32
bool terminated = TerminateThread((HANDLE)m_pThreadObj, 0) != 0;
#else
bool terminated = pthread_cancel(*(pthread_t*)m_pThreadObj) == 0;
#endif
if (terminated)
{
m_iThreadCount--;
}
m_pMutexThread->Unlock();
return terminated;
}
#ifdef WIN32
void __cdecl Thread::thread_handler(void* pObject)
#else
void* Thread::thread_handler(void* pObject)
#endif
{
m_pMutexThread->Lock();
m_iThreadCount++;
m_pMutexThread->Unlock();
debug("Entering Thread-func");
Thread* pThread = (Thread*)pObject;
pThread->Run();
debug("Thread-func exited");
pThread->m_bRunning = false;
if (pThread->m_bAutoDestroy)
{
debug("Autodestroying Thread-object");
delete pThread;
}
m_pMutexThread->Lock();
m_iThreadCount--;
m_pMutexThread->Unlock();
#ifndef WIN32
return NULL;
#endif
}
int Thread::GetThreadCount()
{
m_pMutexThread->Lock();
int iThreadCount = m_iThreadCount;
m_pMutexThread->Unlock();
return iThreadCount;
}