PageRenderTime 43ms CodeModel.GetById 2ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llapr.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 779 lines | 582 code | 105 blank | 92 comment | 83 complexity | e709c2d110d0c1ea71e57cbee84340c3 MD5 | raw file
  1/** 
  2 * @file llapr.cpp
  3 * @author Phoenix
  4 * @date 2004-11-28
  5 * @brief Helper functions for using the apache portable runtime library.
  6 *
  7 * $LicenseInfo:firstyear=2004&license=viewerlgpl$
  8 * Second Life Viewer Source Code
  9 * Copyright (C) 2010, Linden Research, Inc.
 10 * 
 11 * This library is free software; you can redistribute it and/or
 12 * modify it under the terms of the GNU Lesser General Public
 13 * License as published by the Free Software Foundation;
 14 * version 2.1 of the License only.
 15 * 
 16 * This library is distributed in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * Lesser General Public License for more details.
 20 * 
 21 * You should have received a copy of the GNU Lesser General Public
 22 * License along with this library; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24 * 
 25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26 * $/LicenseInfo$
 27 */
 28
 29#include "linden_common.h"
 30#include "llapr.h"
 31#include "apr_dso.h"
 32
 33apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
 34LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
 35apr_thread_mutex_t *gLogMutexp = NULL;
 36apr_thread_mutex_t *gCallStacksLogMutexp = NULL;
 37
 38const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool
 39
 40void ll_init_apr()
 41{
 42	if (!gAPRPoolp)
 43	{
 44		// Initialize APR and create the global pool
 45		apr_initialize();
 46		apr_pool_create(&gAPRPoolp, NULL);
 47		
 48		// Initialize the logging mutex
 49		apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
 50		apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
 51	}
 52
 53	if(!LLAPRFile::sAPRFilePoolp)
 54	{
 55		LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ;
 56	}
 57}
 58
 59
 60void ll_cleanup_apr()
 61{
 62	LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
 63
 64	if (gLogMutexp)
 65	{
 66		// Clean up the logging mutex
 67
 68		// All other threads NEED to be done before we clean up APR, so this is okay.
 69		apr_thread_mutex_destroy(gLogMutexp);
 70		gLogMutexp = NULL;
 71	}
 72	if (gCallStacksLogMutexp)
 73	{
 74		// Clean up the logging mutex
 75
 76		// All other threads NEED to be done before we clean up APR, so this is okay.
 77		apr_thread_mutex_destroy(gCallStacksLogMutexp);
 78		gCallStacksLogMutexp = NULL;
 79	}
 80	if (gAPRPoolp)
 81	{
 82		apr_pool_destroy(gAPRPoolp);
 83		gAPRPoolp = NULL;
 84	}
 85	if (LLAPRFile::sAPRFilePoolp)
 86	{
 87		delete LLAPRFile::sAPRFilePoolp ;
 88		LLAPRFile::sAPRFilePoolp = NULL ;
 89	}
 90	apr_terminate();
 91}
 92
 93//
 94//
 95//LLAPRPool
 96//
 97LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) 	
 98	: mParent(parent),
 99	mReleasePoolFlag(releasePoolFlag),
