comparison tango/tango/io/MappedBuffer.d @ 132:1700239cab2e trunk

[svn r136] MAJOR UNSTABLE UPDATE!!! Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
author lindquist
date Fri, 11 Jan 2008 17:57:40 +0100
parents
children
comparison
equal deleted inserted replaced
131:5825d48b27d1 132:1700239cab2e
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.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 ulong size; // length of file
148
149 this (FileConduit host)
150 {
151 super(0);
152
153 this.host = host;
154 size = 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 .. cast(int) 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 }