summaryrefslogtreecommitdiff
path: root/apt-pkg/contrib/mmap.cc
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg/contrib/mmap.cc')
-rw-r--r--apt-pkg/contrib/mmap.cc108
1 files changed, 87 insertions, 21 deletions
diff --git a/apt-pkg/contrib/mmap.cc b/apt-pkg/contrib/mmap.cc
index 04a45811b..5f56178f4 100644
--- a/apt-pkg/contrib/mmap.cc
+++ b/apt-pkg/contrib/mmap.cc
@@ -13,17 +13,13 @@
libc6 generates warnings -- which should be errors, g++ isn't properly
strict.
- The configure test notes that some OS's have broken private mmap's
- so on those OS's we can't use mmap. This means we have to use
- configure to test mmap and can't rely on the POSIX
- _POSIX_MAPPED_FILES test.
-
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
#define _BSD_SOURCE
#include <apt-pkg/mmap.h>
#include <apt-pkg/error.h>
+#include <apt-pkg/configuration.h>
#include <apti18n.h>
@@ -31,6 +27,8 @@
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
#include <cstring>
/*}}}*/
@@ -141,6 +139,20 @@ bool MMap::Sync(unsigned long Start,unsigned long Stop)
}
/*}}}*/
+// DynamicMMapSegfaultHandler /*{{{*/
+// ---------------------------------------------------------------------
+/* In theory, the mmap should never segfault because we check the available
+ size of our mmap before we use it, but there are a few reports out there
+ which state that the mmap segfaults without further notice. So this handler
+ will take care of all these segfaults which should never happen... */
+void DynamicMMapSegfaultHandler(int)
+{
+ _error->Error(_("Dynamic MMap segfaults, most likely because it ran out of room. "
+ "Please increase the size of APT::Cache-Limit. (man 5 apt.conf)"));
+ _error->DumpErrors();
+ exit(EXIT_FAILURE);
+}
+ /*}}}*/
// DynamicMMap::DynamicMMap - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
@@ -166,13 +178,30 @@ DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace)
/*}}}*/
// DynamicMMap::DynamicMMap - Constructor for a non-file backed map /*{{{*/
// ---------------------------------------------------------------------
-/* This is just a fancy malloc really.. */
+/* We try here to use mmap to reserve some space - this is much more
+ cooler than the fallback solution to simply allocate a char array
+ and could come in handy later than we are able to grow such an mmap */
DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long WorkSpace) :
MMap(Flags | NoImmMap | UnMapped), Fd(0), WorkSpace(WorkSpace)
{
if (_error->PendingError() == true)
return;
-
+
+ if (_config->FindB("MMap::SegfaultHandler",true) == true)
+ {
+ struct sigaction sa;
+ sa.sa_handler = DynamicMMapSegfaultHandler;
+ sigaction(SIGSEGV, &sa, NULL);
+ }
+
+#ifdef _POSIX_MAPPED_FILES
+ // use anonymous mmap() to get the memory
+ Base = (unsigned char*) mmap(0, WorkSpace, PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ if(Base != MAP_FAILED)
+ return;
+#endif
+ // fallback to a static allocated space
Base = new unsigned char[WorkSpace];
memset(Base,0,WorkSpace);
iSize = 0;
@@ -185,7 +214,11 @@ DynamicMMap::~DynamicMMap()
{
if (Fd == 0)
{
+#ifdef _POSIX_MAPPED_FILES
+ munmap(Base, WorkSpace);
+#else
delete [] (unsigned char *)Base;
+#endif
return;
}
@@ -207,14 +240,16 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln)
iSize = Result + Size;
- // Just in case error check
- if (Result + Size > WorkSpace)
+ // try to grow the buffer
+ while(Result + Size > WorkSpace)
{
- _error->Error(_("Dynamic MMap ran out of room. Please increase the size "
- "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace);
- return 0;
+ if(!Grow())
+ {
+ _error->Error(_("Dynamic MMap ran out of room. Please increase the size "
+ "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace);
+ return 0;
+ }
}
-
return Result;
}
/*}}}*/
@@ -234,7 +269,6 @@ unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
if (I->ItemSize == ItemSize)
break;
}
-
// No pool is allocated, use an unallocated one
if (I == Pools + PoolCount)
{
@@ -270,14 +304,17 @@ unsigned long DynamicMMap::WriteString(const char *String,
unsigned long Len)
{
unsigned long Result = iSize;
- // Just in case error check
- if (Result + Len > WorkSpace)
+ // try to grow the buffer
+ while(Result + Len > WorkSpace)
{
- _error->Error(_("Dynamic MMap ran out of room. Please increase the size "
- "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace);
- return 0;
- }
-
+ if(!Grow())
+ {
+ _error->Error(_("Dynamic MMap ran out of room. Please increase the size "
+ "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace);
+ return 0;
+ }
+ }
+
if (Len == (unsigned long)-1)
Len = strlen(String);
iSize += Len + 1;
@@ -286,3 +323,32 @@ unsigned long DynamicMMap::WriteString(const char *String,
return Result;
}
/*}}}*/
+// DynamicMMap::Grow - Grow the mmap /*{{{*/
+// ---------------------------------------------------------------------
+/* This method will try to grow the mmap we currently use. This doesn't
+ work most of the time because we can't move the mmap around in the
+ memory for now as this would require to adjust quite a lot of pointers
+ but why we should not at least try to grow it before we give up? */
+bool DynamicMMap::Grow()
+{
+#ifdef _POSIX_MAPPED_FILES
+ unsigned long newSize = WorkSpace + 1024*1024;
+
+ if(Fd != 0)
+ {
+ Fd->Seek(newSize - 1);
+ char C = 0;
+ Fd->Write(&C,sizeof(C));
+ }
+
+ Base = mremap(Base, WorkSpace, newSize, 0);
+ if(Base == MAP_FAILED)
+ return false;
+
+ WorkSpace = newSize;
+ return true;
+#else
+ return false;
+#endif
+}
+ /*}}}*/