]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/mmap.cc
d710662435e5c21e20f52ba09720eef9c603f18c
   1 // -*- mode: cpp; mode: fold -*- 
   3 // $Id: mmap.cc,v 1.22 2001/05/27 05:19:30 jgg Exp $ 
   4 /* ###################################################################### 
   6    MMap Class - Provides 'real' mmap or a faked mmap using read(). 
  10    Some broken versions of glibc2 (libc6) have a broken definition 
  11    of mmap that accepts a char * -- all other systems (and libc5) use 
  12    void *. We can't safely do anything here that would be portable, so 
  13    libc6 generates warnings -- which should be errors, g++ isn't properly 
  16    ##################################################################### */ 
  18 // Include Files                                                        /*{{{*/ 
  20 #include <apt-pkg/mmap.h> 
  21 #include <apt-pkg/error.h> 
  35 // MMap::MMap - Constructor                                             /*{{{*/ 
  36 // --------------------------------------------------------------------- 
  38 MMap::MMap(FileFd 
&F
,unsigned long Flags
) : Flags(Flags
), iSize(0), 
  39                      Base(0), SyncToFd(NULL
) 
  41    if ((Flags 
& NoImmMap
) != NoImmMap
) 
  45 // MMap::MMap - Constructor                                             /*{{{*/ 
  46 // --------------------------------------------------------------------- 
  48 MMap::MMap(unsigned long Flags
) : Flags(Flags
), iSize(0), 
  49                      Base(0), SyncToFd(NULL
) 
  53 // MMap::~MMap - Destructor                                             /*{{{*/ 
  54 // --------------------------------------------------------------------- 
  61 // MMap::Map - Perform the mapping                                      /*{{{*/ 
  62 // --------------------------------------------------------------------- 
  64 bool MMap::Map(FileFd 
&Fd
) 
  68    // Set the permissions. 
  71    if ((Flags 
& ReadOnly
) != ReadOnly
) 
  73    if ((Flags 
& Public
) != Public
) 
  77       return _error
->Error(_("Can't mmap an empty file")); 
  80    Base 
= mmap(0,iSize
,Prot
,Map
,Fd
.Fd(),0); 
  81    if (Base 
== (void *)-1) 
  83       if (errno 
== ENODEV 
|| errno 
== EINVAL
) 
  85          // The filesystem doesn't support this particular kind of mmap. 
  86          // So we allocate a buffer and read the whole file into it. 
  87          int const dupped_fd 
= dup(Fd
.Fd()); 
  89             return _error
->Errno("mmap", _("Couldn't duplicate file descriptor %i"), Fd
.Fd()); 
  91          Base 
= new unsigned char[iSize
]; 
  92          SyncToFd 
= new FileFd (dupped_fd
); 
  93          if (!SyncToFd
->Seek(0L) || !SyncToFd
->Read(Base
, iSize
)) 
  97          return _error
