aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:45:50 -0500
committerJacek Antonelli2008-08-15 23:45:50 -0500
commit2a4dea528f670b9bb1f77ef27a8a1dd16603d114 (patch)
tree95c68e362703c9099d571ecbdc6142b1cda1e005 /linden/indra/llcommon
parentSecond Life viewer sources 1.20.6 (diff)
downloadmeta-impy-2a4dea528f670b9bb1f77ef27a8a1dd16603d114.zip
meta-impy-2a4dea528f670b9bb1f77ef27a8a1dd16603d114.tar.gz
meta-impy-2a4dea528f670b9bb1f77ef27a8a1dd16603d114.tar.bz2
meta-impy-2a4dea528f670b9bb1f77ef27a8a1dd16603d114.tar.xz
Second Life viewer sources 1.20.7
Diffstat (limited to 'linden/indra/llcommon')
-rw-r--r--linden/indra/llcommon/files.lst4
-rw-r--r--linden/indra/llcommon/llapp.cpp163
-rw-r--r--linden/indra/llcommon/llapp.h3
-rw-r--r--linden/indra/llcommon/llapr.cpp12
-rw-r--r--linden/indra/llcommon/llares.cpp5
-rw-r--r--linden/indra/llcommon/llcommon.vcproj15
-rw-r--r--linden/indra/llcommon/llcommon_vc8.vcproj36
-rw-r--r--linden/indra/llcommon/llcommon_vc9.vcproj20
-rw-r--r--linden/indra/llcommon/llerror.cpp69
-rw-r--r--linden/indra/llcommon/llerror.h82
-rw-r--r--linden/indra/llcommon/llfile.cpp6
-rw-r--r--linden/indra/llcommon/llfile.h2
-rw-r--r--linden/indra/llcommon/llfindlocale.cpp525
-rw-r--r--linden/indra/llcommon/llfindlocale.h65
-rw-r--r--linden/indra/llcommon/llheartbeat.cpp165
-rw-r--r--linden/indra/llcommon/llheartbeat.h73
-rw-r--r--linden/indra/llcommon/llindraconfigfile.cpp107
-rw-r--r--linden/indra/llcommon/llindraconfigfile.h50
-rw-r--r--linden/indra/llcommon/llkeyusetracker.h220
-rw-r--r--linden/indra/llcommon/lllivefile.h2
-rw-r--r--linden/indra/llcommon/llmemory.cpp2
-rw-r--r--linden/indra/llcommon/llprocessor.cpp2
-rw-r--r--linden/indra/llcommon/llptrskipmap.h6
-rw-r--r--linden/indra/llcommon/llsdserialize.h2
-rw-r--r--linden/indra/llcommon/llsdutil.h12
-rw-r--r--linden/indra/llcommon/llsys.cpp14
-rw-r--r--linden/indra/llcommon/lltimer.cpp84
-rw-r--r--linden/indra/llcommon/lltimer.h10
-rw-r--r--linden/indra/llcommon/llversionserver.h6
-rw-r--r--linden/indra/llcommon/llversionviewer.h2
30 files changed, 1590 insertions, 174 deletions
diff --git a/linden/indra/llcommon/files.lst b/linden/indra/llcommon/files.lst
index 6f03155..fd6a07c 100644
--- a/linden/indra/llcommon/files.lst
+++ b/linden/indra/llcommon/files.lst
@@ -12,12 +12,16 @@ llcommon/llerrorthread.cpp
12llcommon/llevent.cpp 12llcommon/llevent.cpp
13llcommon/llfasttimer.cpp 13llcommon/llfasttimer.cpp
14llcommon/llfile.cpp 14llcommon/llfile.cpp
15llcommon/llfindlocale.cpp
15llcommon/llfixedbuffer.cpp 16llcommon/llfixedbuffer.cpp
16llcommon/llformat.cpp 17llcommon/llformat.cpp
17llcommon/llframetimer.cpp 18llcommon/llframetimer.cpp
19llcommon/llheartbeat.cpp
20llcommon/llindraconfigfile.cpp
18llcommon/lllog.cpp 21llcommon/lllog.cpp
19llcommon/llliveappconfig.cpp 22llcommon/llliveappconfig.cpp
20llcommon/lllivefile.cpp 23llcommon/lllivefile.cpp
24llcommon/lllog.cpp
21llcommon/llmemory.cpp 25llcommon/llmemory.cpp
22llcommon/llmemorystream.cpp 26llcommon/llmemorystream.cpp
23llcommon/llmetrics.cpp 27llcommon/llmetrics.cpp
diff --git a/linden/indra/llcommon/llapp.cpp b/linden/indra/llcommon/llapp.cpp
index bd2e377..ebace4e 100644
--- a/linden/indra/llcommon/llapp.cpp
+++ b/linden/indra/llcommon/llapp.cpp
@@ -49,11 +49,24 @@
49LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop); 49LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
50BOOL ConsoleCtrlHandler(DWORD fdwCtrlType); 50BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
51#else 51#else
52#include <unistd.h> // for fork() 52# include <signal.h>
53# include <unistd.h> // for fork()
53void setup_signals(); 54void setup_signals();
54void default_unix_signal_handler(int signum, siginfo_t *info, void *); 55void default_unix_signal_handler(int signum, siginfo_t *info, void *);
55const S32 LL_SMACKDOWN_SIGNAL = SIGUSR1; 56# if LL_DARWIN
56#endif 57/* OSX doesn't support SIGRT* */
58S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
59S32 LL_HEARTBEAT_SIGNAL = SIGUSR2;
60# else
61/* We want reliable delivery of our signals - SIGRT* is it. */
62/* Old LinuxThreads versions eat SIGRTMIN+0 to SIGRTMIN+2, avoid those. */
63/* Note that SIGRTMIN/SIGRTMAX may expand to a glibc function call with a
64 nonconstant result so these are not consts and cannot be used in constant-
65 expressions. SIGRTMAX may return -1 on rare broken setups. */
66S32 LL_SMACKDOWN_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-1) : SIGUSR1;
67S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2;
68# endif // LL_DARWIN
69#endif // LL_WINDOWS
57 70
58// the static application instance 71// the static application instance
59LLApp* LLApp::sApplication = NULL; 72LLApp* LLApp::sApplication = NULL;
@@ -523,6 +536,9 @@ void setup_signals()
523 sigaction(SIGSEGV, &act, NULL); 536 sigaction(SIGSEGV, &act, NULL);
524 sigaction(SIGSYS, &act, NULL); 537 sigaction(SIGSYS, &act, NULL);
525 538
539 sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL);
540 sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
541
526 // Asynchronous signals that are normally ignored 542 // Asynchronous signals that are normally ignored
527 sigaction(SIGCHLD, &act, NULL); 543 sigaction(SIGCHLD, &act, NULL);
528 sigaction(SIGUSR2, &act, NULL); 544 sigaction(SIGUSR2, &act, NULL);
@@ -533,7 +549,6 @@ void setup_signals()
533 sigaction(SIGINT, &act, NULL); 549 sigaction(SIGINT, &act, NULL);
534 550
535 // Asynchronous signals that result in core 551 // Asynchronous signals that result in core
536 sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
537 sigaction(SIGQUIT, &act, NULL); 552 sigaction(SIGQUIT, &act, NULL);
538} 553}
539 554
@@ -555,6 +570,9 @@ void clear_signals()
555 sigaction(SIGSEGV, &act, NULL); 570 sigaction(SIGSEGV, &act, NULL);
556 sigaction(SIGSYS, &act, NULL); 571 sigaction(SIGSYS, &act, NULL);
557 572
573 sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL);
574 sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
575
558 // Asynchronous signals that are normally ignored 576 // Asynchronous signals that are normally ignored
559 sigaction(SIGCHLD, &act, NULL); 577 sigaction(SIGCHLD, &act, NULL);
560 578
@@ -565,7 +583,6 @@ void clear_signals()
565 583
566 // Asynchronous signals that result in core 584 // Asynchronous signals that result in core
567 sigaction(SIGUSR2, &act, NULL); 585 sigaction(SIGUSR2, &act, NULL);
568 sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
569 sigaction(SIGQUIT, &act, NULL); 586 sigaction(SIGQUIT, &act, NULL);
570} 587}
571 588
@@ -586,16 +603,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
586 603
587 switch (signum) 604 switch (signum)
588 { 605 {
589 case SIGALRM: 606 case SIGCHLD:
590 case SIGPIPE:
591 case SIGUSR2:
592 // We don't care about these signals, ignore them
593 if (LLApp::sLogInSignal)
594 {
595 llinfos << "Signal handler - Ignoring this signal" << llendl;
596 }
597 return;
598 case SIGCHLD:
599 if (LLApp::sLogInSignal) 607 if (LLApp::sLogInSignal)
600 { 608 {
601 llinfos << "Signal handler - Got SIGCHLD from " << info->si_pid << llendl; 609 llinfos << "Signal handler - Got SIGCHLD from " << info->si_pid << llendl;
@@ -624,59 +632,6 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
624 clear_signals(); 632 clear_signals();
625 raise(signum); 633 raise(signum);
626 return; 634 return;
627 case LL_SMACKDOWN_SIGNAL: // Smackdown treated just like any other app termination, for now
628 if (LLApp::sLogInSignal)
629 {
630 llwarns << "Signal handler - Handling smackdown signal!" << llendl;
631 }
632 else
633 {
634 // Don't log anything, even errors - this is because this signal could happen anywhere.
635 LLError::setDefaultLevel(LLError::LEVEL_NONE);
636 }
637
638 // Change the signal that we reraise to SIGABRT, so we generate a core dump.
639 signum = SIGABRT;
640 case SIGBUS:
641 case SIGSEGV:
642 case SIGQUIT:
643 if (LLApp::sLogInSignal)
644 {
645 llwarns << "Signal handler - Handling fatal signal!" << llendl;
646 }
647 if (LLApp::isError())
648 {
649 // Received second fatal signal while handling first, just die right now
650 // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app.
651 clear_signals();
652
653 if (LLApp::sLogInSignal)
654 {
655 llwarns << "Signal handler - Got another fatal signal while in the error handler, die now!" << llendl;
656 }
657 raise(signum);
658 return;
659 }
660
661 if (LLApp::sLogInSignal)
662 {
663 llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl;
664 }
665 // Flag status to ERROR, so thread_error does its work.
666 LLApp::setError();
667 // Block in the signal handler until somebody says that we're done.
668 while (LLApp::sErrorThreadRunning && !LLApp::isStopped())
669 {
670 ms_sleep(10);
671 }
672
673 if (LLApp::sLogInSignal)
674 {
675 llwarns << "Signal handler - App is stopped, reraising signal" << llendl;
676 }
677 clear_signals();
678 raise(signum);
679 return;
680 case SIGINT: 635 case SIGINT:
681 case SIGHUP: 636 case SIGHUP:
682 case SIGTERM: 637 case SIGTERM:
@@ -697,10 +652,76 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
697 } 652 }
698 LLApp::setQuitting(); 653 LLApp::setQuitting();
699 return; 654 return;
655 case SIGALRM:
656 case SIGPIPE:
657 case SIGUSR2:
700 default: 658 default:
701 if (LLApp::sLogInSignal) 659 if (signum == LL_SMACKDOWN_SIGNAL ||
702 { 660 signum == SIGBUS ||
703 llwarns << "Signal handler - Unhandled signal, ignoring!" << llendl; 661 signum == SIGILL ||
662 signum == SIGFPE ||
663 signum == SIGSEGV ||
664 signum == SIGQUIT)
665 {
666 if (signum == LL_SMACKDOWN_SIGNAL)
667 {
668 // Smackdown treated just like any other app termination, for now
669 if (LLApp::sLogInSignal)
670 {
671 llwarns << "Signal handler - Handling smackdown signal!" << llendl;
672 }
673 else
674 {
675 // Don't log anything, even errors - this is because this signal could happen anywhere.
676 LLError::setDefaultLevel(LLError::LEVEL_NONE);
677 }
678
679 // Change the signal that we reraise to SIGABRT, so we generate a core dump.
680 signum = SIGABRT;
681 }
682
683 if (LLApp::sLogInSignal)
684 {
685 llwarns << "Signal handler - Handling fatal signal!" << llendl;
686 }
687 if (LLApp::isError())
688 {
689 // Received second fatal signal while handling first, just die right now
690 // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app.
691 clear_signals();
692
693 if (LLApp::sLogInSignal)
694 {
695 llwarns << "Signal handler - Got another fatal signal while in the error handler, die now!" << llendl;
696 }
697 raise(signum);
698 return;
699 }
700
701 if (LLApp::sLogInSignal)
702 {
703 llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl;
704 }
705 // Flag status to ERROR, so thread_error does its work.
706 LLApp::setError();
707 // Block in the signal handler until somebody says that we're done.
708 while (LLApp::sErrorThreadRunning && !LLApp::isStopped())
709 {
710 ms_sleep(10);
711 }
712
713 if (LLApp::sLogInSignal)
714 {
715 llwarns << "Signal handler - App is stopped, reraising signal" << llendl;
716 }
717 clear_signals();
718 raise(signum);
719 return;
720 } else {
721 if (LLApp::sLogInSignal)
722 {
723 llinfos << "Signal handler - Unhandled signal " << signum << ", ignoring!" << llendl;
724 }
704 } 725 }
705 } 726 }
706} 727}
diff --git a/linden/indra/llcommon/llapp.h b/linden/indra/llcommon/llapp.h
index 50a70ae..9d8ff88 100644
--- a/linden/indra/llcommon/llapp.h
+++ b/linden/indra/llcommon/llapp.h
@@ -46,7 +46,8 @@ typedef void (*LLAppErrorHandler)();
46typedef void (*LLAppChildCallback)(int pid, bool exited, int status); 46typedef void (*LLAppChildCallback)(int pid, bool exited, int status);
47 47
48#if !LL_WINDOWS 48#if !LL_WINDOWS
49extern const S32 LL_SMACKDOWN_SIGNAL; 49extern S32 LL_SMACKDOWN_SIGNAL;
50extern S32 LL_HEARTBEAT_SIGNAL;
50 51
51// Clear all of the signal handlers (which we want to do for the child process when we fork 52// Clear all of the signal handlers (which we want to do for the child process when we fork
52void clear_signals(); 53void clear_signals();
diff --git a/linden/indra/llcommon/llapr.cpp b/linden/indra/llcommon/llapr.cpp
index 08c40a4..78bf876 100644
--- a/linden/indra/llcommon/llapr.cpp
+++ b/linden/indra/llcommon/llapr.cpp
@@ -54,7 +54,7 @@ void ll_init_apr()
54 54
55void ll_cleanup_apr() 55void ll_cleanup_apr()
56{ 56{
57 llinfos << "Cleaning up APR" << llendl; 57 LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
58 58
59 if (gLogMutexp) 59 if (gLogMutexp)
60 { 60 {
@@ -118,7 +118,7 @@ bool ll_apr_warn_status(apr_status_t status)
118 if(APR_SUCCESS == status) return false; 118 if(APR_SUCCESS == status) return false;
119#ifndef LL_WINDOWS 119#ifndef LL_WINDOWS
120 char buf[MAX_STRING]; /* Flawfinder: ignore */ 120 char buf[MAX_STRING]; /* Flawfinder: ignore */
121 llwarns << "APR: " << apr_strerror(status, buf, MAX_STRING) << llendl; 121 LL_WARNS_ONCE("APR") << "APR: " << apr_strerror(status, buf, MAX_STRING) << LL_ENDL;
122#endif 122#endif
123 return true; 123 return true;
124} 124}
@@ -294,7 +294,7 @@ bool ll_apr_file_remove(const LLString& filename, apr_pool_t* pool)
294 s = apr_file_remove(filename.c_str(), pool); 294 s = apr_file_remove(filename.c_str(), pool);
295 if (s != APR_SUCCESS) 295 if (s != APR_SUCCESS)
296 { 296 {
297 lldebugs << "ll_apr_file_remove failed on file: " << filename << llendl; 297 LL_DEBUGS("APR") << "ll_apr_file_remove failed on file: " << filename << LL_ENDL;
298 ll_apr_warn_status(s); 298 ll_apr_warn_status(s);
299 return false; 299 return false;
300 } 300 }
@@ -308,7 +308,7 @@ bool ll_apr_file_rename(const LLString& filename, const LLString& newname, apr_p
308 s = apr_file_rename(filename.c_str(), newname.c_str(), pool); 308 s = apr_file_rename(filename.c_str(), newname.c_str(), pool);
309 if (s != APR_SUCCESS) 309 if (s != APR_SUCCESS)
310 { 310 {
311 lldebugs << "ll_apr_file_rename failed on file: " << filename << llendl; 311 LL_DEBUGS("APR") << "ll_apr_file_rename failed on file: " << filename << LL_ENDL;
312 ll_apr_warn_status(s); 312 ll_apr_warn_status(s);
313 return false; 313 return false;
314 } 314 }
@@ -365,7 +365,7 @@ bool ll_apr_dir_make(const LLString& dirname, apr_pool_t* pool)
365 s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool); 365 s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool);
366 if (s != APR_SUCCESS) 366 if (s != APR_SUCCESS)
367 { 367 {
368 lldebugs << "ll_apr_dir_make failed on file: " << dirname << llendl; 368 LL_DEBUGS("APR") << "ll_apr_dir_make failed on file: " << dirname << LL_ENDL;
369 ll_apr_warn_status(s); 369 ll_apr_warn_status(s);
370 return false; 370 return false;
371 } 371 }
@@ -379,7 +379,7 @@ bool ll_apr_dir_remove(const LLString& dirname, apr_pool_t* pool)
379 s = apr_file_remove(dirname.c_str(), pool); 379 s = apr_file_remove(dirname.c_str(), pool);
380 if (s != APR_SUCCESS) 380 if (s != APR_SUCCESS)
381 { 381 {
382 lldebugs << "ll_apr_dir_remove failed on file: " << dirname << llendl; 382 LL_DEBUGS("APR") << "ll_apr_dir_remove failed on file: " << dirname << LL_ENDL;
383 ll_apr_warn_status(s); 383 ll_apr_warn_status(s);
384 return false; 384 return false;
385 } 385 }
diff --git a/linden/indra/llcommon/llares.cpp b/linden/indra/llcommon/llares.cpp
index 4adf0c3..4d054e4 100644
--- a/linden/indra/llcommon/llares.cpp
+++ b/linden/indra/llcommon/llares.cpp
@@ -154,7 +154,7 @@ void LLAres::getSrvRecords(const std::string &name, SrvResponder *resp)
154 154
155void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp) 155void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp)
156{ 156{
157 llinfos << "Rewriting " << uri << llendl; 157 LL_DEBUGS2("AppInit","Rewrite") << "Rewriting " << uri << LL_ENDL;
158 158
159 resp->mUri = LLURI(uri); 159 resp->mUri = LLURI(uri);
160 search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(), 160 search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(),
@@ -163,7 +163,8 @@ void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp)
163 163
164LLQueryResponder::LLQueryResponder() 164LLQueryResponder::LLQueryResponder()
165 : LLAres::QueryResponder(), 165 : LLAres::QueryResponder(),
166 mResult(ARES_ENODATA) 166 mResult(ARES_ENODATA),
167 mType(RES_INVALID)
167{ 168{
168} 169}
169 170
diff --git a/linden/indra/llcommon/llcommon.vcproj b/linden/indra/llcommon/llcommon.vcproj
index ab4e67a..f54ea13 100644
--- a/linden/indra/llcommon/llcommon.vcproj
+++ b/linden/indra/llcommon/llcommon.vcproj
@@ -199,6 +199,9 @@
199 RelativePath=".\llfile.cpp"> 199 RelativePath=".\llfile.cpp">
200 </File> 200 </File>
201 <File 201 <File
202 RelativePath=".\llfindlocale.cpp">
203 </File>
204 <File
202 RelativePath=".\llfixedbuffer.cpp"> 205 RelativePath=".\llfixedbuffer.cpp">
203 </File> 206 </File>
204 <File 207 <File
@@ -208,6 +211,12 @@
208 RelativePath=".\llframetimer.cpp"> 211 RelativePath=".\llframetimer.cpp">
209 </File> 212 </File>
210 <File 213 <File
214 RelativePath=".\llheartbeat.cpp">
215 </File>
216 <File
217 RelativePath=".\llindraconfigfile.cpp">
218 </File>
219 <File
211 RelativePath=".\llliveappconfig.cpp"> 220 RelativePath=".\llliveappconfig.cpp">
212 </File> 221 </File>
213 <File 222 <File
@@ -417,12 +426,18 @@
417 RelativePath=".\llhash.h"> 426 RelativePath=".\llhash.h">
418 </File> 427 </File>
419 <File 428 <File
429 RelativePath=".\llheartbeat.h">
430 </File>
431 <File
420 RelativePath=".\llindexedqueue.h"> 432 RelativePath=".\llindexedqueue.h">
421 </File> 433 </File>
422 <File 434 <File
423 RelativePath=".\llkeythrottle.h"> 435 RelativePath=".\llkeythrottle.h">
424 </File> 436 </File>
425 <File 437 <File
438 RelativePath=".\llkeyusetracker.h">
439 </File>
440 <File
426 RelativePath=".\lllinkedqueue.h"> 441 RelativePath=".\lllinkedqueue.h">
427 </File> 442 </File>
428 <File 443 <File
diff --git a/linden/indra/llcommon/llcommon_vc8.vcproj b/linden/indra/llcommon/llcommon_vc8.vcproj
index 5578075..a298499 100644
--- a/linden/indra/llcommon/llcommon_vc8.vcproj
+++ b/linden/indra/llcommon/llcommon_vc8.vcproj
@@ -289,6 +289,10 @@
289 > 289 >
290 </File> 290 </File>
291 <File 291 <File
292 RelativePath=".\llfindlocale.cpp"
293 >
294 </File>
295 <File
292 RelativePath=".\llfixedbuffer.cpp" 296 RelativePath=".\llfixedbuffer.cpp"
293 > 297 >
294 </File> 298 </File>
@@ -301,6 +305,14 @@
301 > 305 >
302 </File> 306 </File>
303 <File 307 <File
308 RelativePath=".\llheartbeat.cpp"
309 >
310 </File>
311 <File
312 RelativePath=".\llindraconfigfile.cpp"
313 >
314 </File>
315 <File
304 RelativePath=".\llliveappconfig.cpp" 316 RelativePath=".\llliveappconfig.cpp"
305 > 317 >
306 </File> 318 </File>
@@ -563,6 +575,10 @@
563 > 575 >
564 </File> 576 </File>
565 <File 577 <File
578 RelativePath=".\llfindlocale.h"
579 >
580 </File>
581 <File
566 RelativePath=".\llfixedbuffer.h" 582 RelativePath=".\llfixedbuffer.h"
567 > 583 >
568 </File> 584 </File>
@@ -587,6 +603,10 @@
587 > 603 >
588 </File> 604 </File>
589 <File 605 <File
606 RelativePath=".\llindraconfigfile.h"
607 >
608 </File>
609 <File
590 RelativePath=".\lllinkedqueue.h" 610 RelativePath=".\lllinkedqueue.h"
591 > 611 >
592 </File> 612 </File>
@@ -759,6 +779,22 @@
759 > 779 >
760 </File> 780 </File>
761 <File 781 <File
782 RelativePath=".\metaclass.h"
783 >
784 </File>
785 <File
786 RelativePath=".\metaclasst.h"
787 >
788 </File>
789 <File
790 RelativePath=".\metaproperty.h"
791 >
792 </File>
793 <File
794 RelativePath=".\metapropertyt.h"
795 >
796 </File>
797 <File
762 RelativePath=".\new_mem_ops.h" 798 RelativePath=".\new_mem_ops.h"
763 > 799 >
764 </File> 800 </File>
diff --git a/linden/indra/llcommon/llcommon_vc9.vcproj b/linden/indra/llcommon/llcommon_vc9.vcproj
index 0bb2d11..1ae534d 100644
--- a/linden/indra/llcommon/llcommon_vc9.vcproj
+++ b/linden/indra/llcommon/llcommon_vc9.vcproj
@@ -290,6 +290,10 @@
290 > 290 >
291 </File> 291 </File>
292 <File 292 <File
293 RelativePath=".\llfindlocale.cpp"
294 >
295 </File>
296 <File
293 RelativePath=".\llfixedbuffer.cpp" 297 RelativePath=".\llfixedbuffer.cpp"
294 > 298 >
295 </File> 299 </File>
@@ -302,6 +306,14 @@
302 > 306 >
303 </File> 307 </File>
304 <File 308 <File
309 RelativePath=".\llheartbeat.cpp"
310 >
311 </File>
312 <File
313 RelativePath=".\llindraconfigfile.cpp"
314 >
315 </File>
316 <File
305 RelativePath=".\llliveappconfig.cpp" 317 RelativePath=".\llliveappconfig.cpp"
306 > 318 >
307 </File> 319 </File>
@@ -564,6 +576,10 @@
564 > 576 >
565 </File> 577 </File>
566 <File 578 <File
579 RelativePath=".\llfindlocale.h"
580 >
581 </File>
582 <File
567 RelativePath=".\llfixedbuffer.h" 583 RelativePath=".\llfixedbuffer.h"
568 > 584 >
569 </File> 585 </File>
@@ -588,6 +604,10 @@
588 > 604 >
589 </File> 605 </File>
590 <File 606 <File
607 RelativePath=".\llindraconfigfile.h"
608 >
609 </File>
610 <File
591 RelativePath=".\lllinkedqueue.h" 611 RelativePath=".\lllinkedqueue.h"
592 > 612 >
593 </File> 613 </File>
diff --git a/linden/indra/llcommon/llerror.cpp b/linden/indra/llcommon/llerror.cpp
index 0e7db89..b74b288 100644
--- a/linden/indra/llcommon/llerror.cpp
+++ b/linden/indra/llcommon/llerror.cpp
@@ -408,6 +408,8 @@ namespace LLError
408 LevelMap functionLevelMap; 408 LevelMap functionLevelMap;
409 LevelMap classLevelMap; 409 LevelMap classLevelMap;
410 LevelMap fileLevelMap; 410 LevelMap fileLevelMap;
411 LevelMap tagLevelMap;
412 std::map<std::string, unsigned int> uniqueLogMessages;
411 413
412 LLError::FatalFunction crashFunction; 414 LLError::FatalFunction crashFunction;
413 LLError::TimeFunction timeFunction; 415 LLError::TimeFunction timeFunction;
@@ -494,11 +496,17 @@ namespace LLError
494namespace LLError 496namespace LLError
495{ 497{
496 CallSite::CallSite(ELevel level, 498 CallSite::CallSite(ELevel level,
497 const char* file, int line, 499 const char* file,
498 const std::type_info& class_info, const char* function) 500 int line,
501 const std::type_info& class_info,
502 const char* function,
503 const char* broadTag,
504 const char* narrowTag,
505 bool printOnce)
499 : mLevel(level), mFile(file), mLine(line), 506 : mLevel(level), mFile(file), mLine(line),
500 mClassInfo(class_info), mFunction(function), 507 mClassInfo(class_info), mFunction(function),
501 mCached(false), mShouldLog(false) 508 mCached(false), mShouldLog(false),
509 mBroadTag(broadTag), mNarrowTag(narrowTag), mPrintOnce(printOnce)
502 { } 510 { }
503 511
504 512
@@ -552,6 +560,15 @@ namespace
552#endif 560#endif
553 561
554 LogControlFile& e = LogControlFile::fromDirectory(dir); 562 LogControlFile& e = LogControlFile::fromDirectory(dir);
563
564 // NOTE: We want to explicitly load the file before we add it to the event timer
565 // that checks for changes to the file. Else, we're not actually loading the file yet,
566 // and most of the initialization happens without any attention being paid to the
567 // log control file. Not to mention that when it finally gets checked later,
568 // all log statements that have been evaluated already become dirty and need to be
569 // evaluated for printing again. So, make sure to call checkAndReload()
570 // before addToEventTimer().
571 e.checkAndReload();
555 e.addToEventTimer(); 572 e.addToEventTimer();
556 } 573 }
557} 574}
@@ -625,6 +642,14 @@ namespace LLError
625 g.invalidateCallSites(); 642 g.invalidateCallSites();
626 s.fileLevelMap[file_name] = level; 643 s.fileLevelMap[file_name] = level;
627 } 644 }
645
646 void setTagLevel(const std::string& tag_name, ELevel level)
647 {
648 Globals& g = Globals::get();
649 Settings& s = Settings::get();
650 g.invalidateCallSites();
651 s.tagLevelMap[tag_name] = level;
652 }
628} 653}
629 654
630namespace { 655namespace {
@@ -674,6 +699,8 @@ namespace LLError
674 s.functionLevelMap.clear(); 699 s.functionLevelMap.clear();
675 s.classLevelMap.clear(); 700 s.classLevelMap.clear();
676 s.fileLevelMap.clear(); 701 s.fileLevelMap.clear();
702 s.tagLevelMap.clear();
703 s.uniqueLogMessages.clear();
677 704
678 setPrintLocation(config["print-location"]); 705 setPrintLocation(config["print-location"]);
679 setDefaultLevel(decodeLevel(config["default-level"])); 706 setDefaultLevel(decodeLevel(config["default-level"]));
@@ -689,6 +716,7 @@ namespace LLError
689 setLevels(s.functionLevelMap, entry["functions"], level); 716 setLevels(s.functionLevelMap, entry["functions"], level);
690 setLevels(s.classLevelMap, entry["classes"], level); 717 setLevels(s.classLevelMap, entry["classes"], level);
691 setLevels(s.fileLevelMap, entry["files"], level); 718 setLevels(s.fileLevelMap, entry["files"], level);
719 setLevels(s.tagLevelMap, entry["tags"], level);
692 } 720 }
693 } 721 }
694} 722}
@@ -850,7 +878,7 @@ namespace {
850 return false; 878 return false;
851 } 879 }
852 880
853 level = i->second; 881 level = i->second;
854 return true; 882 return true;
855 } 883 }
856 884
@@ -929,9 +957,15 @@ namespace LLError
929 957
930 ELevel compareLevel = s.defaultLevel; 958 ELevel compareLevel = s.defaultLevel;
931 959
932 checkLevelMap(s.functionLevelMap, function_name, compareLevel) 960 // The most specific match found will be used as the log level,
961 // since the computation short circuits.
962 // So, in increasing order of importance:
963 // Default < Broad Tag < File < Class < Function < Narrow Tag
964 ((site.mNarrowTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mNarrowTag, compareLevel) : false)
965 || checkLevelMap(s.functionLevelMap, function_name, compareLevel)
933 || checkLevelMap(s.classLevelMap, class_name, compareLevel) 966 || checkLevelMap(s.classLevelMap, class_name, compareLevel)
934 || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel); 967 || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel)
968 || ((site.mBroadTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mBroadTag, compareLevel) : false);
935 969
936 site.mCached = true; 970 site.mCached = true;
937 g.addCallSite(site); 971 g.addCallSite(site);
@@ -1018,6 +1052,29 @@ namespace LLError
1018 #endif 1052 #endif
1019 prefix << site.mFunction << ": "; 1053 prefix << site.mFunction << ": ";
1020 } 1054 }
1055
1056 if (site.mPrintOnce)
1057 {
1058 std::map<std::string, unsigned int>::iterator messageIter = s.uniqueLogMessages.find(message);
1059 if (messageIter != s.uniqueLogMessages.end())
1060 {
1061 messageIter->second++;
1062 unsigned int num_messages = messageIter->second;
1063 if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0)
1064 {
1065 prefix << "ONCE (" << num_messages << "th time seen): ";
1066 }
1067 else
1068 {
1069 return;
1070 }
1071 }
1072 else
1073 {
1074 prefix << "ONCE: ";
1075 s.uniqueLogMessages[message] = 1;
1076 }
1077 }
1021 1078
1022 prefix << message; 1079 prefix << message;
1023 message = prefix.str(); 1080 message = prefix.str();
diff --git a/linden/indra/llcommon/llerror.h b/linden/indra/llcommon/llerror.h
index e1ace39..0a066bf 100644
--- a/linden/indra/llcommon/llerror.h
+++ b/linden/indra/llcommon/llerror.h
@@ -45,23 +45,23 @@
45 45
46 Code can log messages with constuctions like this: 46 Code can log messages with constuctions like this:
47 47
48 llinfos << "request to fizzbip agent " << agent_id 48 LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id
49 << " denied due to timeout" << llendl; 49 << " denied due to timeout" << LL_ENDL;
50 50
51 Messages can be logged to one of four increasing levels of concern, 51 Messages can be logged to one of four increasing levels of concern,
52 using one of four "streams": 52 using one of four "streams":
53 53
54 lldebugs - debug messages that are normally supressed 54 LL_DEBUGS("StringTag") - debug messages that are normally supressed
55 llinfos - informational messages that are normall shown 55 LL_INFOS("StringTag") - informational messages that are normall shown
56 llwarns - warning messages that singal a problem 56 LL_WARNS("StringTag") - warning messages that singal a problem
57 llerrs - error messages that are major, unrecoverable failures 57 LL_ERRS("StringTag") - error messages that are major, unrecoverable failures
58 58
59 The later (llerrs) automatically crashes the process after the message 59 The later (LL_ERRS("StringTag")) automatically crashes the process after the message
60 is logged. 60 is logged.
61 61
62 Note that these "streams" are actually #define magic. Rules for use: 62 Note that these "streams" are actually #define magic. Rules for use:
63 * they cannot be used as normal streams, only to start a message 63 * they cannot be used as normal streams, only to start a message
64 * messages written to them MUST be terminated with llendl 64 * messages written to them MUST be terminated with LL_ENDL
65 * between the opening and closing, the << operator is indeed 65 * between the opening and closing, the << operator is indeed
66 writing onto a std::ostream, so all conversions and stream 66 writing onto a std::ostream, so all conversions and stream
67 formating are available 67 formating are available
@@ -85,7 +85,7 @@
85 { 85 {
86 if (i > 100) 86 if (i > 100)
87 { 87 {
88 llwanrs << "called with a big value for i: " << i << llendl; 88 LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL;
89 } 89 }
90 ... 90 ...
91 } 91 }
@@ -100,7 +100,7 @@
100 100
101 Lastly, logging is now very efficient in both compiled code and execution 101 Lastly, logging is now very efficient in both compiled code and execution
102 when skipped. There is no need to wrap messages, even debugging ones, in 102 when skipped. There is no need to wrap messages, even debugging ones, in
103 #ifdef _DEBUG constructs. lldebugs messages are compiled into all builds, 103 #ifdef _DEBUG constructs. LL_DEBUGS("StringTag") messages are compiled into all builds,
104 even release. Which means you can use them to help debug even when deployed 104 even release. Which means you can use them to help debug even when deployed
105 to a real grid. 105 to a real grid.
106*/ 106*/
@@ -144,7 +144,7 @@ namespace LLError
144 // intended for public use. 144 // intended for public use.
145 public: 145 public:
146 CallSite(ELevel, const char* file, int line, 146 CallSite(ELevel, const char* file, int line,
147 const std::type_info& class_info, const char* function); 147 const std::type_info& class_info, const char* function, const char* broadTag, const char* narrowTag, bool printOnce);
148 148
149 bool shouldLog() 149 bool shouldLog()
150 { return mCached ? mShouldLog : Log::shouldLog(*this); } 150 { return mCached ? mShouldLog : Log::shouldLog(*this); }
@@ -156,9 +156,12 @@ namespace LLError
156 // these describe the call site and never change 156 // these describe the call site and never change
157 const ELevel mLevel; 157 const ELevel mLevel;
158 const char* const mFile; 158 const char* const mFile;
159 const int mLine; 159 const int mLine;
160 const std::type_info& mClassInfo; 160 const std::type_info& mClassInfo;
161 const char* const mFunction; 161 const char* const mFunction;
162 const char* const mBroadTag;
163 const char* const mNarrowTag;
164 const bool mPrintOnce;
162 165
163 // these implement a cache of the call to shouldLog() 166 // these implement a cache of the call to shouldLog()
164 bool mCached; 167 bool mCached;
@@ -200,39 +203,66 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
200 See top of file for common usage. 203 See top of file for common usage.
201*/ 204*/
202 205
203#define lllog(level) \ 206#define lllog(level, broadTag, narrowTag, once) \
204 { \ 207 { \
205 static LLError::CallSite _site( \ 208 static LLError::CallSite _site( \
206 level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__);\ 209 level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, broadTag, narrowTag, once);\
207 if (_site.shouldLog()) \ 210 if (_site.shouldLog()) \
208 { \ 211 { \
209 std::ostringstream* _out = LLError::Log::out(); \ 212 std::ostringstream* _out = LLError::Log::out(); \
210 (*_out) 213 (*_out)
211 214
215// DEPRECATED: Don't call directly, use LL_ENDL instead, which actually looks like a macro
212#define llendl \ 216#define llendl \
213 LLError::End(); \ 217 LLError::End(); \
214 LLError::Log::flush(_out, _site); \ 218 LLError::Log::flush(_out, _site); \
215 } \ 219 } \
216 } 220 }
217 221
218#define llinfos lllog(LLError::LEVEL_INFO) 222// DEPRECATED: Use the new macros that allow tags and *look* like macros.
219#define lldebugs lllog(LLError::LEVEL_DEBUG) 223#define lldebugs lllog(LLError::LEVEL_DEBUG, NULL, NULL, false)
220#define llwarns lllog(LLError::LEVEL_WARN) 224#define llinfos lllog(LLError::LEVEL_INFO, NULL, NULL, false)
221#define llerrs lllog(LLError::LEVEL_ERROR) 225#define llwarns lllog(LLError::LEVEL_WARN, NULL, NULL, false)
222 226#define llerrs lllog(LLError::LEVEL_ERROR, NULL, NULL, false)
223#define llcont (*_out) 227#define llcont (*_out)
228
229// NEW Macros for debugging, allow the passing of a string tag
230
231// One Tag
232#define LL_DEBUGS(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, false)
233#define LL_INFOS(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, false)
234#define LL_WARNS(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, false)
235#define LL_ERRS(broadTag) lllog(LLError::LEVEL_ERROR, broadTag, NULL, false)
236// Two Tags
237#define LL_DEBUGS2(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, false)
238#define LL_INFOS2(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, false)
239#define LL_WARNS2(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, false)
240#define LL_ERRS2(broadTag, narrowTag) lllog(LLError::LEVEL_ERROR, broadTag, narrowTag, false)
241
242// Only print the log message once (good for warnings or infos that would otherwise
243// spam the log file over and over, such as tighter loops).
244#define LL_DEBUGS_ONCE(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, true)
245#define LL_INFOS_ONCE(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, true)
246#define LL_WARNS_ONCE(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, true)
247#define LL_DEBUGS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, true)
248#define LL_INFOS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, true)
249#define LL_WARNS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, true)
250
251#define LL_ENDL llendl
252#define LL_CONT (*_out)
253
224 /* 254 /*
225 Use this construct if you need to do computation in the middle of a 255 Use this construct if you need to do computation in the middle of a
226 message: 256 message:
227 257
228 llinfos << "the agent " << agend_id; 258 LL_INFOS("AgentGesture") << "the agent " << agend_id;
229 switch (f) 259 switch (f)
230 { 260 {
231 case FOP_SHRUGS: llcont << "shrugs"; break; 261 case FOP_SHRUGS: LL_CONT << "shrugs"; break;
232 case FOP_TAPS: llcont << "points at " << who; break; 262 case FOP_TAPS: LL_CONT << "points at " << who; break;
233 case FOP_SAYS: llcont << "says " << message; break; 263 case FOP_SAYS: LL_CONT << "says " << message; break;
234 } 264 }
235 llcont << " for " << t << " seconds" << llendl; 265 LL_CONT << " for " << t << " seconds" << LL_ENDL;
236 266
237 Such computation is done iff the message will be logged. 267 Such computation is done iff the message will be logged.
238 */ 268 */
diff --git a/linden/indra/llcommon/llfile.cpp b/linden/indra/llcommon/llfile.cpp
index 32e9622..fc0d481 100644
--- a/linden/indra/llcommon/llfile.cpp
+++ b/linden/indra/llcommon/llfile.cpp
@@ -160,7 +160,7 @@ LLFILE * LLFile::_Fiopen(const char *filename, std::ios::openmode mode,int) // p
160 | ios_base::binary, 160 | ios_base::binary,
161 0}; 161 0};
162 162
163 FILE *fp = 0; 163 LLFILE *fp = 0;
164 int n; 164 int n;
165 ios_base::openmode atendflag = mode & ios_base::ate; 165 ios_base::openmode atendflag = mode & ios_base::ate;
166 ios_base::openmode norepflag = mode & ios_base::_Noreplace; 166 ios_base::openmode norepflag = mode & ios_base::_Noreplace;
@@ -207,7 +207,7 @@ void llifstream::open(const char* _Filename, /* Flawfinder: ignore */
207 int _Prot) 207 int _Prot)
208{ // open a C stream with specified mode 208{ // open a C stream with specified mode
209 209
210 FILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::in, _Prot); 210 LLFILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::in, _Prot);
211 if(filep == NULL) 211 if(filep == NULL)
212 { 212 {
213 _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/ 213 _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
@@ -258,7 +258,7 @@ void llofstream::open(const char* _Filename, /* Flawfinder: ignore */
258 int _Prot) 258 int _Prot)
259{ // open a C stream with specified mode 259{ // open a C stream with specified mode
260 260
261 FILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::out, _Prot); 261 LLFILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::out, _Prot);
262 if(filep == NULL) 262 if(filep == NULL)
263 { 263 {
264 _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/ 264 _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
diff --git a/linden/indra/llcommon/llfile.h b/linden/indra/llcommon/llfile.h
index d449ec9..189edbf 100644
--- a/linden/indra/llcommon/llfile.h
+++ b/linden/indra/llcommon/llfile.h
@@ -42,6 +42,8 @@
42 42
43typedef FILE LLFILE; 43typedef FILE LLFILE;
44 44
45#include <fstream>
46
45#ifdef LL_WINDOWS 47#ifdef LL_WINDOWS
46#define USE_LLFILESTREAMS 1 48#define USE_LLFILESTREAMS 1
47#else 49#else
diff --git a/linden/indra/llcommon/llfindlocale.cpp b/linden/indra/llcommon/llfindlocale.cpp
new file mode 100644
index 0000000..47da974
--- /dev/null
+++ b/linden/indra/llcommon/llfindlocale.cpp
@@ -0,0 +1,525 @@
1/**
2 * @file llfindlocale.cpp
3 * @brief Detect system language setting
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 *
22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above,
24 * and agree to abide by those obligations.
25 *
26 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
27 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
28 * COMPLETENESS OR PERFORMANCE.
29 * $/LicenseInfo$
30 */
31
32/* Yes, this was originally C code. */
33
34#include "linden_common.h"
35
36#include <stdlib.h>
37#include <string.h>
38#include <ctype.h>
39
40#ifdef WIN32
41#include <windows.h>
42#include <winnt.h>
43#endif
44
45#include "llfindlocale.h"
46
47static int
48is_lcchar(const int c) {
49 return isalnum(c);
50}
51
52static void
53lang_country_variant_from_envstring(const char *str,
54 char **lang,
55 char **country,
56 char **variant) {
57 int end = 0;
58 int start;
59
60 /* get lang, if any */
61 start = end;
62 while (is_lcchar(str[end])) {
63 ++end;
64 }
65 if (start != end) {
66 int i;
67 int len = end - start;
68 char *s = (char*)malloc(len + 1);
69 for (i=0; i<len; ++i) {
70 s[i] = tolower(str[start + i]);
71 }
72 s[i] = '\0';
73 *lang = s;
74 } else {
75 *lang = NULL;
76 }
77
78 if (str[end] && str[end]!=':') { /* not at end of str */
79 ++end;
80 }
81
82 /* get country, if any */
83 start = end;
84 while (is_lcchar(str[end])) {
85 ++end;
86 }
87 if (start != end) {
88 int i;
89 int len = end - start;
90 char *s = (char*)malloc(len + 1);
91 for (i=0; i<len; ++i) {
92 s[i] = toupper(str[start + i]);
93 }
94 s[i] = '\0';
95 *country = s;
96 } else {
97 *country = NULL;
98 }
99
100 if (str[end] && str[end]!=':') { /* not at end of str */
101 ++end;
102 }
103
104 /* get variant, if any */
105 start = end;
106 while (str[end] && str[end]!=':') {
107 ++end;
108 }
109 if (start != end) {
110 int i;
111 int len = end - start;
112 char *s = (char*)malloc(len + 1);
113 for (i=0; i<len; ++i) {
114 s[i] = str[start + i];
115 }
116 s[i] = '\0';
117 *variant = s;
118 } else {
119 *variant = NULL;
120 }
121}
122
123
124static int
125accumulate_locstring(const char *str, FL_Locale *l) {
126 char *lang = NULL;
127 char *country = NULL;
128 char *variant = NULL;
129 if (str) {
130 lang_country_variant_from_envstring(str, &lang, &country, &variant);
131 if (lang) {
132 l->lang = lang;
133 l->country = country;
134 l->variant = variant;
135 return 1;
136 }
137 }
138 free(lang); free(country); free(variant);
139 return 0;
140}
141
142
143static int
144accumulate_env(const char *name, FL_Locale *l) {
145 char *env;
146 char *lang = NULL;
147 char *country = NULL;
148 char *variant = NULL;
149 env = getenv(name);
150 if (env) {
151 return accumulate_locstring(env, l);
152 }
153 free(lang); free(country); free(variant);
154 return 0;
155}
156
157
158static void
159canonise_fl(FL_Locale *l) {
160 /* this function fixes some common locale-specifying mistakes */
161 /* en_UK -> en_GB */
162 if (l->lang && 0 == strcmp(l->lang, "en")) {
163 if (l->country && 0 == strcmp(l->country, "UK")) {
164 free((void*)l->country);
165 l->country = strdup("GB");
166 }
167 }
168 /* ja_JA -> ja_JP */
169 if (l->lang && 0 == strcmp(l->lang, "ja")) {
170 if (l->country && 0 == strcmp(l->country, "JA")) {
171 free((void*)l->country);
172 l->country = strdup("JP");
173 }
174 }
175}
176
177
178#ifdef WIN32
179#include <stdio.h>
180#define ML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##pn##_##sn)
181#define MLN(pn) MAKELANGID(LANG_##pn, SUBLANG_DEFAULT)
182#define RML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##sn)
183typedef struct {
184 LANGID id;
185 char* code;
186} IDToCode;
187static const IDToCode both_to_code[] = {
188 {ML(ENGLISH,US), "en_US.ISO_8859-1"},
189 {ML(ENGLISH,CAN), "en_CA"}, /* english / canadian */
190 {ML(ENGLISH,UK), "en_GB"},
191 {ML(ENGLISH,EIRE), "en_IE"},
192 {ML(ENGLISH,AUS), "en_AU"},
193 {MLN(GERMAN), "de_DE"},
194 {MLN(SPANISH), "es_ES"},
195 {ML(SPANISH,MEXICAN), "es_MX"},
196 {MLN(FRENCH), "fr_FR"},
197 {ML(FRENCH,CANADIAN), "fr_CA"},
198 {ML(FRENCH,BELGIAN), "fr_BE"}, /* ? */
199 {ML(DUTCH,BELGIAN), "nl_BE"}, /* ? */
200 {ML(PORTUGUESE,BRAZILIAN), "pt_BR"},
201 {MLN(PORTUGUESE), "pt_PT"},
202 {MLN(SWEDISH), "sv_SE"},
203 {ML(CHINESE,HONGKONG), "zh_HK"},
204 /* these are machine-generated and not yet verified */
205 {RML(AFRIKAANS,DEFAULT), "af_ZA"},
206 {RML(ALBANIAN,DEFAULT), "sq_AL"},
207 {RML(ARABIC,ARABIC_ALGERIA), "ar_DZ"},
208 {RML(ARABIC,ARABIC_BAHRAIN), "ar_BH"},
209 {RML(ARABIC,ARABIC_EGYPT), "ar_EG"},
210 {RML(ARABIC,ARABIC_IRAQ), "ar_IQ"},
211 {RML(ARABIC,ARABIC_JORDAN), "ar_JO"},
212 {RML(ARABIC,ARABIC_KUWAIT), "ar_KW"},
213 {RML(ARABIC,ARABIC_LEBANON), "ar_LB"},
214 {RML(ARABIC,ARABIC_LIBYA), "ar_LY"},
215 {RML(ARABIC,ARABIC_MOROCCO), "ar_MA"},
216 {RML(ARABIC,ARABIC_OMAN), "ar_OM"},
217 {RML(ARABIC,ARABIC_QATAR), "ar_QA"},
218 {RML(ARABIC,ARABIC_SAUDI_ARABIA), "ar_SA"},
219 {RML(ARABIC,ARABIC_SYRIA), "ar_SY"},
220 {RML(ARABIC,ARABIC_TUNISIA), "ar_TN"},
221 {RML(ARABIC,ARABIC_UAE), "ar_AE"},
222 {RML(ARABIC,ARABIC_YEMEN), "ar_YE"},
223 {RML(ARMENIAN,DEFAULT), "hy_AM"},
224 {RML(AZERI,AZERI_CYRILLIC), "az_AZ"},
225 {RML(AZERI,AZERI_LATIN), "az_AZ"},
226 {RML(BASQUE,DEFAULT), "eu_ES"},
227 {RML(BELARUSIAN,DEFAULT), "be_BY"},
228/*{RML(BRETON,DEFAULT), "br_FR"},*/
229 {RML(BULGARIAN,DEFAULT), "bg_BG"},
230 {RML(CATALAN,DEFAULT), "ca_ES"},
231 {RML(CHINESE,CHINESE_HONGKONG), "zh_HK"},
232 {RML(CHINESE,CHINESE_MACAU), "zh_MO"},
233 {RML(CHINESE,CHINESE_SIMPLIFIED), "zh_CN"},
234 {RML(CHINESE,CHINESE_SINGAPORE), "zh_SG"},
235 {RML(CHINESE,CHINESE_TRADITIONAL), "zh_TW"},
236/*{RML(CORNISH,DEFAULT), "kw_GB"},*/
237 {RML(CZECH,DEFAULT), "cs_CZ"},
238 {RML(DANISH,DEFAULT), "da_DK"},
239 {RML(DUTCH,DUTCH), "nl_NL"},
240 {RML(DUTCH,DUTCH_BELGIAN), "nl_BE"},
241/*{RML(DUTCH,DUTCH_SURINAM), "nl_SR"},*/
242 {RML(ENGLISH,ENGLISH_AUS), "en_AU"},
243 {RML(ENGLISH,ENGLISH_BELIZE), "en_BZ"},
244 {RML(ENGLISH,ENGLISH_CAN), "en_CA"},
245 {RML(ENGLISH,ENGLISH_CARIBBEAN), "en_CB"},
246 {RML(ENGLISH,ENGLISH_EIRE), "en_IE"},
247 {RML(ENGLISH,ENGLISH_JAMAICA), "en_JM"},
248 {RML(ENGLISH,ENGLISH_NZ), "en_NZ"},
249 {RML(ENGLISH,ENGLISH_PHILIPPINES), "en_PH"},
250 {RML(ENGLISH,ENGLISH_SOUTH_AFRICA), "en_ZA"},
251 {RML(ENGLISH,ENGLISH_TRINIDAD), "en_TT"},
252 {RML(ENGLISH,ENGLISH_UK), "en_GB"},
253 {RML(ENGLISH,ENGLISH_US), "en_US"},
254 {RML(ENGLISH,ENGLISH_ZIMBABWE), "en_ZW"},
255/*{RML(ESPERANTO,DEFAULT), "eo_"},*/
256 {RML(ESTONIAN,DEFAULT), "et_EE"},
257 {RML(FAEROESE,DEFAULT), "fo_FO"},
258 {RML(FARSI,DEFAULT), "fa_IR"},
259 {RML(FINNISH,DEFAULT), "fi_FI"},
260 {RML(FRENCH,FRENCH), "fr_FR"},
261 {RML(FRENCH,FRENCH_BELGIAN), "fr_BE"},
262 {RML(FRENCH,FRENCH_CANADIAN), "fr_CA"},
263 {RML(FRENCH,FRENCH_LUXEMBOURG), "fr_LU"},
264 {RML(FRENCH,FRENCH_MONACO), "fr_MC"},
265 {RML(FRENCH,FRENCH_SWISS), "fr_CH"},
266/*{RML(GAELIC,GAELIC), "ga_IE"},*/
267/*{RML(GAELIC,GAELIC_MANX), "gv_GB"},*/
268/*{RML(GAELIC,GAELIC_SCOTTISH), "gd_GB"},*/
269/*{RML(GALICIAN,DEFAULT), "gl_ES"},*/
270 {RML(GEORGIAN,DEFAULT), "ka_GE"},
271 {RML(GERMAN,GERMAN), "de_DE"},
272 {RML(GERMAN,GERMAN_AUSTRIAN), "de_AT"},
273 {RML(GERMAN,GERMAN_LIECHTENSTEIN), "de_LI"},
274 {RML(GERMAN,GERMAN_LUXEMBOURG), "de_LU"},
275 {RML(GERMAN,GERMAN_SWISS), "de_CH"},
276 {RML(GREEK,DEFAULT), "el_GR"},
277 {RML(GUJARATI,DEFAULT), "gu_IN"},
278 {RML(HEBREW,DEFAULT), "he_IL"},
279 {RML(HINDI,DEFAULT), "hi_IN"},
280 {RML(HUNGARIAN,DEFAULT), "hu_HU"},
281 {RML(ICELANDIC,DEFAULT), "is_IS"},
282 {RML(INDONESIAN,DEFAULT), "id_ID"},
283 {RML(ITALIAN,ITALIAN), "it_IT"},
284 {RML(ITALIAN,ITALIAN_SWISS), "it_CH"},
285 {RML(JAPANESE,DEFAULT), "ja_JP"},
286 {RML(KANNADA,DEFAULT), "kn_IN"},
287 {RML(KAZAK,DEFAULT), "kk_KZ"},
288 {RML(KONKANI,DEFAULT), "kok_IN"},
289 {RML(KOREAN,KOREAN), "ko_KR"},
290/*{RML(KYRGYZ,DEFAULT), "ky_KG"},*/
291 {RML(LATVIAN,DEFAULT), "lv_LV"},
292 {RML(LITHUANIAN,LITHUANIAN), "lt_LT"},
293 {RML(MACEDONIAN,DEFAULT), "mk_MK"},
294 {RML(MALAY,MALAY_BRUNEI_DARUSSALAM), "ms_BN"},
295 {RML(MALAY,MALAY_MALAYSIA), "ms_MY"},
296 {RML(MARATHI,DEFAULT), "mr_IN"},
297/*{RML(MONGOLIAN,DEFAULT), "mn_MN"},*/
298 {RML(NORWEGIAN,NORWEGIAN_BOKMAL), "nb_NO"},
299 {RML(NORWEGIAN,NORWEGIAN_NYNORSK), "nn_NO"},
300 {RML(POLISH,DEFAULT), "pl_PL"},
301 {RML(PORTUGUESE,PORTUGUESE), "pt_PT"},
302 {RML(PORTUGUESE,PORTUGUESE_BRAZILIAN), "pt_BR"},
303 {RML(PUNJABI,DEFAULT), "pa_IN"},
304 {RML(ROMANIAN,DEFAULT), "ro_RO"},
305 {RML(RUSSIAN,DEFAULT), "ru_RU"},
306 {RML(SANSKRIT,DEFAULT), "sa_IN"},
307 {RML(SERBIAN,DEFAULT), "hr_HR"},
308 {RML(SERBIAN,SERBIAN_CYRILLIC), "sr_SP"},
309 {RML(SERBIAN,SERBIAN_LATIN), "sr_SP"},
310 {RML(SLOVAK,DEFAULT), "sk_SK"},
311 {RML(SLOVENIAN,DEFAULT), "sl_SI"},
312 {RML(SPANISH,SPANISH), "es_ES"},
313 {RML(SPANISH,SPANISH_ARGENTINA), "es_AR"},
314 {RML(SPANISH,SPANISH_BOLIVIA), "es_BO"},
315 {RML(SPANISH,SPANISH_CHILE), "es_CL"},
316 {RML(SPANISH,SPANISH_COLOMBIA), "es_CO"},
317 {RML(SPANISH,SPANISH_COSTA_RICA), "es_CR"},
318 {RML(SPANISH,SPANISH_DOMINICAN_REPUBLIC), "es_DO"},
319 {RML(SPANISH,SPANISH_ECUADOR), "es_EC"},
320 {RML(SPANISH,SPANISH_EL_SALVADOR), "es_SV"},
321 {RML(SPANISH,SPANISH_GUATEMALA), "es_GT"},
322 {RML(SPANISH,SPANISH_HONDURAS), "es_HN"},
323 {RML(SPANISH,SPANISH_MEXICAN), "es_MX"},
324 {RML(SPANISH,SPANISH_MODERN), "es_ES"},
325 {RML(SPANISH,SPANISH_NICARAGUA), "es_NI"},
326 {RML(SPANISH,SPANISH_PANAMA), "es_PA"},
327 {RML(SPANISH,SPANISH_PARAGUAY), "es_PY"},
328 {RML(SPANISH,SPANISH_PERU), "es_PE"},
329 {RML(SPANISH,SPANISH_PUERTO_RICO), "es_PR"},
330 {RML(SPANISH,SPANISH_URUGUAY), "es_UY"},
331 {RML(SPANISH,SPANISH_VENEZUELA), "es_VE"},
332 {RML(SWAHILI,DEFAULT), "sw_KE"},
333 {RML(SWEDISH,SWEDISH), "sv_SE"},
334 {RML(SWEDISH,SWEDISH_FINLAND), "sv_FI"},
335/*{RML(SYRIAC,DEFAULT), "syr_SY"},*/
336 {RML(TAMIL,DEFAULT), "ta_IN"},
337 {RML(TATAR,DEFAULT), "tt_TA"},
338 {RML(TELUGU,DEFAULT), "te_IN"},
339 {RML(THAI,DEFAULT), "th_TH"},
340 {RML(TURKISH,DEFAULT), "tr_TR"},
341 {RML(UKRAINIAN,DEFAULT), "uk_UA"},
342 {RML(URDU,URDU_PAKISTAN), "ur_PK"},
343 {RML(UZBEK,UZBEK_CYRILLIC), "uz_UZ"},
344 {RML(UZBEK,UZBEK_LATIN), "uz_UZ"},
345 {RML(VIETNAMESE,DEFAULT), "vi_VN"},
346/*{RML(WALON,DEFAULT), "wa_BE"},*/
347/*{RML(WELSH,DEFAULT), "cy_GB"},*/
348};
349static const IDToCode primary_to_code[] = {
350 {LANG_AFRIKAANS, "af"},
351 {LANG_ARABIC, "ar"},
352 {LANG_AZERI, "az"},
353 {LANG_BULGARIAN, "bg"},
354/*{LANG_BRETON, "br"},*/
355 {LANG_BELARUSIAN, "by"},
356 {LANG_CATALAN, "ca"},
357 {LANG_CZECH, "cs"},
358/*{LANG_WELSH, "cy"},*/
359 {LANG_DANISH, "da"},
360 {LANG_GERMAN, "de"},
361 {LANG_GREEK, "el"},
362 {LANG_ENGLISH, "en"},
363/*{LANG_ESPERANTO, "eo"},*/
364 {LANG_SPANISH, "es"},
365 {LANG_ESTONIAN, "et"},
366 {LANG_BASQUE, "eu"},
367 {LANG_FARSI, "fa"},
368 {LANG_FINNISH, "fi"},
369 {LANG_FAEROESE, "fo"},
370 {LANG_FRENCH, "fr"},
371/*{LANG_GAELIC, "ga"},*/
372/*{LANG_GALICIAN, "gl"},*/
373 {LANG_GUJARATI, "gu"},
374 {LANG_HEBREW, "he"},
375 {LANG_HINDI, "hi"},
376 {LANG_SERBIAN, "hr"},
377 {LANG_HUNGARIAN, "hu"},
378 {LANG_ARMENIAN, "hy"},
379 {LANG_INDONESIAN, "id"},
380 {LANG_ITALIAN, "it"},
381 {LANG_JAPANESE, "ja"},
382 {LANG_GEORGIAN, "ka"},
383 {LANG_KAZAK, "kk"},
384 {LANG_KANNADA, "kn"},
385 {LANG_KOREAN, "ko"},
386/*{LANG_KYRGYZ, "ky"},*/
387 {LANG_LITHUANIAN, "lt"},
388 {LANG_LATVIAN, "lv"},
389 {LANG_MACEDONIAN, "mk"},
390/*{LANG_MONGOLIAN, "mn"},*/
391 {LANG_MARATHI, "mr"},
392 {LANG_MALAY, "ms"},
393 {LANG_NORWEGIAN, "nb"},
394 {LANG_DUTCH, "nl"},
395 {LANG_NORWEGIAN, "nn"},
396 {LANG_NORWEGIAN, "no"},/* unofficial? */
397 {LANG_PUNJABI, "pa"},
398 {LANG_POLISH, "pl"},
399 {LANG_PORTUGUESE, "pt"},
400 {LANG_ROMANIAN, "ro"},
401 {LANG_RUSSIAN, "ru"},
402 {LANG_SLOVAK, "sk"},
403 {LANG_SLOVENIAN, "sl"},
404 {LANG_ALBANIAN, "sq"},
405 {LANG_SERBIAN, "sr"},
406 {LANG_SWEDISH, "sv"},
407 {LANG_SWAHILI, "sw"},
408 {LANG_TAMIL, "ta"},
409 {LANG_THAI, "th"},
410 {LANG_TURKISH, "tr"},
411 {LANG_TATAR, "tt"},
412 {LANG_UKRAINIAN, "uk"},
413 {LANG_URDU, "ur"},
414 {LANG_UZBEK, "uz"},
415 {LANG_VIETNAMESE, "vi"},
416/*{LANG_WALON, "wa"},*/
417 {LANG_CHINESE, "zh"},
418};
419static int num_primary_to_code =
420 sizeof(primary_to_code) / sizeof(*primary_to_code);
421static int num_both_to_code =
422 sizeof(both_to_code) / sizeof(*both_to_code);
423
424static const int
425lcid_to_fl(LCID lcid,
426 FL_Locale *rtn) {
427 LANGID langid = LANGIDFROMLCID(lcid);
428 LANGID primary_lang = PRIMARYLANGID(langid);
429 /*LANGID sub_lang = SUBLANGID(langid);*/
430 int i;
431 /* try to find an exact primary/sublanguage combo that we know about */
432 for (i=0; i<num_both_to_code; ++i) {
433 if (both_to_code[i].id == langid) {
434 accumulate_locstring(both_to_code[i].code, rtn);
435 return 1;
436 }
437 }
438 /* fallback to just checking the primary language id */
439 for (i=0; i<num_primary_to_code; ++i) {
440 if (primary_to_code[i].id == primary_lang) {
441 accumulate_locstring(primary_to_code[i].code, rtn);
442 return 1;
443 }
444 }
445 return 0;
446}
447#endif
448
449
450FL_Success
451FL_FindLocale(FL_Locale **locale, FL_Domain domain) {
452 FL_Success success = FL_FAILED;
453 FL_Locale *rtn = (FL_Locale*)malloc(sizeof(FL_Locale));
454 rtn->lang = NULL;
455 rtn->country = NULL;
456 rtn->variant = NULL;
457
458#ifdef WIN32
459 /* win32 >= mswindows95 */
460 {
461 LCID lcid = GetThreadLocale();
462 if (lcid_to_fl(lcid, rtn)) {
463 success = FL_CONFIDENT;
464 }
465 if (success == FL_FAILED) {
466 /* assume US English on mswindows systems unless we know otherwise */
467 if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
468 success = FL_DEFAULT_GUESS;
469 }
470 }
471 }
472#else
473 /* assume unixoid */
474 {
475 /* examples: */
476 /* sv_SE.ISO_8859-1 */
477 /* fr_FR.ISO8859-1 */
478 /* no_NO_NB */
479 /* no_NO_NY */
480 /* no_NO */
481 /* de_DE */
482 /* try the various vars in decreasing order of authority */
483 if (accumulate_env("LC_ALL", rtn) ||
484 accumulate_env("LC_MESSAGES", rtn) ||
485 accumulate_env("LANG", rtn) ||
486 accumulate_env("LANGUAGE", rtn)) {
487 success = FL_CONFIDENT;
488 }
489 if (success == FL_FAILED) {
490 /* assume US English on unixoid systems unless we know otherwise */
491 if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
492 success = FL_DEFAULT_GUESS;
493 }
494 }
495 }
496#endif
497
498 if (success != FL_FAILED) {
499 canonise_fl(rtn);
500 }
501
502 *locale = rtn;
503 return success;
504}
505
506
507void
508FL_FreeLocale(FL_Locale **locale) {
509 if (locale) {
510 FL_Locale *l = *locale;
511 if (l) {
512 if (l->lang) {
513 free((void*)l->lang);
514 }
515 if (l->country) {
516 free((void*)l->country);
517 }
518 if (l->variant) {
519 free((void*)l->variant);
520 }
521 free(l);
522 *locale = NULL;
523 }
524 }
525}
diff --git a/linden/indra/llcommon/llfindlocale.h b/linden/indra/llcommon/llfindlocale.h
new file mode 100644
index 0000000..6cc2dbb
--- /dev/null
+++ b/linden/indra/llcommon/llfindlocale.h
@@ -0,0 +1,65 @@
1/**
2 * @file llfindlocale.h
3 * @brief Detect system language setting
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 *
22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above,
24 * and agree to abide by those obligations.
25 *
26 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
27 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
28 * COMPLETENESS OR PERFORMANCE.
29 * $/LicenseInfo$
30 */
31
32#ifndef __findlocale_h_
33#define __findlocale_h_
34
35typedef const char* FL_Lang;
36typedef const char* FL_Country;
37typedef const char* FL_Variant;
38
39typedef struct {
40 FL_Lang lang;
41 FL_Country country;
42 FL_Variant variant;
43} FL_Locale;
44
45typedef enum {
46 /* for some reason we failed to even guess: this should never happen */
47 FL_FAILED = 0,
48 /* couldn't query locale -- returning a guess (almost always English) */
49 FL_DEFAULT_GUESS = 1,
50 /* the returned locale type was found by successfully asking the system */
51 FL_CONFIDENT = 2
52} FL_Success;
53
54typedef enum {
55 FL_MESSAGES = 0
56} FL_Domain;
57
58/* This allocates/fills in a FL_Locale structure with pointers to
59 strings (which should be treated as static), or NULL for inappropriate /
60 undetected fields. */
61FL_Success FL_FindLocale(FL_Locale **locale, FL_Domain domain);
62/* This should be used to free the struct written by FL_FindLocale */
63void FL_FreeLocale(FL_Locale **locale);
64
65#endif /*__findlocale_h_*/
diff --git a/linden/indra/llcommon/llheartbeat.cpp b/linden/indra/llcommon/llheartbeat.cpp
new file mode 100644
index 0000000..13bcd46
--- /dev/null
+++ b/linden/indra/llcommon/llheartbeat.cpp
@@ -0,0 +1,165 @@
1/**
2 * @file llheartbeat.cpp
3 * @brief Class encapsulating logic for telling a watchdog that we live.
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 *
22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above,
24 * and agree to abide by those obligations.
25 *
26 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
27 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
28 * COMPLETENESS OR PERFORMANCE.
29 * $/LicenseInfo$
30 */
31
32#include <errno.h>
33#include <signal.h>
34
35#include "linden_common.h"
36#include "llapp.h"
37
38#include "llheartbeat.h"
39
40LLHeartbeat::LLHeartbeat(F32 secs_between_heartbeat,
41 F32 aggressive_heartbeat_panic_secs,
42 F32 aggressive_heartbeat_max_blocking_secs)
43 : mSecsBetweenHeartbeat(secs_between_heartbeat),
44 mAggressiveHeartbeatPanicSecs(aggressive_heartbeat_panic_secs),
45 mAggressiveHeartbeatMaxBlockingSecs(aggressive_heartbeat_max_blocking_secs),
46 mSuppressed(false)
47{
48 mBeatTimer.reset();
49 mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat);
50 mPanicTimer.reset();
51 mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs);
52}
53
54LLHeartbeat::~LLHeartbeat()
55{
56 // do nothing.
57}
58
59void
60LLHeartbeat::setSuppressed(bool is_suppressed)
61{
62 mSuppressed = is_suppressed;
63}
64
65// returns 0 on success, -1 on permanent failure, 1 on temporary failure
66int
67LLHeartbeat::rawSend()
68{
69#if LL_WINDOWS
70 return 0; // Pretend we succeeded.
71#else
72 if (mSuppressed)
73 return 0; // Pretend we succeeded.
74
75 union sigval dummy;
76 int result = sigqueue(getppid(), LL_HEARTBEAT_SIGNAL, dummy);
77 if (result == 0)
78 return 0; // success
79
80 int err = errno;
81 if (err == EAGAIN)
82 return 1; // failed to queue, try again
83
84 return -1; // other failure.
85#endif
86}
87
88int
89LLHeartbeat::rawSendWithTimeout(F32 timeout_sec)
90{
91 int result = 0;
92
93 // Spin tightly until our heartbeat is digested by the watchdog
94 // or we time-out. We don't really want to sleep because our
95 // wake-up time might be undesirably synchronised to a hidden
96 // clock by the system's scheduler.
97 mTimeoutTimer.reset();
98 mTimeoutTimer.setTimerExpirySec(timeout_sec);
99 do {
100 result = rawSend();
101 //llinfos << " HEARTSENDc=" << result << llendl;
102 } while (result==1 && !mTimeoutTimer.hasExpired());
103
104 return result;
105}
106
107bool
108LLHeartbeat::send(F32 timeout_sec)
109{
110 bool total_success = false;
111 int result = 1;
112
113 if (timeout_sec > 0.f) {
114 // force a spin until success or timeout
115 result = rawSendWithTimeout(timeout_sec);
116 } else {
117 if (mBeatTimer.hasExpired()) {
118 // zero-timeout; we don't care too much whether our
119 // heartbeat was digested.
120 result = rawSend();
121 //llinfos << " HEARTSENDb=" << result << llendl;
122 }
123 }
124
125 if (result == -1) {
126 // big failure.
127 } else if (result == 0) {
128 total_success = true;
129 } else {
130 // need to retry at some point
131 }
132
133 if (total_success) {
134 mBeatTimer.reset();
135 mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat);
136 // reset the time until we start panicking about lost
137 // heartbeats again.
138 mPanicTimer.reset();
139 mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs);
140 } else {
141 // leave mBeatTimer as expired so we'll lazily poke the
142 // watchdog again next time through.
143 }
144
145 if (mPanicTimer.hasExpired()) {
146 // It's been ages since we successfully had a heartbeat
147 // digested by the watchdog. Sit here and spin a while
148 // in the hope that we can force it through.
149 llwarns << "Unable to deliver heartbeat to launcher for " << mPanicTimer.getElapsedTimeF32() << " seconds. Going to try very hard for up to " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << llendl;
150 result = rawSendWithTimeout(mAggressiveHeartbeatMaxBlockingSecs);
151 if (result == 0) {
152 total_success = true;
153 } else {
154 // we couldn't even force it through. That's bad,
155 // but we'll try again in a while.
156 llwarns << "Could not deliver heartbeat to launcher even after trying very hard for " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << llendl;
157 }
158
159 // in any case, reset the panic timer.
160 mPanicTimer.reset();
161 mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs);
162 }
163
164 return total_success;
165}
diff --git a/linden/indra/llcommon/llheartbeat.h b/linden/indra/llcommon/llheartbeat.h
new file mode 100644
index 0000000..8a2fa0a
--- /dev/null
+++ b/linden/indra/llcommon/llheartbeat.h
@@ -0,0 +1,73 @@
1/**
2 * @file llheartbeat.h
3 * @brief Class encapsulating logic for telling a watchdog that we live.
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 *
22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above,
24 * and agree to abide by those obligations.
25 *
26 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
27 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
28 * COMPLETENESS OR PERFORMANCE.
29 * $/LicenseInfo$
30 */
31
32#ifndef LL_LLHEARTBEAT_H
33#define LL_LLHEARTBEAT_H
34
35#include "linden_common.h"
36
37#include "lltimer.h"
38
39// Note: Win32 does not support the heartbeat/smackdown system;
40// heartbeat-delivery turns into a no-op there.
41
42class LLHeartbeat
43{
44public:
45 // secs_between_heartbeat: after a heartbeat is successfully delivered,
46 // we suppress sending more for this length of time.
47 // aggressive_heartbeat_panic_secs: if we've been failing to
48 // successfully deliver heartbeats for this length of time then
49 // we block for a while until we're really sure we got one delivered.
50 // aggressive_heartbeat_max_blocking_secs: this is the length of
51 // time we block for when we're aggressively ensuring that a 'panic'
52 // heartbeat was delivered.
53 LLHeartbeat(F32 secs_between_heartbeat = 5.0f,
54 F32 aggressive_heartbeat_panic_secs = 10.0f,
55 F32 aggressive_heartbeat_max_blocking_secs = 4.0f);
56 ~LLHeartbeat();
57
58 bool send(F32 timeout_sec = 0.0f);
59 void setSuppressed(bool is_suppressed);
60
61private:
62 int rawSend();
63 int rawSendWithTimeout(F32 timeout_sec);
64 F32 mSecsBetweenHeartbeat;
65 F32 mAggressiveHeartbeatPanicSecs;
66 F32 mAggressiveHeartbeatMaxBlockingSecs;
67 bool mSuppressed;
68 LLTimer mBeatTimer;
69 LLTimer mPanicTimer;
70 LLTimer mTimeoutTimer;
71};
72
73#endif // LL_HEARTBEAT_H
diff --git a/linden/indra/llcommon/llindraconfigfile.cpp b/linden/indra/llcommon/llindraconfigfile.cpp
new file mode 100644
index 0000000..7ef1a9b
--- /dev/null
+++ b/linden/indra/llcommon/llindraconfigfile.cpp
@@ -0,0 +1,107 @@
1/**
2 * @file llindraconfigfile.cpp
3 *
4 *
5 * This class is an LLLiveFile that has config info for indra
6 * Currently only whether it's blacklisted
7 *
8 * $LicenseInfo:firstyear=2007&license=internal$
9 *
10 * Copyright (c) 2007-2008, Linden Research, Inc.
11 *
12 * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of
13 * this source code is governed by the Linden Lab Source Code Disclosure
14 * Agreement ("Agreement") previously entered between you and Linden
15 * Lab. By accessing, using, copying, modifying or distributing this
16 * software, you acknowledge that you have been informed of your
17 * obligations under the Agreement and agree to abide by those obligations.
18 *
19 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
20 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
21 * COMPLETENESS OR PERFORMANCE.
22 * $/LicenseInfo$
23 */
24
25#include "llindraconfigfile.h"
26
27#include "llfile.h"
28#include "llsd.h"
29#include "llsdserialize.h"
30#include "llframetimer.h"
31
32static std::string sConfigDir = "";
33static const char indraConfigFileName[] = "indra.xml";
34
35
36LLIndraConfigFile::LLIndraConfigFile()
37 : LLLiveFile(filename(), configFileRefreshRate),
38 mConfig(LLSD())
39{
40}
41
42//static
43void LLIndraConfigFile::initClass(const std::string& config_dir)
44{
45 sConfigDir = config_dir;
46 llinfos << "LLIndraConfigFile::initClass config dir "
47 << config_dir << "/" << indraConfigFileName << llendl;
48}
49
50LLSD LLIndraConfigFile::getConfig(const std::string& config_name)
51{
52 if (sConfigDir.empty())
53 {
54 llerrs << "LLIndraConfigFile::initClass() not called" << llendl;
55 }
56
57 LLFrameTimer::updateFrameTime();
58
59 static LLIndraConfigFile the_file;
60 the_file.checkAndReload();
61
62 return the_file.mConfig[config_name];
63}
64
65std::string LLIndraConfigFile::filename()
66{
67 std::ostringstream ostr;
68
69 ostr << sConfigDir
70 << "/" << indraConfigFileName;
71
72 return ostr.str();
73}
74
75/* virtual */
76void LLIndraConfigFile::loadFile()
77{
78 llinfos << "LLIndraConfigFile::loadFile: reading from "
79 << filename() << llendl;
80
81 LLSD config;
82
83 {
84 llifstream file(filename().c_str());
85 if (file.is_open())
86 {
87 LLSDSerialize::fromXML(config, file);
88 }
89
90 if (config.isUndefined())
91 {
92 llinfos << "LLIndraConfigFile::loadFile: file missing, ill-formed,"
93 " or simply undefined; not changing the blacklist" << llendl;
94 return;
95 }
96 }
97
98 if (config.isMap())
99 {
100 mConfig = config;
101 }
102 else
103 {
104 llwarns << "LLIndraConfigFile: " << indraConfigFileName << " expects a map; wrong format" << llendl;
105 return;
106 }
107}
diff --git a/linden/indra/llcommon/llindraconfigfile.h b/linden/indra/llcommon/llindraconfigfile.h
new file mode 100644
index 0000000..271a848
--- /dev/null
+++ b/linden/indra/llcommon/llindraconfigfile.h
@@ -0,0 +1,50 @@
1/**
2 * @file llindraconfigfile.h
3 * @brief manages configuration file for indra.xml
4 *
5 * $LicenseInfo:firstyear=2007&license=internal$
6 *
7 * Copyright (c) 2007-2008, Linden Research, Inc.
8 *
9 * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of
10 * this source code is governed by the Linden Lab Source Code Disclosure
11 * Agreement ("Agreement") previously entered between you and Linden
12 * Lab. By accessing, using, copying, modifying or distributing this
13 * software, you acknowledge that you have been informed of your
14 * obligations under the Agreement and agree to abide by those obligations.
15 *
16 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
17 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
18 * COMPLETENESS OR PERFORMANCE.
19 * $/LicenseInfo$
20 */
21
22#ifndef LL_LLINDRACONFIGFILE_H
23#define LL_LLINDRACONFIGFILE_H
24
25#include <string>
26#include "linden_common.h"
27
28#include "lllivefile.h"
29#include "llsd.h"
30
31
32// To use, call LLIndraConfigFile::initClass(config_dir);
33// Then whenever getConfig is called, it will check and reload automatically
34
35class LLIndraConfigFile : public LLLiveFile
36{
37public:
38 LLIndraConfigFile();
39 static void initClass(const std::string& config_dir);
40 static LLSD getConfig(const std::string& config_name);
41
42private:
43 static std::string filename();
44
45protected:
46 /* virtual */ void loadFile();
47 LLSD mConfig;
48};
49
50#endif //LL_LLINDRACONFIGFILE_H
diff --git a/linden/indra/llcommon/llkeyusetracker.h b/linden/indra/llcommon/llkeyusetracker.h
new file mode 100644
index 0000000..c37ba24
--- /dev/null
+++ b/linden/indra/llcommon/llkeyusetracker.h
@@ -0,0 +1,220 @@
1/**
2 * @file llkeyusetracker.h
3 * @brief Declaration of the LLKeyUseTracker class.
4 *
5 * $LicenseInfo:firstyear=2003&license=viewergpl$
6 *
7 * Copyright (c) 2003-2008, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 *
22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above,
24 * and agree to abide by those obligations.
25 *
26 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
27 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
28 * COMPLETENESS OR PERFORMANCE.
29 * $/LicenseInfo$
30 */
31
32#ifndef LL_KEYUSETRACKER_H
33#define LL_KEYUSETRACKER_H
34
35// This is a generic cache for an arbitrary data type indexed against an
36// arbitrary key type. The cache length is determined by expiration time
37// tince against last use and set size. The age of elements and the size
38// of the cache are queryable.
39//
40// This is implemented as a list, which makes search O(n). If you reuse this
41// for something with a large dataset, consider reimplementing with a Boost
42// multimap based on both a map(key) and priority queue(last_use).
43
44template <class TKey, class TData>
45class KeyUseTrackerNodeImpl
46{
47public:
48 U64 mLastUse;
49 U32 mUseCount;
50 TKey mKey;
51 TData mData;
52
53 KeyUseTrackerNodeImpl( TKey k, TData d ) :
54 mLastUse(0),
55 mUseCount(0),
56 mKey( k ),
57 mData( d )
58 {
59 }
60};
61
62
63template <class TKey, class TData>
64class LLKeyUseTracker
65{
66 typedef KeyUseTrackerNodeImpl<TKey,TData> TKeyUseTrackerNode;
67 typedef std::list<TKeyUseTrackerNode *> TKeyList;
68 TKeyList mKeyList;
69 U64 mMemUsecs;
70 U64 mLastExpire;
71 U32 mMaxCount;
72 U32 mCount;
73
74 static U64 getTime()
75 {
76 // This function operates on a frame basis, not instantaneous.
77 // We can rely on its output for determining first use in a
78 // frame.
79 return LLFrameTimer::getTotalTime();
80 }
81
82 void ageKeys()
83 {
84 U64 now = getTime();
85 if( now == mLastExpire )
86 {
87 return;
88 }
89 mLastExpire = now;
90
91 while( !mKeyList.empty() && (now - mKeyList.front()->mLastUse > mMemUsecs ) )
92 {
93 delete mKeyList.front();
94 mKeyList.pop_front();
95 mCount--;
96 }
97 }
98
99 TKeyUseTrackerNode *findNode( TKey key )
100 {
101 ageKeys();
102
103 typename TKeyList::iterator i;
104 for( i = mKeyList.begin(); i != mKeyList.end(); i++ )
105 {
106 if( (*i)->mKey == key )
107 return *i;
108 }
109
110 return NULL;
111 }
112
113 TKeyUseTrackerNode *removeNode( TKey key )
114 {
115 TKeyUseTrackerNode *i;
116 i = findNode( key );
117 if( i )
118 {
119 mKeyList.remove( i );
120 mCount--;
121 return i;
122 }
123
124 return NULL;
125 }
126
127public:
128 LLKeyUseTracker( U32 memory_seconds, U32 max_count ) :
129 mLastExpire(0),
130 mMaxCount( max_count ),
131 mCount(0)
132 {
133 mMemUsecs = ((U64)memory_seconds) * 1000000;
134 }
135
136 ~LLKeyUseTracker()
137 {
138 // Flush list
139 while( !mKeyList.empty() )
140 {
141 delete mKeyList.front();
142 mKeyList.pop_front();
143 mCount--;
144 }
145 }
146
147 void markUse( TKey key, TData data )
148 {
149 TKeyUseTrackerNode *node = removeNode( key );
150 if( !node )
151 {
152 node = new TKeyUseTrackerNode(key, data);
153 }
154 else
155 {
156 // Update data
157 node->mData = data;
158 }
159 node->mLastUse = getTime();
160 node->mUseCount++;
161 mKeyList.push_back( node );
162 mCount++;
163
164 // Too many items? Drop head
165 if( mCount > mMaxCount )
166 {
167 delete mKeyList.front();
168 mKeyList.pop_front();
169 mCount--;
170 }
171 }
172
173 void forgetKey( TKey key )
174 {
175 TKeyUseTrackerNode *node = removeNode( key );
176 if( node )
177 {
178 delete node;
179 }
180 }
181
182 U32 getUseCount( TKey key )
183 {
184 TKeyUseTrackerNode *node = findNode( key );
185 if( node )
186 {
187 return node->mUseCount;
188 }
189 return 0;
190 }
191
192 U64 getTimeSinceUse( TKey key )
193 {
194 TKeyUseTrackerNode *node = findNode( key );
195 if( node )
196 {
197 U64 now = getTime();
198 U64 delta = now - node->mLastUse;
199 return (U32)( delta / 1000000 );
200 }
201 return 0;
202 }
203
204 TData *getLastUseData( TKey key )
205 {
206 TKeyUseTrackerNode *node = findNode( key );
207 if( node )
208 {
209 return &node->mData;
210 }
211 return NULL;
212 }
213
214 U32 getKeyCount()
215 {
216 return mCount;
217 }
218};
219
220#endif
diff --git a/linden/indra/llcommon/lllivefile.h b/linden/indra/llcommon/lllivefile.h
index 1d55f7b..0a18fe0 100644
--- a/linden/indra/llcommon/lllivefile.h
+++ b/linden/indra/llcommon/lllivefile.h
@@ -32,6 +32,8 @@
32#ifndef LL_LLLIVEFILE_H 32#ifndef LL_LLLIVEFILE_H
33#define LL_LLLIVEFILE_H 33#define LL_LLLIVEFILE_H
34 34
35const F32 configFileRefreshRate = 5.0; // seconds
36
35 37
36class LLLiveFile 38class LLLiveFile
37{ 39{
diff --git a/linden/indra/llcommon/llmemory.cpp b/linden/indra/llcommon/llmemory.cpp
index 0f08877..5edeb4b 100644
--- a/linden/indra/llcommon/llmemory.cpp
+++ b/linden/indra/llcommon/llmemory.cpp
@@ -387,7 +387,7 @@ U64 getCurrentRSS()
387U64 getCurrentRSS() 387U64 getCurrentRSS()
388{ 388{
389 static const char statPath[] = "/proc/self/stat"; 389 static const char statPath[] = "/proc/self/stat";
390 FILE *fp = fopen(statPath, "r"); 390 LLFILE *fp = LLFile::fopen(statPath, "r");
391 U64 rss = 0; 391 U64 rss = 0;
392 392
393 if (fp == NULL) 393 if (fp == NULL)
diff --git a/linden/indra/llcommon/llprocessor.cpp b/linden/indra/llcommon/llprocessor.cpp
index d67a9c4..1c0f7e0 100644
--- a/linden/indra/llcommon/llprocessor.cpp
+++ b/linden/indra/llcommon/llprocessor.cpp
@@ -2230,7 +2230,7 @@ bool CProcessor::WriteInfoTextFile(const char *strFilename)
2230 return false; 2230 return false;
2231 2231
2232 // Then we create a new file (CREATE_ALWAYS) 2232 // Then we create a new file (CREATE_ALWAYS)
2233 FILE *file = LLFile::fopen(strFilename, "w"); /* Flawfinder: ignore */ 2233 LLFILE *file = LLFile::fopen(strFilename, "w"); /* Flawfinder: ignore */
2234 if (!file) 2234 if (!file)
2235 return false; 2235 return false;
2236 2236
diff --git a/linden/indra/llcommon/llptrskipmap.h b/linden/indra/llcommon/llptrskipmap.h
index b369d77..8592197 100644
--- a/linden/indra/llcommon/llptrskipmap.h
+++ b/linden/indra/llcommon/llptrskipmap.h
@@ -238,7 +238,8 @@ private:
238template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> 238template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH>
239inline LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::LLPtrSkipMap() 239inline LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::LLPtrSkipMap()
240 : mInsertFirst(NULL), 240 : mInsertFirst(NULL),
241 mEquals(defaultEquals) 241 mEquals(defaultEquals),
242 mNumberOfSteps(0)
242{ 243{
243 if (BINARY_DEPTH < 2) 244 if (BINARY_DEPTH < 2)
244 { 245 {
@@ -259,7 +260,8 @@ template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH>
259inline LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::LLPtrSkipMap(insert_func insert_first, 260inline LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::LLPtrSkipMap(insert_func insert_first,
260 equals_func equals) 261 equals_func equals)
261: mInsertFirst(insert_first), 262: mInsertFirst(insert_first),
262 mEquals(equals) 263 mEquals(equals),
264 mNumberOfSteps(0)
263{ 265{
264 if (BINARY_DEPTH < 2) 266 if (BINARY_DEPTH < 2)
265 { 267 {
diff --git a/linden/indra/llcommon/llsdserialize.h b/linden/indra/llcommon/llsdserialize.h
index 41e0aa5..f5282b4 100644
--- a/linden/indra/llcommon/llsdserialize.h
+++ b/linden/indra/llcommon/llsdserialize.h
@@ -390,7 +390,7 @@ public:
390 /** 390 /**
391 * Options for output 391 * Options for output
392 */ 392 */
393 enum e_formatter_options_type 393 typedef enum e_formatter_options_type
394 { 394 {
395 OPTIONS_NONE = 0, 395 OPTIONS_NONE = 0,
396 OPTIONS_PRETTY = 1 396 OPTIONS_PRETTY = 1
diff --git a/linden/indra/llcommon/llsdutil.h b/linden/indra/llcommon/llsdutil.h
index c058185..ae6d694 100644
--- a/linden/indra/llcommon/llsdutil.h
+++ b/linden/indra/llcommon/llsdutil.h
@@ -101,4 +101,16 @@ BOOL compare_llsd_with_template(
101 const LLSD& template_llsd, 101 const LLSD& template_llsd,
102 LLSD& resultant_llsd); 102 LLSD& resultant_llsd);
103 103
104// Simple function to copy data out of input & output iterators if
105// there is no need for casting.
106template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
107{
108 LLSD dest;
109 for (; iter != end; ++iter)
110 {
111 dest.append(*iter);
112 }
113 return dest;
114}
115
104#endif // LL_LLSDUTIL_H 116#endif // LL_LLSDUTIL_H
diff --git a/linden/indra/llcommon/llsys.cpp b/linden/indra/llcommon/llsys.cpp
index ccdcd00..1285851 100644
--- a/linden/indra/llcommon/llsys.cpp
+++ b/linden/indra/llcommon/llsys.cpp
@@ -293,7 +293,7 @@ U32 LLOSInfo::getProcessVirtualSizeKB()
293#if LL_WINDOWS 293#if LL_WINDOWS
294#endif 294#endif
295#if LL_LINUX 295#if LL_LINUX
296 FILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); 296 LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb");
297 S32 numRead = 0; 297 S32 numRead = 0;
298 char buff[STATUS_SIZE]; /* Flawfinder: ignore */ 298 char buff[STATUS_SIZE]; /* Flawfinder: ignore */
299 299
@@ -336,7 +336,7 @@ U32 LLOSInfo::getProcessResidentSizeKB()
336#if LL_WINDOWS 336#if LL_WINDOWS
337#endif 337#endif
338#if LL_LINUX 338#if LL_LINUX
339 FILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); 339 LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb");
340 if (status_filep != NULL) 340 if (status_filep != NULL)
341 { 341 {
342 S32 numRead = 0; 342 S32 numRead = 0;
@@ -398,7 +398,7 @@ LLCPUInfo::LLCPUInfo()
398 398
399#elif LL_LINUX 399#elif LL_LINUX
400 std::map< LLString, LLString > cpuinfo; 400 std::map< LLString, LLString > cpuinfo;
401 FILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb"); 401 LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb");
402 if(cpuinfo_fp) 402 if(cpuinfo_fp)
403 { 403 {
404 char line[MAX_STRING]; 404 char line[MAX_STRING];
@@ -486,7 +486,7 @@ void LLCPUInfo::stream(std::ostream& s) const
486 } 486 }
487#else 487#else
488 // *NOTE: This works on linux. What will it do on other systems? 488 // *NOTE: This works on linux. What will it do on other systems?
489 FILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb"); 489 LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb");
490 if(cpuinfo) 490 if(cpuinfo)
491 { 491 {
492 char line[MAX_STRING]; 492 char line[MAX_STRING];
@@ -621,7 +621,7 @@ void LLMemoryInfo::stream(std::ostream& s) const
621 s << "Total Physical KB: " << phys << std::endl; 621 s << "Total Physical KB: " << phys << std::endl;
622#else 622#else
623 // *NOTE: This works on linux. What will it do on other systems? 623 // *NOTE: This works on linux. What will it do on other systems?
624 FILE* meminfo = LLFile::fopen(MEMINFO_FILE,"rb"); 624 LLFILE* meminfo = LLFile::fopen(MEMINFO_FILE,"rb");
625 if(meminfo) 625 if(meminfo)
626 { 626 {
627 char line[MAX_STRING]; /* Flawfinder: ignore */ 627 char line[MAX_STRING]; /* Flawfinder: ignore */
@@ -665,7 +665,7 @@ BOOL gunzip_file(const char *srcfile, const char *dstfile)
665 BOOL retval = FALSE; 665 BOOL retval = FALSE;
666 gzFile src = NULL; 666 gzFile src = NULL;
667 U8 buffer[UNCOMPRESS_BUFFER_SIZE]; 667 U8 buffer[UNCOMPRESS_BUFFER_SIZE];
668 FILE *dst = NULL; 668 LLFILE *dst = NULL;
669 S32 bytes = 0; 669 S32 bytes = 0;
670 (void *) strcpy(tmpfile, dstfile); /* Flawfinder: ignore */ 670 (void *) strcpy(tmpfile, dstfile); /* Flawfinder: ignore */
671 (void *) strncat(tmpfile, ".t", sizeof(tmpfile) - strlen(tmpfile) -1); /* Flawfinder: ignore */ 671 (void *) strncat(tmpfile, ".t", sizeof(tmpfile) - strlen(tmpfile) -1); /* Flawfinder: ignore */
@@ -700,7 +700,7 @@ BOOL gzip_file(const char *srcfile, const char *dstfile)
700 BOOL retval = FALSE; 700 BOOL retval = FALSE;
701 U8 buffer[COMPRESS_BUFFER_SIZE]; 701 U8 buffer[COMPRESS_BUFFER_SIZE];
702 gzFile dst = NULL; 702 gzFile dst = NULL;
703 FILE *src = NULL; 703 LLFILE *src = NULL;
704 S32 bytes = 0; 704 S32 bytes = 0;
705 (void *) strcpy(tmpfile, dstfile); /* Flawfinder: ignore */ 705 (void *) strcpy(tmpfile, dstfile); /* Flawfinder: ignore */
706 (void *) strncat(tmpfile, ".t", sizeof(tmpfile) - strlen(tmpfile) -1); /* Flawfinder: ignore */ 706 (void *) strncat(tmpfile, ".t", sizeof(tmpfile) - strlen(tmpfile) -1); /* Flawfinder: ignore */
diff --git a/linden/indra/llcommon/lltimer.cpp b/linden/indra/llcommon/lltimer.cpp
index a421dce..25d9897 100644
--- a/linden/indra/llcommon/lltimer.cpp
+++ b/linden/indra/llcommon/lltimer.cpp
@@ -39,10 +39,8 @@
39# define WIN32_LEAN_AND_MEAN 39# define WIN32_LEAN_AND_MEAN
40# include <winsock2.h> 40# include <winsock2.h>
41# include <windows.h> 41# include <windows.h>
42#elif LL_LINUX || LL_SOLARIS 42#elif LL_LINUX || LL_SOLARIS || LL_DARWIN
43# include <sys/time.h> 43# include <errno.h>
44# include <sched.h>
45#elif LL_DARWIN
46# include <sys/time.h> 44# include <sys/time.h>
47#else 45#else
48# error "architecture not supported" 46# error "architecture not supported"
@@ -81,42 +79,55 @@ U64 gLastTotalTimeClockCount = 0;
81//--------------------------------------------------------------------------- 79//---------------------------------------------------------------------------
82 80
83#if LL_WINDOWS 81#if LL_WINDOWS
84void ms_sleep(long ms) 82void ms_sleep(U32 ms)
85{ 83{
86 Sleep((U32)ms); 84 Sleep(ms);
87} 85}
88 86#elif LL_LINUX || LL_SOLARIS || LL_DARWIN
89void llyield() 87void ms_sleep(U32 ms)
90{ 88{
91 SleepEx(0, TRUE); // Relinquishes time slice to any thread of equal priority, can be woken up by extended IO functions 89 long mslong = ms; // tv_nsec is a long
92} 90 struct timespec thiswait, nextwait;
93#elif LL_LINUX || LL_SOLARIS 91 bool sleep_more = false;
94void ms_sleep(long ms)
95{
96 struct timespec t;
97 t.tv_sec = ms / 1000;
98 t.tv_nsec = (ms % 1000) * 1000000l;
99 nanosleep(&t, NULL);
100}
101 92
102void llyield() 93 thiswait.tv_sec = ms / 1000;
103{ 94 thiswait.tv_nsec = (mslong % 1000) * 1000000l;
104 sched_yield(); 95 do {
105} 96 int result = nanosleep(&thiswait, &nextwait);
106#elif LL_DARWIN
107void ms_sleep(long ms)
108{
109 struct timespec t;
110 t.tv_sec = ms / 1000;
111 t.tv_nsec = (ms % 1000) * 1000000l;
112 nanosleep(&t, NULL);
113}
114 97
115void llyield() 98 // check if sleep was interrupted by a signal; unslept
116{ 99 // remainder was written back into 't' and we just nanosleep
117// sched_yield(); 100 // again.
101 sleep_more = (result == -1 && EINTR == errno);
102
103 if (sleep_more)
104 {
105 if ( nextwait.tv_sec > thiswait.tv_sec ||
106 (nextwait.tv_sec == thiswait.tv_sec &&
107 nextwait.tv_nsec >= thiswait.tv_nsec) )
108 {
109 // if the remaining time isn't actually going
110 // down then we're being shafted by low clock
111 // resolution - manually massage the sleep time
112 // downward.
113 if (nextwait.tv_nsec > 1000000) {
114 // lose 1ms
115 nextwait.tv_nsec -= 1000000;
116 } else {
117 if (nextwait.tv_sec == 0) {
118 // already so close to finished
119 sleep_more = false;
120 } else {
121 // lose up to 1ms
122 nextwait.tv_nsec = 0;
123 }
124 }
125 }
126 thiswait = nextwait;
127 }
128 } while (sleep_more);
118} 129}
119#else 130#else
120# error "architecture not supported" 131# error "architecture not supported"
121#endif 132#endif
122 133
@@ -323,7 +334,7 @@ void LLTimer::setTimerExpirySec(F32 expiration)
323 + (U64)((F32)(expiration * gClockFrequency)); 334 + (U64)((F32)(expiration * gClockFrequency));
324} 335}
325 336
326F32 LLTimer::getRemainingTimeF32() 337F32 LLTimer::getRemainingTimeF32() const
327{ 338{
328 U64 cur_ticks = get_clock_count(); 339 U64 cur_ticks = get_clock_count();
329 if (cur_ticks > mExpirationTicks) 340 if (cur_ticks > mExpirationTicks)
@@ -348,7 +359,7 @@ BOOL LLTimer::checkExpirationAndReset(F32 expiration)
348} 359}
349 360
350 361
351BOOL LLTimer::hasExpired() 362BOOL LLTimer::hasExpired() const
352{ 363{
353 return (get_clock_count() >= mExpirationTicks) 364 return (get_clock_count() >= mExpirationTicks)
354 ? TRUE : FALSE; 365 ? TRUE : FALSE;
@@ -550,3 +561,4 @@ void LLEventTimer::updateClass()
550 } 561 }
551} 562}
552 563
564
diff --git a/linden/indra/llcommon/lltimer.h b/linden/indra/llcommon/lltimer.h
index 8a4bc76..91b93d6 100644
--- a/linden/indra/llcommon/lltimer.h
+++ b/linden/indra/llcommon/lltimer.h
@@ -87,11 +87,11 @@ public:
87 void setLastClockCount(U64 current_count); // Sets the timer so that the next elapsed call will be relative to this time 87 void setLastClockCount(U64 current_count); // Sets the timer so that the next elapsed call will be relative to this time
88 void setTimerExpirySec(F32 expiration); 88 void setTimerExpirySec(F32 expiration);
89 BOOL checkExpirationAndReset(F32 expiration); 89 BOOL checkExpirationAndReset(F32 expiration);
90 BOOL hasExpired(); 90 BOOL hasExpired() const;
91 F32 getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset 91 F32 getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset
92 F64 getElapsedTimeAndResetF64(); 92 F64 getElapsedTimeAndResetF64();
93 93
94 F32 getRemainingTimeF32(); 94 F32 getRemainingTimeF32() const;
95 95
96 static BOOL knownBadTimer(); 96 static BOOL knownBadTimer();
97 97
@@ -112,12 +112,8 @@ U64 get_clock_count();
112F64 calc_clock_frequency(U32 msecs); 112F64 calc_clock_frequency(U32 msecs);
113void update_clock_frequencies(); 113void update_clock_frequencies();
114 114
115
116// Sleep for milliseconds 115// Sleep for milliseconds
117void ms_sleep(long ms); 116void ms_sleep(U32 ms);
118
119// Yield
120//void llyield(); // Yield your timeslice - not implemented yet for Mac, so commented out.
121 117
122// Returns the correct UTC time in seconds, like time(NULL). 118// Returns the correct UTC time in seconds, like time(NULL).
123// Useful on the viewer, which may have its local clock set wrong. 119// Useful on the viewer, which may have its local clock set wrong.
diff --git a/linden/indra/llcommon/llversionserver.h b/linden/indra/llcommon/llversionserver.h
index e865b6a..e3ceadf 100644
--- a/linden/indra/llcommon/llversionserver.h
+++ b/linden/indra/llcommon/llversionserver.h
@@ -33,9 +33,9 @@
33#define LL_LLVERSIONSERVER_H 33#define LL_LLVERSIONSERVER_H
34 34
35const S32 LL_VERSION_MAJOR = 1; 35const S32 LL_VERSION_MAJOR = 1;
36const S32 LL_VERSION_MINOR = 20; 36const S32 LL_VERSION_MINOR = 21;
37const S32 LL_VERSION_PATCH = 0; 37const S32 LL_VERSION_PATCH = 1;
38const S32 LL_VERSION_BUILD = 83892; 38const S32 LL_VERSION_BUILD = 86526;
39 39
40const char * const LL_CHANNEL = "Second Life Server"; 40const char * const LL_CHANNEL = "Second Life Server";
41 41
diff --git a/linden/indra/llcommon/llversionviewer.h b/linden/indra/llcommon/llversionviewer.h
index 71bb12e..db3d42d 100644
--- a/linden/indra/llcommon/llversionviewer.h
+++ b/linden/indra/llcommon/llversionviewer.h
@@ -34,7 +34,7 @@
34 34
35const S32 LL_VERSION_MAJOR = 1; 35const S32 LL_VERSION_MAJOR = 1;
36const S32 LL_VERSION_MINOR = 20; 36const S32 LL_VERSION_MINOR = 20;
37const S32 LL_VERSION_PATCH = 5; 37const S32 LL_VERSION_PATCH = 7;
38const S32 LL_VERSION_BUILD = 0; 38const S32 LL_VERSION_BUILD = 0;
39 39
40const char * const LL_CHANNEL = "Second Life Release"; 40const char * const LL_CHANNEL = "Second Life Release";