]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/mmap.cc
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>
34 // MMap::MMap - Constructor /*{{{*/
35 // ---------------------------------------------------------------------
37 MMap::MMap(FileFd
&F
,unsigned long Flags
) : Flags(Flags
), iSize(0),
40 if ((Flags
& NoImmMap
) != NoImmMap
)
44 // MMap::MMap - Constructor /*{{{*/
45 // ---------------------------------------------------------------------
47 MMap::MMap(unsigned long Flags
) : Flags(Flags
), iSize(0),
52 // MMap::~MMap - Destructor /*{{{*/
53 // ---------------------------------------------------------------------
60 // MMap::Map - Perform the mapping /*{{{*/
61 // ---------------------------------------------------------------------
63 bool MMap::Map(FileFd
&Fd
)
67 // Set the permissions.
70 if ((Flags
& ReadOnly
) != ReadOnly
)
72 if ((Flags
& Public
) != Public
)
76 return _error
->Error(_("Can't mmap an empty file"));
79 Base
= mmap(0,iSize
,Prot
,Map
,Fd
.Fd(),0);
80 if (Base
== (void *)-1)
81 return _error
->Errno("mmap",_("Couldn't make mmap of %lu bytes"),iSize
);
86 // MMap::Close - Close the map /*{{{*/
87 // ---------------------------------------------------------------------
89 bool MMap::Close(bool DoSync
)
91 if ((Flags
& UnMapped
) == UnMapped
|| Base
== 0 || iSize
== 0)
97 if (munmap((char *)Base
,iSize
) != 0)
98 _error
->Warning("Unable to munmap");
105 // MMap::Sync - Syncronize the map with the disk /*{{{*/
106 // ---------------------------------------------------------------------
107 /* This is done in syncronous mode - the docs indicate that this will
108 not return till all IO is complete */
111 if ((Flags
& UnMapped
) == UnMapped
)
114 #ifdef _POSIX_SYNCHRONIZED_IO
115 if ((Flags
& ReadOnly
) != ReadOnly
)
116 if (msync((char *)Base
,iSize
,MS_SYNC
) < 0)
117 return _error
->Errno("msync","Unable to write mmap");
122 // MMap::Sync - Syncronize a section of the file to disk /*{{{*/
123 // ---------------------------------------------------------------------
125 bool MMap::Sync(unsigned long Start
,unsigned long Stop
)
127 if ((Flags
& UnMapped
) == UnMapped
)
130 #ifdef _POSIX_SYNCHRONIZED_IO
131 unsigned long PSize
= sysconf(_SC_PAGESIZE
);
132 if ((Flags
& ReadOnly
) != ReadOnly
)
133 if (msync((char *)Base
+(int)(Start
/PSize
)*PSize
,Stop
- Start
,MS_SYNC
) < 0)
134 return _error
->Errno("msync","Unable to write mmap");
140 // DynamicMMap::DynamicMMap - Constructor /*{{{*/
141 // ---------------------------------------------------------------------
143 DynamicMMap::DynamicMMap(FileFd
&F
,unsigned long Flags
,unsigned long const &Workspace
,
144 unsigned long const &Grow
, unsigned long const &Limit
) :
145 MMap(F
,Flags
| NoImmMap
), Fd(&F
), WorkSpace(Workspace
),
146 GrowFactor(Grow
), Limit(Limit
)
148 if (_error
->PendingError() == true)
151 unsigned long EndOfFile
= Fd
->Size();
152 if (EndOfFile
> WorkSpace
)
153 WorkSpace
= EndOfFile
;
154 else if(WorkSpace
> 0)
156 Fd
->Seek(WorkSpace
- 1);
158 Fd
->Write(&C
,sizeof(C
));
165 // DynamicMMap::DynamicMMap - Constructor for a non-file backed map /*{{{*/
166 // ---------------------------------------------------------------------
167 /* We try here to use mmap to reserve some space - this is much more
168 cooler than the fallback solution to simply allocate a char array
169 and could come in handy later than we are able to grow such an mmap */
170 DynamicMMap::DynamicMMap(unsigned long Flags
,unsigned long const &WorkSpace
,
171 unsigned long const &Grow
, unsigned long const &Limit
) :
172 MMap(Flags
| NoImmMap
| UnMapped
), Fd(0), WorkSpace(WorkSpace
),
173 GrowFactor(Grow
), Limit(Limit
)
175 if (_error
->PendingError() == true)
178 // disable Moveable if we don't grow
183 // kfreebsd doesn't have mremap, so we use the fallback
184 if ((Flags
& Moveable
) == Moveable
)
188 #ifdef _POSIX_MAPPED_FILES
189 if ((Flags
& Fallback
) != Fallback
) {
190 // Set the permissions.
191 int Prot
= PROT_READ
;
192 int Map
= MAP_PRIVATE
| MAP_ANONYMOUS
;
193 if ((Flags
& ReadOnly
) != ReadOnly
)
195 if ((Flags
& Public
) == Public
)
196 Map
= MAP_SHARED
| MAP_ANONYMOUS
;
198 // use anonymous mmap() to get the memory
199 Base
= (unsigned char*) mmap(0, WorkSpace
, Prot
, Map
, -1, 0);
201 if(Base
== MAP_FAILED
)
202 _error
->Errno("DynamicMMap",_("Couldn't make mmap of %lu bytes"),WorkSpace
);
208 // fallback to a static allocated space
209 Base
= new unsigned char[WorkSpace
];
210 memset(Base
,0,WorkSpace
);
214 // DynamicMMap::~DynamicMMap - Destructor /*{{{*/
215 // ---------------------------------------------------------------------
216 /* We truncate the file to the size of the memory data set */
217 DynamicMMap::~DynamicMMap()
221 #ifdef _POSIX_MAPPED_FILES
222 munmap(Base
, WorkSpace
);
224 delete [] (unsigned char *)Base
;
229 unsigned long EndOfFile
= iSize
;
232 if(ftruncate(Fd
->Fd(),EndOfFile
) < 0)
233 _error
->Errno("ftruncate", _("Failed to truncate file"));
236 // DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space /*{{{*/
237 // ---------------------------------------------------------------------
238 /* This allocates a block of memory aligned to the given size */
239 unsigned long DynamicMMap::RawAllocate(unsigned long Size
,unsigned long Aln
)
241 unsigned long Result
= iSize
;
243 Result
+= Aln
- (iSize%Aln
);
245 iSize
= Result
+ Size
;
247 // try to grow the buffer
248 while(Result
+ Size
> WorkSpace
)
252 _error
->Error(_("Dynamic MMap ran out of room. Please increase the size "
253 "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace
);
260 // DynamicMMap::Allocate - Pooled aligned allocation /*{{{*/
261 // ---------------------------------------------------------------------
262 /* This allocates an Item of size ItemSize so that it is aligned to its
264 unsigned long DynamicMMap::Allocate(unsigned long ItemSize
)
266 // Look for a matching pool entry
269 for (I
= Pools
; I
!= Pools
+ PoolCount
; I
++)
271 if (I
->ItemSize
== 0)
273 if (I
->ItemSize
== ItemSize
)
276 // No pool is allocated, use an unallocated one
277 if (I
== Pools
+ PoolCount
)
279 // Woops, we ran out, the calling code should allocate more.
282 _error
->Error("Ran out of allocation pools");
287 I
->ItemSize
= ItemSize
;
291 unsigned long Result
= 0;
292 // Out of space, allocate some more
295 const unsigned long size
= 20*1024;
296 I
->Count
= size
/ItemSize
;
297 Result
= RawAllocate(size
,ItemSize
);
298 // Does the allocation failed ?
299 if (Result
== 0 && _error
->PendingError())
307 I
->Start
+= ItemSize
;
308 return Result
/ItemSize
;
311 // DynamicMMap::WriteString - Write a string to the file /*{{{*/
312 // ---------------------------------------------------------------------
313 /* Strings are not aligned to anything */
314 unsigned long DynamicMMap::WriteString(const char *String
,
317 if (Len
== (unsigned long)-1)
318 Len
= strlen(String
);
320 unsigned long Result
= RawAllocate(Len
+1,0);
322 if (Result
== 0 && _error
->PendingError())
325 memcpy((char *)Base
+ Result
,String
,Len
);
326 ((char *)Base
)[Result
+ Len
] = 0;
330 // DynamicMMap::Grow - Grow the mmap /*{{{*/
331 // ---------------------------------------------------------------------
332 /* This method is a wrapper around different methods to (try to) grow
333 a mmap (or our char[]-fallback). Encounterable environments:
334 1. Moveable + !Fallback + linux -> mremap with MREMAP_MAYMOVE
335 2. Moveable + !Fallback + !linux -> not possible (forbidden by constructor)
336 3. Moveable + Fallback -> realloc
337 4. !Moveable + !Fallback + linux -> mremap alone - which will fail in 99,9%
338 5. !Moveable + !Fallback + !linux -> not possible (forbidden by constructor)
339 6. !Moveable + Fallback -> not possible
340 [ While Moveable and Fallback stands for the equally named flags and
341 "linux" indicates a linux kernel instead of a freebsd kernel. ]
342 So what you can see here is, that a MMAP which want to be growable need
343 to be moveable to have a real chance but that this method will at least try
344 the nearly impossible 4 to grow it before it finally give up: Never say never. */
345 bool DynamicMMap::Grow() {
346 if (Limit
!= 0 && WorkSpace
>= Limit
)
347 return _error
->Error(_("The size of a MMap has already reached the defined limit of %lu bytes,"
348 "abort the try to grow the MMap."), Limit
);
350 unsigned long const newSize
= WorkSpace
+ 1024*1024;
353 Fd
->Seek(newSize
- 1);
355 Fd
->Write(&C
,sizeof(C
));
357 if ((Flags
& Fallback
) != Fallback
) {
358 #if defined(_POSIX_MAPPED_FILES) && defined(__linux__)
359 #ifdef MREMAP_MAYMOVE
360 if ((Flags
& Moveable
) == Moveable
)
361 Base
= mremap(Base
, WorkSpace
, newSize
, MREMAP_MAYMOVE
);
364 Base
= mremap(Base
, WorkSpace
, newSize
, 0);
366 if(Base
== MAP_FAILED
)
372 if ((Flags
& Moveable
) != Moveable
)
375 Base
= realloc(Base
, newSize
);