]> git.decadent.org.uk Git - dak.git/blob - tools/dsync-0.0/libdsync/contrib/mmap.cc
Merge mainline
[dak.git] / tools / dsync-0.0 / libdsync / contrib / mmap.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: mmap.cc,v 1.3 1999/10/24 06:53:12 jgg Exp $
4 /* ######################################################################
5    
6    MMap Class - Provides 'real' mmap or a faked mmap using read().
7
8    MMap cover class.
9
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
14    strict.
15    
16    The configure test notes that some OS's have broken private mmap's
17    so on those OS's we can't use mmap. This means we have to use
18    configure to test mmap and can't rely on the POSIX
19    _POSIX_MAPPED_FILES test.
20    
21    ##################################################################### */
22                                                                         /*}}}*/
23 // Include Files                                                        /*{{{*/
24 #ifdef __GNUG__
25 #pragma implementation "dsync/mmap.h"
26 #endif 
27
28 #define _BSD_SOURCE
29 #include <dsync/mmap.h>
30 #include <dsync/error.h>
31
32 #include <sys/mman.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36                                                                         /*}}}*/
37
38 // MMap::MMap - Constructor                                             /*{{{*/
39 // ---------------------------------------------------------------------
40 /* */
41 MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
42                      Base(0)
43 {
44    if ((Flags & NoImmMap) != NoImmMap)
45       Map(F);
46 }
47                                                                         /*}}}*/
48 // MMap::MMap - Constructor                                             /*{{{*/
49 // ---------------------------------------------------------------------
50 /* */
51 MMap::MMap(unsigned long Flags) : Flags(Flags), iSize(0),
52                      Base(0)
53 {
54 }
55                                                                         /*}}}*/
56 // MMap::~MMap - Destructor                                             /*{{{*/
57 // ---------------------------------------------------------------------
58 /* */
59 MMap::~MMap()
60 {
61    Close();
62 }
63                                                                         /*}}}*/
64 // MMap::Map - Perform the mapping                                      /*{{{*/
65 // ---------------------------------------------------------------------
66 /* */
67 bool MMap::Map(FileFd &Fd)
68 {
69    iSize = Fd.Size();
70    
71    // Set the permissions.
72    int Prot = PROT_READ;
73    int Map = MAP_SHARED;
74    if ((Flags & ReadOnly) != ReadOnly)
75       Prot |= PROT_WRITE;
76    if ((Flags & Public) != Public)
77       Map = MAP_PRIVATE;
78    
79    if (iSize == 0)
80       return _error->Error("Can't mmap an empty file");
81    
82    // Map it.
83    Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0);
84    if (Base == (void *)-1)
85       return _error->Errno("mmap","Couldn't make mmap of %u bytes",iSize);
86
87    return true;
88 }
89                                                                         /*}}}*/
90 // MMap::Close - Close the map                                          /*{{{*/
91 // ---------------------------------------------------------------------
92 /* */
93 bool MMap::Close(bool DoSync)
94 {
95    if ((Flags & UnMapped) == UnMapped || Base == 0 || iSize == 0)
96       return true;
97    
98    if (DoSync == true)
99       Sync();
100    
101    if (munmap((char *)Base,iSize) != 0)
102       _error->Warning("Unable to munmap");
103    
104    iSize = 0;
105    return true;
106 }
107                                                                         /*}}}*/
108 // MMap::Sync - Syncronize the map with the disk                        /*{{{*/
109 // ---------------------------------------------------------------------
110 /* This is done in syncronous mode - the docs indicate that this will 
111    not return till all IO is complete */
112 bool MMap::Sync()
113 {   
114    if ((Flags & UnMapped) == UnMapped)
115       return true;
116    
117 #ifdef _POSIX_SYNCHRONIZED_IO   
118    if ((Flags & ReadOnly) != ReadOnly)
119       if (msync((char *)Base,iSize,MS_SYNC) != 0)
120          return _error->Errno("msync","Unable to write mmap");
121 #endif   
122    return true;
123 }
124                                                                         /*}}}*/
125 // MMap::Sync - Syncronize a section of the file to disk                /*{{{*/
126 // ---------------------------------------------------------------------
127 /* */
128 bool MMap::Sync(unsigned long Start,unsigned long Stop)
129 {
130    if ((Flags & UnMapped) == UnMapped)
131       return true;
132    
133 #ifdef _POSIX_SYNCHRONIZED_IO
134    unsigned long PSize = sysconf(_SC_PAGESIZE);
135    if ((Flags & ReadOnly) != ReadOnly)
136       if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) != 0)
137          return _error->Errno("msync","Unable to write mmap");
138 #endif   
139    return true;
140 }
141                                                                         /*}}}*/
142
143 // DynamicMMap::DynamicMMap - Constructor                               /*{{{*/
144 // ---------------------------------------------------------------------
145 /* */
146 DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace) : 
147              MMap(F,Flags | NoImmMap), Fd(&F), WorkSpace(WorkSpace)
148 {
149    if (_error->PendingError() == true)
150       return;
151    
152    unsigned long EndOfFile = Fd->Size();
153    Fd->Seek(WorkSpace);
154    char C = 0;
155    Fd->Write(&C,sizeof(C));
156    Map(F);
157    iSize = EndOfFile;
158 }
159                                                                         /*}}}*/
160 // DynamicMMap::DynamicMMap - Constructor for a non-file backed map     /*{{{*/
161 // ---------------------------------------------------------------------
162 /* This is just a fancy malloc really.. */
163 DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long WorkSpace) :
164              MMap(Flags | NoImmMap | UnMapped), Fd(0), WorkSpace(WorkSpace)
165 {
166    if (_error->PendingError() == true)
167       return;
168    
169    Base = new unsigned char[WorkSpace];
170    iSize = 0;
171 }
172                                                                         /*}}}*/
173 // DynamicMMap::~DynamicMMap - Destructor                               /*{{{*/
174 // ---------------------------------------------------------------------
175 /* We truncate the file to the size of the memory data set */
176 DynamicMMap::~DynamicMMap()
177 {
178    if (Fd == 0)
179    {
180       delete [] (unsigned char *)Base;
181       return;
182    }
183    
184    unsigned long EndOfFile = iSize;
185    Sync();
186    iSize = WorkSpace;
187    Close(false);
188    ftruncate(Fd->Fd(),EndOfFile);
189    Fd->Close();
190 }  
191                                                                         /*}}}*/
192 // DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space   /*{{{*/
193 // ---------------------------------------------------------------------
194 /* This allocates a block of memory aligned to the given size */
195 unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln)
196 {
197    unsigned long Result = iSize;
198    if (Aln != 0)
199       Result += Aln - (iSize%Aln);
200    
201    iSize = Result + Size;
202    
203    // Just in case error check
204    if (Result + Size > WorkSpace)
205    {
206       _error->Error("Dynamic MMap ran out of room");
207       return 0;
208    }
209
210    return Result;
211 }
212                                                                         /*}}}*/
213 // DynamicMMap::Allocate - Pooled aligned allocation                    /*{{{*/
214 // ---------------------------------------------------------------------
215 /* This allocates an Item of size ItemSize so that it is aligned to its
216    size in the file. */
217 unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
218 {   
219    // Look for a matching pool entry
220    Pool *I;
221    Pool *Empty = 0;
222    for (I = Pools; I != Pools + PoolCount; I++)
223    {
224       if (I->ItemSize == 0)
225          Empty = I;
226       if (I->ItemSize == ItemSize)
227          break;
228    }
229
230    // No pool is allocated, use an unallocated one
231    if (I == Pools + PoolCount)
232    {
233       // Woops, we ran out, the calling code should allocate more.
234       if (Empty == 0)
235       {
236          _error->Error("Ran out of allocation pools");
237          return 0;
238       }
239       
240       I = Empty;
241       I->ItemSize = ItemSize;
242       I->Count = 0;
243    }
244    
245    // Out of space, allocate some more
246    if (I->Count == 0)
247    {
248       I->Count = 20*1024/ItemSize;
249       I->Start = RawAllocate(I->Count*ItemSize,ItemSize);
250    }   
251
252    I->Count--;
253    unsigned long Result = I->Start;
254    I->Start += ItemSize;  
255    return Result/ItemSize;
256 }
257                                                                         /*}}}*/
258 // DynamicMMap::WriteString - Write a string to the file                /*{{{*/
259 // ---------------------------------------------------------------------
260 /* Strings are not aligned to anything */
261 unsigned long DynamicMMap::WriteString(const char *String,
262                                        unsigned long Len)
263 {
264    unsigned long Result = iSize;
265    // Just in case error check
266    if (Result + Len > WorkSpace)
267    {
268       _error->Error("Dynamic MMap ran out of room");
269       return 0;
270    }   
271    
272    if (Len == (unsigned long)-1)
273       Len = strlen(String);
274    iSize += Len + 1;
275    memcpy((char *)Base + Result,String,Len);
276    ((char *)Base)[Result + Len] = 0;
277    return Result;
278 }
279                                                                         /*}}}*/