]>
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");
141 // DynamicMMap::DynamicMMap - Constructor /*{{{*/
142 // ---------------------------------------------------------------------
144 DynamicMMap::DynamicMMap(FileFd
&F
,unsigned long Flags
,unsigned long WorkSpace
) :
145 MMap(F
,Flags
| NoImmMap
), Fd(&F
), WorkSpace(WorkSpace
)
147 if (_error
->PendingError() == true)
150 unsigned long EndOfFile
= Fd
->Size();
151 if (EndOfFile
> WorkSpace
)
152 WorkSpace
= EndOfFile
;
153 else if(WorkSpace
> 0)
155 Fd
->Seek(WorkSpace
- 1);
157 Fd
->Write(&C
,sizeof(C
));
164 // DynamicMMap::DynamicMMap - Constructor for a non-file backed map /*{{{*/
165 // ---------------------------------------------------------------------
166 /* We try here to use mmap to reserve some space - this is much more
167 cooler than the fallback solution to simply allocate a char array
168 and could come in handy later than we are able to grow such an mmap */
169 DynamicMMap::DynamicMMap(unsigned long Flags
,unsigned long WorkSpace
) :
170 MMap(Flags
| NoImmMap
| UnMapped
), Fd(0), WorkSpace(WorkSpace
)
172 if (_error
->PendingError() == true)
175 #ifdef _POSIX_MAPPED_FILES
176 // use anonymous mmap() to get the memory
177 Base
= (unsigned char*) mmap(0, WorkSpace
, PROT_READ
|PROT_WRITE
,
178 MAP_ANONYMOUS
|MAP_PRIVATE
, -1, 0);
179 if(Base
!= MAP_FAILED
)
182 // fallback to a static allocated space
183 Base
= new unsigned char[WorkSpace
];
184 memset(Base
,0,WorkSpace
);
188 // DynamicMMap::~DynamicMMap - Destructor /*{{{*/
189 // ---------------------------------------------------------------------
190 /* We truncate the file to the size of the memory data set */
191 DynamicMMap::~DynamicMMap()
195 #ifdef _POSIX_MAPPED_FILES
196 munmap(Base
, WorkSpace
);
198 delete [] (unsigned char *)Base
;
203 unsigned long EndOfFile
= iSize
;
206 if(ftruncate(Fd
->Fd(),EndOfFile
) < 0)
207 _error
->Errno("ftruncate", _("Failed to truncate file"));
210 // DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space /*{{{*/
211 // ---------------------------------------------------------------------
212 /* This allocates a block of memory aligned to the given size */
213 unsigned long DynamicMMap::RawAllocate(unsigned long Size
,unsigned long Aln
)
215 unsigned long Result
= iSize
;
217 Result
+= Aln
- (iSize%Aln
);
219 iSize
= Result
+ Size
;
221 // try to grow the buffer
222 while(Result
+ Size
> WorkSpace
)
226 _error
->Error(_("Dynamic MMap ran out of room. Please increase the size "
227 "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace
);
234 // DynamicMMap::Allocate - Pooled aligned allocation /*{{{*/
235 // ---------------------------------------------------------------------
236 /* This allocates an Item of size ItemSize so that it is aligned to its
238 unsigned long DynamicMMap::Allocate(unsigned long ItemSize
)
240 // Look for a matching pool entry
243 for (I
= Pools
; I
!= Pools
+ PoolCount
; I
++)
245 if (I
->ItemSize
== 0)
247 if (I
->ItemSize
== ItemSize
)
250 // No pool is allocated, use an unallocated one
251 if (I
== Pools
+ PoolCount
)
253 // Woops, we ran out, the calling code should allocate more.
256 _error
->Error("Ran out of allocation pools");
261 I
->ItemSize
= ItemSize
;
265 unsigned long Result
= 0;
266 // Out of space, allocate some more
269 const unsigned long size
= 20*1024;
270 I
->Count
= size
/ItemSize
;
271 Result
= RawAllocate(size
,ItemSize
);
272 // Does the allocation failed ?
273 if (Result
== 0 && _error
->PendingError())
281 I
->Start
+= ItemSize
;
282 return Result
/ItemSize
;
285 // DynamicMMap::WriteString - Write a string to the file /*{{{*/
286 // ---------------------------------------------------------------------
287 /* Strings are not aligned to anything */
288 unsigned long DynamicMMap::WriteString(const char *String
,
291 if (Len
== (unsigned long)-1)
292 Len
= strlen(String
);
294 unsigned long Result
= RawAllocate(Len
+1,0);
296 if (Result
== 0 && _error
->PendingError())
299 memcpy((char *)Base
+ Result
,String
,Len
);
300 ((char *)Base
)[Result
+ Len
] = 0;
304 // DynamicMMap::Grow - Grow the mmap /*{{{*/
305 // ---------------------------------------------------------------------
306 /* This method will try to grow the mmap we currently use. This doesn't
307 work most of the time because we can't move the mmap around in the
308 memory for now as this would require to adjust quite a lot of pointers
309 but why we should not at least try to grow it before we give up? */
310 bool DynamicMMap::Grow()
312 #ifdef _POSIX_MAPPED_FILES
313 unsigned long newSize
= WorkSpace
+ 1024*1024;
317 Fd
->Seek(newSize
- 1);
319 Fd
->Write(&C
,sizeof(C
));
322 Base
= mremap(Base
, WorkSpace
, newSize
, 0);
323 if(Base
== MAP_FAILED
)