100	mMaxSize(size),
101	mPool(NULL)
102{	
103	createAPRPool() ;
104}
105
106LLAPRPool::~LLAPRPool() 
107{
108	releaseAPRPool() ;
109}
110
111void LLAPRPool::createAPRPool()
112{
113	if(mPool)
114	{
115		return ;
116	}
117
118	mStatus = apr_pool_create(&mPool, mParent);
119	ll_apr_warn_status(mStatus) ;
120
121	if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes.
122	{
123		apr_allocator_t *allocator = apr_pool_allocator_get(mPool); 
124		if (allocator) 
125		{ 
126			apr_allocator_max_free_set(allocator, mMaxSize) ;
127		}
128	}
129}
130
131void LLAPRPool::releaseAPRPool()
132{
133	if(!mPool)
134	{
135		return ;
136	}
137
138	if(!mParent || mReleasePoolFlag)
139	{
140		apr_pool_destroy(mPool) ;
141		mPool = NULL ;
142	}
143}
144
145//virtual
146apr_pool_t* LLAPRPool::getAPRPool() 
147{	
148	return mPool ; 
149}
150
151LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) 
152				  : LLAPRPool(parent, size, releasePoolFlag),
153				  mNumActiveRef(0),
154				  mNumTotalRef(0),
155				  mMutexPool(NULL),
156				  mMutexp(NULL)
157{
158	//create mutex
159	if(!is_local) //not a local apr_pool, that is: shared by multiple threads.
160	{
161		apr_pool_create(&mMutexPool, NULL); // Create a pool for mutex
162		apr_thread_mutex_create(&mMutexp, APR_THREAD_MUTEX_UNNESTED, mMutexPool);
163	}
164}
165
166LLVolatileAPRPool::~LLVolatileAPRPool()
167{
168	//delete mutex
169	if(mMutexp)
170	{
171		apr_thread_mutex_destroy(mMutexp);
172		apr_pool_destroy(mMutexPool);
173	}
174}
175
176//
177//define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool().
178//
179//virtual 
180apr_pool_t* LLVolatileAPRPool::getAPRPool() 
181{
182	return LLVolatileAPRPool::getVolatileAPRPool() ;
183}
184
185apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() 
186{	
187	LLScopedLock lock(mMutexp) ;
188
189	mNumTotalRef++ ;
190	mNumActiveRef++ ;
191
192	if(!mPool)
193	{
194		createAPRPool() ;
195	}
196	
197	return mPool ;
198}
199
200void LLVolatileAPRPool::clearVolatileAPRPool() 
201{
202	LLScopedLock lock(mMutexp) ;
203
204	if(mNumActiveRef > 0)
205	{
206		mNumActiveRef--;
207		if(mNumActiveRef < 1)
208		{
209			if(isFull()) 
210			{
211				mNumTotalRef = 0 ;
212
213				//destroy the apr_pool.
214				releaseAPRPool() ;
215			}
216			else 
217			{
218				//This does not actually free the memory, 
219				//it just allows the pool to re-use this memory for the next allocation. 
220				apr_pool_clear(mPool) ;
221			}
222		}
223	}
224	else
225	{
226		llassert_always(mNumActiveRef > 0) ;
227	}
228
229	//paranoia check if the pool is jammed.
230	//will remove the check before going to release.
231	llassert_always(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
232}
233
234BOOL LLVolatileAPRPool::isFull()
235{
236	return mNumTotalRef > FULL_VOLATILE_APR_POOL ;
237}
238//---------------------------------------------------------------------
239//
240// LLScopedLock
241//
242LLScopedLock::LLScopedLock(apr_thread_mutex_t* mutex) : mMutex(mutex)
243{
244	if(mutex)
245	{
246		if(ll_apr_warn_status(apr_thread_mutex_lock(mMutex)))
247		{
248			mLocked = false;
249		}
250		else
251		{
252			mLocked = true;
253		}
254	}
255	else
256	{
257		mLocked = false;
258	}
259}
260
261LLScopedLock::~LLScopedLock()
262{
263	unlock();
264}
265
266void LLScopedLock::unlock()
267{
268	if(mLocked)
269	{
270		if(!ll_apr_warn_status(apr_thread_mutex_unlock(mMutex)))
271		{
272			mLocked = false;
273		}
274	}
275}
276
277//---------------------------------------------------------------------
278
279bool ll_apr_warn_status(apr_status_t status)
280{
281	if(APR_SUCCESS == status) return false;
282	char buf[MAX_STRING];	/* Flawfinder: ignore */
283	apr_strerror(status, buf, sizeof(buf));
284	LL_WARNS("APR") << "APR: " << buf << LL_ENDL;
285	return true;
286}
287
288bool ll_apr_warn_status(apr_status_t status, apr_dso_handle_t *handle)
289{
290    bool result = ll_apr_warn_status(status);
291    // Despite observed truncation of actual Mac dylib load errors, increasing
292    // this buffer to more than MAX_STRING doesn't help: it appears that APR
293    // stores the output in a fixed 255-character internal buffer. (*sigh*)
294    char buf[MAX_STRING];           /* Flawfinder: ignore */
295    apr_dso_error(handle, buf, sizeof(buf));
296    LL_WARNS("APR") << "APR: " << buf << LL_ENDL;
297    return result;
298}
299
300void ll_apr_assert_status(apr_status_t status)
301{
302	llassert(! ll_apr_warn_status(status));
303}
304
305void ll_apr_assert_status(apr_status_t status, apr_dso_handle_t *handle)
306{
307    llassert(! ll_apr_warn_status(status, handle));
308}
309
310//---------------------------------------------------------------------
311//
312// LLAPRFile functions
313//
314LLAPRFile::LLAPRFile()
315	: mFile(NULL),
316	  mCurrentFilePoolp(NULL)
317{
318}
319
320LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool)
321	: mFile(NULL),
322	  mCurrentFilePoolp(NULL)
323{
324	open(filename, flags, pool);
325}
326
327LLAPRFile::~LLAPRFile()
328{
329	close() ;
330}
331
332apr_status_t LLAPRFile::close() 
333{
334	apr_status_t ret = APR_SUCCESS ;
335	if(mFile)
336	{
337		ret = apr_file_close(mFile);
338		mFile = NULL ;
339	}
340
341	if(mCurrentFilePoolp)
342	{
343		mCurrentFilePoolp->clearVolatileAPRPool() ;
344		mCurrentFilePoolp = NULL ;
345	}
346
347	return ret ;
348}
349
350apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool, S32* sizep)
351{
352	apr_status_t s ;
353
354	//check if already open some file
355	llassert_always(!mFile) ;
356	llassert_always(!mCurrentFilePoolp) ;
357	
358	apr_pool_t* apr_pool = pool ? pool->getVolatileAPRPool() : NULL ;
359	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(apr_pool));
360
361	if (s != APR_SUCCESS || !mFile)
362	{
363		mFile = NULL ;
364		
365		if (sizep)
366		{
367			*sizep = 0;
368		}
369	}
370	else if (sizep)
371	{
372		S32 file_size = 0;
373		apr_off_t offset = 0;
374		if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS)
375		{
376			llassert_always(offset <= 0x7fffffff);
377			file_size = (S32)offset;
378			offset = 0;
379			apr_file_seek(mFile, APR_SET, &offset);
380		}
381		*sizep = file_size;
382	}
383
384	if(!mCurrentFilePoolp)
385	{
386		mCurrentFilePoolp = pool ;
387
388		if(!mFile)
389		{
390			close() ;
391		}
392	}
393
394	return s ;
395}
396
397//use gAPRPoolp.
398apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
399{
400	apr_status_t s;
401
402	//check if already open some file
403	llassert_always(!mFile) ;
404	llassert_always(!mCurrentFilePoolp) ;
405	llassert_always(use_global_pool) ; //be aware of using gAPRPoolp.
406	
407	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp);
408	if (s != APR_SUCCESS || !mFile)
409	{
410		mFile = NULL ;
411		close() ;
412		return s;
413	}
414
415	return s;
416}
417
418apr_pool_t* LLAPRFile::getAPRFilePool(apr_pool_t* pool)
419{	
420	if(!pool)
421	{
422		mCurrentFilePoolp = sAPRFilePoolp ;
423		return mCurrentFilePoolp->getVolatileAPRPool() ;
424	}
425
426	return pool ;
427}
428
429// File I/O
430S32 LLAPRFile::read(void *buf, S32 nbytes)
431{
432	if(!mFile) 
433	{
434		llwarns << "apr mFile is removed by somebody else. Can not read." << llendl ;
435		return 0;
436	}
437	
438	apr_size_t sz = nbytes;
439	apr_status_t s = apr_file_read(mFile, buf, &sz);
440	if (s != APR_SUCCESS)
441	{
442		ll_apr_warn_status(s);
443		return 0;
444	}
445	else
446	{
447		llassert_always(sz <= 0x7fffffff);
448		return (S32)sz;
449	}
450}
451
452S32 LLAPRFile::write(const void *buf, S32 nbytes)
453{
454	if(!mFile) 
455	{
456		llwarns << "apr mFile is removed by somebody else. Can not write." << llendl ;
457		return 0;
458	}
459	
460	apr_size_t sz = nbytes;
461	apr_status_t s = apr_file_write(mFile, buf, &sz);
462	if (s != APR_SUCCESS)
463	{
464		ll_apr_warn_status(s);
465		return 0;
466	}
467	else
468	{
469		llassert_always(sz <= 0x7fffffff);
470		return (S32)sz;
471	}
472}
473
474S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset)
475{
476	return LLAPRFile::seek(mFile, where, offset) ;
477}
478
479//
480//*******************************************************************************************************************************
481//static components of LLAPRFile
482//
483
484//static
485apr_status_t LLAPRFile::close(apr_file_t* file_handle, LLVolatileAPRPool* pool) 
486{
487	apr_status_t ret = APR_SUCCESS ;
488	if(file_handle)
489	{
490		ret = apr_file_close(file_handle);
491		file_handle = NULL ;
492	}
493
494	if(pool)
495	{
496		pool->clearVolatileAPRPool() ;
497	}
498
499	return ret ;
500}
501
502//static
503apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags)
504{
505	apr_status_t s;
506	apr_file_t* file_handle ;
507
508	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
509
510	s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());
511	if (s != APR_SUCCESS || !file_handle)
512	{
513		ll_apr_warn_status(s);
514		LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL;
515		file_handle = NULL ;
516		close(file_handle, pool) ;
517		return NULL;
518	}
519
520	return file_handle ;
521}
522
523//static
524S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
525{
526	if(!file_handle)
527	{
528		return -1 ;
529	}
530
531	apr_status_t s;
532	apr_off_t apr_offset;
533	if (offset >= 0)
534	{
535		apr_offset = (apr_off_t)offset;
536		s = apr_file_seek(file_handle, where, &apr_offset);
537	}
538	else
539	{
540		apr_offset = 0;
541		s = apr_file_seek(file_handle, APR_END, &apr_offset);
542	}
543	if (s != APR_SUCCESS)
544	{
545		ll_apr_warn_status(s);
546		return -1;
547	}
548	else
549	{
550		llassert_always(apr_offset <= 0x7fffffff);
551		return (S32)apr_offset;
552	}
553}
554
555//static
556S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
557{
558	//*****************************************
559	apr_file_t* file_handle = open(filename, pool, APR_READ|APR_BINARY); 
560	//*****************************************	
561	if (!file_handle)
562	{
563		return 0;
564	}
565
566	llassert(offset >= 0);
567
568	if (offset > 0)
569		offset = LLAPRFile::seek(file_handle, APR_SET, offset);
570	
571	apr_size_t bytes_read;
572	if (offset < 0)
573	{
574		bytes_read = 0;
575	}
576	else
577	{
578		bytes_read = nbytes ;		
579		apr_status_t s = apr_file_read(file_handle, buf, &bytes_read);
580		if (s != APR_SUCCESS)
581		{
582			LL_WARNS("APR") << " Attempting to read filename: " << filename << LL_ENDL;
583			ll_apr_warn_status(s);
584			bytes_read = 0;
585		}
586		else
587		{
588			llassert_always(bytes_read <= 0x7fffffff);		
589		}
590	}
591	
592	//*****************************************
593	close(file_handle, pool) ; 
594	//*****************************************
595	return (S32)bytes_read;
596}
597
598//static
599S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
600{
601	apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
602	if (offset < 0)
603	{
604		flags |= APR_APPEND;
605		offset = 0;
606	}
607	
608	//*****************************************
609	apr_file_t* file_handle = open(filename, pool, flags);
610	//*****************************************
611	if (!file_handle)
612	{
613		return 0;
614	}
615
616	if (offset > 0)
617	{
618		offset = LLAPRFile::seek(file_handle, APR_SET, offset);
619	}
620	
621	apr_size_t bytes_written;
622	if (offset < 0)
623	{
624		bytes_written = 0;
625	}
626	else
627	{
628		bytes_written = nbytes ;		
629		apr_status_t s = apr_file_write(file_handle, buf, &bytes_written);
630		if (s != APR_SUCCESS)
631		{
632			LL_WARNS("APR") << " Attempting to write filename: " << filename << LL_ENDL;
633			ll_apr_warn_status(s);
634			bytes_written = 0;
635		}
636		else
637		{
638			llassert_always(bytes_written <= 0x7fffffff);
639		}
640	}
641
642	//*****************************************
643	LLAPRFile::close(file_handle, pool);
644	//*****************************************
645
646	return (S32)bytes_written;
647}
648
649//static
650bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool)
651{
652	apr_status_t s;
653
654	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
655	s = apr_file_remove(filename.c_str(), pool->getVolatileAPRPool());
656	pool->clearVolatileAPRPool() ;
657
658	if (s != APR_SUCCESS)
659	{
660		ll_apr_warn_status(s);
661		LL_WARNS("APR") << " Attempting to remove filename: " << filename << LL_ENDL;
662		return false;
663	}
664	return true;
665}
666
667//static
668bool LLAPRFile::rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool)
669{
670	apr_status_t s;
671
672	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
673	s = apr_file_rename(filename.c_str(), newname.c_str(), pool->getVolatileAPRPool());
674	pool->clearVolatileAPRPool() ;
675	
676	if (s != APR_SUCCESS)
677	{
678		ll_apr_warn_status(s);
679		LL_WARNS("APR") << " Attempting to rename filename: " << filename << LL_ENDL;
680		return false;
681	}
682	return true;
683}
684
685//static
686bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags)
687{
688	apr_file_t* apr_file;
689	apr_status_t s;
690
691	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
692	s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());	
693
694	if (s != APR_SUCCESS || !apr_file)
695	{
696		pool->clearVolatileAPRPool() ;
697		return false;
698	}
699	else
700	{
701		apr_file_close(apr_file) ;
702		pool->clearVolatileAPRPool() ;
703		return true;
704	}
705}
706
707//static
708S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool)
709{
710	apr_file_t* apr_file;
711	apr_finfo_t info;
712	apr_status_t s;
713	
714	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
715	s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool->getVolatileAPRPool());
716	
717	if (s != APR_SUCCESS || !apr_file)
718	{		
719		pool->clearVolatileAPRPool() ;
720		
721		return 0;
722	}
723	else
724	{
725		apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file);		
726
727		apr_file_close(apr_file) ;
728		pool->clearVolatileAPRPool() ;
729		
730		if (s == APR_SUCCESS)
731		{
732			return (S32)info.size;
733		}
734		else
735		{
736			return 0;
737		}
738	}
739}
740
741//static
742bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool)
743{
744	apr_status_t s;
745
746	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
747	s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool->getVolatileAPRPool());
748	pool->clearVolatileAPRPool() ;
749		
750	if (s != APR_SUCCESS)
751	{
752		ll_apr_warn_status(s);
753		LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL;
754		return false;
755	}
756	return true;
757}
758
759//static
760bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool)
761{
762	apr_status_t s;
763
764	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
765	s = apr_file_remove(dirname.c_str(), pool->getVolatileAPRPool());
766	pool->clearVolatileAPRPool() ;
767	
768	if (s != APR_SUCCESS)
769	{
770		ll_apr_warn_status(s);
771		LL_WARNS("APR") << " Attempting to remove directory: " << dirname << LL_ENDL;
772		return false;
773	}
774	return true;
775}
776//
777//end of static components of LLAPRFile
778//*******************************************************************************************************************************
779//