]>
Commit | Line | Data |
---|---|---|
1f2e0df8 | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
57702541 | 2 | // Copyright (c) 2009-2014 The Bitcoin developers |
1f2e0df8 | 3 | // Distributed under the MIT/X11 software license, see the accompanying |
3a25a2b9 | 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
51ed9ec9 | 5 | |
1f2e0df8 WL |
6 | #ifndef BITCOIN_UTIL_H |
7 | #define BITCOIN_UTIL_H | |
8 | ||
51ed9ec9 BD |
9 | #if defined(HAVE_CONFIG_H) |
10 | #include "bitcoin-config.h" | |
11 | #endif | |
12 | ||
13 | #include "compat.h" | |
14 | #include "serialize.h" | |
b77dfdc9 | 15 | #include "tinyformat.h" |
1f2e0df8 | 16 | |
51ed9ec9 BD |
17 | #include <cstdio> |
18 | #include <exception> | |
51ed9ec9 | 19 | #include <map> |
65ec9eab | 20 | #include <stdarg.h> |
51ed9ec9 BD |
21 | #include <stdint.h> |
22 | #include <string> | |
23 | #include <utility> | |
24 | #include <vector> | |
65ec9eab | 25 | |
6853e627 | 26 | #ifndef WIN32 |
6644d98d | 27 | #include <sys/resource.h> |
51ed9ec9 BD |
28 | #include <sys/time.h> |
29 | #include <sys/types.h> | |
85663f2c | 30 | #endif |
1f2e0df8 | 31 | |
ee12c3d6 | 32 | #include <boost/filesystem/path.hpp> |
51ed9ec9 | 33 | #include <boost/thread.hpp> |
1f2e0df8 | 34 | |
51ed9ec9 BD |
35 | class CNetAddr; |
36 | class uint256; | |
bde280b9 | 37 | |
51ed9ec9 BD |
38 | static const int64_t COIN = 100000000; |
39 | static const int64_t CENT = 1000000; | |
ed6d0b5f | 40 | |
1f2e0df8 WL |
41 | #define BEGIN(a) ((char*)&(a)) |
42 | #define END(a) ((char*)&((&(a))[1])) | |
43 | #define UBEGIN(a) ((unsigned char*)&(a)) | |
44 | #define UEND(a) ((unsigned char*)&((&(a))[1])) | |
45 | #define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) | |
1f2e0df8 | 46 | |
1f2e0df8 | 47 | // This is needed because the foreach macro can't get over the comma in pair<t1, t2> |
9aef9bca | 48 | #define PAIRTYPE(t1, t2) std::pair<t1, t2> |
1f2e0df8 | 49 | |
1f2e0df8 WL |
50 | // Align by increasing pointer, must have extra space at end of buffer |
51 | template <size_t nBytes, typename T> | |
52 | T* alignup(T* p) | |
53 | { | |
54 | union | |
55 | { | |
56 | T* ptr; | |
57 | size_t n; | |
58 | } u; | |
59 | u.ptr = p; | |
60 | u.n = (u.n + (nBytes-1)) & ~(nBytes-1); | |
61 | return u.ptr; | |
62 | } | |
63 | ||
6853e627 | 64 | #ifdef WIN32 |
1f2e0df8 | 65 | #define MSG_DONTWAIT 0 |
26ce92b3 | 66 | |
1f2e0df8 WL |
67 | #ifndef S_IRUSR |
68 | #define S_IRUSR 0400 | |
69 | #define S_IWUSR 0200 | |
70 | #endif | |
1f2e0df8 | 71 | #else |
1f2e0df8 | 72 | #define MAX_PATH 1024 |
1b43bf0d | 73 | #endif |
93714039 | 74 | // As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0 |
51ed9ec9 | 75 | #if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) |
93714039 | 76 | #define MSG_NOSIGNAL 0 |
77 | #endif | |
1b43bf0d | 78 | |
51ed9ec9 | 79 | inline void MilliSleep(int64_t n) |
1f2e0df8 | 80 | { |
e2654c8d | 81 | // Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50 |
82 | // until fixed in 1.52. Use the deprecated sleep method for the broken case. | |
83 | // See: https://svn.boost.org/trac/boost/ticket/7238 | |
35b8af92 | 84 | #if defined(HAVE_WORKING_BOOST_SLEEP_FOR) |
1b43bf0d | 85 | boost::this_thread::sleep_for(boost::chrono::milliseconds(n)); |
35b8af92 | 86 | #elif defined(HAVE_WORKING_BOOST_SLEEP) |
1b43bf0d | 87 | boost::this_thread::sleep(boost::posix_time::milliseconds(n)); |
35b8af92 | 88 | #else |
cd696e64 | 89 | //should never get here |
35b8af92 | 90 | #error missing boost sleep implementation |
1f2e0df8 | 91 | #endif |
1b43bf0d | 92 | } |
1f2e0df8 | 93 | |
1f2e0df8 WL |
94 | |
95 | ||
96 | extern std::map<std::string, std::string> mapArgs; | |
97 | extern std::map<std::string, std::vector<std::string> > mapMultiArgs; | |
98 | extern bool fDebug; | |
99 | extern bool fPrintToConsole; | |
9e9056cd | 100 | extern bool fPrintToDebugLog; |
1f2e0df8 | 101 | extern bool fServer; |
1f2e0df8 | 102 | extern std::string strMiscWarning; |
1f2e0df8 | 103 | extern bool fLogTimestamps; |
ee337423 | 104 | extern volatile bool fReopenDebugLog; |
1f2e0df8 WL |
105 | |
106 | void RandAddSeed(); | |
107 | void RandAddSeedPerfmon(); | |
5248ff40 | 108 | void SetupEnvironment(); |
e51321fb | 109 | |
b77dfdc9 WL |
110 | /* Return true if log accepts specified category */ |
111 | bool LogAcceptCategory(const char* category); | |
112 | /* Send a string to the log output */ | |
113 | int LogPrintStr(const std::string &str); | |
114 | ||
115 | #define strprintf tfm::format | |
881a85a2 | 116 | #define LogPrintf(...) LogPrint(NULL, __VA_ARGS__) |
52d3a481 | 117 | |
b77dfdc9 WL |
118 | /* When we switch to C++11, this can be switched to variadic templates instead |
119 | * of this macro-based construction (see tinyformat.h). | |
b0a90fbb | 120 | */ |
b77dfdc9 WL |
121 | #define MAKE_ERROR_AND_LOG_FUNC(n) \ |
122 | /* Print to debug.log if -debug=category switch is given OR category is NULL. */ \ | |
123 | template<TINYFORMAT_ARGTYPES(n)> \ | |
124 | static inline int LogPrint(const char* category, const char* format, TINYFORMAT_VARARGS(n)) \ | |
125 | { \ | |
126 | if(!LogAcceptCategory(category)) return 0; \ | |
127 | return LogPrintStr(tfm::format(format, TINYFORMAT_PASSARGS(n))); \ | |
128 | } \ | |
129 | /* Log error and return false */ \ | |
130 | template<TINYFORMAT_ARGTYPES(n)> \ | |
131 | static inline bool error(const char* format, TINYFORMAT_VARARGS(n)) \ | |
132 | { \ | |
2383e488 | 133 | LogPrintStr("ERROR: " + tfm::format(format, TINYFORMAT_PASSARGS(n)) + "\n"); \ |
b77dfdc9 WL |
134 | return false; \ |
135 | } | |
136 | ||
137 | TINYFORMAT_FOREACH_ARGNUM(MAKE_ERROR_AND_LOG_FUNC) | |
138 | ||
139 | /* Zero-arg versions of logging and error, these are not covered by | |
140 | * TINYFORMAT_FOREACH_ARGNUM | |
141 | */ | |
142 | static inline int LogPrint(const char* category, const char* format) | |
143 | { | |
144 | if(!LogAcceptCategory(category)) return 0; | |
145 | return LogPrintStr(format); | |
146 | } | |
147 | static inline bool error(const char* format) | |
148 | { | |
2383e488 | 149 | LogPrintStr(std::string("ERROR: ") + format + "\n"); |
b77dfdc9 WL |
150 | return false; |
151 | } | |
b0a90fbb | 152 | |
1f2e0df8 | 153 | void PrintExceptionContinue(std::exception* pex, const char* pszThread); |
51ed9ec9 BD |
154 | std::string FormatMoney(int64_t n, bool fPlus=false); |
155 | bool ParseMoney(const std::string& str, int64_t& nRet); | |
156 | bool ParseMoney(const char* pszIn, int64_t& nRet); | |
17faf562 | 157 | std::string SanitizeString(const std::string& str); |
1f2e0df8 WL |
158 | std::vector<unsigned char> ParseHex(const char* psz); |
159 | std::vector<unsigned char> ParseHex(const std::string& str); | |
922e8e29 | 160 | bool IsHex(const std::string& str); |
4b603f1c PW |
161 | std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = NULL); |
162 | std::string DecodeBase64(const std::string& str); | |
163 | std::string EncodeBase64(const unsigned char* pch, size_t len); | |
164 | std::string EncodeBase64(const std::string& str); | |
c4c99ade PW |
165 | std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = NULL); |
166 | std::string DecodeBase32(const std::string& str); | |
167 | std::string EncodeBase32(const unsigned char* pch, size_t len); | |
168 | std::string EncodeBase32(const std::string& str); | |
3ae07355 | 169 | void ParseParameters(int argc, const char*const argv[]); |
768e5d52 | 170 | void FileCommit(FILE *fileout); |
1eb57879 | 171 | bool TruncateFile(FILE *file, unsigned int length); |
ba29a559 | 172 | int RaiseFileDescriptorLimit(int nMinFD); |
bba89aa8 | 173 | void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); |
768e5d52 | 174 | bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest); |
2b7709dc | 175 | bool TryCreateDirectory(const boost::filesystem::path& p); |
ee12c3d6 PW |
176 | boost::filesystem::path GetDefaultDataDir(); |
177 | const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); | |
178 | boost::filesystem::path GetConfigFile(); | |
179 | boost::filesystem::path GetPidFile(); | |
a034c7eb | 180 | #ifndef WIN32 |
ee12c3d6 | 181 | void CreatePidFile(const boost::filesystem::path &path, pid_t pid); |
a034c7eb | 182 | #endif |
f4203de3 | 183 | void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet); |
3e468840 PK |
184 | #ifdef WIN32 |
185 | boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); | |
186 | #endif | |
597fa4cd | 187 | boost::filesystem::path GetTempPath(); |
1f2e0df8 WL |
188 | void ShrinkDebugFile(); |
189 | int GetRandInt(int nMax); | |
51ed9ec9 | 190 | uint64_t GetRand(uint64_t nMax); |
f718aedd | 191 | uint256 GetRandHash(); |
51ed9ec9 BD |
192 | int64_t GetTime(); |
193 | void SetMockTime(int64_t nMockTimeIn); | |
194 | int64_t GetAdjustedTime(); | |
195 | int64_t GetTimeOffset(); | |
1f2e0df8 | 196 | std::string FormatFullVersion(); |
f8ded588 | 197 | std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments); |
51ed9ec9 | 198 | void AddTimeData(const CNetAddr& ip, int64_t nTime); |
429039d4 | 199 | void runCommand(std::string strCommand); |
1f2e0df8 WL |
200 | |
201 | ||
202 | ||
203 | ||
204 | ||
205 | ||
206 | ||
207 | ||
208 | ||
51ed9ec9 | 209 | inline std::string i64tostr(int64_t n) |
1f2e0df8 | 210 | { |
f48742c2 | 211 | return strprintf("%d", n); |
1f2e0df8 WL |
212 | } |
213 | ||
214 | inline std::string itostr(int n) | |
215 | { | |
216 | return strprintf("%d", n); | |
217 | } | |
218 | ||
51ed9ec9 | 219 | inline int64_t atoi64(const char* psz) |
1f2e0df8 WL |
220 | { |
221 | #ifdef _MSC_VER | |
222 | return _atoi64(psz); | |
223 | #else | |
224 | return strtoll(psz, NULL, 10); | |
225 | #endif | |
226 | } | |
227 | ||
51ed9ec9 | 228 | inline int64_t atoi64(const std::string& str) |
1f2e0df8 WL |
229 | { |
230 | #ifdef _MSC_VER | |
231 | return _atoi64(str.c_str()); | |
232 | #else | |
233 | return strtoll(str.c_str(), NULL, 10); | |
234 | #endif | |
235 | } | |
236 | ||
237 | inline int atoi(const std::string& str) | |
238 | { | |
239 | return atoi(str.c_str()); | |
240 | } | |
241 | ||
0d4ea1cf WL |
242 | /** |
243 | * Convert string to signed 32-bit integer with strict parse error feedback. | |
244 | * @returns true if the entire string could be parsed as valid integer, | |
245 | * false if not the entire string could be parsed or when overflow or underflow occured. | |
246 | */ | |
247 | bool ParseInt32(const std::string& str, int32_t *out); | |
248 | ||
1f2e0df8 WL |
249 | inline int roundint(double d) |
250 | { | |
251 | return (int)(d > 0 ? d + 0.5 : d - 0.5); | |
252 | } | |
253 | ||
51ed9ec9 | 254 | inline int64_t roundint64(double d) |
1f2e0df8 | 255 | { |
51ed9ec9 | 256 | return (int64_t)(d > 0 ? d + 0.5 : d - 0.5); |
1f2e0df8 WL |
257 | } |
258 | ||
51ed9ec9 | 259 | inline int64_t abs64(int64_t n) |
1f2e0df8 WL |
260 | { |
261 | return (n >= 0 ? n : -n); | |
262 | } | |
263 | ||
264 | template<typename T> | |
265 | std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) | |
266 | { | |
ac4e7f62 WL |
267 | std::string rv; |
268 | static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', | |
269 | '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; | |
88dc2d6c WL |
270 | rv.reserve((itend-itbegin)*3); |
271 | for(T it = itbegin; it < itend; ++it) | |
272 | { | |
273 | unsigned char val = (unsigned char)(*it); | |
274 | if(fSpaces && it != itbegin) | |
275 | rv.push_back(' '); | |
276 | rv.push_back(hexmap[val>>4]); | |
277 | rv.push_back(hexmap[val&15]); | |
278 | } | |
279 | ||
ac4e7f62 | 280 | return rv; |
1f2e0df8 WL |
281 | } |
282 | ||
5d891489 PW |
283 | template<typename T> |
284 | inline std::string HexStr(const T& vch, bool fSpaces=false) | |
1f2e0df8 WL |
285 | { |
286 | return HexStr(vch.begin(), vch.end(), fSpaces); | |
287 | } | |
288 | ||
97789d37 WL |
289 | /** Format a paragraph of text to a fixed width, adding spaces for |
290 | * indentation to any added line. | |
291 | */ | |
292 | std::string FormatParagraph(const std::string in, size_t width=79, size_t indent=0); | |
293 | ||
51ed9ec9 | 294 | inline int64_t GetPerformanceCounter() |
1f2e0df8 | 295 | { |
51ed9ec9 | 296 | int64_t nCounter = 0; |
6853e627 | 297 | #ifdef WIN32 |
1f2e0df8 WL |
298 | QueryPerformanceCounter((LARGE_INTEGER*)&nCounter); |
299 | #else | |
300 | timeval t; | |
301 | gettimeofday(&t, NULL); | |
51ed9ec9 | 302 | nCounter = (int64_t) t.tv_sec * 1000000 + t.tv_usec; |
1f2e0df8 WL |
303 | #endif |
304 | return nCounter; | |
305 | } | |
306 | ||
51ed9ec9 | 307 | inline int64_t GetTimeMillis() |
1f2e0df8 WL |
308 | { |
309 | return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - | |
310 | boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds(); | |
311 | } | |
312 | ||
51ed9ec9 | 313 | inline int64_t GetTimeMicros() |
0ae0712b PW |
314 | { |
315 | return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - | |
316 | boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds(); | |
317 | } | |
318 | ||
3e8ac6af | 319 | std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime); |
1f2e0df8 | 320 | |
1f2e0df8 WL |
321 | inline bool IsSwitchChar(char c) |
322 | { | |
6853e627 | 323 | #ifdef WIN32 |
1f2e0df8 WL |
324 | return c == '-' || c == '/'; |
325 | #else | |
326 | return c == '-'; | |
327 | #endif | |
328 | } | |
329 | ||
3ae07355 GA |
330 | /** |
331 | * Return string argument or default value | |
332 | * | |
333 | * @param strArg Argument to get (e.g. "-foo") | |
334 | * @param default (e.g. "1") | |
335 | * @return command-line argument or default value | |
336 | */ | |
337 | std::string GetArg(const std::string& strArg, const std::string& strDefault); | |
1f2e0df8 | 338 | |
3ae07355 GA |
339 | /** |
340 | * Return integer argument or default value | |
341 | * | |
342 | * @param strArg Argument to get (e.g. "-foo") | |
343 | * @param default (e.g. 1) | |
344 | * @return command-line argument (0 if invalid number) or default value | |
345 | */ | |
51ed9ec9 | 346 | int64_t GetArg(const std::string& strArg, int64_t nDefault); |
1f2e0df8 | 347 | |
3ae07355 GA |
348 | /** |
349 | * Return boolean argument or default value | |
350 | * | |
351 | * @param strArg Argument to get (e.g. "-foo") | |
352 | * @param default (true or false) | |
353 | * @return command-line argument or default value | |
354 | */ | |
3260b4c0 | 355 | bool GetBoolArg(const std::string& strArg, bool fDefault); |
1f2e0df8 | 356 | |
0fcf91ea GA |
357 | /** |
358 | * Set an argument if it doesn't already have a value | |
359 | * | |
360 | * @param strArg Argument to set (e.g. "-foo") | |
361 | * @param strValue Value (e.g. "1") | |
362 | * @return true if argument gets set, false if it already had a value | |
363 | */ | |
364 | bool SoftSetArg(const std::string& strArg, const std::string& strValue); | |
365 | ||
366 | /** | |
367 | * Set a boolean argument if it doesn't already have a value | |
368 | * | |
369 | * @param strArg Argument to set (e.g. "-foo") | |
370 | * @param fValue Value (e.g. false) | |
371 | * @return true if argument gets set, false if it already had a value | |
372 | */ | |
7bf8b7c2 | 373 | bool SoftSetBoolArg(const std::string& strArg, bool fValue); |
1f2e0df8 | 374 | |
907a2aa4 GM |
375 | /** |
376 | * MWC RNG of George Marsaglia | |
377 | * This is intended to be fast. It has a period of 2^59.3, though the | |
378 | * least significant 16 bits only have a period of about 2^30.1. | |
379 | * | |
380 | * @return random value | |
381 | */ | |
382 | extern uint32_t insecure_rand_Rz; | |
383 | extern uint32_t insecure_rand_Rw; | |
384 | static inline uint32_t insecure_rand(void) | |
385 | { | |
b001c871 PK |
386 | insecure_rand_Rz = 36969 * (insecure_rand_Rz & 65535) + (insecure_rand_Rz >> 16); |
387 | insecure_rand_Rw = 18000 * (insecure_rand_Rw & 65535) + (insecure_rand_Rw >> 16); | |
388 | return (insecure_rand_Rw << 16) + insecure_rand_Rz; | |
907a2aa4 | 389 | } |
1f2e0df8 | 390 | |
907a2aa4 GM |
391 | /** |
392 | * Seed insecure_rand using the random pool. | |
393 | * @param Deterministic Use a determinstic seed | |
394 | */ | |
395 | void seed_insecure_rand(bool fDeterministic=false); | |
1f2e0df8 | 396 | |
42656ea2 GA |
397 | /** |
398 | * Timing-attack-resistant comparison. | |
399 | * Takes time proportional to length | |
400 | * of first argument. | |
401 | */ | |
402 | template <typename T> | |
403 | bool TimingResistantEqual(const T& a, const T& b) | |
404 | { | |
405 | if (b.size() == 0) return a.size() == 0; | |
406 | size_t accumulator = a.size() ^ b.size(); | |
407 | for (size_t i = 0; i < a.size(); i++) | |
408 | accumulator |= a[i] ^ b[i%b.size()]; | |
409 | return accumulator == 0; | |
410 | } | |
411 | ||
ea0796bd | 412 | /** Median filter over a stream of values. |
6b8de05d PW |
413 | * Returns the median of the last N numbers |
414 | */ | |
a8b95ce6 WL |
415 | template <typename T> class CMedianFilter |
416 | { | |
417 | private: | |
418 | std::vector<T> vValues; | |
419 | std::vector<T> vSorted; | |
735a6069 | 420 | unsigned int nSize; |
a8b95ce6 | 421 | public: |
735a6069 | 422 | CMedianFilter(unsigned int size, T initial_value): |
a8b95ce6 WL |
423 | nSize(size) |
424 | { | |
425 | vValues.reserve(size); | |
426 | vValues.push_back(initial_value); | |
427 | vSorted = vValues; | |
428 | } | |
ea0796bd | 429 | |
a8b95ce6 WL |
430 | void input(T value) |
431 | { | |
432 | if(vValues.size() == nSize) | |
433 | { | |
434 | vValues.erase(vValues.begin()); | |
435 | } | |
436 | vValues.push_back(value); | |
437 | ||
438 | vSorted.resize(vValues.size()); | |
439 | std::copy(vValues.begin(), vValues.end(), vSorted.begin()); | |
440 | std::sort(vSorted.begin(), vSorted.end()); | |
441 | } | |
442 | ||
443 | T median() const | |
444 | { | |
445 | int size = vSorted.size(); | |
20091df7 | 446 | assert(size>0); |
a8b95ce6 WL |
447 | if(size & 1) // Odd number of elements |
448 | { | |
449 | return vSorted[size/2]; | |
450 | } | |
451 | else // Even number of elements | |
452 | { | |
453 | return (vSorted[size/2-1] + vSorted[size/2]) / 2; | |
454 | } | |
455 | } | |
1c4aab92 MH |
456 | |
457 | int size() const | |
458 | { | |
459 | return vValues.size(); | |
460 | } | |
461 | ||
462 | std::vector<T> sorted () const | |
463 | { | |
464 | return vSorted; | |
465 | } | |
a8b95ce6 WL |
466 | }; |
467 | ||
6853e627 | 468 | #ifdef WIN32 |
1f2e0df8 WL |
469 | inline void SetThreadPriority(int nPriority) |
470 | { | |
471 | SetThreadPriority(GetCurrentThread(), nPriority); | |
472 | } | |
473 | #else | |
1f2e0df8 | 474 | |
93714039 | 475 | // PRIO_MAX is not defined on Solaris |
476 | #ifndef PRIO_MAX | |
d78900cc | 477 | #define PRIO_MAX 20 |
93714039 | 478 | #endif |
1f2e0df8 WL |
479 | #define THREAD_PRIORITY_LOWEST PRIO_MAX |
480 | #define THREAD_PRIORITY_BELOW_NORMAL 2 | |
481 | #define THREAD_PRIORITY_NORMAL 0 | |
53e71135 | 482 | #define THREAD_PRIORITY_ABOVE_NORMAL (-2) |
1f2e0df8 WL |
483 | |
484 | inline void SetThreadPriority(int nPriority) | |
485 | { | |
486 | // It's unclear if it's even possible to change thread priorities on Linux, | |
487 | // but we really and truly need it for the generation threads. | |
488 | #ifdef PRIO_THREAD | |
489 | setpriority(PRIO_THREAD, 0, nPriority); | |
490 | #else | |
491 | setpriority(PRIO_PROCESS, 0, nPriority); | |
492 | #endif | |
493 | } | |
1f2e0df8 WL |
494 | #endif |
495 | ||
96931d6f | 496 | void RenameThread(const char* name); |
1f2e0df8 | 497 | |
6ccff2cb NS |
498 | inline uint32_t ByteReverse(uint32_t value) |
499 | { | |
b985efaa LR |
500 | value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); |
501 | return (value<<16) | (value>>16); | |
6ccff2cb NS |
502 | } |
503 | ||
72f14d26 GA |
504 | // Standard wrapper for do-something-forever thread functions. |
505 | // "Forever" really means until the thread is interrupted. | |
506 | // Use it like: | |
c43da3f1 | 507 | // new boost::thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, 900000)); |
72f14d26 GA |
508 | // or maybe: |
509 | // boost::function<void()> f = boost::bind(&FunctionWithArg, argument); | |
510 | // threadGroup.create_thread(boost::bind(&LoopForever<boost::function<void()> >, "nothing", f, milliseconds)); | |
51ed9ec9 | 511 | template <typename Callable> void LoopForever(const char* name, Callable func, int64_t msecs) |
72f14d26 GA |
512 | { |
513 | std::string s = strprintf("bitcoin-%s", name); | |
514 | RenameThread(s.c_str()); | |
881a85a2 | 515 | LogPrintf("%s thread start\n", name); |
72f14d26 GA |
516 | try |
517 | { | |
518 | while (1) | |
519 | { | |
72f14d26 | 520 | MilliSleep(msecs); |
c43da3f1 | 521 | func(); |
72f14d26 GA |
522 | } |
523 | } | |
524 | catch (boost::thread_interrupted) | |
525 | { | |
881a85a2 | 526 | LogPrintf("%s thread stop\n", name); |
72f14d26 GA |
527 | throw; |
528 | } | |
529 | catch (std::exception& e) { | |
44235713 WL |
530 | PrintExceptionContinue(&e, name); |
531 | throw; | |
72f14d26 GA |
532 | } |
533 | catch (...) { | |
44235713 WL |
534 | PrintExceptionContinue(NULL, name); |
535 | throw; | |
72f14d26 GA |
536 | } |
537 | } | |
538 | // .. and a wrapper that just calls func once | |
539 | template <typename Callable> void TraceThread(const char* name, Callable func) | |
540 | { | |
541 | std::string s = strprintf("bitcoin-%s", name); | |
542 | RenameThread(s.c_str()); | |
543 | try | |
544 | { | |
881a85a2 | 545 | LogPrintf("%s thread start\n", name); |
72f14d26 | 546 | func(); |
881a85a2 | 547 | LogPrintf("%s thread exit\n", name); |
72f14d26 GA |
548 | } |
549 | catch (boost::thread_interrupted) | |
550 | { | |
881a85a2 | 551 | LogPrintf("%s thread interrupt\n", name); |
72f14d26 GA |
552 | throw; |
553 | } | |
554 | catch (std::exception& e) { | |
44235713 WL |
555 | PrintExceptionContinue(&e, name); |
556 | throw; | |
72f14d26 GA |
557 | } |
558 | catch (...) { | |
44235713 WL |
559 | PrintExceptionContinue(NULL, name); |
560 | throw; | |
72f14d26 GA |
561 | } |
562 | } | |
563 | ||
1f2e0df8 | 564 | #endif |