->Errno("mmap",_("Couldn't make mmap of %lu bytes"), 
 104 // MMap::Close - Close the map                                          /*{{{*/ 
 105 // --------------------------------------------------------------------- 
 107 bool MMap::Close(bool DoSync
) 
 109    if ((Flags 
& UnMapped
) == UnMapped 
|| Base 
== 0 || iSize 
== 0) 
 115    if (SyncToFd 
!= NULL
) 
 117       delete[] (char *)Base
; 
 123       if (munmap((char *)Base
, iSize
) != 0) 
 124          _error
->WarningE("mmap", _("Unable to close mmap")); 
 132 // MMap::Sync - Syncronize the map with the disk                        /*{{{*/ 
 133 // --------------------------------------------------------------------- 
 134 /* This is done in syncronous mode - the docs indicate that this will  
 135    not return till all IO is complete */ 
 138    if ((Flags 
& UnMapped
) == UnMapped
) 
 141 #ifdef _POSIX_SYNCHRONIZED_IO    
 142    if ((Flags 
& ReadOnly
) != ReadOnly
) 
 144       if (SyncToFd 
!= NULL
) 
 146          if (!SyncToFd
->Seek(0) || !SyncToFd
->Write(Base
, iSize
)) 
 151          if (msync((char *)Base
, iSize
, MS_SYNC
) < 0) 
 152             return _error
->Errno("msync", _("Unable to synchronize mmap")); 
 159 // MMap::Sync - Syncronize a section of the file to disk                /*{{{*/ 
 160 // --------------------------------------------------------------------- 
 162 bool MMap::Sync(unsigned long Start
,unsigned long Stop
) 
 164    if ((Flags 
& UnMapped
) == UnMapped
) 
 167 #ifdef _POSIX_SYNCHRONIZED_IO 
 168    unsigned long PSize 
= sysconf(_SC_PAGESIZE
); 
 169    if ((Flags 
& ReadOnly
) != ReadOnly
) 
 173          if (!SyncToFd
->Seek(0) || 
 174              !SyncToFd
->Write (((char *)Base
)+Start
, Stop
-Start
)) 
 179          if (msync((char *)Base
+(int)(Start
/PSize
)*PSize
,Stop 
- Start
,MS_SYNC
) < 0) 
 180             return _error
->Errno("msync", _("Unable to synchronize mmap")); 
 188 // DynamicMMap::DynamicMMap - Constructor                               /*{{{*/ 
 189 // --------------------------------------------------------------------- 
 191 DynamicMMap::DynamicMMap(FileFd 
&F
,unsigned long Flags
,unsigned long const &Workspace
, 
 192                          unsigned long const &Grow
, unsigned long const &Limit
) : 
 193                 MMap(F
,Flags 
| NoImmMap
), Fd(&F
), WorkSpace(Workspace
), 
 194                 GrowFactor(Grow
), Limit(Limit
) 
 196    if (_error
->PendingError() == true) 
 199    unsigned long EndOfFile 
= Fd
->Size(); 
 200    if (EndOfFile 
> WorkSpace
) 
 201       WorkSpace 
= EndOfFile
; 
 202    else if(WorkSpace 
> 0) 
 204       Fd
->Seek(WorkSpace 
- 1); 
 206       Fd
->Write(&C
,sizeof(C
)); 
 213 // DynamicMMap::DynamicMMap - Constructor for a non-file backed map     /*{{{*/ 
 214 // --------------------------------------------------------------------- 
 215 /* We try here to use mmap to reserve some space - this is much more 
 216    cooler than the fallback solution to simply allocate a char array 
 217    and could come in handy later than we are able to grow such an mmap */ 
 218 DynamicMMap::DynamicMMap(unsigned long Flags
,unsigned long const &WorkSpace
, 
 219                          unsigned long const &Grow
, unsigned long const &Limit
) : 
 220                 MMap(Flags 
| NoImmMap 
| UnMapped
), Fd(0), WorkSpace(WorkSpace
), 
 221                 GrowFactor(Grow
), Limit(Limit
) 
 223         if (_error
->PendingError() == true) 
 226         // disable Moveable if we don't grow 
 231         // kfreebsd doesn't have mremap, so we use the fallback 
 232         if ((Flags 
& Moveable
) == Moveable
) 
 236 #ifdef _POSIX_MAPPED_FILES 
 237         if ((Flags 
& Fallback
) != Fallback
) { 
 238                 // Set the permissions. 
 239                 int Prot 
= PROT_READ
; 
 240                 int Map 
= MAP_PRIVATE 
| MAP_ANONYMOUS
; 
 241                 if ((Flags 
& ReadOnly
) != ReadOnly
) 
 243                 if ((Flags 
& Public
) == Public
) 
 244                         Map 
= MAP_SHARED 
| MAP_ANONYMOUS
; 
 246                 // use anonymous mmap() to get the memory 
 247                 Base 
= (unsigned char*) mmap(0, WorkSpace
, Prot
, Map
, -1, 0); 
 249                 if(Base 
== MAP_FAILED
) 
 250                         _error
->Errno("DynamicMMap",_("Couldn't make mmap of %lu bytes"),WorkSpace
); 
 256         // fallback to a static allocated space 
 257         Base 
= new unsigned char[WorkSpace
]; 
 258         memset(Base
,0,WorkSpace
); 
 262 // DynamicMMap::~DynamicMMap - Destructor                               /*{{{*/ 
 263 // --------------------------------------------------------------------- 
 264 /* We truncate the file to the size of the memory data set */ 
 265 DynamicMMap::~DynamicMMap() 
 269 #ifdef _POSIX_MAPPED_FILES 
 270       munmap(Base
, WorkSpace
); 
 272       delete [] (unsigned char *)Base
; 
 277    unsigned long EndOfFile 
= iSize
; 
 280    if(ftruncate(Fd
->Fd(),EndOfFile
) < 0) 
 281       _error
->Errno("ftruncate", _("Failed to truncate file")); 
 284 // DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space   /*{{{*/ 
 285 // --------------------------------------------------------------------- 
 286 /* This allocates a block of memory aligned to the given size */ 
 287 unsigned long DynamicMMap::RawAllocate(unsigned long Size
,unsigned long Aln
) 
 289    unsigned long Result 
= iSize
; 
 291       Result 
+= Aln 
- (iSize%Aln
); 
 293    iSize 
= Result 
+ Size
; 
 295    // try to grow the buffer 
 296    while(Result 
+ Size 
> WorkSpace
) 
 300          _error
->Fatal(_("Dynamic MMap ran out of room. Please increase the size " 
 301                          "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace
); 
 308 // DynamicMMap::Allocate - Pooled aligned allocation                    /*{{{*/ 
 309 // --------------------------------------------------------------------- 
 310 /* This allocates an Item of size ItemSize so that it is aligned to its 
 312 unsigned long DynamicMMap::Allocate(unsigned long ItemSize
) 
 314    // Look for a matching pool entry 
 317    for (I 
= Pools
; I 
!= Pools 
+ PoolCount
; I
++) 
 319       if (I
->ItemSize 
== 0) 
 321       if (I
->ItemSize 
== ItemSize
) 
 324    // No pool is allocated, use an unallocated one 
 325    if (I 
== Pools 
+ PoolCount
) 
 327       // Woops, we ran out, the calling code should allocate more. 
 330          _error
->Error("Ran out of allocation pools"); 
 335       I
->ItemSize 
= ItemSize
; 
 339    unsigned long Result 
= 0; 
 340    // Out of space, allocate some more 
 343       const unsigned long size 
= 20*1024; 
 344       I
->Count 
= size
/ItemSize
; 
 345       Result 
= RawAllocate(size
,ItemSize
); 
 346       // Does the allocation failed ? 
 347       if (Result 
== 0 && _error
->PendingError()) 
 355    I
->Start 
+= ItemSize
; 
 356    return Result
/ItemSize
; 
 359 // DynamicMMap::WriteString - Write a string to the file                /*{{{*/ 
 360 // --------------------------------------------------------------------- 
 361 /* Strings are not aligned to anything */ 
 362 unsigned long DynamicMMap::WriteString(const char *String
, 
 365    if (Len 
== (unsigned long)-1) 
 366       Len 
= strlen(String
); 
 368    unsigned long Result 
= RawAllocate(Len
+1,0); 
 370    if (Result 
== 0 && _error
->PendingError()) 
 373    memcpy((char *)Base 
+ Result
,String
,Len
); 
 374    ((char *)Base
)[Result 
+ Len
] = 0; 
 378 // DynamicMMap::Grow - Grow the mmap                                    /*{{{*/ 
 379 // --------------------------------------------------------------------- 
 380 /* This method is a wrapper around different methods to (try to) grow 
 381    a mmap (or our char[]-fallback). Encounterable environments: 
 382    1. Moveable + !Fallback + linux -> mremap with MREMAP_MAYMOVE 
 383    2. Moveable + !Fallback + !linux -> not possible (forbidden by constructor) 
 384    3. Moveable + Fallback -> realloc 
 385    4. !Moveable + !Fallback + linux -> mremap alone - which will fail in 99,9% 
 386    5. !Moveable + !Fallback + !linux -> not possible (forbidden by constructor) 
 387    6. !Moveable + Fallback -> not possible 
 388    [ While Moveable and Fallback stands for the equally named flags and 
 389      "linux" indicates a linux kernel instead of a freebsd kernel. ] 
 390    So what you can see here is, that a MMAP which want to be growable need 
 391    to be moveable to have a real chance but that this method will at least try 
 392    the nearly impossible 4 to grow it before it finally give up: Never say never. */ 
 393 bool DynamicMMap::Grow() { 
 394         if (Limit 
!= 0 && WorkSpace 
>= Limit
) 
 395                 return _error
->Error(_("Unable to increase the size of the MMap as the " 
 396                                        "limit of %lu bytes is already reached."), Limit
); 
 398         unsigned long const newSize 
= WorkSpace 
+ 1024*1024; 
 401                 Fd
->Seek(newSize 
- 1); 
 403                 Fd
->Write(&C
,sizeof(C
)); 
 405         if ((Flags 
& Fallback
) != Fallback
) { 
 406 #if defined(_POSIX_MAPPED_FILES) && defined(__linux__) 
 407    #ifdef MREMAP_MAYMOVE 
 408                 if ((Flags 
& Moveable
) == Moveable
) 
 409                         Base 
= mremap(Base
, WorkSpace
, newSize
, MREMAP_MAYMOVE
); 
 412                         Base 
= mremap(Base
, WorkSpace
, newSize
, 0); 
 414                 if(Base 
== MAP_FAILED
) 
 420                 if ((Flags 
& Moveable
) != Moveable
) 
 423                 Base 
= realloc(Base
, newSize
);