Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

root/trunk/tango/io/MappedBuffer.d

Revision 3856, 11.7 kB (checked in by kris, 4 months ago)

moved Conduit and friends into tango.io.device in an effort to bring further clarity into tango.io -- this requires adjusting imports such that, for example, tango.io.FileConduit? becomes tango.io.device.FileConduit?

  • Property svn:mime-type set to text/x-dsrc
  • Property svn:eol-style set to native
Line 
1 /*******************************************************************************
2
3         copyright:      Copyright (c) 2004 Kris Bell. All rights reserved
4
5         license:        BSD style: $(LICENSE)
6       
7         version:        Initial release: March 2004
8         
9         author:         Kris
10
11 *******************************************************************************/
12
13 module tango.io.MappedBuffer;
14
15 private import  tango.sys.Common;
16
17 private import  tango.io.Buffer;
18
19 private import  tango.core.Exception;
20
21 public  import  tango.io.device.FileConduit;
22
23 /*******************************************************************************
24
25         Win32 declarations
26
27 *******************************************************************************/
28
29 version (Win32)
30          private extern (Windows)
31                         {
32                         BOOL   UnmapViewOfFile    (LPCVOID);
33                         BOOL   FlushViewOfFile    (LPCVOID, DWORD);
34                         LPVOID MapViewOfFile      (HANDLE, DWORD, DWORD, DWORD, DWORD);
35                         HANDLE CreateFileMappingA (HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCTSTR);
36                         }
37
38 version (Posix)
39         {               
40         private import tango.stdc.posix.sys.mman;
41         }
42
43
44 /*******************************************************************************
45
46         Subclass to treat the buffer as a seekable entity, where all
47         capacity is available for reading and/or writing. To achieve
48         this we must effectively disable the 'limit' watermark, and
49         locate write operations around 'position' instead.
50
51 *******************************************************************************/
52
53 class MappedBuffer : Buffer, IConduit.Seek
54 {
55         private FileConduit     host;                   // the hosting file
56
57         version (Win32)
58         {
59                 private void*   base;                   // array pointer
60                 private HANDLE  mmFile;                 // mapped file
61
62                 /***************************************************************
63
64                         Construct a MappedBuffer upon the given FileConduit.
65                         One should set the file size using seek() & truncate()
66                         to setup the available working space.
67
68                 ***************************************************************/
69
70                 this (FileConduit host)
71                 {
72                         super (0);
73
74                         this.host = host;
75
76                         // can only do 32bit mapping on 32bit platform
77                         auto size = host.length;
78                         assert (size <= uint.max);
79
80                         auto access = host.style.access;
81
82                         DWORD flags = PAGE_READONLY;
83                         if (access & host.Access.Write)
84                             flags = PAGE_READWRITE;
85
86                         auto handle = cast(HANDLE) host.fileHandle;
87                         mmFile = CreateFileMappingA (handle, null, flags, 0, 0, null);
88                         if (mmFile is null)
89                             host.error ();
90
91                         flags = FILE_MAP_READ;
92                         if (access & host.Access.Write)
93                             flags |= FILE_MAP_WRITE;
94
95                         base = MapViewOfFile (mmFile, flags, 0, 0, 0);
96                         if (base is null)
97                             host.error;
98  
99                         void[] mem = base [0 .. cast(int) size];
100                         setContent (mem);
101                 }
102
103                 /***************************************************************
104
105                         Release this mapped buffer without flushing
106
107                 ***************************************************************/
108
109                 override void close ()
110                 {
111                         if (base)
112                             UnmapViewOfFile (base);
113
114                         if (mmFile)
115                             CloseHandle (mmFile);       
116
117                         mmFile = null;
118                         base = null;
119                 }
120
121                 /***************************************************************
122
123                         Flush dirty content out to the drive. This
124                         fails with error 33 if the file content is
125                         virgin. Opening a file for ReadWriteExists
126                         followed by a flush() will cause this.
127
128                 ***************************************************************/
129
130                 override OutputStream flush ()
131                 {
132                         // flush all dirty pages
133                         if (! FlushViewOfFile (base, 0))
134                               host.error ();
135                         return this;
136                 }
137         }
138
139         /***********************************************************************
140                 
141         ***********************************************************************/
142
143         version (Posix)
144         {               
145                 // Linux code: not yet tested on other POSIX systems.
146                 private void*   base;           // array pointer
147                 private uint    size;           // length of file
148
149                 this (FileConduit host)
150                 {
151                         super(0);
152
153                         this.host = host;
154                         size = cast(uint) host.length;
155                        
156                         // Make sure the mapping attributes are consistant with
157                         // the FileConduit attributes.
158                        
159                         auto access = host.style.access;
160                        
161                         int flags = MAP_SHARED;
162                         int protection = PROT_READ;
163                        
164                         if (access & host.Access.Write)
165                             protection |= PROT_WRITE;
166                                
167                         base = mmap (null, size, protection, flags, host.fileHandle(), 0);
168                         if (base is null)
169                             host.error();
170                                
171                         void[] mem = base [0 .. size];
172                         setContent (mem);
173                 }   
174
175                 /***************************************************************
176
177                         Release this mapped buffer without flushing
178
179                 ***************************************************************/
180
181                 override void close ()
182                 {
183                         // NOTE: When a process ends, all mmaps belonging to that process
184                         //       are automatically unmapped by system (Linux).
185                         //       On the other hand, this is NOT the case when the related
186                         //       file descriptor is closed.  This function unmaps explicitly.
187                        
188                         if (base)
189                             if (munmap (base, size))
190                                 host.error();
191                         base = null;   
192                 }
193
194                 /***************************************************************
195
196                         Flush dirty content out to the drive.
197
198                 ***************************************************************/
199
200                 override OutputStream flush ()
201                 {
202                         // MS_ASYNC: delayed flush; equivalent to "add-to-queue"
203                         // MS_SYNC: function flushes file immediately; no return until flush complete
204                         // MS_INVALIDATE: invalidate all mappings of the same file (shared)
205
206                         if (msync (base, size, MS_SYNC | MS_INVALIDATE))
207                             host.error();
208                         return this;
209                 }
210         }
211
212         /***********************************************************************
213         
214                 Seek to the specified position within the buffer, and return
215                 the byte offset of the new location (relative to zero).
216
217         ***********************************************************************/
218
219         long seek (long offset, Anchor anchor = Anchor.Begin)
220         {
221                 uint pos = dimension;
222
223                 if (anchor is Anchor.Begin)
224                     pos = cast(uint) offset;
225                 else
226                    if (anchor is Anchor.End)
227                        pos -= cast(uint) offset;
228                    else
229                       pos = index + cast(uint) offset;
230
231                 return index = pos;
232         }
233
234         /***********************************************************************
235         
236                 Return count of writable bytes available in buffer. This is
237                 calculated simply as capacity() - limit()
238
239         ***********************************************************************/
240
241         override uint writable ()
242         {
243                 return dimension - index;
244         }               
245
246         /***********************************************************************
247         
248                 Bulk copy of data from 'src'. Position is adjusted by 'size'
249                 bytes.
250
251         ***********************************************************************/
252
253         override protected void copy (void *src, uint size)
254         {
255                 // avoid "out of bounds" test on zero size
256                 if (size)
257                    {
258                    // content may overlap ...
259                    memcpy (&data[index], src, size);
260                    index += size;
261                    }
262         }
263
264         /***********************************************************************
265
266                 Exposes the raw data buffer at the current write position,
267                 The delegate is provided with a void[] representing space
268                 available within the buffer at the current write position.
269
270                 The delegate should return the appropriate number of bytes
271                 if it writes valid content, or IConduit.Eof on error.
272
273                 Returns whatever the delegate returns.
274
275         ***********************************************************************/
276
277         override uint write (uint delegate (void[]) dg)
278         {
279                 int count = dg (data [index .. dimension]);
280
281                 if (count != IConduit.Eof)
282                    {
283                    index += count;
284                    assert (index <= dimension);
285                    }
286                 return count;
287         }               
288
289         /***********************************************************************
290
291                 Prohibit compress() from doing anything at all.
292
293         ***********************************************************************/
294
295         override IBuffer compress ()
296         {
297                 return this;
298         }               
299
300         /***********************************************************************
301
302                 Prohibit clear() from doing anything at all.
303
304         ***********************************************************************/
305
306         override InputStream clear ()
307         {       
308                 return this;
309         }               
310
311         /***********************************************************************
312         
313                 Prohibit the setting of another IConduit
314
315         ***********************************************************************/
316
317         override IBuffer setConduit (IConduit conduit)
318         {
319                 error ("cannot setConduit on memory-mapped buffer");
320                 return null;
321         }
322 }
323
324
325 debug (MappedBuffer)
326 {
327         void main()
328         {
329                 auto x = new MappedBuffer(null);
330         }
331 }
Note: See TracBrowser for help on using the browser.