]> Git Repo - VerusCoin.git/blob - src/util.cpp
Merge pull request #4762
[VerusCoin.git] / src / util.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #if defined(HAVE_CONFIG_H)
7 #include "config/bitcoin-config.h"
8 #endif
9
10 #include "util.h"
11
12 #include "chainparamsbase.h"
13 #include "random.h"
14 #include "serialize.h"
15 #include "sync.h"
16 #include "utilstrencodings.h"
17 #include "utiltime.h"
18
19 #include <stdarg.h>
20
21 #ifndef WIN32
22 // for posix_fallocate
23 #ifdef __linux__
24
25 #ifdef _POSIX_C_SOURCE
26 #undef _POSIX_C_SOURCE
27 #endif
28
29 #define _POSIX_C_SOURCE 200112L
30
31 #endif // __linux__
32
33 #include <algorithm>
34 #include <fcntl.h>
35 #include <sys/resource.h>
36 #include <sys/stat.h>
37
38 #else
39
40 #ifdef _MSC_VER
41 #pragma warning(disable:4786)
42 #pragma warning(disable:4804)
43 #pragma warning(disable:4805)
44 #pragma warning(disable:4717)
45 #endif
46
47 #ifdef _WIN32_WINNT
48 #undef _WIN32_WINNT
49 #endif
50 #define _WIN32_WINNT 0x0501
51
52 #ifdef _WIN32_IE
53 #undef _WIN32_IE
54 #endif
55 #define _WIN32_IE 0x0501
56
57 #define WIN32_LEAN_AND_MEAN 1
58 #ifndef NOMINMAX
59 #define NOMINMAX
60 #endif
61
62 #include <io.h> /* for _commit */
63 #include <shlobj.h>
64 #endif
65
66 #ifdef HAVE_SYS_PRCTL_H
67 #include <sys/prctl.h>
68 #endif
69
70 #include <boost/algorithm/string/case_conv.hpp> // for to_lower()
71 #include <boost/algorithm/string/join.hpp>
72 #include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
73 #include <boost/filesystem.hpp>
74 #include <boost/filesystem/fstream.hpp>
75 #include <boost/foreach.hpp>
76 #include <boost/program_options/detail/config_file.hpp>
77 #include <boost/program_options/parsers.hpp>
78 #include <boost/thread.hpp>
79 #include <openssl/crypto.h>
80 #include <openssl/rand.h>
81
82 // Work around clang compilation problem in Boost 1.46:
83 // /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup
84 // See also: http://stackoverflow.com/questions/10020179/compilation-fail-in-boost-librairies-program-options
85 //           http://clang.debian.net/status.php?version=3.0&key=CANNOT_FIND_FUNCTION
86 namespace boost {
87
88     namespace program_options {
89         std::string to_internal(const std::string&);
90     }
91
92 } // namespace boost
93
94 using namespace std;
95
96 map<string, string> mapArgs;
97 map<string, vector<string> > mapMultiArgs;
98 bool fDebug = false;
99 bool fPrintToConsole = false;
100 bool fPrintToDebugLog = true;
101 bool fDaemon = false;
102 bool fServer = false;
103 string strMiscWarning;
104 bool fLogTimestamps = false;
105 bool fLogIPs = false;
106 volatile bool fReopenDebugLog = false;
107
108 // Init OpenSSL library multithreading support
109 static CCriticalSection** ppmutexOpenSSL;
110 void locking_callback(int mode, int i, const char* file, int line)
111 {
112     if (mode & CRYPTO_LOCK) {
113         ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
114     } else {
115         LEAVE_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
116     }
117 }
118
119 // Init
120 class CInit
121 {
122 public:
123     CInit()
124     {
125         // Init OpenSSL library multithreading support
126         ppmutexOpenSSL = (CCriticalSection**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(CCriticalSection*));
127         for (int i = 0; i < CRYPTO_num_locks(); i++)
128             ppmutexOpenSSL[i] = new CCriticalSection();
129         CRYPTO_set_locking_callback(locking_callback);
130
131 #ifdef WIN32
132         // Seed OpenSSL PRNG with current contents of the screen
133         RAND_screen();
134 #endif
135
136         // Seed OpenSSL PRNG with performance counter
137         RandAddSeed();
138     }
139     ~CInit()
140     {
141         // Securely erase the memory used by the PRNG
142         RAND_cleanup();
143         // Shutdown OpenSSL library multithreading support
144         CRYPTO_set_locking_callback(NULL);
145         for (int i = 0; i < CRYPTO_num_locks(); i++)
146             delete ppmutexOpenSSL[i];
147         OPENSSL_free(ppmutexOpenSSL);
148     }
149 }
150 instance_of_cinit;
151
152 // LogPrintf() has been broken a couple of times now
153 // by well-meaning people adding mutexes in the most straightforward way.
154 // It breaks because it may be called by global destructors during shutdown.
155 // Since the order of destruction of static/global objects is undefined,
156 // defining a mutex as a global object doesn't work (the mutex gets
157 // destroyed, and then some later destructor calls OutputDebugStringF,
158 // maybe indirectly, and you get a core dump at shutdown trying to lock
159 // the mutex).
160
161 static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
162 // We use boost::call_once() to make sure these are initialized in
163 // in a thread-safe manner the first time it is called:
164 static FILE* fileout = NULL;
165 static boost::mutex* mutexDebugLog = NULL;
166
167 static void DebugPrintInit()
168 {
169     assert(fileout == NULL);
170     assert(mutexDebugLog == NULL);
171
172     boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
173     fileout = fopen(pathDebug.string().c_str(), "a");
174     if (fileout) setbuf(fileout, NULL); // unbuffered
175
176     mutexDebugLog = new boost::mutex();
177 }
178
179 bool LogAcceptCategory(const char* category)
180 {
181     if (category != NULL)
182     {
183         if (!fDebug)
184             return false;
185
186         // Give each thread quick access to -debug settings.
187         // This helps prevent issues debugging global destructors,
188         // where mapMultiArgs might be deleted before another
189         // global destructor calls LogPrint()
190         static boost::thread_specific_ptr<set<string> > ptrCategory;
191         if (ptrCategory.get() == NULL)
192         {
193             const vector<string>& categories = mapMultiArgs["-debug"];
194             ptrCategory.reset(new set<string>(categories.begin(), categories.end()));
195             // thread_specific_ptr automatically deletes the set when the thread ends.
196         }
197         const set<string>& setCategories = *ptrCategory.get();
198
199         // if not debugging everything and not debugging specific category, LogPrint does nothing.
200         if (setCategories.count(string("")) == 0 &&
201             setCategories.count(string(category)) == 0)
202             return false;
203     }
204     return true;
205 }
206
207 int LogPrintStr(const std::string &str)
208 {
209     int ret = 0; // Returns total number of characters written
210     if (fPrintToConsole)
211     {
212         // print to console
213         ret = fwrite(str.data(), 1, str.size(), stdout);
214     }
215     else if (fPrintToDebugLog && AreBaseParamsConfigured())
216     {
217         static bool fStartedNewLine = true;
218         boost::call_once(&DebugPrintInit, debugPrintInitFlag);
219
220         if (fileout == NULL)
221             return ret;
222
223         boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
224
225         // reopen the log file, if requested
226         if (fReopenDebugLog) {
227             fReopenDebugLog = false;
228             boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
229             if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
230                 setbuf(fileout, NULL); // unbuffered
231         }
232
233         // Debug print useful for profiling
234         if (fLogTimestamps && fStartedNewLine)
235             ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
236         if (!str.empty() && str[str.size()-1] == '\n')
237             fStartedNewLine = true;
238         else
239             fStartedNewLine = false;
240
241         ret = fwrite(str.data(), 1, str.size(), fileout);
242     }
243
244     return ret;
245 }
246
247 static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet)
248 {
249     // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
250     if (name.find("-no") == 0)
251     {
252         std::string positive("-");
253         positive.append(name.begin()+3, name.end());
254         if (mapSettingsRet.count(positive) == 0)
255         {
256             bool value = !GetBoolArg(name, false);
257             mapSettingsRet[positive] = (value ? "1" : "0");
258         }
259     }
260 }
261
262 void ParseParameters(int argc, const char* const argv[])
263 {
264     mapArgs.clear();
265     mapMultiArgs.clear();
266
267     for (int i = 1; i < argc; i++)
268     {
269         std::string str(argv[i]);
270         std::string strValue;
271         size_t is_index = str.find('=');
272         if (is_index != std::string::npos)
273         {
274             strValue = str.substr(is_index+1);
275             str = str.substr(0, is_index);
276         }
277 #ifdef WIN32
278         boost::to_lower(str);
279         if (boost::algorithm::starts_with(str, "/"))
280             str = "-" + str.substr(1);
281 #endif
282
283         if (str[0] != '-')
284             break;
285
286         // Interpret --foo as -foo.
287         // If both --foo and -foo are set, the last takes effect.
288         if (str.length() > 1 && str[1] == '-')
289             str = str.substr(1);
290
291         mapArgs[str] = strValue;
292         mapMultiArgs[str].push_back(strValue);
293     }
294
295     // New 0.6 features:
296     BOOST_FOREACH(const PAIRTYPE(string,string)& entry, mapArgs)
297     {
298         // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
299         InterpretNegativeSetting(entry.first, mapArgs);
300     }
301 }
302
303 std::string GetArg(const std::string& strArg, const std::string& strDefault)
304 {
305     if (mapArgs.count(strArg))
306         return mapArgs[strArg];
307     return strDefault;
308 }
309
310 int64_t GetArg(const std::string& strArg, int64_t nDefault)
311 {
312     if (mapArgs.count(strArg))
313         return atoi64(mapArgs[strArg]);
314     return nDefault;
315 }
316
317 bool GetBoolArg(const std::string& strArg, bool fDefault)
318 {
319     if (mapArgs.count(strArg))
320     {
321         if (mapArgs[strArg].empty())
322             return true;
323         return (atoi(mapArgs[strArg]) != 0);
324     }
325     return fDefault;
326 }
327
328 bool SoftSetArg(const std::string& strArg, const std::string& strValue)
329 {
330     if (mapArgs.count(strArg))
331         return false;
332     mapArgs[strArg] = strValue;
333     return true;
334 }
335
336 bool SoftSetBoolArg(const std::string& strArg, bool fValue)
337 {
338     if (fValue)
339         return SoftSetArg(strArg, std::string("1"));
340     else
341         return SoftSetArg(strArg, std::string("0"));
342 }
343
344 static std::string FormatException(std::exception* pex, const char* pszThread)
345 {
346 #ifdef WIN32
347     char pszModule[MAX_PATH] = "";
348     GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
349 #else
350     const char* pszModule = "bitcoin";
351 #endif
352     if (pex)
353         return strprintf(
354             "EXCEPTION: %s       \n%s       \n%s in %s       \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
355     else
356         return strprintf(
357             "UNKNOWN EXCEPTION       \n%s in %s       \n", pszModule, pszThread);
358 }
359
360 void PrintExceptionContinue(std::exception* pex, const char* pszThread)
361 {
362     std::string message = FormatException(pex, pszThread);
363     LogPrintf("\n\n************************\n%s\n", message);
364     fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
365     strMiscWarning = message;
366 }
367
368 boost::filesystem::path GetDefaultDataDir()
369 {
370     namespace fs = boost::filesystem;
371     // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin
372     // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin
373     // Mac: ~/Library/Application Support/Bitcoin
374     // Unix: ~/.bitcoin
375 #ifdef WIN32
376     // Windows
377     return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
378 #else
379     fs::path pathRet;
380     char* pszHome = getenv("HOME");
381     if (pszHome == NULL || strlen(pszHome) == 0)
382         pathRet = fs::path("/");
383     else
384         pathRet = fs::path(pszHome);
385 #ifdef MAC_OSX
386     // Mac
387     pathRet /= "Library/Application Support";
388     TryCreateDirectory(pathRet);
389     return pathRet / "Bitcoin";
390 #else
391     // Unix
392     return pathRet / ".bitcoin";
393 #endif
394 #endif
395 }
396
397 static boost::filesystem::path pathCached[CBaseChainParams::MAX_NETWORK_TYPES+1];
398 static CCriticalSection csPathCached;
399
400 const boost::filesystem::path &GetDataDir(bool fNetSpecific)
401 {
402     namespace fs = boost::filesystem;
403
404     LOCK(csPathCached);
405
406     int nNet = CBaseChainParams::MAX_NETWORK_TYPES;
407     if (fNetSpecific) nNet = BaseParams().NetworkID();
408
409     fs::path &path = pathCached[nNet];
410
411     // This can be called during exceptions by LogPrintf(), so we cache the
412     // value so we don't have to do memory allocations after that.
413     if (!path.empty())
414         return path;
415
416     if (mapArgs.count("-datadir")) {
417         path = fs::system_complete(mapArgs["-datadir"]);
418         if (!fs::is_directory(path)) {
419             path = "";
420             return path;
421         }
422     } else {
423         path = GetDefaultDataDir();
424     }
425     if (fNetSpecific)
426         path /= BaseParams().DataDir();
427
428     fs::create_directories(path);
429
430     return path;
431 }
432
433 void ClearDatadirCache()
434 {
435     std::fill(&pathCached[0], &pathCached[CBaseChainParams::MAX_NETWORK_TYPES+1],
436         boost::filesystem::path());
437 }
438
439 boost::filesystem::path GetConfigFile()
440 {
441     boost::filesystem::path pathConfigFile(GetArg("-conf", "bitcoin.conf"));
442     if (!pathConfigFile.is_complete())
443         pathConfigFile = GetDataDir(false) / pathConfigFile;
444
445     return pathConfigFile;
446 }
447
448 void ReadConfigFile(map<string, string>& mapSettingsRet,
449                     map<string, vector<string> >& mapMultiSettingsRet)
450 {
451     boost::filesystem::ifstream streamConfig(GetConfigFile());
452     if (!streamConfig.good())
453         return; // No bitcoin.conf file is OK
454
455     set<string> setOptions;
456     setOptions.insert("*");
457
458     for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
459     {
460         // Don't overwrite existing settings so command line settings override bitcoin.conf
461         string strKey = string("-") + it->string_key;
462         if (mapSettingsRet.count(strKey) == 0)
463         {
464             mapSettingsRet[strKey] = it->value[0];
465             // interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set)
466             InterpretNegativeSetting(strKey, mapSettingsRet);
467         }
468         mapMultiSettingsRet[strKey].push_back(it->value[0]);
469     }
470     // If datadir is changed in .conf file:
471     ClearDatadirCache();
472 }
473
474 boost::filesystem::path GetPidFile()
475 {
476     boost::filesystem::path pathPidFile(GetArg("-pid", "bitcoind.pid"));
477     if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
478     return pathPidFile;
479 }
480
481 #ifndef WIN32
482 void CreatePidFile(const boost::filesystem::path &path, pid_t pid)
483 {
484     FILE* file = fopen(path.string().c_str(), "w");
485     if (file)
486     {
487         fprintf(file, "%d\n", pid);
488         fclose(file);
489     }
490 }
491 #endif
492
493 bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest)
494 {
495 #ifdef WIN32
496     return MoveFileExA(src.string().c_str(), dest.string().c_str(),
497                       MOVEFILE_REPLACE_EXISTING);
498 #else
499     int rc = std::rename(src.string().c_str(), dest.string().c_str());
500     return (rc == 0);
501 #endif /* WIN32 */
502 }
503
504 // Ignores exceptions thrown by Boost's create_directory if the requested directory exists.
505 // Specifically handles case where path p exists, but it wasn't possible for the user to
506 // write to the parent directory.
507 bool TryCreateDirectory(const boost::filesystem::path& p)
508 {
509     try
510     {
511         return boost::filesystem::create_directory(p);
512     } catch (boost::filesystem::filesystem_error) {
513         if (!boost::filesystem::exists(p) || !boost::filesystem::is_directory(p))
514             throw;
515     }
516
517     // create_directory didn't create the directory, it had to have existed already
518     return false;
519 }
520
521 void FileCommit(FILE *fileout)
522 {
523     fflush(fileout); // harmless if redundantly called
524 #ifdef WIN32
525     HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(fileout));
526     FlushFileBuffers(hFile);
527 #else
528     #if defined(__linux__) || defined(__NetBSD__)
529     fdatasync(fileno(fileout));
530     #elif defined(__APPLE__) && defined(F_FULLFSYNC)
531     fcntl(fileno(fileout), F_FULLFSYNC, 0);
532     #else
533     fsync(fileno(fileout));
534     #endif
535 #endif
536 }
537
538 bool TruncateFile(FILE *file, unsigned int length) {
539 #if defined(WIN32)
540     return _chsize(_fileno(file), length) == 0;
541 #else
542     return ftruncate(fileno(file), length) == 0;
543 #endif
544 }
545
546 // this function tries to raise the file descriptor limit to the requested number.
547 // It returns the actual file descriptor limit (which may be more or less than nMinFD)
548 int RaiseFileDescriptorLimit(int nMinFD) {
549 #if defined(WIN32)
550     return 2048;
551 #else
552     struct rlimit limitFD;
553     if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
554         if (limitFD.rlim_cur < (rlim_t)nMinFD) {
555             limitFD.rlim_cur = nMinFD;
556             if (limitFD.rlim_cur > limitFD.rlim_max)
557                 limitFD.rlim_cur = limitFD.rlim_max;
558             setrlimit(RLIMIT_NOFILE, &limitFD);
559             getrlimit(RLIMIT_NOFILE, &limitFD);
560         }
561         return limitFD.rlim_cur;
562     }
563     return nMinFD; // getrlimit failed, assume it's fine
564 #endif
565 }
566
567 // this function tries to make a particular range of a file allocated (corresponding to disk space)
568 // it is advisory, and the range specified in the arguments will never contain live data
569 void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
570 #if defined(WIN32)
571     // Windows-specific version
572     HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
573     LARGE_INTEGER nFileSize;
574     int64_t nEndPos = (int64_t)offset + length;
575     nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
576     nFileSize.u.HighPart = nEndPos >> 32;
577     SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
578     SetEndOfFile(hFile);
579 #elif defined(MAC_OSX)
580     // OSX specific version
581     fstore_t fst;
582     fst.fst_flags = F_ALLOCATECONTIG;
583     fst.fst_posmode = F_PEOFPOSMODE;
584     fst.fst_offset = 0;
585     fst.fst_length = (off_t)offset + length;
586     fst.fst_bytesalloc = 0;
587     if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
588         fst.fst_flags = F_ALLOCATEALL;
589         fcntl(fileno(file), F_PREALLOCATE, &fst);
590     }
591     ftruncate(fileno(file), fst.fst_length);
592 #elif defined(__linux__)
593     // Version using posix_fallocate
594     off_t nEndPos = (off_t)offset + length;
595     posix_fallocate(fileno(file), 0, nEndPos);
596 #else
597     // Fallback version
598     // TODO: just write one byte per block
599     static const char buf[65536] = {};
600     fseek(file, offset, SEEK_SET);
601     while (length > 0) {
602         unsigned int now = 65536;
603         if (length < now)
604             now = length;
605         fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
606         length -= now;
607     }
608 #endif
609 }
610
611 void ShrinkDebugFile()
612 {
613     // Scroll debug.log if it's getting too big
614     boost::filesystem::path pathLog = GetDataDir() / "debug.log";
615     FILE* file = fopen(pathLog.string().c_str(), "r");
616     if (file && boost::filesystem::file_size(pathLog) > 10 * 1000000)
617     {
618         // Restart the file with some of the end
619         std::vector <char> vch(200000,0);
620         fseek(file, -vch.size(), SEEK_END);
621         int nBytes = fread(begin_ptr(vch), 1, vch.size(), file);
622         fclose(file);
623
624         file = fopen(pathLog.string().c_str(), "w");
625         if (file)
626         {
627             fwrite(begin_ptr(vch), 1, nBytes, file);
628             fclose(file);
629         }
630     }
631     else if (file != NULL)
632         fclose(file);
633 }
634
635 #ifdef WIN32
636 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate)
637 {
638     namespace fs = boost::filesystem;
639
640     char pszPath[MAX_PATH] = "";
641
642     if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
643     {
644         return fs::path(pszPath);
645     }
646
647     LogPrintf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n");
648     return fs::path("");
649 }
650 #endif
651
652 boost::filesystem::path GetTempPath() {
653 #if BOOST_FILESYSTEM_VERSION == 3
654     return boost::filesystem::temp_directory_path();
655 #else
656     // TODO: remove when we don't support filesystem v2 anymore
657     boost::filesystem::path path;
658 #ifdef WIN32
659     char pszPath[MAX_PATH] = "";
660
661     if (GetTempPathA(MAX_PATH, pszPath))
662         path = boost::filesystem::path(pszPath);
663 #else
664     path = boost::filesystem::path("/tmp");
665 #endif
666     if (path.empty() || !boost::filesystem::is_directory(path)) {
667         LogPrintf("GetTempPath(): failed to find temp path\n");
668         return boost::filesystem::path("");
669     }
670     return path;
671 #endif
672 }
673
674 void runCommand(std::string strCommand)
675 {
676     int nErr = ::system(strCommand.c_str());
677     if (nErr)
678         LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
679 }
680
681 void RenameThread(const char* name)
682 {
683 #if defined(PR_SET_NAME)
684     // Only the first 15 characters are used (16 - NUL terminator)
685     ::prctl(PR_SET_NAME, name, 0, 0, 0);
686 #elif 0 && (defined(__FreeBSD__) || defined(__OpenBSD__))
687     // TODO: This is currently disabled because it needs to be verified to work
688     //       on FreeBSD or OpenBSD first. When verified the '0 &&' part can be
689     //       removed.
690     pthread_set_name_np(pthread_self(), name);
691
692 #elif defined(MAC_OSX) && defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
693
694 // pthread_setname_np is XCode 10.6-and-later
695 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
696     pthread_setname_np(name);
697 #endif
698
699 #else
700     // Prevent warnings for unused parameters...
701     (void)name;
702 #endif
703 }
704
705 void SetupEnvironment()
706 {
707 #ifndef WIN32
708     try
709     {
710 #if BOOST_FILESYSTEM_VERSION == 3
711             boost::filesystem::path::codecvt(); // Raises runtime error if current locale is invalid
712 #else // boost filesystem v2
713             std::locale();                      // Raises runtime error if current locale is invalid
714 #endif
715     } catch(std::runtime_error &e)
716     {
717         setenv("LC_ALL", "C", 1); // Force C locale
718     }
719 #endif
720 }
721
722 void SetThreadPriority(int nPriority)
723 {
724 #ifdef WIN32
725     SetThreadPriority(GetCurrentThread(), nPriority);
726 #else // WIN32
727 #ifdef PRIO_THREAD
728     setpriority(PRIO_THREAD, 0, nPriority);
729 #else // PRIO_THREAD
730     setpriority(PRIO_PROCESS, 0, nPriority);
731 #endif // PRIO_THREAD
732 #endif // WIN32
733 }
This page took 0.058703 seconds and 4 git commands to generate.