aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/llcommon/files.lst6
-rw-r--r--linden/indra/llcommon/imageids.h2
-rw-r--r--linden/indra/llcommon/indra_constants.h12
-rw-r--r--linden/indra/llcommon/linden_common.h1
-rw-r--r--linden/indra/llcommon/llapp.cpp8
-rw-r--r--linden/indra/llcommon/llapr.cpp174
-rw-r--r--linden/indra/llcommon/llapr.h18
-rw-r--r--linden/indra/llcommon/llassettype.cpp14
-rw-r--r--linden/indra/llcommon/llassettype.h1
-rw-r--r--linden/indra/llcommon/llavatarconstants.h12
-rw-r--r--linden/indra/llcommon/llbase32.cpp214
-rw-r--r--linden/indra/llcommon/llbase32.h38
-rw-r--r--linden/indra/llcommon/llbase64.cpp62
-rw-r--r--linden/indra/llcommon/llbase64.h38
-rw-r--r--linden/indra/llcommon/llcommon.cpp1
-rw-r--r--linden/indra/llcommon/llcommon.h1
-rw-r--r--linden/indra/llcommon/llcommon.vcproj38
-rw-r--r--linden/indra/llcommon/llcommon_vc8.vcproj759
-rw-r--r--linden/indra/llcommon/llerror.cpp1043
-rw-r--r--linden/indra/llcommon/llerror.h404
-rw-r--r--linden/indra/llcommon/llerrorbuffer.cpp279
-rw-r--r--linden/indra/llcommon/llerrorbuffer.h117
-rw-r--r--linden/indra/llcommon/llerrorcontrol.h142
-rw-r--r--linden/indra/llcommon/llerrorlegacy.h117
-rw-r--r--linden/indra/llcommon/llerrorstream.cpp188
-rw-r--r--linden/indra/llcommon/llerrorstream.h126
-rw-r--r--linden/indra/llcommon/llevent.cpp10
-rw-r--r--linden/indra/llcommon/llevent.h2
-rw-r--r--linden/indra/llcommon/llfasttimer.h27
-rw-r--r--linden/indra/llcommon/llfile.cpp28
-rw-r--r--linden/indra/llcommon/llfile.h11
-rw-r--r--linden/indra/llcommon/llformat.cpp47
-rw-r--r--linden/indra/llcommon/llformat.h42
-rw-r--r--linden/indra/llcommon/llliveappconfig.cpp65
-rw-r--r--linden/indra/llcommon/llliveappconfig.h (renamed from linden/indra/newview/lldrawpooltreenew.h)37
-rw-r--r--linden/indra/llcommon/lllivefile.cpp88
-rw-r--r--linden/indra/llcommon/lllivefile.h21
-rw-r--r--linden/indra/llcommon/lllslconstants.h4
-rw-r--r--linden/indra/llcommon/llmemory.cpp43
-rw-r--r--linden/indra/llcommon/llmemory.h200
-rw-r--r--linden/indra/llcommon/llmemtype.h1
-rw-r--r--linden/indra/llcommon/llpreprocessor.h7
-rw-r--r--linden/indra/llcommon/llprocessor.cpp10
-rw-r--r--linden/indra/llcommon/llqueuedthread.cpp195
-rw-r--r--linden/indra/llcommon/llqueuedthread.h56
-rw-r--r--linden/indra/llcommon/llsd.cpp6
-rw-r--r--linden/indra/llcommon/llsdserialize.cpp4
-rw-r--r--linden/indra/llcommon/llsdserialize_xml.cpp1
-rw-r--r--linden/indra/llcommon/llsecondlifeurls.cpp4
-rw-r--r--linden/indra/llcommon/llsecondlifeurls.h12
-rw-r--r--linden/indra/llcommon/llstreamtools.cpp2
-rw-r--r--linden/indra/llcommon/llstrider.h1
-rw-r--r--linden/indra/llcommon/llstring.cpp1
-rw-r--r--linden/indra/llcommon/llstring.h13
-rw-r--r--linden/indra/llcommon/llstringtable.h5
-rw-r--r--linden/indra/llcommon/llsys.cpp12
-rw-r--r--linden/indra/llcommon/llthread.cpp63
-rw-r--r--linden/indra/llcommon/llthread.h75
-rw-r--r--linden/indra/llcommon/lluri.cpp482
-rw-r--r--linden/indra/llcommon/lluri.h90
-rw-r--r--linden/indra/llcommon/llversion.h6
-rw-r--r--linden/indra/llcommon/llworkerthread.cpp325
-rw-r--r--linden/indra/llcommon/llworkerthread.h85
-rw-r--r--linden/indra/llcommon/metaproperty.cpp2
-rw-r--r--linden/indra/llcommon/u64.cpp14
65 files changed, 4089 insertions, 1823 deletions
diff --git a/linden/indra/llcommon/files.lst b/linden/indra/llcommon/files.lst
index 2482eec..5fcb8c7 100644
--- a/linden/indra/llcommon/files.lst
+++ b/linden/indra/llcommon/files.lst
@@ -2,18 +2,20 @@ llcommon/bitpack.cpp
2llcommon/llapp.cpp 2llcommon/llapp.cpp
3llcommon/llapr.cpp 3llcommon/llapr.cpp
4llcommon/llassettype.cpp 4llcommon/llassettype.cpp
5llcommon/llbase32.cpp
6llcommon/llbase64.cpp
5llcommon/llcommon.cpp 7llcommon/llcommon.cpp
6llcommon/llcriticaldamp.cpp 8llcommon/llcriticaldamp.cpp
7llcommon/lldate.cpp 9llcommon/lldate.cpp
8llcommon/llerrorbuffer.cpp
9llcommon/llerror.cpp 10llcommon/llerror.cpp
10llcommon/llerrorstream.cpp
11llcommon/llerrorthread.cpp 11llcommon/llerrorthread.cpp
12llcommon/llevent.cpp 12llcommon/llevent.cpp
13llcommon/llfasttimer.cpp 13llcommon/llfasttimer.cpp
14llcommon/llfile.cpp 14llcommon/llfile.cpp
15llcommon/llfixedbuffer.cpp 15llcommon/llfixedbuffer.cpp
16llcommon/llformat.cpp
16llcommon/llframetimer.cpp 17llcommon/llframetimer.cpp
18llcommon/llliveappconfig.cpp
17llcommon/lllivefile.cpp 19llcommon/lllivefile.cpp
18llcommon/llmemory.cpp 20llcommon/llmemory.cpp
19llcommon/llmemorystream.cpp 21llcommon/llmemorystream.cpp
diff --git a/linden/indra/llcommon/imageids.h b/linden/indra/llcommon/imageids.h
index 150322e..d65b374 100644
--- a/linden/indra/llcommon/imageids.h
+++ b/linden/indra/llcommon/imageids.h
@@ -50,7 +50,7 @@
50const LLUUID IMG_CLEAR ("11ee27f5-43c0-414e-afd5-d7f5688c351f"); // VIEWER 50const LLUUID IMG_CLEAR ("11ee27f5-43c0-414e-afd5-d7f5688c351f"); // VIEWER
51const LLUUID IMG_SMOKE ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER 51const LLUUID IMG_SMOKE ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER
52 52
53const LLUUID IMG_DEFAULT ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER 53const LLUUID IMG_DEFAULT ("d2114404-dd59-4a4d-8e6c-49359e91bbf0"); // VIEWER
54 54
55//const LLUUID IMG_SAND ("0ff70ead-4562-45f9-9e8a-52b1a3286868"); // VIEWER 1.5k 55//const LLUUID IMG_SAND ("0ff70ead-4562-45f9-9e8a-52b1a3286868"); // VIEWER 1.5k
56//const LLUUID IMG_GRASS ("5ab48dd5-05d0-4f1a-ace6-efd4e2fb3508"); // VIEWER 1.2k 56//const LLUUID IMG_GRASS ("5ab48dd5-05d0-4f1a-ace6-efd4e2fb3508"); // VIEWER 1.2k
diff --git a/linden/indra/llcommon/indra_constants.h b/linden/indra/llcommon/indra_constants.h
index 31c2559..deb9c9d 100644
--- a/linden/indra/llcommon/indra_constants.h
+++ b/linden/indra/llcommon/indra_constants.h
@@ -28,6 +28,7 @@
28#ifndef LL_INDRA_CONSTANTS_H 28#ifndef LL_INDRA_CONSTANTS_H
29#define LL_INDRA_CONSTANTS_H 29#define LL_INDRA_CONSTANTS_H
30 30
31#include "stdtypes.h"
31#include "lluuid.h" 32#include "lluuid.h"
32 33
33// Viewer object cache version, change if object update 34// Viewer object cache version, change if object update
@@ -105,8 +106,8 @@ const char* const DEFAULT_LOCAL_ASSET_SERVER = "http://localhost:12041/asset/tmp
105const char* const LOCAL_ASSET_URL_FORMAT = "http://%s:12041/asset"; 106const char* const LOCAL_ASSET_URL_FORMAT = "http://%s:12041/asset";
106 107
107const U32 DEFAULT_LAUNCHER_PORT = 12029; 108const U32 DEFAULT_LAUNCHER_PORT = 12029;
108const U32 DEFAULT_BIGBOARD_PORT = 12030; 109//const U32 DEFAULT_BIGBOARD_PORT = 12030; // Deprecated
109const U32 DEFAULT_QUERYSIM_PORT = 12031; 110//const U32 DEFAULT_QUERYSIM_PORT = 12031; // Deprecated
110const U32 DEFAULT_DATA_SERVER_PORT = 12032; 111const U32 DEFAULT_DATA_SERVER_PORT = 12032;
111const U32 DEFAULT_SPACE_SERVER_PORT = 12033; 112const U32 DEFAULT_SPACE_SERVER_PORT = 12033;
112const U32 DEFAULT_VIEWER_PORT = 12034; 113const U32 DEFAULT_VIEWER_PORT = 12034;
@@ -115,8 +116,11 @@ const U32 DEFAULT_USER_SERVER_PORT = 12036;
115const U32 DEFAULT_RPC_SERVER_PORT = 12037; 116const U32 DEFAULT_RPC_SERVER_PORT = 12037;
116const U32 DEFAULT_LOG_DATA_SERVER_PORT = 12039; 117const U32 DEFAULT_LOG_DATA_SERVER_PORT = 12039;
117const U32 DEFAULT_BACKBONE_PORT = 12040; 118const U32 DEFAULT_BACKBONE_PORT = 12040;
119const U32 DEFAULT_CGI_SERVICES_PORT = 12045;
118const U32 DEFAULT_LOCAL_ASSET_PORT = 12041; 120const U32 DEFAULT_LOCAL_ASSET_PORT = 12041;
119const U32 DEFAULT_BACKBONE_CAP_PORT = 12042; 121//const U32 DEFAULT_BACKBONE_CAP_PORT = 12042; // Deprecated
122const U32 DEFAULT_CAP_PROXY_PORT = 12043;
123const U32 DEFAULT_INV_DATA_SERVER_PORT = 12044;
120 124
121// For automatic port discovery when running multiple viewers on one host 125// For automatic port discovery when running multiple viewers on one host
122const U32 PORT_DISCOVERY_RANGE_MIN = 13000; 126const U32 PORT_DISCOVERY_RANGE_MIN = 13000;
@@ -322,7 +326,7 @@ const U32 MAP_ITEM_TELEHUB = 0x01;
322const U32 MAP_ITEM_PG_EVENT = 0x02; 326const U32 MAP_ITEM_PG_EVENT = 0x02;
323const U32 MAP_ITEM_MATURE_EVENT = 0x03; 327const U32 MAP_ITEM_MATURE_EVENT = 0x03;
324const U32 MAP_ITEM_POPULAR = 0x04; 328const U32 MAP_ITEM_POPULAR = 0x04;
325const U32 MAP_ITEM_AGENT_COUNT = 0x05; 329//const U32 MAP_ITEM_AGENT_COUNT = 0x05;
326const U32 MAP_ITEM_AGENT_LOCATIONS = 0x06; 330const U32 MAP_ITEM_AGENT_LOCATIONS = 0x06;
327const U32 MAP_ITEM_LAND_FOR_SALE = 0x07; 331const U32 MAP_ITEM_LAND_FOR_SALE = 0x07;
328const U32 MAP_ITEM_CLASSIFIED = 0x08; 332const U32 MAP_ITEM_CLASSIFIED = 0x08;
diff --git a/linden/indra/llcommon/linden_common.h b/linden/indra/llcommon/linden_common.h
index ff77b3d..b1c5f3b 100644
--- a/linden/indra/llcommon/linden_common.h
+++ b/linden/indra/llcommon/linden_common.h
@@ -49,6 +49,7 @@
49#include "stdtypes.h" 49#include "stdtypes.h"
50#include "lldefs.h" 50#include "lldefs.h"
51#include "llerror.h" 51#include "llerror.h"
52#include "llformat.h"
52#include "llstring.h" 53#include "llstring.h"
53#include "lltimer.h" 54#include "lltimer.h"
54#include "llfasttimer.h" 55#include "llfasttimer.h"
diff --git a/linden/indra/llcommon/llapp.cpp b/linden/indra/llcommon/llapp.cpp
index 42d9050..f48ff8f 100644
--- a/linden/indra/llcommon/llapp.cpp
+++ b/linden/indra/llcommon/llapp.cpp
@@ -30,9 +30,11 @@
30 30
31#include "llcommon.h" 31#include "llcommon.h"
32#include "llapr.h" 32#include "llapr.h"
33#include "llerrorcontrol.h"
33#include "llerrorthread.h" 34#include "llerrorthread.h"
34#include "llframetimer.h" 35#include "llframetimer.h"
35#include "llmemory.h" 36#include "llmemory.h"
37#include "lltimer.h"
36 38
37// 39//
38// Signal handling 40// Signal handling
@@ -193,10 +195,8 @@ LLSD LLApp::getOptionData(OptionPriority level)
193 195
194void LLApp::stepFrame() 196void LLApp::stepFrame()
195{ 197{
196 // Update the static frame timer.
197 LLFrameTimer::updateFrameTime(); 198 LLFrameTimer::updateFrameTime();
198 199 LLEventTimer::updateClass();
199 // Run ready runnables
200 mRunner.run(); 200 mRunner.run();
201} 201}
202 202
@@ -563,7 +563,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
563 else 563 else
564 { 564 {
565 // Don't log anything, even errors - this is because this signal could happen anywhere. 565 // Don't log anything, even errors - this is because this signal could happen anywhere.
566 gErrorStream.setLevel(LLErrorStream::NONE); 566 LLError::setDefaultLevel(LLError::LEVEL_NONE);
567 } 567 }
568 568
569 // Change the signal that we reraise to SIGABRT, so we generate a core dump. 569 // Change the signal that we reraise to SIGABRT, so we generate a core dump.
diff --git a/linden/indra/llcommon/llapr.cpp b/linden/indra/llcommon/llapr.cpp
index 665ee75..550a8d8 100644
--- a/linden/indra/llcommon/llapr.cpp
+++ b/linden/indra/llcommon/llapr.cpp
@@ -122,11 +122,13 @@ void ll_apr_assert_status(apr_status_t status)
122 llassert(ll_apr_warn_status(status) == false); 122 llassert(ll_apr_warn_status(status) == false);
123} 123}
124 124
125apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep) 125// File I/O
126apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep, apr_pool_t* pool)
126{ 127{
127 apr_file_t* apr_file; 128 apr_file_t* apr_file;
128 apr_status_t s; 129 apr_status_t s;
129 s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp); 130 if (pool == NULL) pool = gAPRPoolp;
131 s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool);
130 if (s != APR_SUCCESS) 132 if (s != APR_SUCCESS)
131 { 133 {
132 if (sizep) 134 if (sizep)
@@ -142,6 +144,7 @@ apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* s
142 apr_off_t offset = 0; 144 apr_off_t offset = 0;
143 if (apr_file_seek(apr_file, APR_END, &offset) == APR_SUCCESS) 145 if (apr_file_seek(apr_file, APR_END, &offset) == APR_SUCCESS)
144 { 146 {
147 llassert_always(offset <= 0x7fffffff);
145 file_size = (S32)offset; 148 file_size = (S32)offset;
146 offset = 0; 149 offset = 0;
147 apr_file_seek(apr_file, APR_SET, &offset); 150 apr_file_seek(apr_file, APR_SET, &offset);
@@ -151,6 +154,18 @@ apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* s
151 154
152 return apr_file; 155 return apr_file;
153} 156}
157apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep)
158{
159 return ll_apr_file_open(filename, flags, sizep, NULL);
160}
161apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, apr_pool_t* pool)
162{
163 return ll_apr_file_open(filename, flags, NULL, pool);
164}
165apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags)
166{
167 return ll_apr_file_open(filename, flags, NULL, NULL);
168}
154 169
155S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes) 170S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes)
156{ 171{
@@ -162,10 +177,37 @@ S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes)
162 } 177 }
163 else 178 else
164 { 179 {
180 llassert_always(sz <= 0x7fffffff);
165 return (S32)sz; 181 return (S32)sz;
166 } 182 }
167} 183}
168 184
185S32 ll_apr_file_read_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes)
186{
187 if (pool == NULL) pool = gAPRPoolp;
188 apr_file_t* filep = ll_apr_file_open(filename, APR_READ|APR_BINARY, pool);
189 if (!filep)
190 {
191 return 0;
192 }
193 S32 off;
194 if (offset < 0)
195 off = ll_apr_file_seek(filep, APR_END, 0);
196 else
197 off = ll_apr_file_seek(filep, APR_SET, offset);
198 S32 bytes_read;
199 if (off < 0)
200 {
201 bytes_read = 0;
202 }
203 else
204 {
205 bytes_read = ll_apr_file_read(filep, buf, nbytes );
206 }
207 apr_file_close(filep);
208
209 return bytes_read;
210}
169 211
170S32 ll_apr_file_write(apr_file_t* apr_file, const void *buf, S32 nbytes) 212S32 ll_apr_file_write(apr_file_t* apr_file, const void *buf, S32 nbytes)
171{ 213{
@@ -177,28 +219,73 @@ S32 ll_apr_file_write(apr_file_t* apr_file, const void *buf, S32 nbytes)
177 } 219 }
178 else 220 else
179 { 221 {
222 llassert_always(sz <= 0x7fffffff);
180 return (S32)sz; 223 return (S32)sz;
181 } 224 }
182} 225}
183 226
227S32 ll_apr_file_write_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes)
228{
229 if (pool == NULL) pool = gAPRPoolp;
230 apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
231 if (offset < 0)
232 {
233 flags |= APR_APPEND;
234 offset = 0;
235 }
236 apr_file_t* filep = ll_apr_file_open(filename, flags, pool);
237 if (!filep)
238 {
239 return 0;
240 }
241 if (offset > 0)
242 {
243 offset = ll_apr_file_seek(filep, APR_SET, offset);
244 }
245 S32 bytes_written;
246 if (offset < 0)
247 {
248 bytes_written = 0;
249 }
250 else
251 {
252 bytes_written = ll_apr_file_write(filep, buf, nbytes );
253 }
254 apr_file_close(filep);
255
256 return bytes_written;
257}
258
184S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset) 259S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset)
185{ 260{
186 apr_off_t apr_offset = offset; 261 apr_status_t s;
187 apr_status_t s = apr_file_seek(apr_file, where, &apr_offset); 262 apr_off_t apr_offset;
263 if (offset >= 0)
264 {
265 apr_offset = (apr_off_t)offset;
266 s = apr_file_seek(apr_file, where, &apr_offset);
267 }
268 else
269 {
270 apr_offset = 0;
271 s = apr_file_seek(apr_file, APR_END, &apr_offset);
272 }
188 if (s != APR_SUCCESS) 273 if (s != APR_SUCCESS)
189 { 274 {
190 return -1; 275 return -1;
191 } 276 }
192 else 277 else
193 { 278 {
279 llassert_always(apr_offset <= 0x7fffffff);
194 return (S32)apr_offset; 280 return (S32)apr_offset;
195 } 281 }
196} 282}
197 283
198bool ll_apr_file_remove(const LLString& filename) 284bool ll_apr_file_remove(const LLString& filename, apr_pool_t* pool)
199{ 285{
200 apr_status_t s; 286 apr_status_t s;
201 s = apr_file_remove(filename.c_str(), gAPRPoolp); 287 if (pool == NULL) pool = gAPRPoolp;
288 s = apr_file_remove(filename.c_str(), pool);
202 if (s != APR_SUCCESS) 289 if (s != APR_SUCCESS)
203 { 290 {
204 llwarns << "ll_apr_file_remove failed on file: " << filename << llendl; 291 llwarns << "ll_apr_file_remove failed on file: " << filename << llendl;
@@ -207,10 +294,11 @@ bool ll_apr_file_remove(const LLString& filename)
207 return true; 294 return true;
208} 295}
209 296
210bool ll_apr_file_rename(const LLString& filename, const LLString& newname) 297bool ll_apr_file_rename(const LLString& filename, const LLString& newname, apr_pool_t* pool)
211{ 298{
212 apr_status_t s; 299 apr_status_t s;
213 s = apr_file_rename(filename.c_str(), newname.c_str(), gAPRPoolp); 300 if (pool == NULL) pool = gAPRPoolp;
301 s = apr_file_rename(filename.c_str(), newname.c_str(), pool);
214 if (s != APR_SUCCESS) 302 if (s != APR_SUCCESS)
215 { 303 {
216 llwarns << "ll_apr_file_rename failed on file: " << filename << llendl; 304 llwarns << "ll_apr_file_rename failed on file: " << filename << llendl;
@@ -218,3 +306,73 @@ bool ll_apr_file_rename(const LLString& filename, const LLString& newname)
218 } 306 }
219 return true; 307 return true;
220} 308}
309
310bool ll_apr_file_exists(const LLString& filename, apr_pool_t* pool)
311{
312 apr_file_t* apr_file;
313 apr_status_t s;
314 if (pool == NULL) pool = gAPRPoolp;
315 s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool);
316 if (s != APR_SUCCESS || !apr_file)
317 {
318 return false;
319 }
320 else
321 {
322 apr_file_close(apr_file);
323 return true;
324 }
325}
326
327S32 ll_apr_file_size(const LLString& filename, apr_pool_t* pool)
328{
329 apr_file_t* apr_file;
330 apr_finfo_t info;
331 apr_status_t s;
332 if (pool == NULL) pool = gAPRPoolp;
333 s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool);
334 if (s != APR_SUCCESS || !apr_file)
335 {
336 return 0;
337 }
338 else
339 {
340 apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file);
341 apr_file_close(apr_file);
342 if (s == APR_SUCCESS)
343 {
344 return (S32)info.size;
345 }
346 else
347 {
348 return 0;
349 }
350 }
351}
352
353bool ll_apr_dir_make(const LLString& dirname, apr_pool_t* pool)
354{
355 apr_status_t s;
356 if (pool == NULL) pool = gAPRPoolp;
357 s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool);
358 if (s != APR_SUCCESS)
359 {
360 llwarns << "ll_apr_file_remove failed on file: " << dirname << llendl;
361 return false;
362 }
363 return true;
364}
365
366bool ll_apr_dir_remove(const LLString& dirname, apr_pool_t* pool)
367{
368 apr_status_t s;
369 if (pool == NULL) pool = gAPRPoolp;
370 s = apr_file_remove(dirname.c_str(), pool);
371 if (s != APR_SUCCESS)
372 {
373 llwarns << "ll_apr_file_remove failed on file: " << dirname << llendl;
374 return false;
375 }
376 return true;
377}
378
diff --git a/linden/indra/llcommon/llapr.h b/linden/indra/llcommon/llapr.h
index a5c217c..be6fc6c 100644
--- a/linden/indra/llcommon/llapr.h
+++ b/linden/indra/llcommon/llapr.h
@@ -125,14 +125,24 @@ typedef LLAtomic32<S32> LLAtomicS32;
125#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb" 125#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb"
126#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b" 126#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b"
127#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b" 127#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b"
128apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep = NULL); 128apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep, apr_pool_t* pool);
129apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep);
130apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, apr_pool_t* pool);
131apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags);
129// Returns actual offset, -1 if seek fails 132// Returns actual offset, -1 if seek fails
130S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset); 133S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset);
131// Returns bytes read/written, 0 if read/write fails 134// Returns bytes read/written, 0 if read/write fails:
132S32 ll_apr_file_read(apr_file_t* apr_file, void* buf, S32 nbytes); 135S32 ll_apr_file_read(apr_file_t* apr_file, void* buf, S32 nbytes);
136S32 ll_apr_file_read_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes);
133S32 ll_apr_file_write(apr_file_t* apr_file, const void* buf, S32 nbytes); 137S32 ll_apr_file_write(apr_file_t* apr_file, const void* buf, S32 nbytes);
134bool ll_apr_file_remove(const LLString& filename); 138S32 ll_apr_file_write_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes);
135bool ll_apr_file_rename(const LLString& filename, const LLString& newname); 139// returns false if failure:
140bool ll_apr_file_remove(const LLString& filename, apr_pool_t* pool = NULL);
141bool ll_apr_file_rename(const LLString& filename, const LLString& newname, apr_pool_t* pool = NULL);
142bool ll_apr_file_exists(const LLString& filename, apr_pool_t* pool = NULL);
143S32 ll_apr_file_size(const LLString& filename, apr_pool_t* pool = NULL);
144bool ll_apr_dir_make(const LLString& dirname, apr_pool_t* pool = NULL);
145bool ll_apr_dir_remove(const LLString& dirname, apr_pool_t* pool = NULL);
136 146
137/** 147/**
138 * @brief Function which approprately logs error or remains quiet on 148 * @brief Function which approprately logs error or remains quiet on
diff --git a/linden/indra/llcommon/llassettype.cpp b/linden/indra/llcommon/llassettype.cpp
index 051092e..df00af8 100644
--- a/linden/indra/llcommon/llassettype.cpp
+++ b/linden/indra/llcommon/llassettype.cpp
@@ -203,6 +203,20 @@ const char* LLAssetType::lookupHumanReadable(LLAssetType::EType type)
203 } 203 }
204} 204}
205 205
206// static
207LLAssetType::EType LLAssetType::lookupHumanReadable( const char* name )
208{
209 for( S32 i = 0; i < AT_COUNT; i++ )
210 {
211 if( 0 == strcmp(name, mAssetTypeHumanNames[i]) )
212 {
213 // match
214 return (EType)i;
215 }
216 }
217 return AT_NONE;
218}
219
206EDragAndDropType LLAssetType::lookupDragAndDropType( EType asset ) 220EDragAndDropType LLAssetType::lookupDragAndDropType( EType asset )
207{ 221{
208 switch( asset ) 222 switch( asset )
diff --git a/linden/indra/llcommon/llassettype.h b/linden/indra/llcommon/llassettype.h
index 67dc3ef..da4cf0b 100644
--- a/linden/indra/llcommon/llassettype.h
+++ b/linden/indra/llcommon/llassettype.h
@@ -145,6 +145,7 @@ public:
145 static const char* lookup(EType type); 145 static const char* lookup(EType type);
146 146
147 // translation from a type to a human readable form. 147 // translation from a type to a human readable form.
148 static EType lookupHumanReadable( const char* name );
148 static const char* lookupHumanReadable(EType type); 149 static const char* lookupHumanReadable(EType type);
149 150
150 static EDragAndDropType lookupDragAndDropType( EType ); 151 static EDragAndDropType lookupDragAndDropType( EType );
diff --git a/linden/indra/llcommon/llavatarconstants.h b/linden/indra/llcommon/llavatarconstants.h
index 3335949..1eb5b05 100644
--- a/linden/indra/llcommon/llavatarconstants.h
+++ b/linden/indra/llcommon/llavatarconstants.h
@@ -39,16 +39,16 @@ const char* const BLACKLIST_PROFILE_WEB_URL = "http://secondlife.com/app/webdisa
39// Maximum number of avatar picks 39// Maximum number of avatar picks
40const S32 MAX_AVATAR_PICKS = 10; 40const S32 MAX_AVATAR_PICKS = 10;
41 41
42// For Flags in AvatarPropertiesReply 42// For Flags in AvatarPropertiesReply
43const U32 AVATAR_ALLOW_PUBLISH = 0x1 << 0; // whether profile is externally visible or not 43const U32 AVATAR_ALLOW_PUBLISH = 0x1 << 0; // whether profile is externally visible or not
44const U32 AVATAR_MATURE_PUBLISH = 0x1 << 1; // profile is "mature" 44const U32 AVATAR_MATURE_PUBLISH = 0x1 << 1; // profile is "mature"
45const U32 AVATAR_IDENTIFIED = 0x1 << 2; // whether avatar has provided payment info 45const U32 AVATAR_IDENTIFIED = 0x1 << 2; // whether avatar has provided payment info
46const U32 AVATAR_TRANSACTED = 0x1 << 3; // whether avatar has actively used payment info 46const U32 AVATAR_TRANSACTED = 0x1 << 3; // whether avatar has actively used payment info
47const U32 AVATAR_ONLINE = 0x1 << 4; // the online status of this avatar, if known. 47const U32 AVATAR_ONLINE = 0x1 << 4; // the online status of this avatar, if known.
48 48
49static const std::string VISIBILITY_DEFAULT("default"); 49static const std::string VISIBILITY_DEFAULT("default");
50static const std::string VISIBILITY_HIDDEN("hidden"); 50static const std::string VISIBILITY_HIDDEN("hidden");
51static const std::string VISIBILITY_VISIBLE("visible"); 51static const std::string VISIBILITY_VISIBLE("visible");
52static const std::string VISIBILITY_INVISIBLE("invisible"); 52static const std::string VISIBILITY_INVISIBLE("invisible");
53 53
54#endif 54#endif
diff --git a/linden/indra/llcommon/llbase32.cpp b/linden/indra/llcommon/llbase32.cpp
new file mode 100644
index 0000000..711ba63
--- /dev/null
+++ b/linden/indra/llcommon/llbase32.cpp
@@ -0,0 +1,214 @@
1/**
2 * @file llbase32.cpp
3 * @brief base32 encoding that returns a std::string
4 * @author James Cook
5 *
6 * Based on code from bitter
7 * http://ghostwhitecrab.com/bitter/
8 *
9 * Copyright (c) 2006 Christian Biere <christianbiere@gmx.de>
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the authors nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38#include "linden_common.h"
39
40#include "llbase32.h"
41
42#include <string>
43
44// bitter - base32.c starts here
45
46/*
47 * See RFC 3548 for details about Base 32 encoding:
48 * http://www.faqs.org/rfcs/rfc3548.html
49 */
50
51static const char base32_alphabet[32] = {
52 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
53 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
54 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
55 'Y', 'Z', '2', '3', '4', '5', '6', '7'
56};
57
58size_t
59base32_encode(char *dst, size_t size, const void *data, size_t len)
60{
61 size_t i = 0;
62 const U8 *p = (const U8*)data;
63 const char *end = &dst[size];
64 char *q = dst;
65
66 do {
67 size_t j, k;
68 U8 x[5];
69 char s[8];
70
71 switch (len - i) {
72 case 4: k = 7; break;
73 case 3: k = 5; break;
74 case 2: k = 3; break;
75 case 1: k = 2; break;
76 default:
77 k = 8;
78 }
79
80 for (j = 0; j < 5; j++)
81 x[j] = i < len ? p[i++] : 0;
82
83/*
84 +-------+-----------+--------+
85 | target| source | source |
86 | byte | bits | byte |
87 +-------+-----------+--------+
88 | 0 | 7 6 5 4 3 | 0 |
89 | 1 | 2 1 0 7 6 | 0-1 |
90 | 2 | 5 4 3 2 1 | 1 |
91 | 3 | 0 7 6 5 4 | 1-2 |
92 | 4 | 3 2 1 0 7 | 2-3 |
93 | 5 | 6 5 4 3 2 | 3 |
94 | 6 | 1 0 7 6 5 | 3-4 |
95 | 7 | 4 3 2 1 0 | 4 |
96 +-------+-----------+--------+
97
98*/
99
100 s[0] = (x[0] >> 3);
101 s[1] = ((x[0] & 0x07) << 2) | (x[1] >> 6);
102 s[2] = (x[1] >> 1) & 0x1f;
103 s[3] = ((x[1] & 0x01) << 4) | (x[2] >> 4);
104 s[4] = ((x[2] & 0x0f) << 1) | (x[3] >> 7);
105 s[5] = (x[3] >> 2) & 0x1f;
106 s[6] = ((x[3] & 0x03) << 3) | (x[4] >> 5);
107 s[7] = x[4] & 0x1f;
108
109 for (j = 0; j < k && q != end; j++)
110 *q++ = base32_alphabet[(U8) s[j]];
111
112 } while (i < len);
113
114 return q - dst;
115}
116
117/* *TODO: Implement base32 encode.
118
119#define ARRAY_LEN(a) (sizeof (a) / sizeof((a)[0]))
120
121static inline int
122ascii_toupper(int c)
123{
124 return c >= 97 && c <= 122 ? c - 32 : c;
125}
126
127static inline int
128ascii_tolower(int c)
129{
130 return c >= 65 && c <= 90 ? c + 32 : c;
131}
132
133
134static char base32_map[(unsigned char) -1];
135
136size_t
137base32_decode(char *dst, size_t size, const void *data, size_t len)
138{
139 const char *end = &dst[size];
140 const unsigned char *p = data;
141 char *q = dst;
142 size_t i;
143 unsigned max_pad = 3;
144
145 if (0 == base32_map[0]) {
146 for (i = 0; i < ARRAY_LEN(base32_map); i++) {
147 const char *x;
148
149 x = memchr(base32_alphabet, ascii_toupper(i), sizeof base32_alphabet);
150 base32_map[i] = x ? (x - base32_alphabet) : (unsigned char) -1;
151 }
152 }
153
154 for (i = 0; i < len && max_pad > 0; i++) {
155 unsigned char c;
156 char s[8];
157 size_t j;
158
159 c = p[i];
160 if ('=' == c) {
161 max_pad--;
162 c = 0;
163 } else {
164 c = base32_map[c];
165 if ((unsigned char) -1 == c) {
166 return -1;
167 }
168 }
169
170 j = i % ARRAY_LEN(s);
171 s[j] = c;
172
173 if (7 == j) {
174 char b[5];
175
176 b[0] = ((s[0] << 3) & 0xf8) | ((s[1] >> 2) & 0x07);
177 b[1] = ((s[1] & 0x03) << 6) | ((s[2] & 0x1f) << 1) | ((s[3] >> 4) & 1);
178 b[2] = ((s[3] & 0x0f) << 4) | ((s[4] >> 1) & 0x0f);
179 b[3] = ((s[4] & 1) << 7) | ((s[5] & 0x1f) << 2) | ((s[6] >> 3) & 0x03);
180 b[4] = ((s[6] & 0x07) << 5) | (s[7] & 0x1f);
181
182 for (j = 0; j < ARRAY_LEN(b); j++) {
183 if (q != end)
184 *q = b[j];
185 q++;
186 }
187 }
188 }
189
190 return q - dst;
191}
192*/
193
194
195// static
196std::string LLBase32::encode(const U8* input, size_t input_size)
197{
198 std::string output;
199 if (input)
200 {
201 // Each 5 byte chunk of input is represented by an
202 // 8 byte chunk of output.
203 size_t input_chunks = (input_size + 4) / 5;
204 size_t output_size = input_chunks * 8;
205
206 output.resize(output_size);
207
208 size_t encoded = base32_encode(&output[0], output_size, input, input_size);
209
210 llinfos << "encoded " << encoded << " into buffer of size " << output_size
211 << llendl;
212 }
213 return output;
214}
diff --git a/linden/indra/llcommon/llbase32.h b/linden/indra/llcommon/llbase32.h
new file mode 100644
index 0000000..eaf3efc
--- /dev/null
+++ b/linden/indra/llcommon/llbase32.h
@@ -0,0 +1,38 @@
1/**
2 * @file llbase32.h
3 * @brief base32 encoding that returns a std::string
4 * @author James Cook
5 *
6 * Copyright (c) 2007-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#ifndef LLBASE32_H
30#define LLBASE32_h
31
32class LLBase32
33{
34public:
35 static std::string encode(const U8* input, size_t input_size);
36};
37
38#endif
diff --git a/linden/indra/llcommon/llbase64.cpp b/linden/indra/llcommon/llbase64.cpp
new file mode 100644
index 0000000..0869d3f
--- /dev/null
+++ b/linden/indra/llcommon/llbase64.cpp
@@ -0,0 +1,62 @@
1/**
2 * @file llbase64.cpp
3 * @brief Wrapper for apr base64 encoding that returns a std::string
4 * @author James Cook
5 *
6 * Copyright (c) 2007-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#include "linden_common.h"
30
31#include "llbase64.h"
32
33#include <string>
34
35#include "apr-1/apr_base64.h"
36
37
38// static
39std::string LLBase64::encode(const U8* input, size_t input_size)
40{
41 std::string output;
42 if (input
43 && input_size > 0)
44 {
45 // Yes, it returns int.
46 int b64_buffer_length = apr_base64_encode_len(input_size);
47 char* b64_buffer = new char[b64_buffer_length];
48
49 // This is faster than apr_base64_encode() if you know
50 // you're not on an EBCDIC machine. Also, the output is
51 // null terminated, even though the documentation doesn't
52 // specify. See apr_base64.c for details. JC
53 b64_buffer_length = apr_base64_encode_binary(
54 b64_buffer,
55 input,
56 input_size);
57 output.assign(b64_buffer);
58 delete[] b64_buffer;
59 }
60 return output;
61}
62
diff --git a/linden/indra/llcommon/llbase64.h b/linden/indra/llcommon/llbase64.h
new file mode 100644
index 0000000..d8b4acc
--- /dev/null
+++ b/linden/indra/llcommon/llbase64.h
@@ -0,0 +1,38 @@
1/**
2 * @file llbase64.h
3 * @brief Wrapper for apr base64 encoding that returns a std::string
4 * @author James Cook
5 *
6 * Copyright (c) 2007-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#ifndef LLBASE64_H
30#define LLBASE64_h
31
32class LLBase64
33{
34public:
35 static std::string encode(const U8* input, size_t input_size);
36};
37
38#endif
diff --git a/linden/indra/llcommon/llcommon.cpp b/linden/indra/llcommon/llcommon.cpp
index 50b9849..49675e1 100644
--- a/linden/indra/llcommon/llcommon.cpp
+++ b/linden/indra/llcommon/llcommon.cpp
@@ -27,6 +27,7 @@
27#include "linden_common.h" 27#include "linden_common.h"
28 28
29#include "llcommon.h" 29#include "llcommon.h"
30#include "llthread.h"
30 31
31//static 32//static
32BOOL LLCommon::sAprInitialized = FALSE; 33BOOL LLCommon::sAprInitialized = FALSE;
diff --git a/linden/indra/llcommon/llcommon.h b/linden/indra/llcommon/llcommon.h
index 5d5264c..8b57579 100644
--- a/linden/indra/llcommon/llcommon.h
+++ b/linden/indra/llcommon/llcommon.h
@@ -31,7 +31,6 @@
31#include "llapr.h" 31#include "llapr.h"
32// #include "llframecallbackmanager.h" 32// #include "llframecallbackmanager.h"
33#include "lltimer.h" 33#include "lltimer.h"
34#include "llworkerthread.h"
35#include "llfile.h" 34#include "llfile.h"
36 35
37class LLCommon 36class LLCommon
diff --git a/linden/indra/llcommon/llcommon.vcproj b/linden/indra/llcommon/llcommon.vcproj
index 5cfbc64..403b8c5 100644
--- a/linden/indra/llcommon/llcommon.vcproj
+++ b/linden/indra/llcommon/llcommon.vcproj
@@ -167,22 +167,22 @@
167 RelativePath=".\llassettype.cpp"> 167 RelativePath=".\llassettype.cpp">
168 </File> 168 </File>
169 <File 169 <File
170 RelativePath=".\llcommon.cpp"> 170 RelativePath=".\llbase32.cpp">
171 </File> 171 </File>
172 <File 172 <File
173 RelativePath=".\llcriticaldamp.cpp"> 173 RelativePath=".\llbase64.cpp">
174 </File> 174 </File>
175 <File 175 <File
176 RelativePath=".\lldate.cpp"> 176 RelativePath=".\llcommon.cpp">
177 </File> 177 </File>
178 <File 178 <File
179 RelativePath=".\llerror.cpp"> 179 RelativePath=".\llcriticaldamp.cpp">
180 </File> 180 </File>
181 <File 181 <File
182 RelativePath=".\llerrorbuffer.cpp"> 182 RelativePath=".\lldate.cpp">
183 </File> 183 </File>
184 <File 184 <File
185 RelativePath=".\llerrorstream.cpp"> 185 RelativePath=".\llerror.cpp">
186 </File> 186 </File>
187 <File 187 <File
188 RelativePath=".\llerrorthread.cpp"> 188 RelativePath=".\llerrorthread.cpp">
@@ -200,9 +200,15 @@
200 RelativePath=".\llfixedbuffer.cpp"> 200 RelativePath=".\llfixedbuffer.cpp">
201 </File> 201 </File>
202 <File 202 <File
203 RelativePath=".\llformat.cpp">
204 </File>
205 <File
203 RelativePath=".\llframetimer.cpp"> 206 RelativePath=".\llframetimer.cpp">
204 </File> 207 </File>
205 <File 208 <File
209 RelativePath=".\llliveappconfig.cpp">
210 </File>
211 <File
206 RelativePath=".\lllivefile.cpp"> 212 RelativePath=".\lllivefile.cpp">
207 </File> 213 </File>
208 <File 214 <File
@@ -322,6 +328,12 @@
322 RelativePath=".\llavatarconstants.h"> 328 RelativePath=".\llavatarconstants.h">
323 </File> 329 </File>
324 <File 330 <File
331 RelativePath=".\llbase32.h">
332 </File>
333 <File
334 RelativePath=".\llbase64.h">
335 </File>
336 <File
325 RelativePath=".\llboost.h"> 337 RelativePath=".\llboost.h">
326 </File> 338 </File>
327 <File 339 <File
@@ -364,10 +376,7 @@
364 RelativePath=".\llerror.h"> 376 RelativePath=".\llerror.h">
365 </File> 377 </File>
366 <File 378 <File
367 RelativePath=".\llerrorbuffer.h"> 379 RelativePath=".\llerrorcontrol.h">
368 </File>
369 <File
370 RelativePath=".\llerrorstream.h">
371 </File> 380 </File>
372 <File 381 <File
373 RelativePath=".\llerrorthread.h"> 382 RelativePath=".\llerrorthread.h">
@@ -385,6 +394,9 @@
385 RelativePath=".\llfixedbuffer.h"> 394 RelativePath=".\llfixedbuffer.h">
386 </File> 395 </File>
387 <File 396 <File
397 RelativePath=".\llformat.h">
398 </File>
399 <File
388 RelativePath=".\llframecallbackmanager.h"> 400 RelativePath=".\llframecallbackmanager.h">
389 </File> 401 </File>
390 <File 402 <File
@@ -400,6 +412,9 @@
400 RelativePath=".\lllinkedqueue.h"> 412 RelativePath=".\lllinkedqueue.h">
401 </File> 413 </File>
402 <File 414 <File
415 RelativePath=".\llliveappconfig.h">
416 </File>
417 <File
403 RelativePath=".\lllivefile.h"> 418 RelativePath=".\lllivefile.h">
404 </File> 419 </File>
405 <File 420 <File
@@ -418,6 +433,9 @@
418 RelativePath=".\llmemorystream.h"> 433 RelativePath=".\llmemorystream.h">
419 </File> 434 </File>
420 <File 435 <File
436 RelativePath=".\llmemtype.h">
437 </File>
438 <File
421 RelativePath=".\llmortician.h"> 439 RelativePath=".\llmortician.h">
422 </File> 440 </File>
423 <File 441 <File
diff --git a/linden/indra/llcommon/llcommon_vc8.vcproj b/linden/indra/llcommon/llcommon_vc8.vcproj
new file mode 100644
index 0000000..4fee443
--- /dev/null
+++ b/linden/indra/llcommon/llcommon_vc8.vcproj
@@ -0,0 +1,759 @@
1<?xml version="1.0" encoding="Windows-1252"?>
2<VisualStudioProject
3 ProjectType="Visual C++"
4 Version="8.00"
5 Name="llcommon"
6 ProjectGUID="{7BCB4B2C-8378-4186-88EA-5742B5ABE17F}"
7 RootNamespace="llcommon"
8 Keyword="Win32Proj"
9 >
10 <Platforms>
11 <Platform
12 Name="Win32"
13 />
14 </Platforms>
15 <ToolFiles>
16 </ToolFiles>
17 <Configurations>
18 <Configuration
19 Name="Debug|Win32"
20 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
21 IntermediateDirectory="$(ConfigurationName)"
22 ConfigurationType="4"
23 InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
24 CharacterSet="1"
25 >
26 <Tool
27 Name="VCPreBuildEventTool"
28 />
29 <Tool
30 Name="VCCustomBuildTool"
31 />
32 <Tool
33 Name="VCXMLDataGeneratorTool"
34 />
35 <Tool
36 Name="VCWebServiceProxyGeneratorTool"
37 />
38 <Tool
39 Name="VCMIDLTool"
40 />
41 <Tool
42 Name="VCCLCompilerTool"
43 Optimization="0"
44 AdditionalIncludeDirectories="..\..\libraries\i686-win32\include;..\..\libraries\include\"
45 PreprocessorDefinitions="WIN32;_DEBUG;_LIB;LL_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_USE_32BIT_TIME_T;LL_DEBUG;XML_STATIC;APR_DECLARE_STATIC"
46 MinimalRebuild="true"
47 BasicRuntimeChecks="3"
48 RuntimeLibrary="1"
49 StructMemberAlignment="4"
50 TreatWChar_tAsBuiltInType="false"
51 ForceConformanceInForLoopScope="true"
52 UsePrecompiledHeader="0"
53 WarningLevel="3"
54 WarnAsError="true"
55 Detect64BitPortabilityProblems="false"
56 DebugInformationFormat="4"
57 />
58 <Tool
59 Name="VCManagedResourceCompilerTool"
60 />
61 <Tool
62 Name="VCResourceCompilerTool"
63 />
64 <Tool
65 Name="VCPreLinkEventTool"
66 />
67 <Tool
68 Name="VCLibrarianTool"
69 OutputFile="$(OutDir)/llcommon.lib"
70 />
71 <Tool
72 Name="VCALinkTool"
73 />
74 <Tool
75 Name="VCXDCMakeTool"
76 />
77 <Tool
78 Name="VCBscMakeTool"
79 />
80 <Tool
81 Name="VCFxCopTool"
82 />
83 <Tool
84 Name="VCPostBuildEventTool"
85 />
86 </Configuration>
87 <Configuration
88 Name="Release|Win32"
89 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
90 IntermediateDirectory="$(ConfigurationName)"
91 ConfigurationType="4"
92 InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
93 CharacterSet="1"
94 >
95 <Tool
96 Name="VCPreBuildEventTool"
97 />
98 <Tool
99 Name="VCCustomBuildTool"
100 />
101 <Tool
102 Name="VCXMLDataGeneratorTool"
103 />
104 <Tool
105 Name="VCWebServiceProxyGeneratorTool"
106 />
107 <Tool
108 Name="VCMIDLTool"
109 />
110 <Tool
111 Name="VCCLCompilerTool"
112 InlineFunctionExpansion="2"
113 EnableIntrinsicFunctions="true"
114 AdditionalIncludeDirectories="..\..\libraries\i686-win32\include;..\..\libraries\include\"
115 PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_USE_32BIT_TIME_T;LL_RELEASE;XML_STATIC;APR_DECLARE_STATIC"
116 RuntimeLibrary="0"
117 StructMemberAlignment="0"
118 TreatWChar_tAsBuiltInType="false"
119 ForceConformanceInForLoopScope="true"
120 UsePrecompiledHeader="0"
121 WarningLevel="3"
122 WarnAsError="true"
123 Detect64BitPortabilityProblems="false"
124 DebugInformationFormat="3"
125 />
126 <Tool
127 Name="VCManagedResourceCompilerTool"
128 />
129 <Tool
130 Name="VCResourceCompilerTool"
131 />
132 <Tool
133 Name="VCPreLinkEventTool"
134 />
135 <Tool
136 Name="VCLibrarianTool"
137 OutputFile="$(OutDir)/llcommon.lib"
138 />
139 <Tool
140 Name="VCALinkTool"
141 />
142 <Tool
143 Name="VCXDCMakeTool"
144 />
145 <Tool
146 Name="VCBscMakeTool"
147 />
148 <Tool
149 Name="VCFxCopTool"
150 />
151 <Tool
152 Name="VCPostBuildEventTool"
153 />
154 </Configuration>
155 <Configuration
156 Name="ReleaseNoOpt|Win32"
157 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
158 IntermediateDirectory="$(ConfigurationName)"
159 ConfigurationType="4"
160 InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
161 CharacterSet="1"
162 >
163 <Tool
164 Name="VCPreBuildEventTool"
165 />
166 <Tool
167 Name="VCCustomBuildTool"
168 />
169 <Tool
170 Name="VCXMLDataGeneratorTool"
171 />
172 <Tool
173 Name="VCWebServiceProxyGeneratorTool"
174 />
175 <Tool
176 Name="VCMIDLTool"
177 />
178 <Tool
179 Name="VCCLCompilerTool"
180 Optimization="0"
181 AdditionalIncludeDirectories="..\..\libraries\i686-win32\include;..\..\libraries\include\"
182 PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_USE_32BIT_TIME_T;LL_RELEASE;XML_STATIC;APR_DECLARE_STATIC"
183 RuntimeLibrary="0"
184 StructMemberAlignment="0"
185 TreatWChar_tAsBuiltInType="false"
186 ForceConformanceInForLoopScope="true"
187 UsePrecompiledHeader="0"
188 WarningLevel="3"
189 WarnAsError="true"
190 Detect64BitPortabilityProblems="false"
191 DebugInformationFormat="3"
192 />
193 <Tool
194 Name="VCManagedResourceCompilerTool"
195 />
196 <Tool
197 Name="VCResourceCompilerTool"
198 />
199 <Tool
200 Name="VCPreLinkEventTool"
201 />
202 <Tool
203 Name="VCLibrarianTool"
204 OutputFile="$(OutDir)/llcommon.lib"
205 />
206 <Tool
207 Name="VCALinkTool"
208 />
209 <Tool
210 Name="VCXDCMakeTool"
211 />
212 <Tool
213 Name="VCBscMakeTool"
214 />
215 <Tool
216 Name="VCFxCopTool"
217 />
218 <Tool
219 Name="VCPostBuildEventTool"
220 />
221 </Configuration>
222 </Configurations>
223 <References>
224 </References>
225 <Files>
226 <Filter
227 Name="Source Files"
228 Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
229 UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
230 >
231 <File
232 RelativePath=".\bitpack.cpp"
233 >
234 </File>
235 <File
236 RelativePath=".\llapp.cpp"
237 >
238 </File>
239 <File
240 RelativePath=".\llapr.cpp"
241 >
242 </File>
243 <File
244 RelativePath=".\llassettype.cpp"
245 >
246 </File>
247 <File
248 RelativePath=".\llbase64.cpp"
249 >
250 </File>
251 <File
252 RelativePath=".\llcommon.cpp"
253 >
254 </File>
255 <File
256 RelativePath=".\llcriticaldamp.cpp"
257 >
258 </File>
259 <File
260 RelativePath=".\lldate.cpp"
261 >
262 </File>
263 <File
264 RelativePath=".\llerror.cpp"
265 >
266 </File>
267 <File
268 RelativePath=".\llerrorthread.cpp"
269 >
270 </File>
271 <File
272 RelativePath=".\llevent.cpp"
273 >
274 </File>
275 <File
276 RelativePath=".\llfasttimer.cpp"
277 >
278 </File>
279 <File
280 RelativePath=".\llfile.cpp"
281 >
282 </File>
283 <File
284 RelativePath=".\llfixedbuffer.cpp"
285 >
286 </File>
287 <File
288 RelativePath=".\llformat.cpp"
289 >
290 </File>
291 <File
292 RelativePath=".\llframetimer.cpp"
293 >
294 </File>
295 <File
296 RelativePath=".\lllivefile.cpp"
297 >
298 </File>
299 <File
300 RelativePath=".\llmemory.cpp"
301 >
302 </File>
303 <File
304 RelativePath=".\llmemorystream.cpp"
305 >
306 </File>
307 <File
308 RelativePath=".\llmortician.cpp"
309 >
310 </File>
311 <File
312 RelativePath=".\llprocessor.cpp"
313 >
314 </File>
315 <File
316 RelativePath=".\llqueuedthread.cpp"
317 >
318 </File>
319 <File
320 RelativePath=".\llrun.cpp"
321 >
322 </File>
323 <File
324 RelativePath=".\llsd.cpp"
325 >
326 </File>
327 <File
328 RelativePath=".\llsdserialize.cpp"
329 >
330 </File>
331 <File
332 RelativePath=".\llsdserialize_xml.cpp"
333 >
334 </File>
335 <File
336 RelativePath=".\llsdutil.cpp"
337 >
338 </File>
339 <File
340 RelativePath=".\llsecondlifeurls.cpp"
341 >
342 </File>
343 <File
344 RelativePath=".\llstat.cpp"
345 >
346 </File>
347 <File
348 RelativePath=".\llstreamtools.cpp"
349 >
350 </File>
351 <File
352 RelativePath=".\llstring.cpp"
353 >
354 </File>
355 <File
356 RelativePath=".\llstringtable.cpp"
357 >
358 </File>
359 <File
360 RelativePath=".\llsys.cpp"
361 >
362 </File>
363 <File
364 RelativePath=".\llthread.cpp"
365 >
366 </File>
367 <File
368 RelativePath=".\lltimer.cpp"
369 >
370 </File>
371 <File
372 RelativePath=".\lluri.cpp"
373 >
374 </File>
375 <File
376 RelativePath=".\llworkerthread.cpp"
377 >
378 </File>
379 <File
380 RelativePath=".\metaclass.cpp"
381 >
382 </File>
383 <File
384 RelativePath=".\metaproperty.cpp"
385 >
386 </File>
387 <File
388 RelativePath=".\reflective.cpp"
389 >
390 </File>
391 <File
392 RelativePath=".\timing.cpp"
393 >
394 </File>
395 <File
396 RelativePath=".\u64.cpp"
397 >
398 </File>
399 </Filter>
400 <Filter
401 Name="Header Files"
402 Filter="h;hpp;hxx;hm;inl;inc;xsd"
403 UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
404 >
405 <File
406 RelativePath=".\bitpack.h"
407 >
408 </File>
409 <File
410 RelativePath=".\doublelinkedlist.h"
411 >
412 </File>
413 <File
414 RelativePath=".\imageids.h"
415 >
416 </File>
417 <File
418 RelativePath=".\indra_constants.h"
419 >
420 </File>
421 <File
422 RelativePath=".\linden_common.h"
423 >
424 </File>
425 <File
426 RelativePath=".\linked_lists.h"
427 >
428 </File>
429 <File
430 RelativePath=".\llagentconstants.h"
431 >
432 </File>
433 <File
434 RelativePath=".\llapp.h"
435 >
436 </File>
437 <File
438 RelativePath=".\llapr.h"
439 >
440 </File>
441 <File
442 RelativePath=".\llassettype.h"
443 >
444 </File>
445 <File
446 RelativePath=".\llassoclist.h"
447 >
448 </File>
449 <File
450 RelativePath=".\llavatarconstants.h"
451 >
452 </File>
453 <File
454 RelativePath=".\llbase64.h"
455 >
456 </File>
457 <File
458 RelativePath=".\llboost.h"
459 >
460 </File>
461 <File
462 RelativePath=".\llchat.h"
463 >
464 </File>
465 <File
466 RelativePath=".\llclickaction.h"
467 >
468 </File>
469 <File
470 RelativePath=".\llcommon.h"
471 >
472 </File>
473 <File
474 RelativePath=".\llcriticaldamp.h"
475 >
476 </File>
477 <File
478 RelativePath=".\lldarray.h"
479 >
480 </File>
481 <File
482 RelativePath=".\lldarrayptr.h"
483 >
484 </File>
485 <File
486 RelativePath=".\lldate.h"
487 >
488 </File>
489 <File
490 RelativePath=".\lldefs.h"
491 >
492 </File>
493 <File
494 RelativePath=".\lldlinked.h"
495 >
496 </File>
497 <File
498 RelativePath=".\lldqueueptr.h"
499 >
500 </File>
501 <File
502 RelativePath=".\llendianswizzle.h"
503 >
504 </File>
505 <File
506 RelativePath=".\llenum.h"
507 >
508 </File>
509 <File
510 RelativePath=".\llerror.h"
511 >
512 </File>
513 <File
514 RelativePath=".\llerrorcontrol.h"
515 >
516 </File>
517 <File
518 RelativePath=".\llerrorthread.h"
519 >
520 </File>
521 <File
522 RelativePath=".\llevent.h"
523 >
524 </File>
525 <File
526 RelativePath=".\llfasttimer.h"
527 >
528 </File>
529 <File
530 RelativePath=".\llfile.h"
531 >
532 </File>
533 <File
534 RelativePath=".\llfixedbuffer.h"
535 >
536 </File>
537 <File
538 RelativePath=".\llformat.h"
539 >
540 </File>
541 <File
542 RelativePath=".\llframecallbackmanager.h"
543 >
544 </File>
545 <File
546 RelativePath=".\llframetimer.h"
547 >
548 </File>
549 <File
550 RelativePath=".\llhash.h"
551 >
552 </File>
553 <File
554 RelativePath=".\llindexedqueue.h"
555 >
556 </File>
557 <File
558 RelativePath=".\lllinkedqueue.h"
559 >
560 </File>
561 <File
562 RelativePath=".\lllivefile.h"
563 >
564 </File>
565 <File
566 RelativePath=".\lllocalidhashmap.h"
567 >
568 </File>
569 <File
570 RelativePath=".\lllslconstants.h"
571 >
572 </File>
573 <File
574 RelativePath=".\llmap.h"
575 >
576 </File>
577 <File
578 RelativePath=".\llmemory.h"
579 >
580 </File>
581 <File
582 RelativePath=".\llmemorystream.h"
583 >
584 </File>
585 <File
586 RelativePath=".\llmortician.h"
587 >
588 </File>
589 <File
590 RelativePath=".\llnametable.h"
591 >
592 </File>
593 <File
594 RelativePath=".\llpagemem.h"
595 >
596 </File>
597 <File
598 RelativePath=".\llpreprocessor.h"
599 >
600 </File>
601 <File
602 RelativePath=".\llpriqueuemap.h"
603 >
604 </File>
605 <File
606 RelativePath=".\llprocessor.h"
607 >
608 </File>
609 <File
610 RelativePath=".\llptrskiplist.h"
611 >
612 </File>
613 <File
614 RelativePath=".\llptrskipmap.h"
615 >
616 </File>
617 <File
618 RelativePath=".\llqueuedthread.h"
619 >
620 </File>
621 <File
622 RelativePath=".\llrun.h"
623 >
624 </File>
625 <File
626 RelativePath=".\llsd.h"
627 >
628 </File>
629 <File
630 RelativePath=".\llsdserialize.h"
631 >
632 </File>
633 <File
634 RelativePath=".\llsdserialize_xml.h"
635 >
636 </File>
637 <File
638 RelativePath=".\llsdutil.h"
639 >
640 </File>
641 <File
642 RelativePath=".\llsecondlifeurls.h"
643 >
644 </File>
645 <File
646 RelativePath=".\llskiplist.h"
647 >
648 </File>
649 <File
650 RelativePath=".\llskipmap.h"
651 >
652 </File>
653 <File
654 RelativePath=".\llstat.h"
655 >
656 </File>
657 <File
658 RelativePath=".\llstatenums.h"
659 >
660 </File>
661 <File
662 RelativePath=".\llstl.h"
663 >
664 </File>
665 <File
666 RelativePath=".\llstreamtools.h"
667 >
668 </File>
669 <File
670 RelativePath=".\llstrider.h"
671 >
672 </File>
673 <File
674 RelativePath=".\llstring.h"
675 >
676 </File>
677 <File
678 RelativePath=".\llstringtable.h"
679 >
680 </File>
681 <File
682 RelativePath=".\llsys.h"
683 >
684 </File>
685 <File
686 RelativePath=".\llthread.h"
687 >
688 </File>
689 <File
690 RelativePath=".\lltimer.h"
691 >
692 </File>
693 <File
694 RelativePath=".\lluri.h"
695 >
696 </File>
697 <File
698 RelativePath=".\lluuidhashmap.h"
699 >
700 </File>
701 <File
702 RelativePath=".\llversion.h"
703 >
704 </File>
705 <File
706 RelativePath=".\llworkerthread.h"
707 >
708 </File>
709 <File
710 RelativePath=".\new_mem_ops.h"
711 >
712 </File>
713 <File
714 RelativePath=".\priqueue.h"
715 >
716 </File>
717 <File
718 RelativePath=".\processor.h"
719 >
720 </File>
721 <File
722 RelativePath=".\roles_constants.h"
723 >
724 </File>
725 <File
726 RelativePath=".\stdenums.h"
727 >
728 </File>
729 <File
730 RelativePath=".\stdtypes.h"
731 >
732 </File>
733 <File
734 RelativePath=".\string_table.h"
735 >
736 </File>
737 <File
738 RelativePath=".\timer.h"
739 >
740 </File>
741 <File
742 RelativePath=".\timing.h"
743 >
744 </File>
745 <File
746 RelativePath=".\u64.h"
747 >
748 </File>
749 </Filter>
750 <Filter
751 Name="Resource Files"
752 Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
753 UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
754 >
755 </Filter>
756 </Files>
757 <Globals>
758 </Globals>
759</VisualStudioProject>
diff --git a/linden/indra/llcommon/llerror.cpp b/linden/indra/llcommon/llerror.cpp
index 29f4500..57e098e 100644
--- a/linden/indra/llcommon/llerror.cpp
+++ b/linden/indra/llcommon/llerror.cpp
@@ -1,8 +1,9 @@
1/** 1/**
2 * @file llerror.cpp 2 * @file llerror.cpp
3 * @brief Function to crash. 3 * @date December 2006
4 * @brief error message system
4 * 5 *
5 * Copyright (c) 2001-2007, Linden Research, Inc. 6 * Copyright (c) 2006-2007, Linden Research, Inc.
6 * 7 *
7 * The source code in this file ("Source Code") is provided by Linden Lab 8 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0 9 * to you under the terms of the GNU General Public License, version 2.0
@@ -24,36 +25,1048 @@
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, 25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE. 26 * COMPLETENESS OR PERFORMANCE.
26 */ 27 */
28
27#include "linden_common.h" 29#include "linden_common.h"
28 30
29#include "llerror.h" 31#include "llerror.h"
32#include "llerrorcontrol.h"
33
34#include "llapp.h"
35#include "llapr.h"
36extern apr_thread_mutex_t *gLogMutexp;
37#include "llfile.h"
38#include "llfixedbuffer.h"
39#include "lllivefile.h"
40#include "llsd.h"
41#include "llsdserialize.h"
42
43#include <algorithm>
44#include <cctype>
45#include <map>
46#include <sstream>
47#if !LL_WINDOWS
48#include <stdio.h>
49#include <syslog.h>
50#endif
51#include <time.h>
52#if LL_WINDOWS
53#include <windows.h>
54#endif
55#include <vector>
56
57
58#ifdef __GNUC__
59#include <cxxabi.h>
60#endif
61
62namespace {
63#if !LL_WINDOWS
64 class RecordToSyslog : public LLError::Recorder
65 {
66 public:
67 RecordToSyslog(const std::string& identity)
68 : mIdentity(identity)
69 {
70 openlog(mIdentity.c_str(), LOG_CONS|LOG_PID, LOG_LOCAL0);
71 // we need to set the string from a local copy of the string
72 // since apparanetly openlog expects the const char* to remain
73 // valid even after it returns (presumably until closelog)
74 }
75
76 ~RecordToSyslog()
77 {
78 closelog();
79 }
80
81 virtual void recordMessage(LLError::ELevel level,
82 const std::string& message)
83 {
84 int syslogPriority = LOG_CRIT;
85 switch (level) {
86 case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break;
87 case LLError::LEVEL_INFO: syslogPriority = LOG_INFO; break;
88 case LLError::LEVEL_WARN: syslogPriority = LOG_WARNING; break;
89 case LLError::LEVEL_ERROR: syslogPriority = LOG_CRIT; break;
90 default: syslogPriority = LOG_CRIT;
91 }
92
93 syslog(syslogPriority, "%s", message.c_str());
94 }
95 private:
96 std::string mIdentity;
97 };
98#endif
99
100 class RecordToFile : public LLError::Recorder
101 {
102 public:
103 RecordToFile(const std::string& filename)
104 {
105 mFile.open(filename.c_str(), llofstream::out | llofstream::app);
106 if (!mFile)
107 {
108 llinfos << "Error setting log file to " << filename << llendl;
109 }
110 }
111
112 ~RecordToFile()
113 {
114 mFile.close();
115 }
116
117 bool okay() { return mFile; }
118
119 virtual bool wantsTime() { return true; }
120
121 virtual void recordMessage(LLError::ELevel level,
122 const std::string& message)
123 {
124 mFile << message << std::endl;
125 // mFile.flush();
126 // *FIX: should we do this?
127 }
128
129 private:
130 llofstream mFile;
131 };
132
133
134 class RecordToStderr : public LLError::Recorder
135 {
136 public:
137 RecordToStderr(bool timestamp) : mTimestamp(timestamp) { }
30 138
31LLErrorBuffer gErrorBuffer; 139 virtual bool wantsTime() { return mTimestamp; }
32LLErrorStream gErrorStream(&gErrorBuffer); 140
141 virtual void recordMessage(LLError::ELevel level,
142 const std::string& message)
143 {
144 fprintf(stderr, "%s\n", message.c_str());
145 }
146
147 private:
148 bool mTimestamp;
149 };
33 150
151 class RecordToFixedBuffer : public LLError::Recorder
152 {
153 public:
154 RecordToFixedBuffer(LLFixedBuffer& buffer) : mBuffer(buffer) { }
155
156 virtual void recordMessage(LLError::ELevel level,
157 const std::string& message)
158 {
159 mBuffer.addLine(message.c_str());
160 }
161
162 private:
163 LLFixedBuffer& mBuffer;
164 };
34 165
35void _llcrash_and_loop() 166#if LL_WINDOWS
167 class RecordToWinDebug: public LLError::Recorder
168 {
169 public:
170 virtual void recordMessage(LLError::ELevel level,
171 const std::string& message)
172 {
173 llutf16string utf16str =
174 wstring_to_utf16str(utf8str_to_wstring(message));
175 utf16str += '\n';
176 OutputDebugString(utf16str.c_str());
177 }
178 };
179#endif
180}
181
182
183namespace
36{ 184{
37 // Now, we go kaboom! 185 std::string className(const std::type_info& type)
38 U32* crash = NULL; 186 {
187#ifdef __GNUC__
188 // GCC: type_info::name() returns a mangled class name, must demangle
189
190 static size_t abi_name_len = 100;
191 static char* abi_name_buf = (char*)malloc(abi_name_len);
192 // warning: above is voodoo inferred from the GCC manual,
193 // do NOT change
194
195 int status;
196 // We don't use status, and shouldn't have to pass apointer to it
197 // but gcc 3.3 libstc++'s implementation of demangling is broken
198 // and fails without.
199
200 char* name = abi::__cxa_demangle(type.name(),
201 abi_name_buf, &abi_name_len, &status);
202 // this call can realloc the abi_name_buf pointer (!)
203
204 return name ? name : type.name();
39 205
40 *crash = 0; 206#elif LL_WINDOWS
207 // DevStudio: type_info::name() includes the text "class " at the start
41 208
42 while(TRUE) 209 static const std::string class_prefix = "class ";
210
211 std::string name = type.name();
212 std::string::size_type p = name.find(class_prefix);
213 if (p == std::string::npos)
214 {
215 return name;
216 }
217
218 return name.substr(p + class_prefix.size());
219
220#else
221 return type.name();
222#endif
223 }
224
225 std::string functionName(const std::string& preprocessor_name)
43 { 226 {
227#if LL_WINDOWS
228 // DevStudio: the __FUNCTION__ macro string includes
229 // the type and/or namespace prefixes
230
231 std::string::size_type p = preprocessor_name.rfind(':');
232 if (p == std::string::npos)
233 {
234 return preprocessor_name;
235 }
236 return preprocessor_name.substr(p + 1);
237
238#else
239 return preprocessor_name;
240#endif
241 }
242
243
244 class LogControlFile : public LLLiveFile
245 {
246 LOG_CLASS(LogControlFile);
247
248 public:
249 static LogControlFile& fromDirectory(const std::string& dir);
250
251 virtual void loadFile();
252
253 private:
254 LogControlFile(const std::string &filename)
255 : LLLiveFile(filename)
256 { }
257 };
258
259 LogControlFile& LogControlFile::fromDirectory(const std::string& dir)
260 {
261 std::string dirBase = dir + "/";
262 // NB: We have no abstraction in llcommon for the "proper"
263 // delimiter but it turns out that "/" works on all three platforms
264
265 std::string file = dirBase + "logcontrol-dev.xml";
266
267 llstat stat_info;
268 if (LLFile::stat(file.c_str(), &stat_info)) {
269 // NB: stat returns non-zero if it can't read the file, for example
270 // if it doesn't exist. LLFile has no better abstraction for
271 // testing for file existence.
272
273 file = dirBase + "logcontrol.xml";
274 }
275 return * new LogControlFile(file);
276 // NB: This instance is never freed
277 }
278
279 void LogControlFile::loadFile()
280 {
281 LLSD configuration;
282
283 {
284 llifstream file(filename().c_str());
285 if (file.is_open())
286 {
287 LLSDSerialize::fromXML(configuration, file);
288 }
289
290 if (configuration.isUndefined())
291 {
292 llwarns << filename() << " missing, ill-formed,"
293 " or simply undefined; not changing configuration"
294 << llendl;
295 return;
296 }
297 }
298
299 LLError::configure(configuration);
300 llinfos << "logging reconfigured from " << filename() << llendl;
301 }
302
303
304 typedef std::map<std::string, LLError::ELevel> LevelMap;
305 typedef std::vector<LLError::Recorder*> Recorders;
306 typedef std::vector<LLError::CallSite*> CallSiteVector;
307
308 class Globals
309 {
310 public:
311 std::ostringstream messageStream;
312 bool messageStreamInUse;
313
314 void addCallSite(LLError::CallSite&);
315 void invalidateCallSites();
316
317 static Globals& get();
318 // return the one instance of the globals
319
320 private:
321 CallSiteVector callSites;
322
323 Globals()
324 : messageStreamInUse(false)
325 { }
326
327 };
328
329 void Globals::addCallSite(LLError::CallSite& site)
330 {
331 callSites.push_back(&site);
332 }
44 333
45 // Loop forever, in case the crash didn't work? 334 void Globals::invalidateCallSites()
335 {
336 for (CallSiteVector::const_iterator i = callSites.begin();
337 i != callSites.end();
338 ++i)
339 {
340 (*i)->invalidate();
341 }
342
343 callSites.clear();
344 }
345
346 Globals& Globals::get()
347 {
348 /* This pattern, of returning a reference to a static function
349 variable, is to ensure that this global is constructed before
350 it is used, no matter what the global initializeation sequence
351 is.
352 See C++ FAQ Lite, sections 10.12 through 10.14
353 */
354 static Globals* globals = new Globals;
355 return *globals;
46 } 356 }
47} 357}
48 358
49LLScopedErrorLevel::LLScopedErrorLevel(LLErrorBuffer::ELevel error_level) 359namespace LLError
50{ 360{
51 mOrigErrorLevel = gErrorStream.getErrorLevel(); 361 class Settings
52 gErrorStream.setErrorLevel(error_level); 362 {
363 public:
364 bool printLocation;
365
366 LLError::ELevel defaultLevel;
367
368 LevelMap functionLevelMap;
369 LevelMap classLevelMap;
370 LevelMap fileLevelMap;
371
372 LLError::FatalFunction crashFunction;
373 LLError::TimeFunction timeFunction;
374
375 Recorders recorders;
376 Recorder* fileRecorder;
377 Recorder* fixedBufferRecorder;
378 std::string fileRecorderFileName;
379
380 int shouldLogCallCounter;
381
382 static Settings& get();
383
384 static void reset();
385 static Settings* saveAndReset();
386 static void restore(Settings*);
387
388 private:
389 Settings()
390 : printLocation(false),
391 defaultLevel(LLError::LEVEL_DEBUG),
392 crashFunction(NULL),
393 timeFunction(NULL),
394 fileRecorder(NULL),
395 fixedBufferRecorder(NULL),
396 shouldLogCallCounter(0)
397 { }
398
399 static Settings*& getPtr();
400 };
401
402 Settings& Settings::get()
403 {
404 Settings* p = getPtr();
405 if (!p)
406 {
407 reset();
408 p = getPtr();
409 }
410 return *p;
411 }
412
413 void Settings::reset()
414 {
415 Globals::get().invalidateCallSites();
416
417 Settings*& p = getPtr();
418 delete p;
419 p = new Settings();
420 }
421
422 Settings* Settings::saveAndReset()
423 {
424 Globals::get().invalidateCallSites();
425
426 Settings*& p = getPtr();
427 Settings* originalSettings = p;
428 p = new Settings();
429 return originalSettings;
430 }
431
432 void Settings::restore(Settings* originalSettings)
433 {
434 Globals::get().invalidateCallSites();
435
436 Settings*& p = getPtr();
437 delete p;
438 p = originalSettings;
439 }
440
441 Settings*& Settings::getPtr()
442 {
443 static Settings* currentSettings = NULL;
444 return currentSettings;
445 }
53} 446}
54 447
448namespace LLError
449{
450 CallSite::CallSite(ELevel level,
451 const char* file, int line,
452 const std::type_info& class_info, const char* function)
453 : mLevel(level), mFile(file), mLine(line),
454 mClassInfo(class_info), mFunction(function),
455 mCached(false), mShouldLog(false)
456 { }
457
458
459 void CallSite::invalidate()
460 { mCached = false; }
461}
462
463namespace
464{
465 bool shouldLogToStderr()
466 {
467#if LL_DARWIN
468 // On Mac OS X, stderr from apps launched from the Finder goes to the
469 // console log. It's generally considered bad form to spam too much
470 // there.
471
472 // If stdin is a tty, assume the user launched from the command line and
473 // therefore wants to see stderr. Otherwise, assume we've been launched
474 // from the finder and shouldn't spam stderr.
475 return isatty(0);
476#else
477 return true;
478#endif
479 }
480
481 bool stderrLogWantsTime()
482 {
483#if LL_WINDOWS
484 return false;
485#else
486 return true;
487#endif
488 }
489
490
491 void commonInit(const std::string& dir)
492 {
493 LLError::Settings::reset();
494
495 LLError::setDefaultLevel(LLError::LEVEL_INFO);
496 LLError::setFatalFunction(LLError::crashAndLoop);
497 LLError::setTimeFunction(LLError::utcTime);
498
499 if (shouldLogToStderr())
500 {
501 LLError::addRecorder(new RecordToStderr(stderrLogWantsTime()));
502 }
503
504#if LL_WINDOWS
505 LLError::addRecorder(new RecordToWinDebug);
506#endif
55 507
56LLScopedErrorLevel::~LLScopedErrorLevel() 508 LogControlFile& e = LogControlFile::fromDirectory(dir);
509 e.addToEventTimer();
510 }
511}
512
513namespace LLError
57{ 514{
58 gErrorStream.setErrorLevel(mOrigErrorLevel); 515 void initForServer(const std::string& identity)
516 {
517 std::string dir = LLApp::instance()->getOption("configdir");
518 commonInit(dir);
519#if !LL_WINDOWS
520 addRecorder(new RecordToSyslog(identity));
521#endif
522 }
523
524 void initForApplication(const std::string& dir)
525 {
526 commonInit(dir);
527 }
528
529 void setPrintLocation(bool print)
530 {
531 Settings& s = Settings::get();
532 s.printLocation = print;
533 }
534
535 void setFatalFunction(FatalFunction f)
536 {
537 Settings& s = Settings::get();
538 s.crashFunction = f;
539 }
540
541 void setTimeFunction(TimeFunction f)
542 {
543 Settings& s = Settings::get();
544 s.timeFunction = f;
545 }
546
547 void setDefaultLevel(ELevel level)
548 {
549 Globals& g = Globals::get();
550 Settings& s = Settings::get();
551 g.invalidateCallSites();
552 s.defaultLevel = level;
553 }
554
555 void setFunctionLevel(const std::string& function_name, ELevel level)
556 {
557 Globals& g = Globals::get();
558 Settings& s = Settings::get();
559 g.invalidateCallSites();
560 s.functionLevelMap[function_name] = level;
561 }
562
563 void setClassLevel(const std::string& class_name, ELevel level)
564 {
565 Globals& g = Globals::get();
566 Settings& s = Settings::get();
567 g.invalidateCallSites();
568 s.classLevelMap[class_name] = level;
569 }
570
571 void setFileLevel(const std::string& file_name, ELevel level)
572 {
573 Globals& g = Globals::get();
574 Settings& s = Settings::get();
575 g.invalidateCallSites();
576 s.fileLevelMap[file_name] = level;
577 }
59} 578}
579
580namespace {
581 LLError::ELevel decodeLevel(std::string name)
582 {
583 static LevelMap level_names;
584 if (level_names.empty())
585 {
586 level_names["ALL"] = LLError::LEVEL_ALL;
587 level_names["DEBUG"] = LLError::LEVEL_DEBUG;
588 level_names["INFO"] = LLError::LEVEL_INFO;
589 level_names["WARN"] = LLError::LEVEL_WARN;
590 level_names["ERROR"] = LLError::LEVEL_ERROR;
591 level_names["NONE"] = LLError::LEVEL_NONE;
592 }
593
594 std::transform(name.begin(), name.end(), name.begin(), toupper);
595
596 LevelMap::const_iterator i = level_names.find(name);
597 if (i == level_names.end())
598 {
599 llwarns << "unrecognized logging level: '" << name << "'" << llendl;
600 return LLError::LEVEL_INFO;
601 }
602
603 return i->second;
604 }
605
606 void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level)
607 {
608 LLSD::array_const_iterator i, end;
609 for (i = list.beginArray(), end = list.endArray(); i != end; ++i)
610 {
611 map[*i] = level;
612 }
613 }
614}
615
616namespace LLError
617{
618 void configure(const LLSD& config)
619 {
620 Globals& g = Globals::get();
621 Settings& s = Settings::get();
622
623 g.invalidateCallSites();
624 s.functionLevelMap.clear();
625 s.classLevelMap.clear();
626 s.fileLevelMap.clear();
627
628 setPrintLocation(config["print-location"]);
629 setDefaultLevel(decodeLevel(config["default-level"]));
630
631 LLSD sets = config["settings"];
632 LLSD::array_const_iterator a, end;
633 for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a)
634 {
635 const LLSD& entry = *a;
636
637 ELevel level = decodeLevel(entry["level"]);
638
639 setLevels(s.functionLevelMap, entry["functions"], level);
640 setLevels(s.classLevelMap, entry["classes"], level);
641 setLevels(s.fileLevelMap, entry["files"], level);
642 }
643 }
644}
645
646
647namespace LLError
648{
649 Recorder::~Recorder()
650 { }
651
652 // virtual
653 bool Recorder::wantsTime()
654 { return false; }
655
656
657
658 void addRecorder(Recorder* recorder)
659 {
660 if (recorder == NULL)
661 {
662 return;
663 }
664 Settings& s = Settings::get();
665 s.recorders.push_back(recorder);
666 }
667
668 void removeRecorder(Recorder* recorder)
669 {
670 if (recorder == NULL)
671 {
672 return;
673 }
674 Settings& s = Settings::get();
675 s.recorders.erase(
676 std::remove(s.recorders.begin(), s.recorders.end(), recorder),
677 s.recorders.end());
678 }
679}
680
681namespace LLError
682{
683 void logToFile(const std::string& file_name)
684 {
685 LLError::Settings& s = LLError::Settings::get();
686
687 removeRecorder(s.fileRecorder);
688 delete s.fileRecorder;
689 s.fileRecorder = NULL;
690 s.fileRecorderFileName.clear();
691
692 if (file_name.empty())
693 {
694 return;
695 }
696
697 RecordToFile* f = new RecordToFile(file_name);
698 if (!f->okay())
699 {
700 delete f;
701 return;
702 }
703
704 s.fileRecorderFileName = file_name;
705 s.fileRecorder = f;
706 addRecorder(f);
707 }
708
709 void logToFixedBuffer(LLFixedBuffer* fixedBuffer)
710 {
711 LLError::Settings& s = LLError::Settings::get();
712
713 removeRecorder(s.fixedBufferRecorder);
714 delete s.fixedBufferRecorder;
715 s.fixedBufferRecorder = NULL;
716
717 if (!fixedBuffer)
718 {
719 return;
720 }
721
722 s.fixedBufferRecorder = new RecordToFixedBuffer(*fixedBuffer);
723 addRecorder(s.fixedBufferRecorder);
724 }
725
726 std::string logFileName()
727 {
728 LLError::Settings& s = LLError::Settings::get();
729 return s.fileRecorderFileName;
730 }
731}
732
733namespace
734{
735 void writeToRecorders(LLError::ELevel level, const std::string& message)
736 {
737 LLError::Settings& s = LLError::Settings::get();
738
739 std::string messageWithTime;
740
741 for (Recorders::const_iterator i = s.recorders.begin();
742 i != s.recorders.end();
743 ++i)
744 {
745 LLError::Recorder* r = *i;
746
747 if (r->wantsTime() && s.timeFunction != NULL)
748 {
749 if (messageWithTime.empty())
750 {
751 messageWithTime = s.timeFunction() + " " + message;
752 }
753
754 r->recordMessage(level, messageWithTime);
755 }
756 else
757 {
758 r->recordMessage(level, message);
759 }
760 }
761 }
762}
763
764
765/*
766Recorder formats:
767
768$type = "ERROR" | "WARNING" | "ALERT" | "INFO" | "DEBUG"
769$loc = "$file($line)"
770$msg = "$loc : " if FATAL or printing loc
771 "" otherwise
772$msg += "$type: "
773$msg += contents of stringstream
774
775$time = "%Y-%m-%dT%H:%M:%SZ" if UTC
776 or "%Y-%m-%dT%H:%M:%S %Z" if local
777
778syslog: "$msg"
779file: "$time $msg\n"
780stderr: "$time $msg\n" except on windows, "$msg\n"
781fixedbuf: "$msg"
782winddebug: "$msg\n"
783
784Note: if FATAL, an additional line gets logged first, with $msg set to
785 "$loc : error"
786
787You get:
788 llfoo.cpp(42) : error
789 llfoo.cpp(42) : ERROR: something
790
791*/
792
793namespace {
794 bool checkLevelMap(const LevelMap& map, const std::string& key,
795 LLError::ELevel& level)
796 {
797 LevelMap::const_iterator i = map.find(key);
798 if (i == map.end())
799 {
800 return false;
801 }
802
803 level = i->second;
804 return true;
805 }
806
807 class LogLock
808 {
809 public:
810 LogLock();
811 ~LogLock();
812 bool ok() const { return mOK; }
813 private:
814 bool mLocked;
815 bool mOK;
816 };
817
818 LogLock::LogLock()
819 : mLocked(false), mOK(false)
820 {
821 if (!gLogMutexp)
822 {
823 mOK = true;
824 return;
825 }
826
827 const int MAX_RETRIES = 5;
828 for (int attempts = 0; attempts < MAX_RETRIES; ++attempts)
829 {
830 apr_status_t s = apr_thread_mutex_trylock(gLogMutexp);
831 if (!APR_STATUS_IS_EBUSY(s))
832 {
833 mLocked = true;
834 mOK = true;
835 return;
836 }
837
838 ms_sleep(1);
839 //apr_thread_yield();
840 // Just yielding won't necessarily work, I had problems with
841 // this on Linux - doug 12/02/04
842 }
843
844 // We're hosed, we can't get the mutex. Blah.
845 std::cerr << "LogLock::LogLock: failed to get mutex for log"
846 << std::endl;
847 }
848
849 LogLock::~LogLock()
850 {
851 if (mLocked)
852 {
853 apr_thread_mutex_unlock(gLogMutexp);
854 }
855 }
856}
857
858namespace LLError
859{
860 bool Log::shouldLog(CallSite& site)
861 {
862 LogLock lock;
863 if (!lock.ok())
864 {
865 return false;
866 }
867
868 Globals& g = Globals::get();
869 Settings& s = Settings::get();
870
871 s.shouldLogCallCounter += 1;
872
873 std::string class_name = className(site.mClassInfo);
874 std::string function_name = functionName(site.mFunction);
875 if (site.mClassInfo != typeid(NoClassInfo))
876 {
877 function_name = class_name + "::" + function_name;
878 }
879
880 ELevel compareLevel = s.defaultLevel;
881
882 checkLevelMap(s.functionLevelMap, function_name, compareLevel)
883 || checkLevelMap(s.classLevelMap, class_name, compareLevel)
884 || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel);
885
886 site.mCached = true;
887 g.addCallSite(site);
888 return site.mShouldLog = site.mLevel >= compareLevel;
889 }
890
891
892 std::ostringstream* Log::out()
893 {
894 LogLock lock;
895 if (lock.ok())
896 {
897 Globals& g = Globals::get();
898
899 if (!g.messageStreamInUse)
900 {
901 g.messageStreamInUse = true;
902 return &g.messageStream;
903 }
904 }
905
906 return new std::ostringstream;
907 }
908
909 void Log::flush(std::ostringstream* out, const CallSite& site)
910 {
911 LogLock lock;
912 if (!lock.ok())
913 {
914 return;
915 }
916
917 Globals& g = Globals::get();
918 Settings& s = Settings::get();
919
920 std::string message = out->str();
921 if (out == &g.messageStream)
922 {
923 g.messageStream.clear();
924 g.messageStream.str("");
925 g.messageStreamInUse = false;
926 }
927 else
928 {
929 delete out;
930 }
931
932 if (site.mLevel == LEVEL_ERROR)
933 {
934 std::ostringstream fatalMessage;
935 fatalMessage << abbreviateFile(site.mFile)
936 << "(" << site.mLine << ") : error";
937
938 writeToRecorders(site.mLevel, fatalMessage.str());
939 }
940
941
942 std::ostringstream prefix;
943
944 switch (site.mLevel)
945 {
946 case LEVEL_DEBUG: prefix << "DEBUG: "; break;
947 case LEVEL_INFO: prefix << "INFO: "; break;
948 case LEVEL_WARN: prefix << "WARNING: "; break;
949 case LEVEL_ERROR: prefix << "ERROR: "; break;
950 default: prefix << "XXX: "; break;
951 };
952
953 if (s.printLocation)
954 {
955 prefix << abbreviateFile(site.mFile)
956 << "(" << site.mLine << ") : ";
957 }
958
959 if (message.find(functionName(site.mFunction)) == std::string::npos)
960 {
961 #if LL_WINDOWS
962 // DevStudio: __FUNCTION__ already includes the full class name
963 #else
964 if (site.mClassInfo != typeid(NoClassInfo))
965 {
966 prefix << className(site.mClassInfo) << "::";
967 }
968 #endif
969 prefix << site.mFunction << ": ";
970 }
971
972 prefix << message;
973 message = prefix.str();
974
975 writeToRecorders(site.mLevel, message);
976
977 if (site.mLevel == LEVEL_ERROR && s.crashFunction)
978 {
979 s.crashFunction(message);
980 }
981 }
982}
983
984
985
986
987namespace LLError
988{
989 Settings* saveAndResetSettings()
990 {
991 return Settings::saveAndReset();
992 }
993
994 void restoreSettings(Settings* s)
995 {
996 return Settings::restore(s);
997 }
998
999 std::string removePrefix(std::string& s, const std::string& p)
1000 {
1001 std::string::size_type where = s.find(p);
1002 if (where == std::string::npos)
1003 {
1004 return s;
1005 }
1006
1007 return std::string(s, where + p.size());
1008 }
1009
1010 void replaceChar(std::string& s, char old, char replacement)
1011 {
1012 std::string::size_type i = 0;
1013 std::string::size_type len = s.length();
1014 for ( ; i < len; i++ )
1015 {
1016 if (s[i] == old)
1017 {
1018 s[i] = replacement;
1019 }
1020 }
1021 }
1022
1023 std::string abbreviateFile(const std::string& filePath)
1024 {
1025 std::string f = filePath;
1026#if LL_WINDOWS
1027 replaceChar(f, '\\', '/');
1028#endif
1029 static std::string indra_prefix = "indra/";
1030 f = removePrefix(f, indra_prefix);
1031
1032#if LL_DARWIN
1033 static std::string newview_prefix = "newview/../";
1034 f = removePrefix(f, newview_prefix);
1035#endif
1036
1037 return f;
1038 }
1039
1040 int shouldLogCallCount()
1041 {
1042 Settings& s = Settings::get();
1043 return s.shouldLogCallCounter;
1044 }
1045
1046 void crashAndLoop(const std::string& message)
1047 {
1048 // Now, we go kaboom!
1049 int* crash = NULL;
1050
1051 *crash = 0;
1052
1053 while(true)
1054 {
1055 // Loop forever, in case the crash didn't work?
1056 }
1057 }
1058
1059 std::string utcTime()
1060 {
1061 time_t now = time(NULL);
1062 const size_t BUF_SIZE = 64;
1063 char time_str[BUF_SIZE]; /* Flawfinder: ignore */
1064
1065 int chars = strftime(time_str, BUF_SIZE,
1066 "%Y-%m-%dT%H:%M:%SZ",
1067 gmtime(&now));
1068
1069 return chars ? time_str : "time error";
1070 }
1071}
1072
diff --git a/linden/indra/llcommon/llerror.h b/linden/indra/llcommon/llerror.h
index 04e8eee..1285491 100644
--- a/linden/indra/llcommon/llerror.h
+++ b/linden/indra/llcommon/llerror.h
@@ -1,8 +1,9 @@
1/** 1/**
2 * @file llerror.h 2 * @file llerror.h
3 * @brief Constants, functions, and macros for logging and runtime errors. 3 * @date December 2006
4 * @brief error message system
4 * 5 *
5 * Copyright (c) 2001-2007, Linden Research, Inc. 6 * Copyright (c) 2006-2007, Linden Research, Inc.
6 * 7 *
7 * The source code in this file ("Source Code") is provided by Linden Lab 8 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0 9 * to you under the terms of the GNU General Public License, version 2.0
@@ -29,209 +30,208 @@
29#define LL_LLERROR_H 30#define LL_LLERROR_H
30 31
31#include <sstream> 32#include <sstream>
32#include <stdio.h> 33#include <typeinfo>
33#include <stdarg.h> 34
34 35#include "llerrorlegacy.h"
35#include "llerrorstream.h" 36
36#include "llerrorbuffer.h" 37
37 38/* Error Logging Facility
38// Specific error codes 39
39const S32 LL_ERR_NOERR = 0; 40 Information for most users:
40const S32 LL_ERR_ASSET_REQUEST_FAILED = -1; 41
41//const S32 LL_ERR_ASSET_REQUEST_INVALID = -2; 42 Code can log messages with constuctions like this:
42const S32 LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3; 43
43const S32 LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4; 44 llinfos << "request to fizzbip agent " << agent_id
44const S32 LL_ERR_INSUFFICIENT_PERMISSIONS = -5; 45 << " denied due to timeout" << llendl;
45const S32 LL_ERR_EOF = -39; 46
46const S32 LL_ERR_CANNOT_OPEN_FILE = -42; 47 Messages can be logged to one of four increasing levels of concern,
47const S32 LL_ERR_FILE_NOT_FOUND = -43; 48 using one of four "streams":
48const S32 LL_ERR_FILE_EMPTY = -44; 49
49const S32 LL_ERR_TCP_TIMEOUT = -23016; 50 lldebugs - debug messages that are normally supressed
50const S32 LL_ERR_CIRCUIT_GONE = -23017; 51 llinfos - informational messages that are normall shown
51 52 llwarns - warning messages that singal a problem
52// Error types 53 llerrs - error messages that are major, unrecoverable failures
53 54
54#define LLERR_IMAGE (1 << 1) // Image requests 55 The later (llerrs) automatically crashes the process after the message
55#define LLERR_MESSAGE (1 << 2) // Messaging 56 is logged.
56#define LLERR_PERF (1 << 3) // Performance 57
57#define LLERR_SQL (1 << 4) // SQL statements 58 Note that these "streams" are actually #define magic. Rules for use:
58#define LLERR_DOUG (1 << 5) // Doug's debugging 59 * they cannot be used as normal streams, only to start a message
59#define LLERR_USER_INPUT (1 << 6) // Keyboard and mouse 60 * messages written to them MUST be terminated with llendl
60#define LLERR_TIMING (1 << 7) // Verbose time info 61 * between the opening and closing, the << operator is indeed
61#define LLERR_TASK (1 << 8) // Tracking tasks 62 writing onto a std::ostream, so all conversions and stream
62#define LLERR_MSG_HANDLER (1 << 9) // 63 formating are available
63#define LLERR_CIRCUIT_INFO (1 << 10) // Message system circuit info 64
64#define LLERR_PHYSICS (1 << 11) // physics 65 These messages are automatically logged with function name, and (if enabled)
65#define LLERR_VFS (1 << 12) // VFS 66 file and line of the message. (Note: Existing messages that already include
66const U32 LLERR_ALL = 0xffff; 67 the function name don't get name printed twice.)
67const U32 LLERR_NONE = 0x0; 68
68 69 If you have a class, adding LOG_CLASS line to the declaration will cause
69// Define one of these for different error levels in release... 70 all messages emitted from member functions (normal and static) to be tagged
70// #define RELEASE_SHOW_DEBUG // Define this if you want your release builds to show lldebug output. 71 with the proper class name as well as the function name:
71#define RELEASE_SHOW_INFO // Define this if you want your release builds to show llinfo output 72
72#define RELEASE_SHOW_WARN // Define this if you want your release builds to show llwarn output. 73 class LLFoo
73 74 {
74 75 LOG_CLASS(LLFoo);
75////////////////////////////////////////// 76 public:
76// 77 ...
77// Implementation - ignore 78 };
78// 79
79// 80 void LLFoo::doSomething(int i)
80#ifdef _DEBUG 81 {
81#define SHOW_DEBUG 82 if (i > 100)
82#define SHOW_WARN 83 {
83#define SHOW_INFO 84 llwanrs << "called with a big value for i: " << i << llendl;
84#define SHOW_ASSERT 85 }
85#else // _DEBUG 86 ...
86 87 }
87#ifdef RELEASE_SHOW_DEBUG 88
88#define SHOW_DEBUG 89 will result in messages like:
89#endif 90
90 91 WARN: LLFoo::doSomething: called with a big value for i: 283
91#ifdef RELEASE_SHOW_WARN 92
92#define SHOW_WARN 93 Which messages are logged and which are supressed can be controled at run
93#endif 94 time from the live file logcontrol.xml based on function, class and/or
94 95 source file. See etc/logcontrol-dev.xml for details.
95#ifdef RELEASE_SHOW_INFO 96
96#define SHOW_INFO 97 Lastly, logging is now very efficient in both compiled code and execution
97#endif 98 when skipped. There is no need to wrap messages, even debugging ones, in
98 99 #ifdef _DEBUG constructs. lldebugs messages are compiled into all builds,
99#ifdef RELEASE_SHOW_ASSERT 100 even release. Which means you can use them to help debug even when deployed
100#define SHOW_ASSERT 101 to a real grid.
101#endif 102*/
102 103
103#endif // _DEBUG 104namespace LLError
104
105
106extern LLErrorStream gErrorStream;
107
108
109// LL Error macros
110//
111// Usage:
112//
113// llerrs << "An error, oh my!" << variable << endl;
114// llwarns << "Another error, fuck me!" << variable << endl;
115// llwarnst(LLERR_IMAGE) << "Debug, mother fucker" << endl;
116//
117// NOTE: The output format of filename(lineno): is so that MS DevStudio
118// can parse the output and automatically jump to that location
119
120inline std::string llerrno_string(int errnum)
121{ 105{
122 std::stringstream res; 106 enum ELevel
123 res << "error(" << errnum << "):" << strerror(errnum) << " "; 107 {
124 return res.str(); 108 LEVEL_ALL = 0,
109 // used to indicate that all messagess should be logged
110
111 LEVEL_DEBUG = 0,
112 LEVEL_INFO = 1,
113 LEVEL_WARN = 2,
114 LEVEL_ERROR = 3, // used to be called FATAL
115
116 LEVEL_NONE = 4
117 // not really a level
118 // used to indicate that no messages should be logged
119 };
120
121 /* Macro support
122 The classes CallSite and Log are used by the logging macros below.
123 They are not intended for general use.
124 */
125
126 class CallSite;
127
128 class Log
129 {
130 public:
131 static bool shouldLog(CallSite&);
132 static std::ostringstream* out();
133 static void flush(std::ostringstream*, const CallSite&);
134 };
135
136 class CallSite
137 {
138 // Represents a specific place in the code where a message is logged
139 // This is public because it is used by the macros below. It is not
140 // intended for public use.
141 public:
142 CallSite(ELevel, const char* file, int line,
143 const std::type_info& class_info, const char* function);
144
145 bool shouldLog()
146 { return mCached ? mShouldLog : Log::shouldLog(*this); }
147 // this member function needs to be in-line for efficiency
148
149 void invalidate();
150
151 private:
152 // these describe the call site and never change
153 const ELevel mLevel;
154 const char* const mFile;
155 const int mLine;
156 const std::type_info& mClassInfo;
157 const char* const mFunction;
158
159 // these implement a cache of the call to shouldLog()
160 bool mCached;
161 bool mShouldLog;
162
163 friend class Log;
164 };
165
166
167 class End { };
168 inline std::ostream& operator<<(std::ostream& s, const End&)
169 { return s; }
170 // used to indicate the end of a message
171
172 class NoClassInfo { };
173 // used to indicate no class info known for logging
125} 174}
126 175
127inline std::string llerror_file_line(const char* file, S32 line)
128{
129 std::stringstream res;
130 res << file << "(" <<line << ")";
131 return res.str();
132}
133 176
134// Used to throw an error which is always causes a system halt.
135#define llerrs if (gErrorStream.isEnabledFor(LLErrorBuffer::FATAL)) \
136 { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::FATAL; \
137 llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : error\n"; \
138 llerror_oss << "ERROR: " << llerror_file_line(__FILE__, __LINE__) << " "
139
140// Used to show warnings
141#define llwarns if (gErrorStream.isEnabledFor(LLErrorBuffer::WARN)) \
142 { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::WARN; \
143 if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : WARNING: "; \
144 else llerror_oss << "WARNING: "; \
145 llerror_oss
146
147// Alerts are for serious non-fatal situations that are not supposed to happen and need to alert someone
148#define llalerts if (gErrorStream.isEnabledFor(LLErrorBuffer::WARN)) \
149 { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::WARN; \
150 if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : ALERT: "; \
151 else llerror_oss << "ALERT: "; \
152 llerror_oss
153
154// Used to show informational messages that don't get disabled
155#define llinfos if (gErrorStream.isEnabledFor(LLErrorBuffer::INFO)) \
156 { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::INFO; \
157 if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : INFO: "; \
158 else llerror_oss << "INFO: "; \
159 llerror_oss
160
161#define llinfost(type) if (gErrorStream.isEnabledFor(LLErrorBuffer::INFO, type)) \
162 { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::INFO; \
163 if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : INFO: "; \
164 else llerror_oss << "INFO: [" << #type << "] "; \
165 llerror_oss
166
167// Used for general debugging output
168#define lldebugs if (gErrorStream.isEnabledFor(LLErrorBuffer::DEBUG)) \
169 { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::DEBUG; \
170 if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : DEBUG: "; \
171 else llerror_oss << "DEBUG: "; \
172 llerror_oss
173
174#define lldebugst(type) if (gErrorStream.isEnabledFor(LLErrorBuffer::DEBUG, type)) \
175 { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::DEBUG; \
176 if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : DEBUG: "; \
177 else llerror_oss << "DEBUG: [" << #type << "] "; \
178 llerror_oss
179
180#define llendl std::endl; gErrorStream.crashOnError(llerror_oss, llerror_level); }
181#define llendflush std::endl << std::flush; gErrorStream.crashOnError(llerror_oss, llerror_level); }
182#define llcont llerror_oss
183
184#define llerror(msg, num) llerrs << "Error # " << num << ": " << msg << llendl;
185
186#define llwarning(msg, num) llwarns << "Warning # " << num << ": " << msg << llendl;
187
188#ifdef SHOW_ASSERT
189#define llassert(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
190#else
191#define llassert(func)
192#endif
193#define llassert_always(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
194
195#ifdef SHOW_ASSERT
196#define llverify(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
197#else
198#define llverify(func) (func); // get rid of warning C4189
199#endif
200
201// handy compile-time assert - enforce those template parameters!
202#define cassert(expn) typedef char __C_ASSERT__[(expn)?1:-1]
203
204// Makes the app go down in flames, but on purpose!
205void _llcrash_and_loop();
206
207// Use as follows:
208// llinfos << llformat("Test:%d (%.2f %.2f)", idx, x, y) << llendl;
209//
210// *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun)
211// should perhaps be replaced with boost::format.
212inline std::string llformat(const char *fmt, ...)
213{
214 char tstr[1024]; /* Flawfinder: ignore */
215 va_list va;
216 va_start(va, fmt);
217#if LL_WINDOWS
218 _vsnprintf(tstr, 1024, fmt, va);
219#else
220 vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */
221#endif
222 va_end(va);
223 return std::string(tstr);
224}
225 177
226// Helper class to temporarily change error level for the current scope. 178/*
227class LLScopedErrorLevel 179 Class type information for logging
228{ 180 */
229public: 181
230 LLScopedErrorLevel(LLErrorBuffer::ELevel error_level); 182#define LOG_CLASS(s) typedef s _LL_CLASS_TO_LOG
231 ~LLScopedErrorLevel(); 183 // Declares class to tag logged messages with.
232 184 // See top of file for example of how to use this
233private: 185
234 LLErrorBuffer::ELevel mOrigErrorLevel; 186typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
235}; 187 // Outside a class declartion, or in class without LOG_CLASS(), this
236 188 // typedef causes the messages to not be associated with any class.
189
190
191
192
193
194/*
195 Error Logging Macros
196 See top of file for common usage.
197*/
198
199#define lllog(level) \
200 { \
201 static LLError::CallSite _site( \
202 level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__);\
203 if (_site.shouldLog()) \
204 { \
205 std::ostringstream* _out = LLError::Log::out(); \
206 (*_out)
207
208#define llendl \
209 LLError::End(); \
210 LLError::Log::flush(_out, _site); \
211 } \
212 }
213
214#define llinfos lllog(LLError::LEVEL_INFO)
215#define lldebugs lllog(LLError::LEVEL_DEBUG)
216#define llwarns lllog(LLError::LEVEL_WARN)
217#define llerrs lllog(LLError::LEVEL_ERROR)
218
219#define llcont (*_out)
220 /*
221 Use this construct if you need to do computation in the middle of a
222 message:
223
224 llinfos << "the agent " << agend_id;
225 switch (f)
226 {
227 case FOP_SHRUGS: llcont << "shrugs"; break;
228 case FOP_TAPS: llcont << "points at " << who; break;
229 case FOP_SAYS: llcont << "says " << message; break;
230 }
231 llcont << " for " << t << " seconds" << llendl;
232
233 Such computation is done iff the message will be logged.
234 */
235
236
237#endif // LL_LLERROR_H 237#endif // LL_LLERROR_H
diff --git a/linden/indra/llcommon/llerrorbuffer.cpp b/linden/indra/llcommon/llerrorbuffer.cpp
deleted file mode 100644
index 9de4616..0000000
--- a/linden/indra/llcommon/llerrorbuffer.cpp
+++ /dev/null
@@ -1,279 +0,0 @@
1/**
2 * @file llerrorbuffer.cpp
3 *
4 * Copyright (c) 2002-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28
29#include "llerrorbuffer.h"
30#include "llfixedbuffer.h"
31
32#include <fstream>
33#include <string.h>
34
35#if LL_WINDOWS
36# define WIN32_LEAN_AND_MEAN
37# include <winsock2.h>
38# include <windows.h> // for OutputDebugString
39#else
40# include <syslog.h>
41# include <stdio.h>
42#endif
43
44#include <time.h>
45
46// In order to compile in Visual C++ 6.0, you must use std:: in the header, and then
47// use the std namespace in the cpp. Otherwise, you'll break the (very) fragile C++ parser.
48using namespace std;
49
50LLErrorBuffer::LLErrorBuffer()
51: streambuf(),
52 mFile(NULL),
53 mBuf(),
54 mFixedBuf(NULL),
55 mErrorActive(TRUE),
56 mErrorTimestamp(TRUE),
57 mFileActive(FALSE),
58 mSyslogActive(TRUE),
59 mWinDebugActive(TRUE),
60 mElevatedRemote(FALSE),
61 mIsUTC(TRUE),
62 mLevel(DEBUG),
63 mPriority(DEBUG)
64{
65 mFilename[0] = '\0';
66#if LL_WINDOWS
67 // by default, turn off timestamps in the debug log on windows
68 mErrorTimestamp = FALSE;
69#endif
70}
71
72LLErrorBuffer::~LLErrorBuffer()
73{
74 delete mFile;
75 mFile = NULL;
76}
77
78#if !LL_WINDOWS
79int LLErrorBuffer::ELevelToSyslogPriority(const ELevel l)
80{
81 switch(l)
82 {
83 case DEBUG:
84 return LOG_DEBUG;
85 case INFO:
86 switch(mElevatedRemote)
87 {
88 case TRUE: return LOG_NOTICE;
89 default: return LOG_INFO;
90 }
91 case WARN:
92 return LOG_WARNING;
93 case FATAL:
94 return LOG_CRIT;
95 default:
96 return LOG_CRIT;
97 }
98 return LOG_CRIT;
99}
100#endif // LL_WINDOWS
101
102BOOL LLErrorBuffer::setFile(const char *filename)
103{
104 if (mFile == NULL)
105 {
106 mFile = new llofstream();
107 }
108 if (mFile->is_open())
109 {
110 mFile->close();
111 }
112 if (filename == NULL)
113 {
114 llwarns << "Input filename is NULL!!" << llendl;
115 return FALSE;
116 }
117 mFile->open(filename, llofstream::out | llofstream::app); /* Flawfinder: ignore */
118 if (mFile->is_open())
119 {
120 mFileActive = TRUE;
121 }
122 else
123 {
124 mFileActive = FALSE;
125 delete mFile;
126 mFile = NULL;
127 }
128 snprintf(mFilename, sizeof(mFilename), filename); /* Flawfinder: ignore */
129 return mFileActive;
130}
131
132void LLErrorBuffer::closeFile()
133{
134 if (mFile && mFile->is_open())
135 {
136 mFile->close();
137 mFileActive = FALSE;
138 delete mFile;
139 mFile = NULL;
140 }
141}
142
143const char * LLErrorBuffer::getFilename() const
144{
145 return mFilename;
146}
147
148void LLErrorBuffer::setUTCTimestamp(BOOL utc)
149{
150 mIsUTC = utc;
151}
152
153void LLErrorBuffer::enableError(BOOL active)
154{
155 mErrorActive = active;
156}
157
158void LLErrorBuffer::enableErrorTimestamp(BOOL active)
159{
160 mErrorTimestamp = active;
161}
162
163void LLErrorBuffer::enableFile(BOOL active)
164{
165 if (mFile != NULL)
166 {
167 if (mFile->is_open())
168 mFileActive = active;
169 }
170 else
171 mFileActive = FALSE;
172}
173
174#if !LL_WINDOWS
175void LLErrorBuffer::enableSyslog(BOOL active)
176{
177 mSyslogActive = active;
178}
179#endif // LL_WINDOWS
180
181#if LL_WINDOWS
182void LLErrorBuffer::enableWinDebug(BOOL active)
183{
184 mWinDebugActive = active;
185}
186#endif // LL_WINDOWS
187
188int LLErrorBuffer::overflow(int c)
189{
190 if (EOF != c)
191 {
192 if ('\n' == c)
193 {
194 // If we're not supposed to print anything, don't, but
195 // pretend that we did so taht the iostream doesn't think
196 // there's been a failure
197 if (mPriority < mLevel)
198 {
199 // Flush our message buffer
200 mBuf = "";
201 return 0;
202 }
203#if !LL_WINDOWS
204 if (mSyslogActive)
205 {
206 int pri = ELevelToSyslogPriority(mPriority);
207 syslog(pri, "%s", mBuf.c_str());
208 }
209#endif // LL_WINDOWS
210 const S32 BUF_SIZE = 64;
211 char time_str[BUF_SIZE]; /* Flawfinder: ignore */
212 if (mFileActive || mErrorActive)
213 {
214 time_t now;
215 time(&now);
216 S32 chars;
217 if(mIsUTC)
218 {
219 chars = (S32)strftime(time_str, BUF_SIZE,
220 "%Y-%m-%dT%H:%M:%SZ",
221 gmtime(&now));
222 }
223 else
224 {
225 chars = (S32)strftime(time_str, BUF_SIZE,
226 "%Y-%m-%dT%H:%M:%S %Z",
227 localtime(&now));
228 }
229 if (0 == chars)
230 {
231 strcpy(time_str, "time error"); /* Flawfinder: ignore */
232 }
233 }
234 if (mFileActive)
235 {
236 *mFile << time_str << " " << mBuf << std::endl;
237 }
238 if (mErrorActive)
239 {
240 if (mErrorTimestamp)
241 {
242 fprintf(stderr, "%s %s\n", time_str, mBuf.c_str());
243 }
244 else
245 {
246 fprintf(stderr, "%s\n", mBuf.c_str());
247 }
248
249 // std::cerr goes into the void on the viewer
250 //std::cerr << time_str << ' ' << mBuf << std::endl;
251 }
252 if (mFixedBuf)
253 {
254 mFixedBuf->addLine(mBuf.c_str());
255 }
256#if LL_WINDOWS
257 if (mWinDebugActive)
258 {
259 llutf16string utf16str = wstring_to_utf16str(utf8str_to_wstring(mBuf));
260 utf16str += '\n';
261 OutputDebugString(utf16str.c_str());
262 }
263#endif // LL_WINDOWS
264 // Is there a better way to truncate a string?
265 mBuf.erase(0, mBuf.length()); // Hack, Linux doesn't implement clear()!
266 }
267 else
268 {
269 mBuf += c;
270 }
271 }
272 return 0;
273}
274
275LLErrorBuffer::ELevel LLErrorBuffer::mergeLevel(const LLErrorBuffer::ELevel l)
276{
277 mLevel = llmin(mLevel, l);
278 return mLevel;
279}
diff --git a/linden/indra/llcommon/llerrorbuffer.h b/linden/indra/llcommon/llerrorbuffer.h
deleted file mode 100644
index b52de3a..0000000
--- a/linden/indra/llcommon/llerrorbuffer.h
+++ /dev/null
@@ -1,117 +0,0 @@
1/**
2 * @file llerrorbuffer.h
3 * @brief Buffer implementation for logging.
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLERRORBUFFER_H
29#define LL_LLERRORBUFFER_H
30
31#include <fstream>
32#include <iostream>
33#include <string>
34
35#include "lldefs.h"
36#include "stdtypes.h"
37#include "llfile.h"
38
39// A streambuf that sends it's output into a file, stderr, or syslog.
40//
41// Each output can be enabled/disabled, and a priority can be set.
42
43class LLFixedBuffer;
44
45class LLErrorBuffer : public std::streambuf
46{
47 public:
48
49 // Specify error levels
50 enum ELevel
51 {
52 DEBUG = 0,
53 INFO = 1,
54 WARN = 2,
55 FATAL = 3,
56 NONE = 4 // Do NO error logging (for use in signal handlers)
57 };
58
59 LLErrorBuffer();
60 ~LLErrorBuffer();
61 BOOL setFile(const char *filename);
62 void closeFile();
63 const char *getFilename() const;
64 void setFixedBuffer(LLFixedBuffer *b) { mFixedBuf = b; };
65
66 // Sets the priority of the current message
67 void setPriority(const ELevel l) { mPriority = l; }
68
69 // Only display messages >= to this level
70 void setLevel(const ELevel l) { mLevel = l; }
71 ELevel getLevel() { return mLevel; }
72 // Display messages >= to level l, if l < current level
73 ELevel mergeLevel(const ELevel l);
74
75 // on linux, this sets syslog info to be a LOG_NOTICE which will
76 // be centrally logged. *NOTE: This is very
77 // linux/syslog/configuration dependent.
78 void setElevatedRemote(BOOL b) { mElevatedRemote = b; }
79
80 // logs are in utc rather than local
81 void setUTCTimestamp(BOOL utc);
82
83 // Turn on or off logging outputs
84 void enableError(BOOL active);
85 void enableErrorTimestamp(BOOL active);
86 void enableFile(BOOL active);
87 void enableSyslog(BOOL active);
88#if LL_WINDOWS
89 void enableWinDebug(BOOL active);
90#endif // LL_WINDOWS
91
92 protected:
93 int overflow(int c = EOF);
94
95 private:
96 char mFilename[LL_MAX_PATH]; /* Flawfinder: ignore */
97 int ELevelToSyslogPriority(const ELevel l);
98
99 llofstream *mFile;
100 std::string mBuf;
101 LLFixedBuffer *mFixedBuf;
102
103 BOOL mErrorActive;
104 BOOL mErrorTimestamp;
105 BOOL mFileActive;
106 BOOL mSyslogActive;
107 BOOL mWinDebugActive;
108 BOOL mElevatedRemote;
109 BOOL mIsUTC;
110
111 // If priority < level, output is thrown away
112 ELevel mLevel;
113 // Current message priority
114 ELevel mPriority;
115};
116
117#endif // LL_LLERRORBUFFER_H
diff --git a/linden/indra/llcommon/llerrorcontrol.h b/linden/indra/llcommon/llerrorcontrol.h
new file mode 100644
index 0000000..f2c8755
--- /dev/null
+++ b/linden/indra/llcommon/llerrorcontrol.h
@@ -0,0 +1,142 @@
1/**
2 * @file llerrorcontrol.h
3 * @date December 2006
4 * @brief error message system control
5 *
6 * Copyright (c) 2007-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#ifndef LL_LLERRORCONTROL_H
30#define LL_LLERRORCONTROL_H
31
32#include "llerror.h"
33
34#include <string>
35
36class LLFixedBuffer;
37class LLSD;
38
39/*
40 This is the part of the LLError namespace that manages the messages
41 produced by the logging. The logging support is defined in llerror.h.
42 Most files do not need to include this.
43
44 These implementations are in llerror.cpp.
45*/
46
47
48namespace LLError
49{
50 void initForServer(const std::string& identity);
51 // resets all logging settings to defaults needed by server processes
52 // logs to stderr, syslog, and windows debug log
53 // the identity string is used for in the syslog
54
55 void initForApplication(const std::string& dir);
56 // resets all logging settings to defaults needed by applicaitons
57 // logs to stderr and windows debug log
58 // sets up log configuration from the file logcontrol.xml in dir
59
60
61 /*
62 Settings that control what is logged.
63 Setting a level means log messages at that level or above.
64 */
65
66 void setPrintLocation(bool);
67 void setDefaultLevel(LLError::ELevel);
68 void setFunctionLevel(const std::string& function_name, LLError::ELevel);
69 void setClassLevel(const std::string& class_name, LLError::ELevel);
70 void setFileLevel(const std::string& file_name, LLError::ELevel);
71
72 void configure(const LLSD&);
73 // the LLSD can configure all of the settings
74 // usually read automatically from the live errorlog.xml file
75
76
77 /*
78 Control functions.
79 */
80
81 typedef void (*FatalFunction)(const std::string& message);
82 void crashAndLoop(const std::string& message);
83 // Default fatal funtion: divides by zero and loops forever
84
85 void setFatalFunction(FatalFunction);
86 // The fatal function will be called when an message of LEVEL_ERROR
87 // is logged. Note: supressing a LEVEL_ERROR message from being logged
88 // (by, for example, setting a class level to LEVEL_NONE), will keep
89 // the that message from causing the fatal funciton to be invoked.
90
91 typedef std::string (*TimeFunction)();
92 std::string utcTime();
93
94 void setTimeFunction(TimeFunction);
95 // The function is use to return the current time, formatted for
96 // display by those error recorders that want the time included.
97
98
99
100 class Recorder
101 {
102 // An object that handles the actual output or error messages.
103 public:
104 virtual ~Recorder();
105
106 virtual void recordMessage(LLError::ELevel, const std::string& message) = 0;
107 // use the level for better display, not for filtering
108
109 virtual bool wantsTime(); // default returns false
110 // override and return true if the recorder wants the time string
111 // included in the text of the message
112 };
113
114 void addRecorder(Recorder*);
115 void removeRecorder(Recorder*);
116 // each error message is passed to each recorder via recordMessage()
117
118 void logToFile(const std::string& filename);
119 void logToFixedBuffer(LLFixedBuffer*);
120 // Utilities to add recorders for logging to a file or a fixed buffer
121 // A second call to the same function will remove the logger added
122 // with the first.
123 // Passing the empty string or NULL to just removes any prior.
124 std::string logFileName();
125 // returns name of current logging file, empty string if none
126
127
128 /*
129 Utilities for use by the unit tests of LLError itself.
130 */
131
132 class Settings;
133 Settings* saveAndResetSettings();
134 void restoreSettings(Settings *);
135
136 std::string abbreviateFile(const std::string& filePath);
137 int shouldLogCallCount();
138
139};
140
141#endif // LL_LLERRORCONTROL_H
142
diff --git a/linden/indra/llcommon/llerrorlegacy.h b/linden/indra/llcommon/llerrorlegacy.h
new file mode 100644
index 0000000..5438a21
--- /dev/null
+++ b/linden/indra/llcommon/llerrorlegacy.h
@@ -0,0 +1,117 @@
1/**
2 * @file llerrorlegacy.h
3 * @date January 2007
4 * @brief old things from the older error system
5 *
6 * Copyright (c) 2007-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#ifndef LL_LLERRORLEGACY_H
30#define LL_LLERRORLEGACY_H
31
32
33
34/*
35 LEGACY -- DO NOT USE THIS STUFF ANYMORE
36*/
37
38// Specific error codes
39const int LL_ERR_NOERR = 0;
40const int LL_ERR_ASSET_REQUEST_FAILED = -1;
41//const int LL_ERR_ASSET_REQUEST_INVALID = -2;
42const int LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3;
43const int LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4;
44const int LL_ERR_INSUFFICIENT_PERMISSIONS = -5;
45const int LL_ERR_EOF = -39;
46const int LL_ERR_CANNOT_OPEN_FILE = -42;
47const int LL_ERR_FILE_NOT_FOUND = -43;
48const int LL_ERR_FILE_EMPTY = -44;
49const int LL_ERR_TCP_TIMEOUT = -23016;
50const int LL_ERR_CIRCUIT_GONE = -23017;
51
52
53
54// Define one of these for different error levels in release...
55// #define RELEASE_SHOW_DEBUG // Define this if you want your release builds to show lldebug output.
56#define RELEASE_SHOW_INFO // Define this if you want your release builds to show llinfo output
57#define RELEASE_SHOW_WARN // Define this if you want your release builds to show llwarn output.
58
59
60//////////////////////////////////////////
61//
62// Implementation - ignore
63//
64//
65#ifdef _DEBUG
66#define SHOW_DEBUG
67#define SHOW_WARN
68#define SHOW_INFO
69#define SHOW_ASSERT
70#else // _DEBUG
71
72#ifdef RELEASE_SHOW_DEBUG
73#define SHOW_DEBUG
74#endif
75
76#ifdef RELEASE_SHOW_WARN
77#define SHOW_WARN
78#endif
79
80#ifdef RELEASE_SHOW_INFO
81#define SHOW_INFO
82#endif
83
84#ifdef RELEASE_SHOW_ASSERT
85#define SHOW_ASSERT
86#endif
87
88#endif // _DEBUG
89
90
91
92#define lldebugst(type) lldebugs
93#define llendflush llendl
94
95
96#define llerror(msg, num) llerrs << "Error # " << num << ": " << msg << llendl;
97
98#define llwarning(msg, num) llwarns << "Warning # " << num << ": " << msg << llendl;
99
100#ifdef SHOW_ASSERT
101#define llassert(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
102#else
103#define llassert(func)
104#endif
105#define llassert_always(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
106
107#ifdef SHOW_ASSERT
108#define llverify(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
109#else
110#define llverify(func) (func); // get rid of warning C4189
111#endif
112
113// handy compile-time assert - enforce those template parameters!
114#define cassert(expn) typedef char __C_ASSERT__[(expn)?1:-1] /* Flawfinder: ignore */
115 //XXX: used in two places in llcommon/llskipmap.h
116
117#endif // LL_LLERRORLEGACY_H
diff --git a/linden/indra/llcommon/llerrorstream.cpp b/linden/indra/llcommon/llerrorstream.cpp
deleted file mode 100644
index ed54d88..0000000
--- a/linden/indra/llcommon/llerrorstream.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
1/**
2 * @file llerrorstream.cpp
3 * @brief Implementation of c++ log straming.
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llerrorstream.h"
31#include "llerrorbuffer.h"
32#include "llerror.h"
33
34using namespace std;
35
36// Define this if we're using APR mutexes.
37#include "llapr.h"
38extern apr_thread_mutex_t *gLogMutexp;
39
40// In order to compile in Visual C++ 6.0, you must use std:: in the header, and then
41// use the std namespace in the cpp. Otherwise, you'll break the (very) fragile C++ parser.
42LLErrorStream::LLErrorStream(LLErrorBuffer *eb):
43 ostream(eb),
44 mErrorBuffer(eb),
45 mKill(FALSE),
46 mErrorCallback(NULL)
47{
48#ifdef SHOW_DEBUG
49 setErrorLevel(LLErrorBuffer::DEBUG);
50#else
51#ifdef SHOW_INFO
52 setErrorLevel(LLErrorBuffer::INFO);
53#else
54#ifdef SHOW_WARN
55 setErrorLevel(LLErrorBuffer::WARN);
56#else
57 setErrorLevel(LLErrorBuffer::FATAL);
58#endif // SHOW_WARN
59#endif // SHOW_INFO
60#endif // SHOW_DEBUG
61
62 setDebugMask(LLERR_NONE);
63 setPrintLocation(FALSE);
64}
65
66LLErrorBuffer::ELevel LLErrorStream::ELevelToBufferELevel(const ELevel l)
67{
68 switch (l)
69 {
70 case DEBUG:
71 return LLErrorBuffer::DEBUG;
72 case INFO:
73 return LLErrorBuffer::INFO;
74 case WARN:
75 return LLErrorBuffer::WARN;
76 case FATAL:
77 return LLErrorBuffer::FATAL;
78 default:
79 return LLErrorBuffer::FATAL;
80 }
81}
82
83LLErrorStream::ELevel LLErrorStream::BufferELevelToELevel(const LLErrorBuffer::ELevel l)
84{
85 switch(l)
86 {
87 case LLErrorBuffer::DEBUG:
88 return DEBUG;
89 case LLErrorBuffer::INFO:
90 return INFO;
91 case LLErrorBuffer::WARN:
92 return WARN;
93 case LLErrorBuffer::FATAL:
94 return FATAL;
95 default:
96 return FATAL;
97 }
98}
99
100
101BOOL LLErrorStream::isEnabledFor(const LLErrorBuffer::ELevel l)
102{
103 if (l == LLErrorBuffer::FATAL)
104 {
105 if (LLErrorBuffer::FATAL < getErrorLevel())
106 {
107 // Fatal error, but we're at log level NONE (used by signal handlers)
108 // We want to crash this process now instead of logging
109 _llcrash_and_loop();
110 }
111 }
112 // Always returns false if not safe (recursive call)
113 return (getErrorLevel() <= l);
114}
115
116
117BOOL LLErrorStream::isEnabledFor(const LLErrorBuffer::ELevel l, const U32 type)
118{
119 // Always returns false if not safe (recursive call)
120 return (getErrorLevel() <= l) && (mDebugMask & type);
121}
122
123
124
125void LLErrorStream::crashOnError(std::ostringstream &oss, LLErrorBuffer::ELevel l)
126{
127 if (gLogMutexp)
128 {
129 const S32 MAX_RETRIES = 5;
130 S32 attempts = 0;
131 while (attempts < MAX_RETRIES)
132 {
133 apr_status_t s = apr_thread_mutex_trylock(gLogMutexp);
134 if (!APR_STATUS_IS_EBUSY(s))
135 {
136 break;
137 }
138 else
139 {
140 attempts++;
141 ms_sleep(1);
142
143 //
144 // Just yielding won't necessarily work, I had problems with this on Linux - doug 12/02/04
145 //apr_thread_yield();
146 }
147 }
148 if (attempts == MAX_RETRIES)
149 {
150 // We're hosed, we can't get the mutex.
151 // I guess we just won't log, then. Blah.
152 fprintf(stderr, "LLErrorStream::crashOnError() failed to get mutex for log\n");
153 return;
154 }
155 }
156
157 mErrorBuffer->setPriority(l);
158 if (LLErrorBuffer::FATAL == l)
159 {
160 setError();
161 }
162
163 *this << oss.str();
164
165 if (mKill)
166 {
167 // We want to flush this stream.
168 flush();
169 }
170
171 BOOL crashme = FALSE;
172 if (mKill)
173 {
174 crashme = TRUE;
175 }
176 mKill = FALSE;
177
178 if (gLogMutexp)
179 {
180 apr_thread_mutex_unlock(gLogMutexp);
181 }
182
183 if (crashme)
184 {
185 mErrorCallback(oss.str());
186 _llcrash_and_loop();
187 }
188}
diff --git a/linden/indra/llcommon/llerrorstream.h b/linden/indra/llcommon/llerrorstream.h
deleted file mode 100644
index 4028583..0000000
--- a/linden/indra/llcommon/llerrorstream.h
+++ /dev/null
@@ -1,126 +0,0 @@
1/**
2 * @file llerrorstream.h
3 * @brief Declaration of c++ log straming.
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLERRORSTREAM_H
29#define LL_LLERRORSTREAM_H
30
31// Usage:
32// LLErrorStream gErrorStream(gErrorBuffer);
33//
34// gErrorStream << debug << "This is a debug message" << endl;
35//
36// gErrorStream << fatal << "This message will cause a crash!" << endl;
37
38#include <iostream>
39#include "llerrorbuffer.h"
40#include "stdtypes.h"
41
42class LLFixedBuffer;
43
44class LLErrorStream : public std::ostream
45{
46 public:
47 LLErrorStream(LLErrorBuffer *eb);
48
49 // Specify error levels-- Use LLErrorBuffer::ELevel instead
50 enum ELevel
51 {
52 DEBUG = 0,
53 INFO = 1,
54 WARN = 2,
55 FATAL = 3,
56 NONE = 4 // Don't log anything
57 };
58
59 LLErrorBuffer *mErrorBuffer;
60
61 // This is used to specify if we need to merge the DebugMask
62 // or replace it
63 enum EControl
64 {
65 REPLACE = 0,
66 MERGE = 1
67 };
68
69 void setDebugMask(U32 mask) { mDebugMask = mask; }
70 void mergeDebugMask(U32 mask) { mDebugMask |= mask; }
71 U32 getDebugMask() { return mDebugMask; }
72 void setDebugFlag(U32 flag) { mDebugMask |= flag; }
73 void clearDebugFlag(U32 flag) { mDebugMask &= ~flag; }
74 BOOL setFile(const char *path) { return mErrorBuffer->setFile(path); }
75 void closeFile() { mErrorBuffer->closeFile(); }
76 const char *getFilename() const { return mErrorBuffer->getFilename(); }
77 void setFixedBuffer(LLFixedBuffer *b) { mErrorBuffer->setFixedBuffer(b); }
78 void setErrorLevel(const LLErrorBuffer::ELevel l) { mErrorBuffer->setLevel(l); }
79 LLErrorBuffer::ELevel getErrorLevel() { return mErrorBuffer->getLevel(); }
80 void mergeErrorLevel(const LLErrorBuffer::ELevel l) { mErrorBuffer->mergeLevel(l); }
81 void setError() { mKill = TRUE; };
82 void crashOnError(std::ostringstream &ss, LLErrorBuffer::ELevel l);
83
84 BOOL isEnabledFor(const LLErrorBuffer::ELevel l);
85 BOOL isEnabledFor(const LLErrorBuffer::ELevel l, const U32 type);
86
87
88 void mergeLevel(const LLErrorBuffer::ELevel l) { mErrorBuffer->mergeLevel(l); }
89
90 void setPrintLocation(BOOL b) { mPrintLocation = b; }
91 BOOL getPrintLocation() { return mPrintLocation; }
92
93 void setElevatedRemote(BOOL b) { mErrorBuffer->setElevatedRemote(b); }
94 void setUTCTimestamp(BOOL utc) { mErrorBuffer->setUTCTimestamp(utc); }
95
96 // Deprecated
97 void setLevel(const ELevel l) { setErrorLevel(ELevelToBufferELevel(l)); }
98 ELevel getLevel() { return BufferELevelToELevel(getErrorLevel()); }
99 void mergeLevel(const ELevel l) { mergeErrorLevel(ELevelToBufferELevel(l)); }
100
101
102 // Backwards compatilibity cruft. Should be removed
103 void mergeTime(BOOL b) { } // NOP
104 void mergeLocation(BOOL b) { } // NOP
105 void setTime(BOOL b) { } // NOP
106 char *getTime() { return ""; } // NOP
107
108 typedef void(*LLErrorCallback)(const std::string &error_string);
109 void setErrorCallback(LLErrorCallback callback) {mErrorCallback = callback;}
110
111private:
112 // This maintains the existing ELevel interface, but new code should use
113 // LLErrorBuffer::ELevel instead.
114 LLErrorBuffer::ELevel ELevelToBufferELevel(const ELevel l);
115 ELevel BufferELevelToELevel(const LLErrorBuffer::ELevel l);
116 U32 mDebugMask; // Mask for debugst() output
117
118 BOOL mPrintLocation;
119
120 S32 mSafeDepth; // Counter so we can safely do recursive calls, 0 means we're OK
121 BOOL mKill;
122 LLErrorCallback mErrorCallback;
123};
124
125
126#endif // LL_LLERRORSTREAM_H
diff --git a/linden/indra/llcommon/llevent.cpp b/linden/indra/llcommon/llevent.cpp
index e9b6a51..bbb37c5 100644
--- a/linden/indra/llcommon/llevent.cpp
+++ b/linden/indra/llcommon/llevent.cpp
@@ -186,16 +186,14 @@ void LLSimpleDispatcher::addListener(LLEventListener* listener, LLSD filter, con
186 186
187void LLSimpleDispatcher::removeListener(LLEventListener* listener) 187void LLSimpleDispatcher::removeListener(LLEventListener* listener)
188{ 188{
189 std::vector<LLListenerEntry>::iterator itor; 189 std::vector<LLListenerEntry>::iterator itor = mListeners.begin();
190 for (itor=mListeners.begin(); itor!=mListeners.end();) 190 std::vector<LLListenerEntry>::iterator end = mListeners.end();
191 for (; itor != end; ++itor)
191 { 192 {
192 if ((*itor).listener == listener) 193 if ((*itor).listener == listener)
193 { 194 {
194 mListeners.erase(itor); 195 mListeners.erase(itor);
195 } 196 break;
196 else
197 {
198 ++itor;
199 } 197 }
200 } 198 }
201 listener->handleDetach(mParent); 199 listener->handleDetach(mParent);
diff --git a/linden/indra/llcommon/llevent.h b/linden/indra/llcommon/llevent.h
index c48817e..bcb6ee9 100644
--- a/linden/indra/llcommon/llevent.h
+++ b/linden/indra/llcommon/llevent.h
@@ -31,6 +31,7 @@
31 31
32#include "llsd.h" 32#include "llsd.h"
33#include "llmemory.h" 33#include "llmemory.h"
34#include "llthread.h"
34 35
35class LLEventListener; 36class LLEventListener;
36class LLEvent; 37class LLEvent;
@@ -128,6 +129,7 @@ public:
128 129
129 // Adds a listener to this dispatcher, with a given user data 130 // Adds a listener to this dispatcher, with a given user data
130 // that will be passed to the listener when an event is fired. 131 // that will be passed to the listener when an event is fired.
132 // Duplicate pointers are removed on addtion.
131 void addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata); 133 void addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata);
132 134
133 // Removes a listener from this dispatcher 135 // Removes a listener from this dispatcher
diff --git a/linden/indra/llcommon/llfasttimer.h b/linden/indra/llcommon/llfasttimer.h
index b5e0734..47634ac 100644
--- a/linden/indra/llcommon/llfasttimer.h
+++ b/linden/indra/llcommon/llfasttimer.h
@@ -44,6 +44,7 @@ public:
44 FTM_UPDATE, 44 FTM_UPDATE,
45 FTM_RENDER, 45 FTM_RENDER,
46 FTM_SWAP, 46 FTM_SWAP,
47 FTM_CLIENT_COPY,
47 FTM_IDLE, 48 FTM_IDLE,
48 FTM_SLEEP, 49 FTM_SLEEP,
49 50
@@ -56,13 +57,23 @@ public:
56 FTM_UPDATE_TERRAIN, 57 FTM_UPDATE_TERRAIN,
57 FTM_UPDATE_PRIMITIVES, 58 FTM_UPDATE_PRIMITIVES,
58 FTM_UPDATE_PARTICLES, 59 FTM_UPDATE_PARTICLES,
60 FTM_SIMULATE_PARTICLES,
59 FTM_UPDATE_SKY, 61 FTM_UPDATE_SKY,
60 FTM_UPDATE_TEXTURES, 62 FTM_UPDATE_TEXTURES,
63 FTM_UPDATE_WATER,
64 FTM_UPDATE_CLOUDS,
65 FTM_UPDATE_GRASS,
66 FTM_UPDATE_TREE,
67 FTM_UPDATE_AVATAR,
61 68
62 // common render components 69 // common render components
63 FTM_RENDER_GEOMETRY, 70 FTM_RENDER_GEOMETRY,
64 FTM_RENDER_TERRAIN, 71 FTM_RENDER_TERRAIN,
65 FTM_RENDER_SIMPLE, 72 FTM_RENDER_SIMPLE,
73 FTM_RENDER_FULLBRIGHT,
74 FTM_RENDER_GLOW,
75 FTM_RENDER_GRASS,
76 FTM_RENDER_INVISIBLE,
66 FTM_RENDER_SHINY, 77 FTM_RENDER_SHINY,
67 FTM_RENDER_BUMP, 78 FTM_RENDER_BUMP,
68 FTM_RENDER_TREES, 79 FTM_RENDER_TREES,
@@ -81,6 +92,20 @@ public:
81 FTM_MESSAGES, 92 FTM_MESSAGES,
82 FTM_REBUILD, 93 FTM_REBUILD,
83 FTM_STATESORT, 94 FTM_STATESORT,
95 FTM_STATESORT_DRAWABLE,
96 FTM_STATESORT_POSTSORT,
97 FTM_REBUILD_VBO,
98 FTM_REBUILD_VOLUME_VB,
99 FTM_REBUILD_BRIDGE_VB,
100 FTM_REBUILD_HUD_VB,
101 FTM_REBUILD_TERRAIN_VB,
102 FTM_REBUILD_WATER_VB,
103 FTM_REBUILD_TREE_VB,
104 FTM_REBUILD_PARTICLE_VB,
105 FTM_REBUILD_CLOUD_VB,
106 FTM_REBUILD_GRASS_VB,
107 FTM_REBUILD_NONE_VB,
108 FTM_REBUILD_OCCLUSION_VB,
84 FTM_POOLS, 109 FTM_POOLS,
85 FTM_POOLRENDER, 110 FTM_POOLRENDER,
86 FTM_IDLE_CB, 111 FTM_IDLE_CB,
@@ -90,6 +115,7 @@ public:
90 FTM_UPDATE_LIGHTS, 115 FTM_UPDATE_LIGHTS,
91 FTM_CULL, 116 FTM_CULL,
92 FTM_CULL_REBOUND, 117 FTM_CULL_REBOUND,
118 FTM_FRUSTUM_CULL,
93 FTM_GEO_UPDATE, 119 FTM_GEO_UPDATE,
94 FTM_GEO_RESERVE, 120 FTM_GEO_RESERVE,
95 FTM_GEO_LIGHT, 121 FTM_GEO_LIGHT,
@@ -116,6 +142,7 @@ public:
116 FTM_IMAGE_UPDATE, 142 FTM_IMAGE_UPDATE,
117 FTM_IMAGE_CREATE, 143 FTM_IMAGE_CREATE,
118 FTM_IMAGE_DECODE, 144 FTM_IMAGE_DECODE,
145 FTM_IMAGE_MARK_DIRTY,
119 FTM_PIPELINE, 146 FTM_PIPELINE,
120 FTM_VFILE_WAIT, 147 FTM_VFILE_WAIT,
121 FTM_FLEXIBLE_UPDATE, 148 FTM_FLEXIBLE_UPDATE,
diff --git a/linden/indra/llcommon/llfile.cpp b/linden/indra/llcommon/llfile.cpp
index d9fd360..feac28f 100644
--- a/linden/indra/llcommon/llfile.cpp
+++ b/linden/indra/llcommon/llfile.cpp
@@ -48,6 +48,19 @@ int LLFile::mkdir(const char* dirname, int perms)
48} 48}
49 49
50// static 50// static
51int LLFile::rmdir(const char* dirname)
52{
53#if LL_WINDOWS
54 // permissions are ignored on Windows
55 std::string utf8dirname = dirname;
56 llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname);
57 return _wrmdir(utf16dirname.c_str());
58#else
59 return ::rmdir(dirname);
60#endif
61}
62
63// static
51LLFILE* LLFile::fopen(const char* filename, const char* mode) /* Flawfinder: ignore */ 64LLFILE* LLFile::fopen(const char* filename, const char* mode) /* Flawfinder: ignore */
52{ 65{
53#if LL_WINDOWS 66#if LL_WINDOWS
@@ -184,9 +197,9 @@ void llifstream::close()
184 } 197 }
185} 198}
186 199
187void llifstream::open(const char *_Filename, 200void llifstream::open(const char* _Filename, /* Flawfinder: ignore */
188 ios_base::openmode _Mode, 201 ios_base::openmode _Mode,
189 int _Prot) /* Flawfinder: ignore */ 202 int _Prot)
190{ // open a C stream with specified mode 203{ // open a C stream with specified mode
191 204
192 FILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::in, _Prot); 205 FILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::in, _Prot);
@@ -197,6 +210,7 @@ void llifstream::open(const char *_Filename,
197 } 210 }
198 llassert(_Filebuffer == NULL); 211 llassert(_Filebuffer == NULL);
199 _Filebuffer = new _Myfb(filep); 212 _Filebuffer = new _Myfb(filep);
213 _ShouldClose = true;
200 _Myios::init(_Filebuffer); 214 _Myios::init(_Filebuffer);
201} 215}
202 216
@@ -208,13 +222,17 @@ bool llifstream::is_open() const
208} 222}
209llifstream::~llifstream() 223llifstream::~llifstream()
210{ 224{
225 if (_ShouldClose)
226 {
227 close();
228 }
211 delete _Filebuffer; 229 delete _Filebuffer;
212} 230}
213 231
214llifstream::llifstream(const char *_Filename, 232llifstream::llifstream(const char *_Filename,
215 ios_base::openmode _Mode, 233 ios_base::openmode _Mode,
216 int _Prot) 234 int _Prot)
217 : std::basic_istream< char , std::char_traits< char > >(NULL,true),_Filebuffer(NULL) 235 : std::basic_istream< char , std::char_traits< char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
218 236
219{ // construct with named file and specified mode 237{ // construct with named file and specified mode
220 open(_Filename, _Mode | ios_base::in, _Prot); /* Flawfinder: ignore */ 238 open(_Filename, _Mode | ios_base::in, _Prot); /* Flawfinder: ignore */
@@ -230,9 +248,9 @@ bool llofstream::is_open() const
230 return false; 248 return false;
231} 249}
232 250
233void llofstream::open(const char *_Filename, 251void llofstream::open(const char* _Filename, /* Flawfinder: ignore */
234 ios_base::openmode _Mode, 252 ios_base::openmode _Mode,
235 int _Prot) /* Flawfinder: ignore */ 253 int _Prot)
236{ // open a C stream with specified mode 254{ // open a C stream with specified mode
237 255
238 FILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::out, _Prot); 256 FILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::out, _Prot);
diff --git a/linden/indra/llcommon/llfile.h b/linden/indra/llcommon/llfile.h
index 554308f..5034cf7 100644
--- a/linden/indra/llcommon/llfile.h
+++ b/linden/indra/llcommon/llfile.h
@@ -69,6 +69,7 @@ public:
69 // be overridden by the user's umask. It is ignored on Windows. 69 // be overridden by the user's umask. It is ignored on Windows.
70 static int mkdir(const char* filename, int perms = 0700); 70 static int mkdir(const char* filename, int perms = 0700);
71 71
72 static int rmdir(const char* filename);
72 static int remove(const char* filename); 73 static int remove(const char* filename);
73 static int rename(const char* filename,const char* newname); 74 static int rename(const char* filename,const char* newname);
74 static int stat(const char* filename,llstat* file_status); 75 static int stat(const char* filename,llstat* file_status);
@@ -87,7 +88,7 @@ public:
87 typedef std::basic_ios<char,std::char_traits< char > > _Myios; 88 typedef std::basic_ios<char,std::char_traits< char > > _Myios;
88 89
89 llifstream() 90 llifstream()
90 : std::basic_istream<char,std::char_traits< char > >(NULL,true),_Filebuffer(NULL) 91 : std::basic_istream<char,std::char_traits< char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
91 { // construct unopened 92 { // construct unopened
92 } 93 }
93 94
@@ -97,7 +98,8 @@ public:
97 98
98 explicit llifstream(_Filet *_File) 99 explicit llifstream(_Filet *_File)
99 : std::basic_istream<char,std::char_traits< char > >(NULL,true), 100 : std::basic_istream<char,std::char_traits< char > >(NULL,true),
100 _Filebuffer(new _Myfb(_File)) 101 _Filebuffer(new _Myfb(_File)),
102 _ShouldClose(false)
101 { // construct with specified C stream 103 { // construct with specified C stream
102 } 104 }
103 virtual ~llifstream(); 105 virtual ~llifstream();
@@ -107,13 +109,14 @@ public:
107 return _Filebuffer; 109 return _Filebuffer;
108 } 110 }
109 bool is_open() const; 111 bool is_open() const;
110 void open(const char *_Filename, 112 void open(const char* _Filename, /* Flawfinder: ignore */
111 ios_base::openmode _Mode = ios_base::in, 113 ios_base::openmode _Mode = ios_base::in,
112 int _Prot = (int)ios_base::_Openprot); /* Flawfinder: ignore */ 114 int _Prot = (int)ios_base::_Openprot);
113 void close(); 115 void close();
114 116
115private: 117private:
116 _Myfb* _Filebuffer; // the file buffer 118 _Myfb* _Filebuffer; // the file buffer
119 bool _ShouldClose;
117}; 120};
118 121
119 122
diff --git a/linden/indra/llcommon/llformat.cpp b/linden/indra/llcommon/llformat.cpp
new file mode 100644
index 0000000..f088bc6
--- /dev/null
+++ b/linden/indra/llcommon/llformat.cpp
@@ -0,0 +1,47 @@
1/**
2 * @file llformat.cpp
3 * @date January 2007
4 * @brief string formatting utility
5 *
6 * Copyright (c) 2007-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#include "linden_common.h"
30
31#include "llformat.h"
32
33#include <stdarg.h>
34
35std::string llformat(const char *fmt, ...)
36{
37 char tstr[1024]; /* Flawfinder: ignore */
38 va_list va;
39 va_start(va, fmt);
40#if LL_WINDOWS
41 _vsnprintf(tstr, 1024, fmt, va);
42#else
43 vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */
44#endif
45 va_end(va);
46 return std::string(tstr);
47}
diff --git a/linden/indra/llcommon/llformat.h b/linden/indra/llcommon/llformat.h
new file mode 100644
index 0000000..135f9d2
--- /dev/null
+++ b/linden/indra/llcommon/llformat.h
@@ -0,0 +1,42 @@
1/**
2 * @file llformat.h
3 * @date January 2007
4 * @brief string formatting utility
5 *
6 * Copyright (c) 2007-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#ifndef LL_LLFORMAT_H
30#define LL_LLFORMAT_H
31
32#include <string>
33
34// Use as follows:
35// llinfos << llformat("Test:%d (%.2f %.2f)", idx, x, y) << llendl;
36//
37// *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun)
38// should perhaps be replaced with boost::format.
39
40std::string llformat(const char *fmt, ...);
41
42#endif // LL_LLFORMAT_H
diff --git a/linden/indra/llcommon/llliveappconfig.cpp b/linden/indra/llcommon/llliveappconfig.cpp
new file mode 100644
index 0000000..bcffa7c
--- /dev/null
+++ b/linden/indra/llcommon/llliveappconfig.cpp
@@ -0,0 +1,65 @@
1/**
2 * @file llliveappconfig.cpp
3 * @brief Configuration information for an LLApp that overrides indra.xml
4 *
5 * Copyright (c) 2003-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llliveappconfig.h"
31
32#include "llapp.h"
33#include "llsd.h"
34#include "llsdserialize.h"
35
36LLLiveAppConfig::LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period)
37: LLLiveFile(filename, refresh_period),
38 mApp(app)
39{ }
40
41
42LLLiveAppConfig::~LLLiveAppConfig()
43{ }
44
45// virtual
46void LLLiveAppConfig::loadFile()
47{
48 llinfos << "LLLiveAppConfig::loadFile(): reading from "
49 << filename() << llendl;
50 llifstream file(filename().c_str());
51 LLSD config;
52 if (file.is_open())
53 {
54 LLSDSerialize::fromXML(config, file);
55 if(!config.isMap())
56 {
57 llinfos << "LLDataserverConfig::loadFile(): not an map!"
58 << " Ignoring the data." << llendl;
59 return;
60 }
61 file.close();
62 }
63 mApp->setOptionData(
64 LLApp::PRIORITY_SPECIFIC_CONFIGURATION, config);
65}
diff --git a/linden/indra/newview/lldrawpooltreenew.h b/linden/indra/llcommon/llliveappconfig.h
index 9150331..822410f 100644
--- a/linden/indra/newview/lldrawpooltreenew.h
+++ b/linden/indra/llcommon/llliveappconfig.h
@@ -1,6 +1,6 @@
1/** 1/**
2 * @file lldrawpooltreenew.h 2 * @file llliveappconfig.h
3 * @brief LLDrawPoolTreeNew class definition 3 * @brief Configuration information for an LLApp that overrides indra.xml
4 * 4 *
5 * Copyright (c) 2003-2007, Linden Research, Inc. 5 * Copyright (c) 2003-2007, Linden Research, Inc.
6 * 6 *
@@ -25,31 +25,28 @@
25 * COMPLETENESS OR PERFORMANCE. 25 * COMPLETENESS OR PERFORMANCE.
26 */ 26 */
27 27
28#ifndef LL_LLDRAWPOOLTREENEW_H 28#ifndef LLLIVEAPPCONFIG_H
29#define LL_LLDRAWPOOLTREENEW_H 29#define LLLIVEAPPCONFIG_H
30 30
31#include "lldrawpool.h" 31#include "lllivefile.h"
32 32
33class LLDrawPoolTreeNew : public LLDrawPool 33class LLApp;
34
35class LLLiveAppConfig : public LLLiveFile
34{ 36{
35 LLPointer<LLViewerImage> mTexturep;
36public: 37public:
37 LLDrawPoolTreeNew(LLViewerImage *texturep); 38 // To use this, instantiate a LLLiveAppConfig object inside your main loop.
39 // The traditional name for it is live_config.
40 // Be sure to call live_config.checkAndReload() periodically.
38 41
39 /*virtual*/ LLDrawPool *instancePool(); 42 LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period);
43 ~LLLiveAppConfig();
40 44
41 /*virtual*/ void prerender(); 45protected:
42 /*virtual*/ void render( S32 pass ); 46 /*virtual*/ void loadFile();
43 /*virtual*/ void renderForSelect();
44 /*virtual*/ S32 rebuild();
45 /*virtual*/ BOOL verify() const;
46 /*virtual*/ LLViewerImage *getTexture();
47 /*virtual*/ LLViewerImage *getDebugTexture();
48 /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
49 virtual S32 getMaterialAttribIndex() { return 0; }
50 47
51private: 48private:
52 void renderTree(BOOL selecting = FALSE); 49 LLApp* mApp;
53}; 50};
54 51
55#endif // LL_LLDRAWPOOLTREE_H 52#endif
diff --git a/linden/indra/llcommon/lllivefile.cpp b/linden/indra/llcommon/lllivefile.cpp
index 33e2014..d289671 100644
--- a/linden/indra/llcommon/lllivefile.cpp
+++ b/linden/indra/llcommon/lllivefile.cpp
@@ -27,24 +27,56 @@
27#include "linden_common.h" 27#include "linden_common.h"
28 28
29#include "lllivefile.h" 29#include "lllivefile.h"
30#include "llframetimer.h"
31#include "lltimer.h"
30 32
33class LLLiveFile::Impl
34{
35public:
36 Impl(const std::string &filename, const F32 refresh_period);
37 ~Impl();
38
39 bool check();
40
41
42 bool mForceCheck;
43 F32 mRefreshPeriod;
44 LLFrameTimer mRefreshTimer;
31 45
32LLLiveFile::LLLiveFile(const std::string &filename, const F32 refresh_period) : 46 std::string mFilename;
33mForceCheck(true), 47 time_t mLastModTime;
34mRefreshPeriod(refresh_period), 48 bool mLastExists;
35mFilename(filename), 49
36mLastModTime(0), 50 LLEventTimer* mEventTimer;
37mLastExists(false) 51};
52
53LLLiveFile::Impl::Impl(const std::string &filename, const F32 refresh_period)
54 : mForceCheck(true),
55 mRefreshPeriod(refresh_period),
56 mFilename(filename),
57 mLastModTime(0),
58 mLastExists(false),
59 mEventTimer(NULL)
38{ 60{
39} 61}
40 62
63LLLiveFile::Impl::~Impl()
64{
65 delete mEventTimer;
66}
67
68LLLiveFile::LLLiveFile(const std::string &filename, const F32 refresh_period)
69 : impl(* new Impl(filename, refresh_period))
70{
71}
41 72
42LLLiveFile::~LLLiveFile() 73LLLiveFile::~LLLiveFile()
43{ 74{
75 delete &impl;
44} 76}
45 77
46 78
47bool LLLiveFile::checkAndReload() 79bool LLLiveFile::Impl::check()
48{ 80{
49 if (!mForceCheck && mRefreshTimer.getElapsedTimeF32() < mRefreshPeriod) 81 if (!mForceCheck && mRefreshTimer.getElapsedTimeF32() < mRefreshPeriod)
50 { 82 {
@@ -65,9 +97,8 @@ bool LLLiveFile::checkAndReload()
65 // broken somehow. Clear flags and return. 97 // broken somehow. Clear flags and return.
66 if (mLastExists) 98 if (mLastExists)
67 { 99 {
68 loadFile(); // Load the file, even though it's missing to allow it to clear state.
69 mLastExists = false; 100 mLastExists = false;
70 return true; 101 return true; // no longer existing is a change!
71 } 102 }
72 return false; 103 return false;
73 } 104 }
@@ -87,7 +118,44 @@ bool LLLiveFile::checkAndReload()
87 mLastExists = true; 118 mLastExists = true;
88 mLastModTime = stat_data.st_mtime; 119 mLastModTime = stat_data.st_mtime;
89 120
90 loadFile();
91 return true; 121 return true;
92} 122}
93 123
124bool LLLiveFile::checkAndReload()
125{
126 bool changed = impl.check();
127 if (changed)
128 {
129 loadFile();
130 }
131 return changed;
132}
133
134std::string LLLiveFile::filename() const
135{
136 return impl.mFilename;
137}
138
139namespace
140{
141 class LiveFileEventTimer : public LLEventTimer
142 {
143 public:
144 LiveFileEventTimer(LLLiveFile& f, F32 refresh)
145 : LLEventTimer(refresh), mLiveFile(f)
146 { }
147
148 void tick()
149 { mLiveFile.checkAndReload(); }
150
151 private:
152 LLLiveFile& mLiveFile;
153 };
154
155}
156
157void LLLiveFile::addToEventTimer()
158{
159 impl.mEventTimer = new LiveFileEventTimer(*this, impl.mRefreshPeriod);
160}
161
diff --git a/linden/indra/llcommon/lllivefile.h b/linden/indra/llcommon/lllivefile.h
index b305531..fbf2bdf 100644
--- a/linden/indra/llcommon/lllivefile.h
+++ b/linden/indra/llcommon/lllivefile.h
@@ -28,7 +28,6 @@
28#ifndef LL_LLLIVEFILE_H 28#ifndef LL_LLLIVEFILE_H
29#define LL_LLLIVEFILE_H 29#define LL_LLLIVEFILE_H
30 30
31#include "llframetimer.h"
32 31
33class LLLiveFile 32class LLLiveFile
34{ 33{
@@ -36,18 +35,22 @@ public:
36 LLLiveFile(const std::string &filename, const F32 refresh_period = 5.f); 35 LLLiveFile(const std::string &filename, const F32 refresh_period = 5.f);
37 virtual ~LLLiveFile(); 36 virtual ~LLLiveFile();
38 37
39 bool checkAndReload(); // Returns true if the file changed in any way 38 bool checkAndReload();
39 // Returns true if the file changed in any way
40 // Call this before using anything that was read & cached from the file
41
42 std::string filename() const;
43
44 void addToEventTimer();
45 // Normally, just calling checkAndReload() is enough. In some cases
46 // though, you may need to let the live file periodically check itself.
40 47
41protected: 48protected:
42 virtual void loadFile() = 0; // Implement this to load your file if it changed 49 virtual void loadFile() = 0; // Implement this to load your file if it changed
43 50
44 bool mForceCheck; 51private:
45 F32 mRefreshPeriod; 52 class Impl;
46 LLFrameTimer mRefreshTimer; 53 Impl& impl;
47
48 std::string mFilename;
49 time_t mLastModTime;
50 bool mLastExists;
51}; 54};
52 55
53#endif //LL_LLLIVEFILE_H 56#endif //LL_LLLIVEFILE_H
diff --git a/linden/indra/llcommon/lllslconstants.h b/linden/indra/llcommon/lllslconstants.h
index 52d2858..08c63e3 100644
--- a/linden/indra/llcommon/lllslconstants.h
+++ b/linden/indra/llcommon/lllslconstants.h
@@ -155,4 +155,8 @@ const S32 LIST_STAT_SUM_SQUARES = 7;
155const S32 LIST_STAT_NUM_COUNT = 8; 155const S32 LIST_STAT_NUM_COUNT = 8;
156const S32 LIST_STAT_GEO_MEAN = 9; 156const S32 LIST_STAT_GEO_MEAN = 9;
157 157
158const S32 STRING_TRIM_HEAD = 0x01;
159const S32 STRING_TRIM_TAIL = 0x02;
160const S32 STRING_TRIM = STRING_TRIM_HEAD | STRING_TRIM_TAIL;
161
158#endif 162#endif
diff --git a/linden/indra/llcommon/llmemory.cpp b/linden/indra/llcommon/llmemory.cpp
index 9bfbf88..8528433 100644
--- a/linden/indra/llcommon/llmemory.cpp
+++ b/linden/indra/llcommon/llmemory.cpp
@@ -28,6 +28,12 @@
28#include "linden_common.h" 28#include "linden_common.h"
29 29
30#include "llmemory.h" 30#include "llmemory.h"
31#include "llmemtype.h"
32
33// not defining nullfunc will currently crash when trying to use a LLHandle
34template< typename _Ty >
35 const typename LLHandle< _Ty >::NullFunc
36 LLHandle< _Ty >::sNullFunc = LLHandle< _Ty >::defaultNullFunc;
31 37
32//---------------------------------------------------------------------------- 38//----------------------------------------------------------------------------
33 39
@@ -258,43 +264,6 @@ void operator delete[] (void *p)
258 264
259//---------------------------------------------------------------------------- 265//----------------------------------------------------------------------------
260 266
261//static
262LLMutex* LLThreadSafeRefCount::sMutex = 0;
263
264//static
265void LLThreadSafeRefCount::initClass()
266{
267 if (!sMutex)
268 {
269 sMutex = new LLMutex(0);
270 }
271}
272
273//static
274void LLThreadSafeRefCount::cleanupClass()
275{
276 delete sMutex;
277 sMutex = NULL;
278}
279
280
281//----------------------------------------------------------------------------
282
283LLThreadSafeRefCount::LLThreadSafeRefCount() :
284 mRef(0)
285{
286}
287
288LLThreadSafeRefCount::~LLThreadSafeRefCount()
289{
290 if (mRef != 0)
291 {
292 llerrs << "deleting non-zero reference" << llendl;
293 }
294}
295
296//----------------------------------------------------------------------------
297
298LLRefCount::LLRefCount() : 267LLRefCount::LLRefCount() :
299 mRef(0) 268 mRef(0)
300{ 269{
diff --git a/linden/indra/llcommon/llmemory.h b/linden/indra/llcommon/llmemory.h
index b40ab79..7a7996b 100644
--- a/linden/indra/llcommon/llmemory.h
+++ b/linden/indra/llcommon/llmemory.h
@@ -31,8 +31,6 @@
31#include <cstdlib> 31#include <cstdlib>
32 32
33#include "llerror.h" 33#include "llerror.h"
34#include "llthread.h"
35#include "llmemtype.h"
36 34
37extern S32 gTotalDAlloc; 35extern S32 gTotalDAlloc;
38extern S32 gTotalDAUse; 36extern S32 gTotalDAUse;
@@ -61,53 +59,7 @@ private:
61// LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting 59// LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting
62// x->instantiate(); // does stuff like place x into an update queue 60// x->instantiate(); // does stuff like place x into an update queue
63 61
64class LLThreadSafeRefCount 62// see llthread.h for LLThreadSafeRefCount
65{
66public:
67 static void initClass(); // creates sMutex
68 static void cleanupClass(); // destroys sMutex
69
70private:
71 static LLMutex* sMutex;
72
73private:
74 LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented
75 LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented
76
77protected:
78 virtual ~LLThreadSafeRefCount(); // use unref()
79
80public:
81 LLThreadSafeRefCount();
82
83 void ref()
84 {
85 if (sMutex) sMutex->lock();
86 mRef++;
87 if (sMutex) sMutex->unlock();
88 }
89
90 S32 unref()
91 {
92 llassert(mRef >= 1);
93 if (sMutex) sMutex->lock();
94 S32 res = --mRef;
95 if (sMutex) sMutex->unlock();
96 if (0 == res)
97 {
98 delete this;
99 res = 0;
100 }
101 return res;
102 }
103 S32 getNumRefs() const
104 {
105 return mRef;
106 }
107
108private:
109 S32 mRef;
110};
111 63
112//---------------------------------------------------------------------------- 64//----------------------------------------------------------------------------
113 65
@@ -139,6 +91,7 @@ public:
139 } 91 }
140 return mRef; 92 return mRef;
141 } 93 }
94
142 S32 getNumRefs() const 95 S32 getNumRefs() const
143 { 96 {
144 return mRef; 97 return mRef;
@@ -150,6 +103,7 @@ private:
150 103
151//---------------------------------------------------------------------------- 104//----------------------------------------------------------------------------
152 105
106// Note: relies on Type having ref() and unref() methods
153template <class Type> class LLPointer 107template <class Type> class LLPointer
154{ 108{
155public: 109public:
@@ -268,6 +222,154 @@ protected:
268 Type* mPointer; 222 Type* mPointer;
269}; 223};
270 224
225//template <class Type>
226//class LLPointerTraits
227//{
228// static Type* null();
229//};
230//
231// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL.
232// This is useful in instances where operations on NULL pointers are semantically safe and/or
233// when error checking occurs at a different granularity or in a different part of the code
234// than when referencing an object via a LLHandle.
235//
236
237template <class Type>
238class LLHandle
239{
240public:
241 LLHandle() :
242 mPointer(sNullFunc())
243 {
244 ref();
245 }
246
247 LLHandle(Type* ptr) :
248 mPointer(nonNull(ptr))
249 {
250 ref();
251 }
252
253 LLHandle(const LLHandle<Type>& ptr) :
254 mPointer(ptr.mPointer)
255 {
256 ref();
257 }
258
259 // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
260 template<typename Subclass>
261 LLHandle(const LLHandle<Subclass>& ptr) :
262 mPointer(ptr.get())
263 {
264 ref();
265 }
266
267 ~LLHandle()
268 {
269 unref();
270 }
271
272 Type* get() const { return mPointer; }
273 const Type* operator->() const { return mPointer; }
274 Type* operator->() { return mPointer; }
275 const Type& operator*() const { return *mPointer; }
276 Type& operator*() { return *mPointer; }
277
278 operator BOOL() const { return (mPointer != sNullFunc()); }
279 operator bool() const { return (mPointer != sNullFunc()); }
280 bool operator!() const { return (mPointer == sNullFunc()); }
281 bool isNull() const { return (mPointer == sNullFunc()); }
282 bool notNull() const { return (mPointer != sNullFunc()); }
283
284
285 operator Type*() const { return mPointer; }
286 operator const Type*() const { return mPointer; }
287 bool operator !=(Type* ptr) const { return (mPointer != nonNull(ptr)); }
288 bool operator ==(Type* ptr) const { return (mPointer == nonNull(ptr)); }
289 bool operator ==(const LLHandle<Type>& ptr) const { return (mPointer == ptr.mPointer); }
290 bool operator < (const LLHandle<Type>& ptr) const { return (mPointer < ptr.mPointer); }
291 bool operator > (const LLHandle<Type>& ptr) const { return (mPointer > ptr.mPointer); }
292
293 LLHandle<Type>& operator =(Type* ptr)
294 {
295 if( mPointer != ptr )
296 {
297 unref();
298 mPointer = nonNull(ptr);
299 ref();
300 }
301
302 return *this;
303 }
304
305 LLHandle<Type>& operator =(const LLHandle<Type>& ptr)
306 {
307 if( mPointer != ptr.mPointer )
308 {
309 unref();
310 mPointer = ptr.mPointer;
311 ref();
312 }
313 return *this;
314 }
315
316 // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
317 template<typename Subclass>
318 LLHandle<Type>& operator =(const LLHandle<Subclass>& ptr)
319 {
320 if( mPointer != ptr.get() )
321 {
322 unref();
323 mPointer = ptr.get();
324 ref();
325 }
326 return *this;
327 }
328
329public:
330 typedef Type* (*NullFunc)();
331 static const NullFunc sNullFunc;
332
333protected:
334 void ref()
335 {
336 if (mPointer)
337 {
338 mPointer->ref();
339 }
340 }
341
342 void unref()
343 {
344 if (mPointer)
345 {
346 Type *tempp = mPointer;
347 mPointer = sNullFunc();
348 tempp->unref();
349 if (mPointer != sNullFunc())
350 {
351 llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
352 unref();
353 }
354 }
355 }
356
357 static Type* nonNull(Type* ptr)
358 {
359 return ptr == NULL ? sNullFunc() : ptr;
360 }
361
362 static Type* defaultNullFunc()
363 {
364 llerrs << "No null value provided for LLHandle" << llendl;
365 return NULL;
366 }
367
368protected:
369
370 Type* mPointer;
371};
372
271// LLInitializedPointer is just a pointer with a default constructor that initializes it to NULL 373// LLInitializedPointer is just a pointer with a default constructor that initializes it to NULL
272// NOT a smart pointer like LLPointer<> 374// NOT a smart pointer like LLPointer<>
273// Useful for example in std::map<int,LLInitializedPointer<LLFoo> > 375// Useful for example in std::map<int,LLInitializedPointer<LLFoo> >
diff --git a/linden/indra/llcommon/llmemtype.h b/linden/indra/llcommon/llmemtype.h
index 15ef924..0af1ed3 100644
--- a/linden/indra/llcommon/llmemtype.h
+++ b/linden/indra/llcommon/llmemtype.h
@@ -71,6 +71,7 @@ public:
71 71
72 MTYPE_DRAWABLE, 72 MTYPE_DRAWABLE,
73 MTYPE_OBJECT, 73 MTYPE_OBJECT,
74 MTYPE_VERTEX_DATA,
74 MTYPE_SPACE_PARTITION, 75 MTYPE_SPACE_PARTITION,
75 MTYPE_PIPELINE, 76 MTYPE_PIPELINE,
76 MTYPE_AVATAR, 77 MTYPE_AVATAR,
diff --git a/linden/indra/llcommon/llpreprocessor.h b/linden/indra/llcommon/llpreprocessor.h
index f03fe89..9db0108 100644
--- a/linden/indra/llcommon/llpreprocessor.h
+++ b/linden/indra/llcommon/llpreprocessor.h
@@ -51,7 +51,9 @@
51 #define LL_LIBXUL_ENABLED 1 51 #define LL_LIBXUL_ENABLED 1
52#elif LL_LINUX 52#elif LL_LINUX
53 #define LL_QUICKTIME_ENABLED 0 53 #define LL_QUICKTIME_ENABLED 0
54 #define LL_LIBXUL_ENABLED 0 54 #ifndef LL_LIBXUL_ENABLED
55 #define LL_LIBXUL_ENABLED 1
56 #endif // def LL_LIBXUL_ENABLED
55#endif 57#endif
56 58
57#if LL_LIBXUL_ENABLED && !defined(MOZILLA_INTERNAL_API) 59#if LL_LIBXUL_ENABLED && !defined(MOZILLA_INTERNAL_API)
@@ -80,7 +82,7 @@
80 82
81// Deal with the differeneces on Windows 83// Deal with the differeneces on Windows
82#if defined(LL_WINDOWS) 84#if defined(LL_WINDOWS)
83#define snprintf _snprintf 85#define snprintf _snprintf /*Flawfinder: ignore*/
84#endif // LL_WINDOWS 86#endif // LL_WINDOWS
85 87
86// Static linking with apr on windows needs to be declared. 88// Static linking with apr on windows needs to be declared.
@@ -110,6 +112,7 @@
110#pragma warning( disable : 4284 ) // silly MS warning deep inside their <map> include file 112#pragma warning( disable : 4284 ) // silly MS warning deep inside their <map> include file
111#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. 113#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation.
112#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) 114#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
115#pragma warning( disable : 4996 ) // warning: deprecated
113#endif // LL_WINDOWS 116#endif // LL_WINDOWS
114 117
115#endif // not LL_LINDEN_PREPROCESSOR_H 118#endif // not LL_LINDEN_PREPROCESSOR_H
diff --git a/linden/indra/llcommon/llprocessor.cpp b/linden/indra/llcommon/llprocessor.cpp
index b811678..3408cb1 100644
--- a/linden/indra/llcommon/llprocessor.cpp
+++ b/linden/indra/llcommon/llprocessor.cpp
@@ -604,7 +604,7 @@ bool CProcessor::AnalyzeIntelProcessor()
604 mov sig3, edx 604 mov sig3, edx
605 } 605 }
606 // Then we convert the data to a readable string 606 // Then we convert the data to a readable string
607 snprintf( 607 snprintf( /* Flawfinder: ignore */
608 CPUInfo.strProcessorSerial, 608 CPUInfo.strProcessorSerial,
609 sizeof(CPUInfo.strProcessorSerial), 609 sizeof(CPUInfo.strProcessorSerial),
610 "%04lX-%04lX-%04lX-%04lX-%04lX-%04lX", 610 "%04lX-%04lX-%04lX-%04lX-%04lX-%04lX",
@@ -612,15 +612,15 @@ bool CProcessor::AnalyzeIntelProcessor()
612 sig1 & 0xFFFF, 612 sig1 & 0xFFFF,
613 sig3 >> 16, 613 sig3 >> 16,
614 sig3 & 0xFFFF, 614 sig3 & 0xFFFF,
615 sig2 >> 16, sig2 & 0xFFFF); /* Flawfinder: ignore */ 615 sig2 >> 16, sig2 & 0xFFFF);
616 } 616 }
617 else 617 else
618 { 618 {
619 // If there's no serial number support we just put "No serial number" 619 // If there's no serial number support we just put "No serial number"
620 snprintf( 620 snprintf( /* Flawfinder: ignore */
621 CPUInfo.strProcessorSerial, 621 CPUInfo.strProcessorSerial,
622 sizeof(CPUInfo.strProcessorSerial), 622 sizeof(CPUInfo.strProcessorSerial),
623 "No Processor Serial Number"); /* Flawfinder: ignore */ 623 "No Processor Serial Number");
624 } 624 }
625 625
626 // Now we get the standard processor extensions 626 // Now we get the standard processor extensions
@@ -854,7 +854,7 @@ bool CProcessor::AnalyzeAMDProcessor()
854 break; 854 break;
855 case 0xD: // Model = 0xD: K6-2+ / K6-III+ 855 case 0xD: // Model = 0xD: K6-2+ / K6-III+
856 strcpy(CPUInfo.strModel, "AMD K6-2+ or K6-III+ (0.18 micron)"); /* Flawfinder: ignore */ 856 strcpy(CPUInfo.strModel, "AMD K6-2+ or K6-III+ (0.18 micron)"); /* Flawfinder: ignore */
857 strncat(strCPUName, "AMD K6-2+ or K6-III+ (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); 857 strncat(strCPUName, "AMD K6-2+ or K6-III+ (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
858 break; 858 break;
859 default: // ... 859 default: // ...
860 strcpy(CPUInfo.strModel, "Unknown AMD K5 or K6 model"); /* Flawfinder: ignore */ 860 strcpy(CPUInfo.strModel, "Unknown AMD K5 or K6 model"); /* Flawfinder: ignore */
diff --git a/linden/indra/llcommon/llqueuedthread.cpp b/linden/indra/llcommon/llqueuedthread.cpp
index 565836b..2e4324b 100644
--- a/linden/indra/llcommon/llqueuedthread.cpp
+++ b/linden/indra/llcommon/llqueuedthread.cpp
@@ -31,10 +31,9 @@
31//============================================================================ 31//============================================================================
32 32
33// MAIN THREAD 33// MAIN THREAD
34LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool runalways) : 34LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
35 LLThread(name), 35 LLThread(name),
36 mThreaded(threaded), 36 mThreaded(threaded),
37 mRunAlways(runalways),
38 mIdleThread(TRUE), 37 mIdleThread(TRUE),
39 mNextHandle(0) 38 mNextHandle(0)
40{ 39{
@@ -47,6 +46,12 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool runa
47// MAIN THREAD 46// MAIN THREAD
48LLQueuedThread::~LLQueuedThread() 47LLQueuedThread::~LLQueuedThread()
49{ 48{
49 shutdown();
50 // ~LLThread() will be called here
51}
52
53void LLQueuedThread::shutdown()
54{
50 setQuitting(); 55 setQuitting();
51 56
52 unpause(); // MAIN THREAD 57 unpause(); // MAIN THREAD
@@ -73,61 +78,69 @@ LLQueuedThread::~LLQueuedThread()
73 } 78 }
74 79
75 QueuedRequest* req; 80 QueuedRequest* req;
81 S32 active_count = 0;
76 while ( (req = (QueuedRequest*)mRequestHash.pop_element()) ) 82 while ( (req = (QueuedRequest*)mRequestHash.pop_element()) )
77 { 83 {
84 if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS)
85 {
86 ++active_count;
87 }
78 req->deleteRequest(); 88 req->deleteRequest();
79 } 89 }
80 90 if (active_count)
81 // ~LLThread() will be called here 91 {
92 llwarns << "~LLQueuedThread() called with active requests: " << active_count << llendl;
93 }
82} 94}
83 95
84//---------------------------------------------------------------------------- 96//----------------------------------------------------------------------------
85 97
86// MAIN THREAD 98// MAIN THREAD
87void LLQueuedThread::update(U32 ms_elapsed) 99// virtual
100S32 LLQueuedThread::update(U32 max_time_ms)
88{ 101{
89 updateQueue(0); 102 return updateQueue(max_time_ms);
90} 103}
91 104
92void LLQueuedThread::updateQueue(S32 inc) 105S32 LLQueuedThread::updateQueue(U32 max_time_ms)
93{ 106{
94 // If mRunAlways == TRUE, unpause the thread whenever we put something into the queue. 107 F64 max_time = (F64)max_time_ms * .001;
95 // If mRunAlways == FALSE, we only unpause the thread when updateQueue() is called from the main loop (i.e. between rendered frames) 108 LLTimer timer;
96 109 S32 pending = 1;
97 if (inc == 0) // Frame Update 110
111 // Frame Update
112 if (mThreaded)
98 { 113 {
99 if (mThreaded) 114 pending = getPending();
100 { 115 unpause();
101 unpause(); 116 }
102 wake(); // Wake the thread up if necessary. 117 else
103 } 118 {
104 else 119 while (pending > 0)
105 { 120 {
106 while (processNextRequest() > 0) 121 pending = processNextRequest();
107 ; 122 if (max_time && timer.getElapsedTimeF64() > max_time)
123 break;
108 } 124 }
109 } 125 }
110 else 126 return pending;
127}
128
129void LLQueuedThread::incQueue()
130{
131 // Something has been added to the queue
132 if (!isPaused())
111 { 133 {
112 // Something has been added to the queue 134 if (mThreaded)
113 if (mRunAlways)
114 { 135 {
115 if (mThreaded) 136 wake(); // Wake the thread up if necessary.
116 {
117 wake(); // Wake the thread up if necessary.
118 }
119 else
120 {
121 while(processNextRequest() > 0)
122 ;
123 }
124 } 137 }
125 } 138 }
126} 139}
127 140
128//virtual 141//virtual
129// May be called from any thread 142// May be called from any thread
130S32 LLQueuedThread::getPending(bool child_thread) 143S32 LLQueuedThread::getPending()
131{ 144{
132 S32 res; 145 S32 res;
133 lockData(); 146 lockData();
@@ -141,7 +154,7 @@ void LLQueuedThread::waitOnPending()
141{ 154{
142 while(1) 155 while(1)
143 { 156 {
144 updateQueue(0); 157 update(0);
145 158
146 if (mIdleThread) 159 if (mIdleThread)
147 { 160 {
@@ -200,7 +213,7 @@ bool LLQueuedThread::addRequest(QueuedRequest* req)
200#endif 213#endif
201 unlockData(); 214 unlockData();
202 215
203 updateQueue(1); 216 incQueue();
204 217
205 return true; 218 return true;
206} 219}
@@ -214,7 +227,7 @@ bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_co
214 bool done = false; 227 bool done = false;
215 while(!done) 228 while(!done)
216 { 229 {
217 updateQueue(0); // unpauses 230 update(0); // unpauses
218 lockData(); 231 lockData();
219 QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); 232 QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
220 if (!req) 233 if (!req)
@@ -272,51 +285,47 @@ LLQueuedThread::status_t LLQueuedThread::getRequestStatus(handle_t handle)
272 return res; 285 return res;
273} 286}
274 287
275LLQueuedThread::status_t LLQueuedThread::abortRequest(handle_t handle, U32 flags) 288void LLQueuedThread::abortRequest(handle_t handle, bool autocomplete)
276{ 289{
277 status_t res = STATUS_EXPIRED;
278 lockData(); 290 lockData();
279 QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); 291 QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
280 if (req) 292 if (req)
281 { 293 {
282 res = req->abortRequest(flags); 294 req->setFlags(FLAG_ABORT | (autocomplete ? FLAG_AUTO_COMPLETE : 0));
283 if ((flags & AUTO_COMPLETE) && (res == STATUS_COMPLETE))
284 {
285 mRequestHash.erase(handle);
286 req->deleteRequest();
287// check();
288 }
289#if _DEBUG
290// llinfos << llformat("LLQueuedThread::Aborted req [%08d]",handle) << llendl;
291#endif
292 } 295 }
293 unlockData(); 296 unlockData();
294 return res;
295} 297}
296 298
297// MAIN thread 299// MAIN thread
298LLQueuedThread::status_t LLQueuedThread::setFlags(handle_t handle, U32 flags) 300void LLQueuedThread::setFlags(handle_t handle, U32 flags)
299{ 301{
300 status_t res = STATUS_EXPIRED;
301 lockData(); 302 lockData();
302 QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); 303 QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
303 if (req) 304 if (req)
304 { 305 {
305 res = req->setFlags(flags); 306 req->setFlags(flags);
306 } 307 }
307 unlockData(); 308 unlockData();
308 return res;
309} 309}
310 310
311void LLQueuedThread::setPriority(handle_t handle, U32 priority) 311void LLQueuedThread::setPriority(handle_t handle, U32 priority)
312{ 312{
313 lockData(); 313 lockData();
314 QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); 314 QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
315 if (req && (req->getStatus() == STATUS_QUEUED)) 315 if (req)
316 { 316 {
317 llverify(mRequestQueue.erase(req) == 1); 317 if(req->getStatus() == STATUS_INPROGRESS)
318 req->setPriority(priority); 318 {
319 mRequestQueue.insert(req); 319 // not in list
320 req->setPriority(priority);
321 }
322 else if(req->getStatus() == STATUS_QUEUED)
323 {
324 // remove from list then re-insert
325 llverify(mRequestQueue.erase(req) == 1);
326 req->setPriority(priority);
327 mRequestQueue.insert(req);
328 }
320 } 329 }
321 unlockData(); 330 unlockData();
322} 331}
@@ -328,9 +337,10 @@ bool LLQueuedThread::completeRequest(handle_t handle)
328 QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); 337 QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
329 if (req) 338 if (req)
330 { 339 {
331 llassert(req->getStatus() != STATUS_QUEUED && req->getStatus() != STATUS_ABORT); 340 llassert_always(req->getStatus() != STATUS_QUEUED);
341 llassert_always(req->getStatus() != STATUS_INPROGRESS);
332#if _DEBUG 342#if _DEBUG
333// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl; 343// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl;
334#endif 344#endif
335 mRequestHash.erase(handle); 345 mRequestHash.erase(handle);
336 req->deleteRequest(); 346 req->deleteRequest();
@@ -364,28 +374,34 @@ bool LLQueuedThread::check()
364//============================================================================ 374//============================================================================
365// Runs on its OWN thread 375// Runs on its OWN thread
366 376
367int LLQueuedThread::processNextRequest() 377S32 LLQueuedThread::processNextRequest()
368{ 378{
369 QueuedRequest *req = 0; 379 QueuedRequest *req;
370 // Get next request from pool 380 // Get next request from pool
371 lockData(); 381 lockData();
372 while(1) 382 while(1)
373 { 383 {
374 if (!mRequestQueue.empty()) 384 req = NULL;
385 if (mRequestQueue.empty())
375 { 386 {
376 req = *mRequestQueue.begin(); 387 break;
377 mRequestQueue.erase(mRequestQueue.begin());
378 } 388 }
379 if (req && req->getStatus() == STATUS_ABORT) 389 req = *mRequestQueue.begin();
390 mRequestQueue.erase(mRequestQueue.begin());
391 if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
380 { 392 {
381 req->setStatus(STATUS_ABORTED); 393 req->setStatus(STATUS_ABORTED);
382 req = 0; 394 req->finishRequest(false);
383 } 395 if (req->getFlags() & FLAG_AUTO_COMPLETE)
384 else 396 {
385 { 397 mRequestHash.erase(req);
386 llassert (!req || req->getStatus() == STATUS_QUEUED) 398 req->deleteRequest();
387 break; 399// check();
400 }
401 continue;
388 } 402 }
403 llassert_always(req->getStatus() == STATUS_QUEUED);
404 break;
389 } 405 }
390 if (req) 406 if (req)
391 { 407 {
@@ -393,22 +409,22 @@ int LLQueuedThread::processNextRequest()
393 } 409 }
394 unlockData(); 410 unlockData();
395 411
396 // This is the only place we will cal req->setStatus() after 412 // This is the only place we will call req->setStatus() after
397 // it has initially been seet to STATUS_QUEUED, so it is 413 // it has initially been seet to STATUS_QUEUED, so it is
398 // safe to access req. 414 // safe to access req.
399 if (req) 415 if (req)
400 { 416 {
401 // process request 417 // process request
402 bool complete = processRequest(req); 418 bool complete = req->processRequest();
403 419
404 if (complete) 420 if (complete)
405 { 421 {
406 lockData(); 422 lockData();
407 req->setStatus(STATUS_COMPLETE); 423 req->setStatus(STATUS_COMPLETE);
408 req->finishRequest(); 424 req->finishRequest(true);
409 if (req->getFlags() & AUTO_COMPLETE) 425 if (req->getFlags() & FLAG_AUTO_COMPLETE)
410 { 426 {
411 llverify(mRequestHash.erase(req)) 427 mRequestHash.erase(req);
412 req->deleteRequest(); 428 req->deleteRequest();
413// check(); 429// check();
414 } 430 }
@@ -419,12 +435,18 @@ int LLQueuedThread::processNextRequest()
419 lockData(); 435 lockData();
420 req->setStatus(STATUS_QUEUED); 436 req->setStatus(STATUS_QUEUED);
421 mRequestQueue.insert(req); 437 mRequestQueue.insert(req);
438 U32 priority = req->getPriority();
422 unlockData(); 439 unlockData();
440 if (priority < PRIORITY_NORMAL)
441 {
442 ms_sleep(1); // sleep the thread a little
443 }
423 } 444 }
424 } 445 }
425 446
426 int res; 447 S32 res;
427 if (getPending(true) == 0) 448 S32 pending = getPending();
449 if (pending == 0)
428 { 450 {
429 if (isQuitting()) 451 if (isQuitting())
430 { 452 {
@@ -437,7 +459,7 @@ int LLQueuedThread::processNextRequest()
437 } 459 }
438 else 460 else
439 { 461 {
440 res = 1; 462 res = pending;
441 } 463 }
442 return res; 464 return res;
443} 465}
@@ -445,13 +467,14 @@ int LLQueuedThread::processNextRequest()
445bool LLQueuedThread::runCondition() 467bool LLQueuedThread::runCondition()
446{ 468{
447 // mRunCondition must be locked here 469 // mRunCondition must be locked here
448 return (mRequestQueue.empty() && mIdleThread) ? FALSE : TRUE; 470 if (mRequestQueue.empty() && mIdleThread)
471 return false;
472 else
473 return true;
449} 474}
450 475
451void LLQueuedThread::run() 476void LLQueuedThread::run()
452{ 477{
453 llinfos << "QUEUED THREAD STARTING" << llendl;
454
455 while (1) 478 while (1)
456 { 479 {
457 // this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state. 480 // this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state.
@@ -474,6 +497,8 @@ void LLQueuedThread::run()
474 { 497 {
475 break; 498 break;
476 } 499 }
500
501 //LLThread::yield(); // thread should yield after each request
477 } 502 }
478 503
479 llinfos << "QUEUED THREAD " << mName << " EXITING." << llendl; 504 llinfos << "QUEUED THREAD " << mName << " EXITING." << llendl;
@@ -491,20 +516,18 @@ LLQueuedThread::QueuedRequest::QueuedRequest(LLQueuedThread::handle_t handle, U3
491 516
492LLQueuedThread::QueuedRequest::~QueuedRequest() 517LLQueuedThread::QueuedRequest::~QueuedRequest()
493{ 518{
494 if (mStatus != STATUS_DELETE) 519 llassert_always(mStatus == STATUS_DELETE);
495 {
496 llerrs << "Attemt to directly delete a LLQueuedThread::QueuedRequest; use deleteRequest()" << llendl;
497 }
498} 520}
499 521
500//virtual 522//virtual
501void LLQueuedThread::QueuedRequest::finishRequest() 523void LLQueuedThread::QueuedRequest::finishRequest(bool completed)
502{ 524{
503} 525}
504 526
505//virtual 527//virtual
506void LLQueuedThread::QueuedRequest::deleteRequest() 528void LLQueuedThread::QueuedRequest::deleteRequest()
507{ 529{
530 llassert_always(mStatus != STATUS_INPROGRESS);
508 setStatus(STATUS_DELETE); 531 setStatus(STATUS_DELETE);
509 delete this; 532 delete this;
510} 533}
diff --git a/linden/indra/llcommon/llqueuedthread.h b/linden/indra/llcommon/llqueuedthread.h
index cc21b3b..7231285 100644
--- a/linden/indra/llcommon/llqueuedthread.h
+++ b/linden/indra/llcommon/llqueuedthread.h
@@ -52,7 +52,8 @@ public:
52 PRIORITY_HIGH = 0x30000000, 52 PRIORITY_HIGH = 0x30000000,
53 PRIORITY_NORMAL = 0x20000000, 53 PRIORITY_NORMAL = 0x20000000,
54 PRIORITY_LOW = 0x10000000, 54 PRIORITY_LOW = 0x10000000,
55 PRIORITY_LOWBITS = 0x0FFFFFFF 55 PRIORITY_LOWBITS = 0x0FFFFFFF,
56 PRIORITY_HIGHBITS = 0x70000000
56 }; 57 };
57 enum status_t { 58 enum status_t {
58 STATUS_EXPIRED = -1, 59 STATUS_EXPIRED = -1,
@@ -60,13 +61,13 @@ public:
60 STATUS_QUEUED = 1, 61 STATUS_QUEUED = 1,
61 STATUS_INPROGRESS = 2, 62 STATUS_INPROGRESS = 2,
62 STATUS_COMPLETE = 3, 63 STATUS_COMPLETE = 3,
63 STATUS_ABORT = 4, 64 STATUS_ABORTED = 4,
64 STATUS_ABORTED = 5, 65 STATUS_DELETE = 5
65 STATUS_DELETE = 6
66 }; 66 };
67 enum flags_t { 67 enum flags_t {
68 AUTO_COMPLETE = 1, 68 FLAG_AUTO_COMPLETE = 1,
69 AUTO_DELETE = 2 // child-class dependent 69 FLAG_AUTO_DELETE = 2, // child-class dependent
70 FLAG_ABORT = 4
70 }; 71 };
71 72
72 typedef U32 handle_t; 73 typedef U32 handle_t;
@@ -79,7 +80,7 @@ public:
79 friend class LLQueuedThread; 80 friend class LLQueuedThread;
80 81
81 protected: 82 protected:
82 ~QueuedRequest(); // use deleteRequest() 83 virtual ~QueuedRequest(); // use deleteRequest()
83 84
84 public: 85 public:
85 QueuedRequest(handle_t handle, U32 priority, U32 flags = 0); 86 QueuedRequest(handle_t handle, U32 priority, U32 flags = 0);
@@ -111,26 +112,14 @@ public:
111 mStatus = newstatus; 112 mStatus = newstatus;
112 return oldstatus; 113 return oldstatus;
113 } 114 }
114 status_t abortRequest(U32 flags) 115 void setFlags(U32 flags)
115 { 116 {
116 // NOTE: flags are |'d 117 // NOTE: flags are |'d
117 if (mStatus == STATUS_QUEUED)
118 {
119 setStatus(STATUS_ABORT);
120 }
121 mFlags |= flags; 118 mFlags |= flags;
122 status_t status = mStatus;
123 return status;
124 }
125 status_t setFlags(U32 flags)
126 {
127 // NOTE: flags are |'d
128 mFlags |= flags;
129 status_t status = mStatus;
130 return status;
131 } 119 }
132 120
133 virtual void finishRequest(); // Always called when after has been processed 121 virtual bool processRequest() = 0; // Return true when request has completed
122 virtual void finishRequest(bool completed); // Always called from thread after request has completed or aborted
134 virtual void deleteRequest(); // Only method to delete a request 123 virtual void deleteRequest(); // Only method to delete a request
135 124
136 void setPriority(U32 pri) 125 void setPriority(U32 pri)
@@ -160,9 +149,10 @@ public:
160 static handle_t nullHandle() { return handle_t(0); } 149 static handle_t nullHandle() { return handle_t(0); }
161 150
162public: 151public:
163 LLQueuedThread(const std::string& name, bool threaded = TRUE, bool runalways = TRUE); 152 LLQueuedThread(const std::string& name, bool threaded = true);
164 virtual ~LLQueuedThread(); 153 virtual ~LLQueuedThread();
165 154 virtual void shutdown();
155
166private: 156private:
167 // No copy constructor or copy assignment 157 // No copy constructor or copy assignment
168 LLQueuedThread(const LLQueuedThread&); 158 LLQueuedThread(const LLQueuedThread&);
@@ -174,26 +164,25 @@ private:
174protected: 164protected:
175 handle_t generateHandle(); 165 handle_t generateHandle();
176 bool addRequest(QueuedRequest* req); 166 bool addRequest(QueuedRequest* req);
177 int processNextRequest(void); 167 S32 processNextRequest(void);
168 void incQueue();
178 169
179 virtual bool processRequest(QueuedRequest* req) = 0;
180
181public: 170public:
182 bool waitForResult(handle_t handle, bool auto_complete = true); 171 bool waitForResult(handle_t handle, bool auto_complete = true);
183 172
184 void update(U32 ms_elapsed); 173 virtual S32 update(U32 max_time_ms);
185 void updateQueue(S32 inc); 174 S32 updateQueue(U32 max_time_ms);
175
186 void waitOnPending(); 176 void waitOnPending();
187 void printQueueStats(); 177 void printQueueStats();
188 178
189 S32 getPending(bool child_thread = false); 179 S32 getPending();
190 bool getThreaded() { return mThreaded ? true : false; } 180 bool getThreaded() { return mThreaded ? true : false; }
191 bool getRunAlways() { return mRunAlways ? true : false; }
192 181
193 // Request accessors 182 // Request accessors
194 status_t getRequestStatus(handle_t handle); 183 status_t getRequestStatus(handle_t handle);
195 status_t abortRequest(handle_t handle, U32 flags = 0); 184 void abortRequest(handle_t handle, bool autocomplete);
196 status_t setFlags(handle_t handle, U32 flags); 185 void setFlags(handle_t handle, U32 flags);
197 void setPriority(handle_t handle, U32 priority); 186 void setPriority(handle_t handle, U32 priority);
198 bool completeRequest(handle_t handle); 187 bool completeRequest(handle_t handle);
199 // This is public for support classes like LLWorkerThread, 188 // This is public for support classes like LLWorkerThread,
@@ -205,7 +194,6 @@ public:
205 194
206protected: 195protected:
207 BOOL mThreaded; // if false, run on main thread and do updates during update() 196 BOOL mThreaded; // if false, run on main thread and do updates during update()
208 BOOL mRunAlways; // if false, only wake the threads when updateClass() is called
209 LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle 197 LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
210 198
211 typedef std::set<QueuedRequest*, queued_request_less> request_queue_t; 199 typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
diff --git a/linden/indra/llcommon/llsd.cpp b/linden/indra/llcommon/llsd.cpp
index 7a0ff9d..342e356 100644
--- a/linden/indra/llcommon/llsd.cpp
+++ b/linden/indra/llcommon/llsd.cpp
@@ -27,8 +27,12 @@
27 27
28#include "llsd.h" 28#include "llsd.h"
29 29
30#include <sstream>
30#include <math.h> 31#include <math.h>
32
33#include "llerror.h"
31#include "../llmath/llmath.h" 34#include "../llmath/llmath.h"
35#include "llformat.h"
32 36
33namespace { 37namespace {
34 class ImplMap; 38 class ImplMap;
@@ -251,7 +255,7 @@ namespace {
251 public: 255 public:
252 ImplUUID(const LLSD::UUID& v) : Base(v) { } 256 ImplUUID(const LLSD::UUID& v) : Base(v) { }
253 257
254 virtual LLSD::String asString() const{ return mValue.getString(); } 258 virtual LLSD::String asString() const{ return mValue.asString(); }
255 virtual LLSD::UUID asUUID() const { return mValue; } 259 virtual LLSD::UUID asUUID() const { return mValue; }
256 }; 260 };
257 261
diff --git a/linden/indra/llcommon/llsdserialize.cpp b/linden/indra/llcommon/llsdserialize.cpp
index 4c00c98..653fc66 100644
--- a/linden/indra/llcommon/llsdserialize.cpp
+++ b/linden/indra/llcommon/llsdserialize.cpp
@@ -804,7 +804,7 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const
804 // the size, and read it. 804 // the size, and read it.
805 // *FIX: Should we set a maximum size? 805 // *FIX: Should we set a maximum size?
806 U32 size_nbo = 0; 806 U32 size_nbo = 0;
807 istr.read((char*)&size_nbo, sizeof(U32)); 807 istr.read((char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/
808 S32 size = (S32)ntohl(size_nbo); 808 S32 size = (S32)ntohl(size_nbo);
809 std::vector<U8> value; 809 std::vector<U8> value;
810 if(size) 810 if(size)
@@ -944,7 +944,7 @@ void LLSDFormatter::realFormat(const std::string& format)
944void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const 944void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const
945{ 945{
946 char buffer[MAX_STRING]; /* Flawfinder: ignore */ 946 char buffer[MAX_STRING]; /* Flawfinder: ignore */
947 snprintf(buffer, MAX_STRING, mRealFormat.c_str(), real); 947 snprintf(buffer, MAX_STRING, mRealFormat.c_str(), real); /* Flawfinder: ignore */
948 ostr << buffer; 948 ostr << buffer;
949} 949}
950 950
diff --git a/linden/indra/llcommon/llsdserialize_xml.cpp b/linden/indra/llcommon/llsdserialize_xml.cpp
index 892f454..bb36fa7 100644
--- a/linden/indra/llcommon/llsdserialize_xml.cpp
+++ b/linden/indra/llcommon/llsdserialize_xml.cpp
@@ -190,6 +190,7 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti
190 else 190 else
191 { 191 {
192 // *FIX: memory inefficient. 192 // *FIX: memory inefficient.
193 // *TODO: convert to use LLBase64
193 ostr << pre << "<binary encoding=\"base64\">"; 194 ostr << pre << "<binary encoding=\"base64\">";
194 int b64_buffer_length = apr_base64_encode_len(buffer.size()); 195 int b64_buffer_length = apr_base64_encode_len(buffer.size());
195 char* b64_buffer = new char[b64_buffer_length]; 196 char* b64_buffer = new char[b64_buffer_length];
diff --git a/linden/indra/llcommon/llsecondlifeurls.cpp b/linden/indra/llcommon/llsecondlifeurls.cpp
index 6050d7f..4372373 100644
--- a/linden/indra/llcommon/llsecondlifeurls.cpp
+++ b/linden/indra/llcommon/llsecondlifeurls.cpp
@@ -76,7 +76,5 @@ const char LSL_DOC_URL[] =
76const char SL_KB_URL[] = 76const char SL_KB_URL[] =
77 "http://secondlife.com/knowledgebase/"; 77 "http://secondlife.com/knowledgebase/";
78 78
79const char ACCOUNT_TRANSACTIONS_URL[] =
80 "https://secondlife.com/account/transactions.php";
81
82const char RELEASE_NOTES[] = "releasenotes.txt"; 79const char RELEASE_NOTES[] = "releasenotes.txt";
80
diff --git a/linden/indra/llcommon/llsecondlifeurls.h b/linden/indra/llcommon/llsecondlifeurls.h
index f338bc3..1f7d359 100644
--- a/linden/indra/llcommon/llsecondlifeurls.h
+++ b/linden/indra/llcommon/llsecondlifeurls.h
@@ -50,18 +50,9 @@ extern const char UPGRADE_TO_PREMIUM_URL[];
50// How to get DirectX 9 50// How to get DirectX 9
51extern const char DIRECTX_9_URL[]; 51extern const char DIRECTX_9_URL[];
52 52
53// On AMD with bad AGP controller
54extern const char AMD_AGP_URL[];
55
56// Out of date VIA chipset 53// Out of date VIA chipset
57extern const char VIA_URL[]; 54extern const char VIA_URL[];
58 55
59// Out of date intel chipset driver
60extern const char INTEL_CHIPSET_URL[];
61
62// Out of date SiS chipset driver
63extern const char SIS_CHIPSET_URL[];
64
65// Linden Blogs page 56// Linden Blogs page
66extern const char BLOGS_URL[]; 57extern const char BLOGS_URL[];
67 58
@@ -74,9 +65,6 @@ extern const char LSL_DOC_URL[];
74// SL KnowledgeBase page 65// SL KnowledgeBase page
75extern const char SL_KB_URL[]; 66extern const char SL_KB_URL[];
76 67
77// Account transactions
78extern const char ACCOUNT_TRANSACTIONS_URL[];
79
80// Local Url Release Notes 68// Local Url Release Notes
81extern const char RELEASE_NOTES[]; 69extern const char RELEASE_NOTES[];
82 70
diff --git a/linden/indra/llcommon/llstreamtools.cpp b/linden/indra/llcommon/llstreamtools.cpp
index b68edd3..2c78e05 100644
--- a/linden/indra/llcommon/llstreamtools.cpp
+++ b/linden/indra/llcommon/llstreamtools.cpp
@@ -553,7 +553,7 @@ std::istream& fullread(std::istream& str, char *buf, std::streamsize requested)
553 553
554std::istream& operator>>(std::istream& str, const char *tocheck) 554std::istream& operator>>(std::istream& str, const char *tocheck)
555{ 555{
556 char c; 556 char c = '\0';
557 const char *p; 557 const char *p;
558 p = tocheck; 558 p = tocheck;
559 while (*p && !str.bad()) 559 while (*p && !str.bad())
diff --git a/linden/indra/llcommon/llstrider.h b/linden/indra/llcommon/llstrider.h
index 07b8c48..efc2ae4 100644
--- a/linden/indra/llcommon/llstrider.h
+++ b/linden/indra/llcommon/llstrider.h
@@ -51,6 +51,7 @@ public:
51 Object* operator->() { return mObjectp; } 51 Object* operator->() { return mObjectp; }
52 Object& operator *() { return *mObjectp; } 52 Object& operator *() { return *mObjectp; }
53 Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; } 53 Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
54 Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
54 Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); } 55 Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); }
55}; 56};
56 57
diff --git a/linden/indra/llcommon/llstring.cpp b/linden/indra/llcommon/llstring.cpp
index 5cb42cc..c9f684f 100644
--- a/linden/indra/llcommon/llstring.cpp
+++ b/linden/indra/llcommon/llstring.cpp
@@ -195,6 +195,7 @@ llutf16string utf8str_to_utf16str ( const LLString& utf8str )
195LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len) 195LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len)
196{ 196{
197 LLWString wout; 197 LLWString wout;
198 if((len <= 0) || utf16str.empty()) return wout;
198 199
199 S32 i = 0; 200 S32 i = 0;
200 // craziness to make gcc happy (llutf16string.c_str() is tweaked on linux): 201 // craziness to make gcc happy (llutf16string.c_str() is tweaked on linux):
diff --git a/linden/indra/llcommon/llstring.h b/linden/indra/llcommon/llstring.h
index a83b7cf..0485a1e 100644
--- a/linden/indra/llcommon/llstring.h
+++ b/linden/indra/llcommon/llstring.h
@@ -30,6 +30,7 @@
30 30
31#include "stdtypes.h" 31#include "stdtypes.h"
32#include "llerror.h" 32#include "llerror.h"
33#include "llfile.h"
33#include <algorithm> 34#include <algorithm>
34#include <map> 35#include <map>
35#include <stdio.h> 36#include <stdio.h>
@@ -101,7 +102,7 @@ struct char_traits<U16>
101 102
102 static char_type* 103 static char_type*
103 copy(char_type* __s1, const char_type* __s2, size_t __n) 104 copy(char_type* __s1, const char_type* __s2, size_t __n)
104 { return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); } 105 { return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */
105 106
106 static char_type* 107 static char_type*
107 assign(char_type* __s, size_t __n, char_type __a) 108 assign(char_type* __s, size_t __n, char_type __a)
@@ -922,7 +923,7 @@ void LLStringBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T r
922 923
923//static 924//static
924template<class T> 925template<class T>
925void LLStringBase<T>::replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab ) 926void LLStringBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab )
926{ 927{
927 llassert( spaces_per_tab >= 0 ); 928 llassert( spaces_per_tab >= 0 );
928 929
@@ -931,19 +932,19 @@ void LLStringBase<T>::replaceTabsWithSpaces( std::basic_string<T>& string, size_
931 932
932 LLStringBase<T> out_str; 933 LLStringBase<T> out_str;
933 // Replace tabs with spaces 934 // Replace tabs with spaces
934 for (size_type i = 0; i < string.length(); i++) 935 for (size_type i = 0; i < str.length(); i++)
935 { 936 {
936 if (string[i] == TAB) 937 if (str[i] == TAB)
937 { 938 {
938 for (size_type j = 0; j < spaces_per_tab; j++) 939 for (size_type j = 0; j < spaces_per_tab; j++)
939 out_str += SPACE; 940 out_str += SPACE;
940 } 941 }
941 else 942 else
942 { 943 {
943 out_str += string[i]; 944 out_str += str[i];
944 } 945 }
945 } 946 }
946 string = out_str; 947 str = out_str;
947} 948}
948 949
949//static 950//static
diff --git a/linden/indra/llcommon/llstringtable.h b/linden/indra/llcommon/llstringtable.h
index d53c0e1..ddfef88 100644
--- a/linden/indra/llcommon/llstringtable.h
+++ b/linden/indra/llcommon/llstringtable.h
@@ -29,14 +29,15 @@
29#ifndef LL_STRING_TABLE_H 29#ifndef LL_STRING_TABLE_H
30#define LL_STRING_TABLE_H 30#define LL_STRING_TABLE_H
31 31
32#include "lldefs.h"
33#include "llformat.h"
32#include "llstl.h" 34#include "llstl.h"
33#include <list> 35#include <list>
34#include <set> 36#include <set>
35 37
36#if LL_WINDOWS 38#if LL_WINDOWS
37# if (_MSC_VER >= 1300) 39# if (_MSC_VER >= 1300 && _MSC_VER < 1400)
38# define STRING_TABLE_HASH_MAP 1 40# define STRING_TABLE_HASH_MAP 1
39# pragma warning(disable : 4996)
40# endif 41# endif
41#else 42#else
42//# define STRING_TABLE_HASH_MAP 1 43//# define STRING_TABLE_HASH_MAP 1
diff --git a/linden/indra/llcommon/llsys.cpp b/linden/indra/llcommon/llsys.cpp
index 148e4de..906bc65 100644
--- a/linden/indra/llcommon/llsys.cpp
+++ b/linden/indra/llcommon/llsys.cpp
@@ -132,23 +132,23 @@ LLOSInfo::LLOSInfo() :
132 char tmp[MAX_STRING]; /* Flawfinder: ignore */ 132 char tmp[MAX_STRING]; /* Flawfinder: ignore */
133 if(osvi.dwMajorVersion <= 4) 133 if(osvi.dwMajorVersion <= 4)
134 { 134 {
135 snprintf( 135 snprintf( /* Flawfinder: ignore */
136 tmp, 136 tmp,
137 sizeof(tmp), 137 sizeof(tmp),
138 "version %d.%d %s (Build %d)", 138 "version %d.%d %s (Build %d)",
139 osvi.dwMajorVersion, 139 osvi.dwMajorVersion,
140 osvi.dwMinorVersion, 140 osvi.dwMinorVersion,
141 csdversion.c_str(), 141 csdversion.c_str(),
142 (osvi.dwBuildNumber & 0xffff)); /* Flawfinder: ignore */ 142 (osvi.dwBuildNumber & 0xffff));
143 } 143 }
144 else 144 else
145 { 145 {
146 snprintf( 146 snprintf( /* Flawfinder: ignore */
147 tmp, 147 tmp,
148 sizeof(tmp), 148 sizeof(tmp),
149 "%s (Build %d)", 149 "%s (Build %d)",
150 csdversion.c_str(), 150 csdversion.c_str(),
151 (osvi.dwBuildNumber & 0xffff)); /*Flawfinder: ignore*/ 151 (osvi.dwBuildNumber & 0xffff));
152 } 152 }
153 mOSString += tmp; 153 mOSString += tmp;
154 } 154 }
@@ -250,7 +250,7 @@ U32 LLOSInfo::getProcessVirtualSizeKB()
250#if LL_WINDOWS 250#if LL_WINDOWS
251#endif 251#endif
252#if LL_LINUX 252#if LL_LINUX
253 FILE *status_filep = LLFile::fopen("/proc/self/status", "r"); 253 FILE* status_filep = LLFile::fopen("/proc/self/status", "r"); /* Flawfinder: ignore */
254 S32 numRead = 0; 254 S32 numRead = 0;
255 char buff[STATUS_SIZE]; /* Flawfinder: ignore */ 255 char buff[STATUS_SIZE]; /* Flawfinder: ignore */
256 bzero(buff, STATUS_SIZE); 256 bzero(buff, STATUS_SIZE);
@@ -276,7 +276,7 @@ U32 LLOSInfo::getProcessResidentSizeKB()
276#if LL_WINDOWS 276#if LL_WINDOWS
277#endif 277#endif
278#if LL_LINUX 278#if LL_LINUX
279 FILE *status_filep = LLFile::fopen("/proc/self/status", "r"); 279 FILE* status_filep = LLFile::fopen("/proc/self/status", "r"); /* Flawfinder: ignore */
280 if (status_filep != NULL) 280 if (status_filep != NULL)
281 { 281 {
282 S32 numRead = 0; 282 S32 numRead = 0;
diff --git a/linden/indra/llcommon/llthread.cpp b/linden/indra/llcommon/llthread.cpp
index 290879d..d6b52f7 100644
--- a/linden/indra/llcommon/llthread.cpp
+++ b/linden/indra/llcommon/llthread.cpp
@@ -100,6 +100,11 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
100 100
101LLThread::~LLThread() 101LLThread::~LLThread()
102{ 102{
103 shutdown();
104}
105
106void LLThread::shutdown()
107{
103 // Warning! If you somehow call the thread destructor from itself, 108 // Warning! If you somehow call the thread destructor from itself,
104 // the thread will die in an unclean fashion! 109 // the thread will die in an unclean fashion!
105 if (mAPRThreadp) 110 if (mAPRThreadp)
@@ -205,18 +210,6 @@ void LLThread::checkPause()
205 210
206//============================================================================ 211//============================================================================
207 212
208bool LLThread::isQuitting() const
209{
210 return (QUITTING == mStatus);
211}
212
213
214bool LLThread::isStopped() const
215{
216 return (STOPPED == mStatus);
217}
218
219
220void LLThread::setQuitting() 213void LLThread::setQuitting()
221{ 214{
222 mRunCondition->lock(); 215 mRunCondition->lock();
@@ -347,3 +340,49 @@ void LLCondition::broadcast()
347 apr_thread_cond_broadcast(mAPRCondp); 340 apr_thread_cond_broadcast(mAPRCondp);
348} 341}
349 342
343//============================================================================
344
345//----------------------------------------------------------------------------
346
347//static
348LLMutex* LLThreadSafeRefCount::sMutex = 0;
349
350//static
351void LLThreadSafeRefCount::initClass()
352{
353 if (!sMutex)
354 {
355 sMutex = new LLMutex(0);
356 }
357}
358
359//static
360void LLThreadSafeRefCount::cleanupClass()
361{
362 delete sMutex;
363 sMutex = NULL;
364}
365
366
367//----------------------------------------------------------------------------
368
369LLThreadSafeRefCount::LLThreadSafeRefCount() :
370 mRef(0)
371{
372}
373
374LLThreadSafeRefCount::~LLThreadSafeRefCount()
375{
376 if (mRef != 0)
377 {
378 llerrs << "deleting non-zero reference" << llendl;
379 }
380}
381
382//============================================================================
383
384LLResponder::~LLResponder()
385{
386}
387
388//============================================================================
diff --git a/linden/indra/llcommon/llthread.h b/linden/indra/llcommon/llthread.h
index 2a13d72..cdf1d33 100644
--- a/linden/indra/llcommon/llthread.h
+++ b/linden/indra/llcommon/llthread.h
@@ -30,6 +30,7 @@
30 30
31#include "llapr.h" 31#include "llapr.h"
32#include "llapp.h" 32#include "llapp.h"
33#include "llmemory.h"
33 34
34#include "apr-1/apr_thread_cond.h" 35#include "apr-1/apr_thread_cond.h"
35 36
@@ -49,19 +50,20 @@ public:
49 50
50 LLThread(const std::string& name, apr_pool_t *poolp = NULL); 51 LLThread(const std::string& name, apr_pool_t *poolp = NULL);
51 virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state. 52 virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state.
52 53 virtual void shutdown(); // stops the thread
54
53 static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure. 55 static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure.
54 56
55 57
56 bool isQuitting() const; 58 bool isQuitting() const { return (QUITTING == mStatus); }
57 bool isStopped() const; 59 bool isStopped() const { return (STOPPED == mStatus); }
58 60
59 // PAUSE / RESUME functionality. See source code for important usage notes. 61 // PAUSE / RESUME functionality. See source code for important usage notes.
60public: 62public:
61 // Called from MAIN THREAD. 63 // Called from MAIN THREAD.
62 void pause(); 64 void pause();
63 void unpause(); 65 void unpause();
64 bool isPaused() { return mPaused ? true : false; } 66 bool isPaused() { return isStopped() || mPaused == TRUE; }
65 67
66 // Cause the thread to wake up and check its condition 68 // Cause the thread to wake up and check its condition
67 void wake(); 69 void wake();
@@ -79,7 +81,7 @@ public:
79 81
80private: 82private:
81 BOOL mPaused; 83 BOOL mPaused;
82 84
83 // static function passed to APR thread creation routine 85 // static function passed to APR thread creation routine
84 static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap); 86 static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap);
85 87
@@ -180,4 +182,67 @@ void LLThread::unlockData()
180 182
181//============================================================================ 183//============================================================================
182 184
185// see llmemory.h for LLPointer<> definition
186
187class LLThreadSafeRefCount
188{
189public:
190 static void initClass(); // creates sMutex
191 static void cleanupClass(); // destroys sMutex
192
193private:
194 static LLMutex* sMutex;
195
196private:
197 LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented
198 LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented
199
200protected:
201 virtual ~LLThreadSafeRefCount(); // use unref()
202
203public:
204 LLThreadSafeRefCount();
205
206 void ref()
207 {
208 if (sMutex) sMutex->lock();
209 mRef++;
210 if (sMutex) sMutex->unlock();
211 }
212
213 S32 unref()
214 {
215 llassert(mRef >= 1);
216 if (sMutex) sMutex->lock();
217 S32 res = --mRef;
218 if (sMutex) sMutex->unlock();
219 if (0 == res)
220 {
221 delete this;
222 res = 0;
223 }
224 return res;
225 }
226 S32 getNumRefs() const
227 {
228 return mRef;
229 }
230
231private:
232 S32 mRef;
233};
234
235//============================================================================
236
237// Simple responder for self destructing callbacks
238// Pure virtual class
239class LLResponder : public LLThreadSafeRefCount
240{
241public:
242 virtual ~LLResponder();
243 virtual void completed(bool success) = 0;
244};
245
246//============================================================================
247
183#endif // LL_LLTHREAD_H 248#endif // LL_LLTHREAD_H
diff --git a/linden/indra/llcommon/lluri.cpp b/linden/indra/llcommon/lluri.cpp
index e697ec1..bc3540e 100644
--- a/linden/indra/llcommon/lluri.cpp
+++ b/linden/indra/llcommon/lluri.cpp
@@ -32,273 +32,86 @@
32#include "llapp.h" 32#include "llapp.h"
33#include "lluri.h" 33#include "lluri.h"
34#include "llsd.h" 34#include "llsd.h"
35 35#include <iomanip>
36
36#include "../llmath/lluuid.h" 37#include "../llmath/lluuid.h"
37 38
38// uric = reserved | unreserved | escaped 39
39// reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," 40// static
40// unreserved = alphanum | mark 41std::string LLURI::escape(const std::string& str, const std::string & allowed)
41// mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
42// escaped = "%" hex hex
43static const char* ESCAPED_CHARACTERS[256] =
44{ 42{
45 "%00", // 0 43 std::ostringstream ostr;
46 "%01", // 1 44
47 "%02", // 2 45 std::string::const_iterator it = str.begin();
48 "%03", // 3 46 std::string::const_iterator end = str.end();
49 "%04", // 4 47 for(; it != end; ++it)
50 "%05", // 5 48 {
51 "%06", // 6 49 std::string::value_type c = *it;
52 "%07", // 7 50 if(allowed.find(c) == std::string::npos)
53 "%08", // 8 51 {
54 "%09", // 9 52 ostr << "%"
55 "%0a", // 10 53 << std::uppercase << std::hex << std::setw(2) << std::setfill('0')
56 "%0b", // 11 54 << static_cast<U32>(c);
57 "%0c", // 12 55 }
58 "%0d", // 13 56 else
59 "%0e", // 14 57 {
60 "%0f", // 15 58 ostr << c;
61 "%10", // 16 59 }
62 "%11", // 17 60 }
63 "%12", // 18 61 return ostr.str();
64 "%13", // 19 62}
65 "%14", // 20 63
66 "%15", // 21 64// static
67 "%16", // 22 65std::string LLURI::unescape(const std::string& str)
68 "%17", // 23 66{
69 "%18", // 24 67 std::ostringstream ostr;
70 "%19", // 25 68 std::string::const_iterator it = str.begin();
71 "%1a", // 26 69 std::string::const_iterator end = str.end();
72 "%1b", // 27 70 for(; it != end; ++it)
73 "%1c", // 28 71 {
74 "%1d", // 29 72 if((*it) == '%')
75 "%1e", // 30 73 {
76 "%1f", // 31 74 ++it;
77 "%20", // 32 75 if(it == end) break;
78 "!", // 33 76 U8 c = hex_as_nybble(*it++);
79 "%22", // 34 77 c = c << 4;
80 "%23", // 35 78 if (it == end) break;
81 "$", // 36 79 c |= hex_as_nybble(*it);
82 "%25", // 37 80 ostr.put((char)c);
83 "&", // 38 81 }
84 "'", // 39 82 else
85 "(", // 40 83 {
86 ")", // 41 84 ostr.put(*it);
87 "*", // 42 85 }
88 "+", // 43 86 }
89 ",", // 44 87 return ostr.str();
90 "-", // 45 88}
91 ".", // 46 89
92 "/", // 47 90namespace
93 "0", // 48 91{
94 "1", // 49 92 const std::string unreserved()
95 "2", // 50 93 {
96 "3", // 51 94 static const std::string s =
97 "4", // 52 95 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
98 "5", // 53 96 "0123456789"
99 "6", // 54 97 "-._~";
100 "7", // 55 98 return s;
101 "8", // 56 99 }
102 "9", // 57 100 const std::string sub_delims()
103 ":", // 58 101 {
104 ";", // 59 102 static const std::string s = "!$&'()*+,;=";
105 "%3c", // 60 103 return s;
106 "=", // 61 104 }
107 "%3e", // 62 105
108 "?", // 63 106 std::string escapeHostAndPort(const std::string& s)
109 "@", // 64 107 { return LLURI::escape(s, unreserved() + sub_delims() +":"); }
110 "A", // 65 108 std::string escapePathComponent(const std::string& s)
111 "B", // 66 109 { return LLURI::escape(s, unreserved() + sub_delims() + ":@"); }
112 "C", // 67 110 std::string escapeQueryVariable(const std::string& s)
113 "D", // 68 111 { return LLURI::escape(s, unreserved() + ":@!$'()*+,"); } // sub_delims - "&;=" + ":@"
114 "E", // 69 112 std::string escapeQueryValue(const std::string& s)
115 "F", // 70 113 { return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@"
116 "G", // 71 114}
117 "H", // 72
118 "I", // 73
119 "J", // 74
120 "K", // 75
121 "L", // 76
122 "M", // 77
123 "N", // 78
124 "O", // 79
125 "P", // 80
126 "Q", // 81
127 "R", // 82
128 "S", // 83
129 "T", // 84
130 "U", // 85
131 "V", // 86
132 "W", // 87
133 "X", // 88
134 "Y", // 89
135 "Z", // 90
136 "%5b", // 91
137 "%5c", // 92
138 "%5d", // 93
139 "%5e", // 94
140 "_", // 95
141 "%60", // 96
142 "a", // 97
143 "b", // 98
144 "c", // 99
145 "d", // 100
146 "e", // 101
147 "f", // 102
148 "g", // 103
149 "h", // 104
150 "i", // 105
151 "j", // 106
152 "k", // 107
153 "l", // 108
154 "m", // 109
155 "n", // 110
156 "o", // 111
157 "p", // 112
158 "q", // 113
159 "r", // 114
160 "s", // 115
161 "t", // 116
162 "u", // 117
163 "v", // 118
164 "w", // 119
165 "x", // 120
166 "y", // 121
167 "z", // 122
168 "%7b", // 123
169 "%7c", // 124
170 "%7d", // 125
171 "~", // 126
172 "%7f", // 127
173 "%80", // 128
174 "%81", // 129
175 "%82", // 130
176 "%83", // 131
177 "%84", // 132
178 "%85", // 133
179 "%86", // 134
180 "%87", // 135
181 "%88", // 136
182 "%89", // 137
183 "%8a", // 138
184 "%8b", // 139
185 "%8c", // 140
186 "%8d", // 141
187 "%8e", // 142
188 "%8f", // 143
189 "%90", // 144
190 "%91", // 145
191 "%92", // 146
192 "%93", // 147
193 "%94", // 148
194 "%95", // 149
195 "%96", // 150
196 "%97", // 151
197 "%98", // 152
198 "%99", // 153
199 "%9a", // 154
200 "%9b", // 155
201 "%9c", // 156
202 "%9d", // 157
203 "%9e", // 158
204 "%9f", // 159
205 "%a0", // 160
206 "%a1", // 161
207 "%a2", // 162
208 "%a3", // 163
209 "%a4", // 164
210 "%a5", // 165
211 "%a6", // 166
212 "%a7", // 167
213 "%a8", // 168
214 "%a9", // 169
215 "%aa", // 170
216 "%ab", // 171
217 "%ac", // 172
218 "%ad", // 173
219 "%ae", // 174
220 "%af", // 175
221 "%b0", // 176
222 "%b1", // 177
223 "%b2", // 178
224 "%b3", // 179
225 "%b4", // 180
226 "%b5", // 181
227 "%b6", // 182
228 "%b7", // 183
229 "%b8", // 184
230 "%b9", // 185
231 "%ba", // 186
232 "%bb", // 187
233 "%bc", // 188
234 "%bd", // 189
235 "%be", // 190
236 "%bf", // 191
237 "%c0", // 192
238 "%c1", // 193
239 "%c2", // 194
240 "%c3", // 195
241 "%c4", // 196
242 "%c5", // 197
243 "%c6", // 198
244 "%c7", // 199
245 "%c8", // 200
246 "%c9", // 201
247 "%ca", // 202
248 "%cb", // 203
249 "%cc", // 204
250 "%cd", // 205
251 "%ce", // 206
252 "%cf", // 207
253 "%d0", // 208
254 "%d1", // 209
255 "%d2", // 210
256 "%d3", // 211
257 "%d4", // 212
258 "%d5", // 213
259 "%d6", // 214
260 "%d7", // 215
261 "%d8", // 216
262 "%d9", // 217
263 "%da", // 218
264 "%db", // 219
265 "%dc", // 220
266 "%dd", // 221
267 "%de", // 222
268 "%df", // 223
269 "%e0", // 224
270 "%e1", // 225
271 "%e2", // 226
272 "%e3", // 227
273 "%e4", // 228
274 "%e5", // 229
275 "%e6", // 230
276 "%e7", // 231
277 "%e8", // 232
278 "%e9", // 233
279 "%ea", // 234
280 "%eb", // 235
281 "%ec", // 236
282 "%ed", // 237
283 "%ee", // 238
284 "%ef", // 239
285 "%f0", // 240
286 "%f1", // 241
287 "%f2", // 242
288 "%f3", // 243
289 "%f4", // 244
290 "%f5", // 245
291 "%f6", // 246
292 "%f7", // 247
293 "%f8", // 248
294 "%f9", // 249
295 "%fa", // 250
296 "%fb", // 251
297 "%fc", // 252
298 "%fd", // 253
299 "%fe", // 254
300 "%ff" // 255
301};
302 115
303LLURI::LLURI() 116LLURI::LLURI()
304{ 117{
@@ -371,24 +184,23 @@ LLURI::~LLURI()
371{ 184{
372} 185}
373 186
374 187// static
375LLURI LLURI::buildHTTP(const std::string& host_port, 188LLURI LLURI::buildHTTP(const std::string& prefix,
376 const LLSD& path) 189 const LLSD& path)
377{ 190{
378 LLURI result; 191 LLURI result;
379 192
380 // TODO: deal with '/' '?' '#' in host_port 193 // TODO: deal with '/' '?' '#' in host_port
381 S32 index = host_port.find("://"); 194 if (prefix.find("://") != prefix.npos)
382 if (index != host_port.npos)
383 { 195 {
384 // The scheme is part of the host_port 196 // it is a prefix
385 result.mScheme = ""; 197 result = LLURI(prefix);
386 result.mEscapedAuthority = escape(host_port);
387 } 198 }
388 else 199 else
389 { 200 {
390 result.mScheme = "HTTP"; 201 // it is just a host and optional port
391 result.mEscapedAuthority = "//" + escape(host_port); 202 result.mScheme = "http";
203 result.mEscapedAuthority = escapeHostAndPort(prefix);
392 } 204 }
393 205
394 if (path.isArray()) 206 if (path.isArray())
@@ -399,20 +211,20 @@ LLURI LLURI::buildHTTP(const std::string& host_port,
399 ++it) 211 ++it)
400 { 212 {
401 lldebugs << "PATH: inserting " << it->asString() << llendl; 213 lldebugs << "PATH: inserting " << it->asString() << llendl;
402 result.mEscapedPath += "/" + escape(it->asString()); 214 result.mEscapedPath += "/" + escapePathComponent(it->asString());
403 } 215 }
404 } 216 }
405 result.mEscapedOpaque = result.mEscapedAuthority + 217 result.mEscapedOpaque = "//" + result.mEscapedAuthority +
406 result.mEscapedPath; 218 result.mEscapedPath;
407 return result; 219 return result;
408} 220}
409 221
410// static 222// static
411LLURI LLURI::buildHTTP(const std::string& host_port, 223LLURI LLURI::buildHTTP(const std::string& prefix,
412 const LLSD& path, 224 const LLSD& path,
413 const LLSD& query) 225 const LLSD& query)
414{ 226{
415 LLURI result = buildHTTP(host_port, path); 227 LLURI result = buildHTTP(prefix, path);
416 // break out and escape each query component 228 // break out and escape each query component
417 if (query.isMap()) 229 if (query.isMap())
418 { 230 {
@@ -420,8 +232,8 @@ LLURI LLURI::buildHTTP(const std::string& host_port,
420 it != query.endMap(); 232 it != query.endMap();
421 it++) 233 it++)
422 { 234 {
423 result.mEscapedQuery += escape(it->first) + 235 result.mEscapedQuery += escapeQueryVariable(it->first) +
424 (it->second.isUndefined() ? "" : "=" + it->second.asString()) + 236 (it->second.isUndefined() ? "" : "=" + escapeQueryValue(it->second.asString())) +
425 "&"; 237 "&";
426 } 238 }
427 if (query.size() > 0) 239 if (query.size() > 0)
@@ -433,8 +245,61 @@ LLURI LLURI::buildHTTP(const std::string& host_port,
433} 245}
434 246
435// static 247// static
248LLURI LLURI::buildHTTP(const std::string& host,
249 const U32& port,
250 const LLSD& path)
251{
252 return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path);
253}
254
255// static
256LLURI LLURI::buildHTTP(const std::string& host,
257 const U32& port,
258 const LLSD& path,
259 const LLSD& query)
260{
261 return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path, query);
262}
263
264
265namespace {
266 LLURI buildBackboneURL(LLApp* app,
267 const std::string& p1 = "",
268 const std::string& p2 = "",
269 const std::string& p3 = "")
270 {
271 std::string host = "localhost:12040";
272
273 if (app)
274 {
275 host = app->getOption("backbone-host-port").asString();
276 }
277
278 LLSD path = LLSD::emptyArray();
279 if (!p1.empty()) path.append(p1);
280 if (!p2.empty()) path.append(p2);
281 if (!p3.empty()) path.append(p3);
282
283 return LLURI::buildHTTP(host, path);
284 }
285}
286
287
288// static
436LLURI LLURI::buildAgentPresenceURI(const LLUUID& agent_id, LLApp* app) 289LLURI LLURI::buildAgentPresenceURI(const LLUUID& agent_id, LLApp* app)
437{ 290{
291 return buildBackboneURL(app, "agent", agent_id.asString(), "presence");
292}
293
294// static
295LLURI LLURI::buildBulkAgentPresenceURI(LLApp* app)
296{
297 return buildBackboneURL(app, "agent", "presence");
298}
299
300// static
301LLURI LLURI::buildBulkAgentNamesURI(LLApp* app)
302{
438 std::string host = "localhost:12040"; 303 std::string host = "localhost:12040";
439 304
440 if (app) 305 if (app)
@@ -444,14 +309,19 @@ LLURI LLURI::buildAgentPresenceURI(const LLUUID& agent_id, LLApp* app)
444 309
445 LLSD path = LLSD::emptyArray(); 310 LLSD path = LLSD::emptyArray();
446 path.append("agent"); 311 path.append("agent");
447 path.append(agent_id); 312 path.append("names");
448 path.append("presence");
449 313
450 return buildHTTP(host, path); 314 return buildHTTP(host, path);
451} 315}
452 316
453// static 317// static
454LLURI LLURI::buildBulkAgentPresenceURI(LLApp* app) 318LLURI LLURI::buildAgentSessionURI(const LLUUID& agent_id, LLApp* app)
319{
320 return buildBackboneURL(app, "agent", agent_id.asString(), "session");
321}
322
323// static
324LLURI LLURI::buildInventoryHostURI(const LLUUID& agent_id, LLApp* app)
455{ 325{
456 std::string host = "localhost:12040"; 326 std::string host = "localhost:12040";
457 327
@@ -462,13 +332,15 @@ LLURI LLURI::buildBulkAgentPresenceURI(LLApp* app)
462 332
463 LLSD path = LLSD::emptyArray(); 333 LLSD path = LLSD::emptyArray();
464 path.append("agent"); 334 path.append("agent");
465 path.append("presence"); 335 path.append(agent_id);
336 path.append("inventory");
337 path.append("host");
466 338
467 return buildHTTP(host, path); 339 return buildHTTP(host, path);
468} 340}
469 341
470// static 342// static
471LLURI LLURI::buildAgentSessionURI(const LLUUID& agent_id, LLApp* app) 343LLURI LLURI::buildAgentNameURI(const LLUUID& agent_id, LLApp* app)
472{ 344{
473 std::string host = "localhost:12040"; 345 std::string host = "localhost:12040";
474 346
@@ -480,7 +352,7 @@ LLURI LLURI::buildAgentSessionURI(const LLUUID& agent_id, LLApp* app)
480 LLSD path = LLSD::emptyArray(); 352 LLSD path = LLSD::emptyArray();
481 path.append("agent"); 353 path.append("agent");
482 path.append(agent_id); 354 path.append(agent_id);
483 path.append("session"); 355 path.append("name");
484 356
485 return buildHTTP(host, path); 357 return buildHTTP(host, path);
486} 358}
@@ -636,43 +508,3 @@ LLSD LLURI::queryMap(std::string escaped_query_string)
636 return result; 508 return result;
637} 509}
638 510
639// static
640std::string LLURI::escape(const std::string& str)
641{
642 std::ostringstream ostr;
643 std::string::const_iterator it = str.begin();
644 std::string::const_iterator end = str.end();
645 S32 c;
646 for(; it != end; ++it)
647 {
648 c = (S32)(*it);
649 ostr << ESCAPED_CHARACTERS[c];
650 }
651 return ostr.str();
652}
653
654// static
655std::string LLURI::unescape(const std::string& str)
656{
657 std::ostringstream ostr;
658 std::string::const_iterator it = str.begin();
659 std::string::const_iterator end = str.end();
660 for(; it != end; ++it)
661 {
662 if((*it) == '%')
663 {
664 ++it;
665 if(it == end) break;
666 U8 c = hex_as_nybble(*it++);
667 c = c << 4;
668 if (it == end) break;
669 c |= hex_as_nybble(*it);
670 ostr.put((char)c);
671 }
672 else
673 {
674 ostr.put(*it);
675 }
676 }
677 return ostr.str();
678}
diff --git a/linden/indra/llcommon/lluri.h b/linden/indra/llcommon/lluri.h
index f69472f..60b3d48 100644
--- a/linden/indra/llcommon/lluri.h
+++ b/linden/indra/llcommon/lluri.h
@@ -45,54 +45,70 @@ class LLApp;
45class LLURI 45class LLURI
46{ 46{
47public: 47public:
48 LLURI(); 48 LLURI();
49 LLURI(const std::string& escaped_str); 49 LLURI(const std::string& escaped_str);
50 // construct from escaped string, as would be transmitted on the net 50 // construct from escaped string, as would be transmitted on the net
51 51
52 ~LLURI(); 52 ~LLURI();
53 53
54 static LLURI buildHTTP(const std::string& host_port, 54 static LLURI buildHTTP(const std::string& prefix,
55 const LLSD& path); 55 const LLSD& path);
56 static LLURI buildHTTP(const std::string& host_port, 56 static LLURI buildHTTP(const std::string& prefix,
57 const LLSD& path, 57 const LLSD& path,
58 const LLSD& query); 58 const LLSD& query);
59 59 // prefix is either a full URL prefix of the form "http://example.com:8080",
60 std::string asString() const; 60 // or it can be simply a host and optional port like "example.com" or
61 // the whole URI, escaped as needed 61 // "example.com:8080", in these cases, the "http://" will be added
62 62
63 // Parts of a URI 63 static LLURI buildHTTP(const std::string& host,
64 // These functions return parts of the decoded URI. The returned 64 const U32& port,
65 // strings are un-escaped as needed 65 const LLSD& path);
66 66 static LLURI buildHTTP(const std::string& host,
67 // for all schemes 67 const U32& port,
68 std::string scheme() const; // ex.: "http", note lack of colon 68 const LLSD& path,
69 std::string opaque() const; // everything after the colon 69 const LLSD& query);
70
71
72 std::string asString() const;
73 // the whole URI, escaped as needed
74
75 // Parts of a URI
76 // These functions return parts of the decoded URI. The returned
77 // strings are un-escaped as needed
78
79 // for all schemes
80 std::string scheme() const; // ex.: "http", note lack of colon
81 std::string opaque() const; // everything after the colon
82
83 // for schemes that follow path like syntax (http, https, ftp)
84 std::string authority() const; // ex.: "host.com:80"
85 std::string hostName() const; // ex.: "host.com"
86 U16 hostPort() const; // ex.: 80, will include implicit port
87 std::string path() const; // ex.: "/abc/def", includes leading slash
88 // LLSD pathArray() const; // above decoded into an array of strings
89 std::string query() const; // ex.: "x=34", section after "?"
90 LLSD queryMap() const; // above decoded into a map
91 static LLSD queryMap(std::string escaped_query_string);
70 92
71 // for schemes that follow path like syntax (http, https, ftp) 93 // Escaping Utilities
72 std::string authority() const; // ex.: "bob@host.com:80" 94 // Escape a string by urlencoding all the characters that aren't in the allowed string.
73 std::string hostName() const; // ex.: "host.com" 95 static std::string escape(const std::string& str, const std::string & allowed);
74 U16 hostPort() const; // ex.: 80, will include implicit port 96 static std::string unescape(const std::string& str);
75 std::string path() const; // ex.: "/abc/def", includes leading slash
76// LLSD pathArray() const; // above decoded into an array of strings
77 std::string query() const; // ex.: "x=34", section after "?"
78 LLSD queryMap() const; // above decoded into a map
79 static LLSD queryMap(std::string escaped_query_string);
80
81 // Escaping Utilities
82 static std::string escape(const std::string& str);
83 static std::string unescape(const std::string& str);
84 97
85 // Functions for building specific URIs for web services 98 // Functions for building specific URIs for web services
86 static LLURI buildAgentPresenceURI(const LLUUID& agent_id, LLApp* app); 99 static LLURI buildAgentPresenceURI(const LLUUID& agent_id, LLApp* app);
87 static LLURI buildBulkAgentPresenceURI(LLApp* app); 100 static LLURI buildBulkAgentPresenceURI(LLApp* app);
101 static LLURI buildBulkAgentNamesURI(LLApp* app);
88 static LLURI buildAgentSessionURI(const LLUUID& agent_id, LLApp* app); 102 static LLURI buildAgentSessionURI(const LLUUID& agent_id, LLApp* app);
89 static LLURI buildAgentLoginInfoURI(const LLUUID& agent_id, const std::string& dataserver); 103 static LLURI buildAgentLoginInfoURI(const LLUUID& agent_id, const std::string& dataserver);
104 static LLURI buildInventoryHostURI(const LLUUID& agent_id, LLApp* app);
105 static LLURI buildAgentNameURI(const LLUUID& agent_id, LLApp* app);
90private: 106private:
91 std::string mScheme; 107 std::string mScheme;
92 std::string mEscapedOpaque; 108 std::string mEscapedOpaque;
93 std::string mEscapedAuthority; 109 std::string mEscapedAuthority;
94 std::string mEscapedPath; 110 std::string mEscapedPath;
95 std::string mEscapedQuery; 111 std::string mEscapedQuery;
96}; 112};
97 113
98#endif // LL_LLURI_H 114#endif // LL_LLURI_H
diff --git a/linden/indra/llcommon/llversion.h b/linden/indra/llcommon/llversion.h
index af21f72..a3e5152 100644
--- a/linden/indra/llcommon/llversion.h
+++ b/linden/indra/llcommon/llversion.h
@@ -32,9 +32,9 @@
32 32
33// MUST ALSO change version number in secondlife setup.nsi 33// MUST ALSO change version number in secondlife setup.nsi
34const S32 LL_VERSION_MAJOR = 1; 34const S32 LL_VERSION_MAJOR = 1;
35const S32 LL_VERSION_MINOR = 13; 35const S32 LL_VERSION_MINOR = 14;
36const S32 LL_VERSION_PATCH = 3; 36const S32 LL_VERSION_PATCH = 0;
37const S32 LL_VERSION_BUILD = 2; 37const S32 LL_VERSION_BUILD = 0;
38 38
39 39
40 40
diff --git a/linden/indra/llcommon/llworkerthread.cpp b/linden/indra/llcommon/llworkerthread.cpp
index 3190046..4f99393 100644
--- a/linden/indra/llcommon/llworkerthread.cpp
+++ b/linden/indra/llcommon/llworkerthread.cpp
@@ -33,98 +33,86 @@
33#endif 33#endif
34 34
35//============================================================================ 35//============================================================================
36
37/*static*/ LLWorkerThread* LLWorkerThread::sLocal = NULL;
38/*static*/ std::set<LLWorkerThread*> LLWorkerThread::sThreadList;
39
40//============================================================================
41// Run on MAIN thread 36// Run on MAIN thread
42 37
43//static 38LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) :
44void LLWorkerThread::initClass(bool local_is_threaded, bool local_run_always) 39 LLQueuedThread(name, threaded),
40 mWorkerAPRPoolp(NULL)
45{ 41{
46 if (!sLocal) 42 apr_pool_create(&mWorkerAPRPoolp, NULL);
47 { 43 mDeleteMutex = new LLMutex(getAPRPool());
48 sLocal = new LLWorkerThread(local_is_threaded, local_run_always);
49 }
50} 44}
51 45
52//static 46LLWorkerThread::~LLWorkerThread()
53void LLWorkerThread::cleanupClass()
54{ 47{
55 if (sLocal) 48 // Delete any workers in the delete queue (should be safe - had better be!)
49 if (!mDeleteList.empty())
56 { 50 {
57 while (sLocal->getPending()) 51 llwarns << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size()
58 { 52 << " entries in delete list." << llendl;
59 sLocal->update(0);
60 }
61 delete sLocal;
62 sLocal = NULL;
63 llassert(sThreadList.size() == 0);
64 } 53 }
65}
66 54
67//static 55 delete mDeleteMutex;
68S32 LLWorkerThread::updateClass(U32 ms_elapsed) 56
69{ 57 // ~LLQueuedThread() will be called here
70 for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++)
71 {
72 (*iter)->update(ms_elapsed);
73 }
74 return getAllPending();
75} 58}
76 59
77//static 60// virtual
78S32 LLWorkerThread::getAllPending() 61S32 LLWorkerThread::update(U32 max_time_ms)
79{ 62{
80 S32 res = 0; 63 S32 res = LLQueuedThread::update(max_time_ms);
81 for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++) 64 // Delete scheduled workers
65 std::vector<LLWorkerClass*> delete_list;
66 std::vector<LLWorkerClass*> abort_list;
67 mDeleteMutex->lock();
68 for (delete_list_t::iterator iter = mDeleteList.begin();
69 iter != mDeleteList.end(); )
82 { 70 {
83 res += (*iter)->getPending(); 71 delete_list_t::iterator curiter = iter++;
72 LLWorkerClass* worker = *curiter;
73 if (worker->deleteOK())
74 {
75 if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED))
76 {
77 delete_list.push_back(worker);
78 mDeleteList.erase(curiter);
79 }
80 else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED))
81 {
82 abort_list.push_back(worker);
83 }
84 }
84 } 85 }
85 return res; 86 mDeleteMutex->unlock();
86} 87 // abort and delete after releasing mutex
87 88 for (std::vector<LLWorkerClass*>::iterator iter = abort_list.begin();
88//static 89 iter != abort_list.end(); ++iter)
89void LLWorkerThread::pauseAll()
90{
91 for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++)
92 { 90 {
93 (*iter)->pause(); 91 (*iter)->abortWork(false);
94 } 92 }
95} 93 for (std::vector<LLWorkerClass*>::iterator iter = delete_list.begin();
96 94 iter != delete_list.end(); ++iter)
97//static
98void LLWorkerThread::waitOnAllPending()
99{
100 for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++)
101 { 95 {
102 (*iter)->waitOnPending(); 96 LLWorkerClass* worker = *iter;
97 if (worker->mRequestHandle)
98 {
99 // Finished but not completed
100 completeRequest(worker->mRequestHandle);
101 worker->mRequestHandle = LLWorkerThread::nullHandle();
102 worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK);
103 }
104 delete *iter;
103 } 105 }
106 return res;
104} 107}
105 108
106//---------------------------------------------------------------------------- 109//----------------------------------------------------------------------------
107 110
108LLWorkerThread::LLWorkerThread(bool threaded, bool runalways) : 111LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority)
109 LLQueuedThread("Worker", threaded, runalways)
110{
111 sThreadList.insert(this);
112}
113
114LLWorkerThread::~LLWorkerThread()
115{
116 llverify(sThreadList.erase(this) == 1);
117 // ~LLQueuedThread() will be called here
118}
119
120//----------------------------------------------------------------------------
121
122
123LLWorkerThread::handle_t LLWorkerThread::add(LLWorkerClass* workerclass, S32 param, U32 priority)
124{ 112{
125 handle_t handle = generateHandle(); 113 handle_t handle = generateHandle();
126 114
127 Request* req = new Request(handle, priority, workerclass, param); 115 WorkRequest* req = new WorkRequest(handle, priority, workerclass, param);
128 116
129 bool res = addRequest(req); 117 bool res = addRequest(req);
130 if (!res) 118 if (!res)
@@ -137,63 +125,80 @@ LLWorkerThread::handle_t LLWorkerThread::add(LLWorkerClass* workerclass, S32 par
137 return handle; 125 return handle;
138} 126}
139 127
140//============================================================================ 128void LLWorkerThread::deleteWorker(LLWorkerClass* workerclass)
141// Runs on its OWN thread
142
143bool LLWorkerThread::processRequest(QueuedRequest* qreq)
144{ 129{
145 Request *req = (Request*)qreq; 130 mDeleteMutex->lock();
146 131 mDeleteList.push_back(workerclass);
147 req->getWorkerClass()->setWorking(true); 132 mDeleteMutex->unlock();
148
149 bool complete = req->getWorkerClass()->doWork(req->getParam());
150
151 req->getWorkerClass()->setWorking(false);
152
153 LLThread::yield(); // worker thread should yield after each request
154
155 return complete;
156} 133}
157 134
158//============================================================================ 135//============================================================================
136// Runs on its OWN thread
159 137
160LLWorkerThread::Request::Request(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param) : 138LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param) :
161 LLQueuedThread::QueuedRequest(handle, priority), 139 LLQueuedThread::QueuedRequest(handle, priority),
162 mWorkerClass(workerclass), 140 mWorkerClass(workerclass),
163 mParam(param) 141 mParam(param)
164{ 142{
165} 143}
166 144
167void LLWorkerThread::Request::deleteRequest() 145LLWorkerThread::WorkRequest::~WorkRequest()
146{
147}
148
149// virtual (required for access by LLWorkerThread)
150void LLWorkerThread::WorkRequest::deleteRequest()
168{ 151{
169 LLQueuedThread::QueuedRequest::deleteRequest(); 152 LLQueuedThread::QueuedRequest::deleteRequest();
170} 153}
171 154
155// virtual
156bool LLWorkerThread::WorkRequest::processRequest()
157{
158 LLWorkerClass* workerclass = getWorkerClass();
159 workerclass->setWorking(true);
160 bool complete = workerclass->doWork(getParam());
161 workerclass->setWorking(false);
162 return complete;
163}
164
165// virtual
166void LLWorkerThread::WorkRequest::finishRequest(bool completed)
167{
168 LLWorkerClass* workerclass = getWorkerClass();
169 workerclass->finishWork(getParam(), completed);
170 U32 flags = LLWorkerClass::WCF_WORK_FINISHED | (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED);
171 workerclass->setFlags(flags);
172}
173
172//============================================================================ 174//============================================================================
173// LLWorkerClass:: operates in main thread 175// LLWorkerClass:: operates in main thread
174 176
175LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& name) 177LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& name)
176 : mWorkerThread(workerthread), 178 : mWorkerThread(workerthread),
177 mWorkerClassName(name), 179 mWorkerClassName(name),
178 mWorkHandle(LLWorkerThread::nullHandle()), 180 mRequestHandle(LLWorkerThread::nullHandle()),
181 mMutex(workerthread->getWorkerAPRPool()),
179 mWorkFlags(0) 182 mWorkFlags(0)
180{ 183{
181 if (!mWorkerThread) 184 if (!mWorkerThread)
182 { 185 {
183 mWorkerThread = LLWorkerThread::sLocal; 186 llerrs << "LLWorkerClass() called with NULL workerthread: " << name << llendl;
184 } 187 }
185} 188}
189
186LLWorkerClass::~LLWorkerClass() 190LLWorkerClass::~LLWorkerClass()
187{ 191{
188 if (mWorkHandle != LLWorkerThread::nullHandle()) 192 llassert_always(!(mWorkFlags & WCF_WORKING));
193 llassert_always(mWorkFlags & WCF_DELETE_REQUESTED);
194 if (mRequestHandle != LLWorkerThread::nullHandle())
189 { 195 {
190 LLWorkerThread::Request* workreq = (LLWorkerThread::Request*)mWorkerThread->getRequest(mWorkHandle); 196 LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
191 if (!workreq) 197 if (!workreq)
192 { 198 {
193 llerrs << "LLWorkerClass destroyed with stale work handle" << llendl; 199 llerrs << "LLWorkerClass destroyed with stale work handle" << llendl;
194 } 200 }
195 if (workreq->getStatus() != LLWorkerThread::STATUS_ABORT && 201 if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED &&
196 workreq->getStatus() != LLWorkerThread::STATUS_ABORTED &&
197 workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE) 202 workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE)
198 { 203 {
199 llerrs << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << llendl; 204 llerrs << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << llendl;
@@ -203,21 +208,58 @@ LLWorkerClass::~LLWorkerClass()
203 208
204void LLWorkerClass::setWorkerThread(LLWorkerThread* workerthread) 209void LLWorkerClass::setWorkerThread(LLWorkerThread* workerthread)
205{ 210{
206 if (mWorkHandle != LLWorkerThread::nullHandle()) 211 mMutex.lock();
212 if (mRequestHandle != LLWorkerThread::nullHandle())
207 { 213 {
208 llerrs << "LLWorkerClass attempt to change WorkerThread with active worker!" << llendl; 214 llerrs << "LLWorkerClass attempt to change WorkerThread with active worker!" << llendl;
209 } 215 }
210 mWorkerThread = workerthread; 216 mWorkerThread = workerthread;
217 mMutex.unlock();
218}
219
220//----------------------------------------------------------------------------
221
222//virtual
223void LLWorkerClass::finishWork(S32 param, bool success)
224{
225}
226
227//virtual
228bool LLWorkerClass::deleteOK()
229{
230 return true; // default always OK
231}
232
233//----------------------------------------------------------------------------
234
235// Called from worker thread
236void LLWorkerClass::setWorking(bool working)
237{
238 mMutex.lock();
239 if (working)
240 {
241 llassert_always(!(mWorkFlags & WCF_WORKING));
242 setFlags(WCF_WORKING);
243 }
244 else
245 {
246 llassert_always((mWorkFlags & WCF_WORKING));
247 clearFlags(WCF_WORKING);
248 }
249 mMutex.unlock();
211} 250}
212 251
213//---------------------------------------------------------------------------- 252//----------------------------------------------------------------------------
214 253
215bool LLWorkerClass::yield() 254bool LLWorkerClass::yield()
216{ 255{
217 llassert(mWorkFlags & WCF_WORKING);
218 LLThread::yield(); 256 LLThread::yield();
219 mWorkerThread->checkPause(); 257 mWorkerThread->checkPause();
220 return (getFlags() & WCF_ABORT_REQUESTED) ? true : false; 258 bool res;
259 mMutex.lock();
260 res = (getFlags() & WCF_ABORT_REQUESTED) ? true : false;
261 mMutex.unlock();
262 return res;
221} 263}
222 264
223//---------------------------------------------------------------------------- 265//----------------------------------------------------------------------------
@@ -225,7 +267,9 @@ bool LLWorkerClass::yield()
225// calls startWork, adds doWork() to queue 267// calls startWork, adds doWork() to queue
226void LLWorkerClass::addWork(S32 param, U32 priority) 268void LLWorkerClass::addWork(S32 param, U32 priority)
227{ 269{
228 if (mWorkHandle != LLWorkerThread::nullHandle()) 270 mMutex.lock();
271 llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK)));
272 if (mRequestHandle != LLWorkerThread::nullHandle())
229 { 273 {
230 llerrs << "LLWorkerClass attempt to add work with active worker!" << llendl; 274 llerrs << "LLWorkerClass attempt to add work with active worker!" << llendl;
231 } 275 }
@@ -233,70 +277,93 @@ void LLWorkerClass::addWork(S32 param, U32 priority)
233// llinfos << "addWork: " << mWorkerClassName << " Param: " << param << llendl; 277// llinfos << "addWork: " << mWorkerClassName << " Param: " << param << llendl;
234#endif 278#endif
235 startWork(param); 279 startWork(param);
236 mWorkHandle = mWorkerThread->add(this, param, priority); 280 clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED);
281 setFlags(WCF_HAVE_WORK);
282 mRequestHandle = mWorkerThread->addWorkRequest(this, param, priority);
283 mMutex.unlock();
237} 284}
238 285
239void LLWorkerClass::abortWork() 286void LLWorkerClass::abortWork(bool autocomplete)
240{ 287{
288 mMutex.lock();
241#if _DEBUG 289#if _DEBUG
242// LLWorkerThread::Request* workreq = mWorkerThread->getRequest(mWorkHandle); 290// LLWorkerThread::WorkRequest* workreq = mWorkerThread->getRequest(mRequestHandle);
243// if (workreq) 291// if (workreq)
244// llinfos << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << llendl; 292// llinfos << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << llendl;
245#endif 293#endif
246 mWorkerThread->abortRequest(mWorkHandle); 294 if (mRequestHandle != LLWorkerThread::nullHandle())
247 setFlags(WCF_ABORT_REQUESTED); 295 {
296 mWorkerThread->abortRequest(mRequestHandle, autocomplete);
297 mWorkerThread->setPriority(mRequestHandle, LLQueuedThread::PRIORITY_IMMEDIATE);
298 setFlags(WCF_ABORT_REQUESTED);
299 }
300 mMutex.unlock();
248} 301}
249 302
250// if doWork is complete or aborted, call endWork() and return true 303// if doWork is complete or aborted, call endWork() and return true
251bool LLWorkerClass::checkWork() 304bool LLWorkerClass::checkWork(bool aborting)
252{ 305{
306 LLMutexLock lock(&mMutex);
253 bool complete = false, abort = false; 307 bool complete = false, abort = false;
254 LLWorkerThread::Request* workreq = (LLWorkerThread::Request*)mWorkerThread->getRequest(mWorkHandle); 308 if (mRequestHandle != LLWorkerThread::nullHandle())
255 llassert(workreq);
256 if (getFlags(WCF_ABORT_REQUESTED) || workreq->getStatus() == LLWorkerThread::STATUS_ABORTED)
257 { 309 {
258 complete = true; 310 LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
259 abort = true; 311 llassert_always(workreq);
312 LLQueuedThread::status_t status = workreq->getStatus();
313 if (status == LLWorkerThread::STATUS_ABORTED)
314 {
315 complete = true;
316 abort = true;
317 }
318 else if (status == LLWorkerThread::STATUS_COMPLETE)
319 {
320 complete = true;
321 }
322 else
323 {
324 llassert_always(!aborting || (workreq->getFlags() & LLQueuedThread::FLAG_ABORT));
325 }
326 if (complete)
327 {
328 llassert_always(!(getFlags(WCF_WORKING)));
329 endWork(workreq->getParam(), abort);
330 mWorkerThread->completeRequest(mRequestHandle);
331 mRequestHandle = LLWorkerThread::nullHandle();
332 clearFlags(WCF_HAVE_WORK);
333 }
260 } 334 }
261 else if (workreq->getStatus() == LLWorkerThread::STATUS_COMPLETE) 335 else
262 { 336 {
263 complete = true; 337 complete = true;
264 } 338 }
265 if (complete)
266 {
267#if _DEBUG
268// llinfos << "endWork: " << mWorkerClassName << " Param: " << workreq->getParam() << llendl;
269#endif
270 endWork(workreq->getParam(), abort);
271 mWorkerThread->completeRequest(mWorkHandle);
272 mWorkHandle = LLWorkerThread::nullHandle();
273 }
274 return complete; 339 return complete;
275} 340}
276 341
277void LLWorkerClass::killWork() 342void LLWorkerClass::scheduleDelete()
278{ 343{
279 if (haveWork()) 344 bool do_delete = false;
345 mMutex.lock();
346 if (!(getFlags(WCF_DELETE_REQUESTED)))
280 { 347 {
281 abortWork(); 348 setFlags(WCF_DELETE_REQUESTED);
282 bool paused = mWorkerThread->isPaused(); 349 do_delete = true;
283 while (!checkWork()) 350 }
284 { 351 mMutex.unlock();
285 mWorkerThread->updateQueue(0); 352 if (do_delete)
286 } 353 {
287 if (paused) 354 mWorkerThread->deleteWorker(this);
288 {
289 mWorkerThread->pause();
290 }
291 } 355 }
292} 356}
293 357
294void LLWorkerClass::setPriority(U32 priority) 358void LLWorkerClass::setPriority(U32 priority)
295{ 359{
296 if (haveWork()) 360 mMutex.lock();
361 if (mRequestHandle != LLWorkerThread::nullHandle())
297 { 362 {
298 mWorkerThread->setPriority(mWorkHandle, priority); 363 mRequestPriority = priority;
364 mWorkerThread->setPriority(mRequestHandle, priority);
299 } 365 }
366 mMutex.unlock();
300} 367}
301 368
302//============================================================================ 369//============================================================================
diff --git a/linden/indra/llcommon/llworkerthread.h b/linden/indra/llcommon/llworkerthread.h
index f01e67b..17b7e7b 100644
--- a/linden/indra/llcommon/llworkerthread.h
+++ b/linden/indra/llcommon/llworkerthread.h
@@ -47,13 +47,13 @@ class LLWorkerClass;
47class LLWorkerThread : public LLQueuedThread 47class LLWorkerThread : public LLQueuedThread
48{ 48{
49public: 49public:
50 class Request : public LLQueuedThread::QueuedRequest 50 class WorkRequest : public LLQueuedThread::QueuedRequest
51 { 51 {
52 protected: 52 protected:
53 ~Request() {}; // use deleteRequest() 53 virtual ~WorkRequest(); // use deleteRequest()
54 54
55 public: 55 public:
56 Request(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param); 56 WorkRequest(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param);
57 57
58 S32 getParam() 58 S32 getParam()
59 { 59 {
@@ -64,6 +64,8 @@ public:
64 return mWorkerClass; 64 return mWorkerClass;
65 } 65 }
66 66
67 /*virtual*/ bool processRequest();
68 /*virtual*/ void finishRequest(bool completed);
67 /*virtual*/ void deleteRequest(); 69 /*virtual*/ void deleteRequest();
68 70
69 private: 71 private:
@@ -71,26 +73,24 @@ public:
71 S32 mParam; 73 S32 mParam;
72 }; 74 };
73 75
74public: 76private:
75 LLWorkerThread(bool threaded = true, bool runalways = true); 77 typedef std::list<LLWorkerClass*> delete_list_t;
76 ~LLWorkerThread(); 78 delete_list_t mDeleteList;
77 79 LLMutex* mDeleteMutex;
78protected: 80 apr_pool_t* mWorkerAPRPoolp;
79 /*virtual*/ bool processRequest(QueuedRequest* req);
80 81
81public: 82public:
82 handle_t add(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL); 83 LLWorkerThread(const std::string& name, bool threaded = true);
83 84 ~LLWorkerThread();
84 static void initClass(bool local_is_threaded = true, bool local_run_always = true); // Setup sLocal
85 static S32 updateClass(U32 ms_elapsed);
86 static S32 getAllPending();
87 static void pauseAll();
88 static void waitOnAllPending();
89 static void cleanupClass(); // Delete sLocal
90 85
91public: 86 apr_pool_t* getWorkerAPRPool() { return mWorkerAPRPoolp; }
92 static LLWorkerThread* sLocal; // Default worker thread 87
93 static std::set<LLWorkerThread*> sThreadList; // array of threads (includes sLocal) 88 /*virtual*/ S32 update(U32 max_time_ms);
89
90 handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL);
91
92 void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
93 S32 getNumDeletes() { return mDeleteList.size(); } // debug
94}; 94};
95 95
96//============================================================================ 96//============================================================================
@@ -112,11 +112,17 @@ public:
112 112
113class LLWorkerClass 113class LLWorkerClass
114{ 114{
115 friend class LLWorkerThread;
116 friend class LLWorkerThread::WorkRequest;
115public: 117public:
116 typedef LLWorkerThread::handle_t handle_t; 118 typedef LLWorkerThread::handle_t handle_t;
117 enum FLAGS 119 enum FLAGS
118 { 120 {
119 WCF_WORKING = 0x01, 121 WCF_HAVE_WORK = 0x01,
122 WCF_WORKING = 0x02,
123 WCF_WORK_FINISHED = 0x10,
124 WCF_WORK_ABORTED = 0x20,
125 WCF_DELETE_REQUESTED = 0x40,
120 WCF_ABORT_REQUESTED = 0x80 126 WCF_ABORT_REQUESTED = 0x80
121 }; 127 };
122 128
@@ -125,17 +131,29 @@ public:
125 virtual ~LLWorkerClass(); 131 virtual ~LLWorkerClass();
126 132
127 // pure virtual, called from WORKER THREAD, returns TRUE if done 133 // pure virtual, called from WORKER THREAD, returns TRUE if done
128 virtual bool doWork(S32 param)=0; // Called from LLWorkerThread::processRequest() 134 virtual bool doWork(S32 param)=0; // Called from WorkRequest::processRequest()
129 135 // virtual, called from finishRequest() after completed or aborted
130 // called from WORKER THREAD 136 virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD)
131 void setWorking(bool working) { working ? setFlags(WCF_WORKING) : clearFlags(WCF_WORKING); } 137 // virtual, returns true if safe to delete the worker
138 virtual bool deleteOK(); // called from update() (WORK THREAD)
132 139
140 // schedlueDelete(): schedules deletion once aborted or completed
141 void scheduleDelete();
142
143 bool haveWork() { return getFlags(WCF_HAVE_WORK); } // may still be true if aborted
133 bool isWorking() { return getFlags(WCF_WORKING); } 144 bool isWorking() { return getFlags(WCF_WORKING); }
134 bool wasAborted() { return getFlags(WCF_ABORT_REQUESTED); } 145 bool wasAborted() { return getFlags(WCF_ABORT_REQUESTED); }
146
147 // setPriority(): changes the priority of a request
148 void setPriority(U32 priority);
149 U32 getPriority() { return mRequestPriority; }
135 150
136 const std::string& getName() const { return mWorkerClassName; } 151 const std::string& getName() const { return mWorkerClassName; }
137 152
138protected: 153protected:
154 // called from WORKER THREAD
155 void setWorking(bool working);
156
139 // Call from doWork only to avoid eating up cpu time. 157 // Call from doWork only to avoid eating up cpu time.
140 // Returns true if work has been aborted 158 // Returns true if work has been aborted
141 // yields the current thread and calls mWorkerThread->checkPause() 159 // yields the current thread and calls mWorkerThread->checkPause()
@@ -147,20 +165,11 @@ protected:
147 void addWork(S32 param, U32 priority = LLWorkerThread::PRIORITY_NORMAL); 165 void addWork(S32 param, U32 priority = LLWorkerThread::PRIORITY_NORMAL);
148 166
149 // abortWork(): requests that work be aborted 167 // abortWork(): requests that work be aborted
150 void abortWork(); 168 void abortWork(bool autocomplete);
151 169
152 // checkWork(): if doWork is complete or aborted, call endWork() and return true 170 // checkWork(): if doWork is complete or aborted, call endWork() and return true
153 bool checkWork(); 171 bool checkWork(bool aborting = false);
154 172
155 // haveWork(): return true if mWorkHandle != null
156 bool haveWork() { return mWorkHandle != LLWorkerThread::nullHandle(); }
157
158 // killWork(): aborts work and waits for the abort to process
159 void killWork();
160
161 // setPriority(): changes the priority of a request
162 void setPriority(U32 priority);
163
164private: 173private:
165 void setFlags(U32 flags) { mWorkFlags = mWorkFlags | flags; } 174 void setFlags(U32 flags) { mWorkFlags = mWorkFlags | flags; }
166 void clearFlags(U32 flags) { mWorkFlags = mWorkFlags & ~flags; } 175 void clearFlags(U32 flags) { mWorkFlags = mWorkFlags & ~flags; }
@@ -175,9 +184,11 @@ private:
175protected: 184protected:
176 LLWorkerThread* mWorkerThread; 185 LLWorkerThread* mWorkerThread;
177 std::string mWorkerClassName; 186 std::string mWorkerClassName;
178 handle_t mWorkHandle; 187 handle_t mRequestHandle;
188 U32 mRequestPriority; // last priority set
179 189
180private: 190private:
191 LLMutex mMutex;
181 LLAtomicU32 mWorkFlags; 192 LLAtomicU32 mWorkFlags;
182}; 193};
183 194
diff --git a/linden/indra/llcommon/metaproperty.cpp b/linden/indra/llcommon/metaproperty.cpp
index e4983cc..312dd9d 100644
--- a/linden/indra/llcommon/metaproperty.cpp
+++ b/linden/indra/llcommon/metaproperty.cpp
@@ -44,7 +44,7 @@ const LLMetaClass& LLMetaProperty::getObjectMetaClass() const
44{ 44{
45 return mObjectClass; 45 return mObjectClass;
46} 46}
47 47
48void LLMetaProperty::checkObjectClass(const LLReflective* object) const 48void LLMetaProperty::checkObjectClass(const LLReflective* object) const
49{ 49{
50 if(! mObjectClass.isInstance(object)) 50 if(! mObjectClass.isInstance(object))
diff --git a/linden/indra/llcommon/u64.cpp b/linden/indra/llcommon/u64.cpp
index 45baa13..744e0ab 100644
--- a/linden/indra/llcommon/u64.cpp
+++ b/linden/indra/llcommon/u64.cpp
@@ -33,7 +33,7 @@
33U64 str_to_U64(const char *str) 33U64 str_to_U64(const char *str)
34{ 34{
35 U64 result = 0; 35 U64 result = 0;
36 char *aptr = strpbrk(str,"0123456789"); 36 const char *aptr = strpbrk(str,"0123456789");
37 37
38 if (!aptr) 38 if (!aptr)
39 { 39 {
@@ -66,27 +66,27 @@ char* U64_to_str(U64 value, char* result, S32 result_size)
66 66
67 if (part1) 67 if (part1)
68 { 68 {
69 snprintf( 69 snprintf( /* Flawfinder: ignore */
70 result, 70 result,
71 result_size, 71 result_size,
72 "%u%07u%07u", 72 "%u%07u%07u",
73 part1,part2,part3); /* Flawfinder: ignore */ 73 part1,part2,part3);
74 } 74 }
75 else if (part2) 75 else if (part2)
76 { 76 {
77 snprintf( 77 snprintf( /* Flawfinder: ignore */
78 result, 78 result,
79 result_size, 79 result_size,
80 "%u%07u", 80 "%u%07u",
81 part2,part3); /* Flawfinder: ignore */ 81 part2,part3);
82 } 82 }
83 else 83 else
84 { 84 {
85 snprintf( 85 snprintf( /* Flawfinder: ignore */
86 result, 86 result,
87 result_size, 87 result_size,
88 "%u", 88 "%u",
89 part3); /* Flawfinder: ignore */ 89 part3);
90 } 90 }
91 return (result); 91 return (result);
92} 92}