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