Mercurial > projects > ldc
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 } |