2
* See the file LICENSE for redistribution information.
4
* Copyright (c) 1996-2002
5
* Sleepycat Software. All rights reserved.
11
static const char revid[] = "$Id$";
17
__P((DB_ENV *, char *, REGINFO *, DB_FH *, size_t, int, int, int, void **));
18
static int __os_unique_name __P((char *, HANDLE, char *, size_t));
22
* Create/join a shared memory region.
25
__os_r_sysattach(dbenv, infop, rp)
34
* Try to open/create the file. We DO NOT need to ensure that multiple
35
* threads/processes attempting to simultaneously create the region are
36
* properly ordered, our caller has already taken care of that.
38
if ((ret = __os_open(dbenv, infop->name,
40
F_ISSET(infop, REGION_CREATE_OK) ? DB_OSO_CREATE: 0,
41
infop->mode, &fh)) != 0) {
42
__db_err(dbenv, "%s: %s", infop->name, db_strerror(ret));
47
* On Windows/9X, files that are opened by multiple processes do not
48
* share data correctly. For this reason, the DB_SYSTEM_MEM flag is
49
* implied for any application that does not specify the DB_PRIVATE
52
is_system = F_ISSET(dbenv, DB_ENV_SYSTEM_MEM) ||
53
(!F_ISSET(dbenv, DB_ENV_PRIVATE) && __os_is_winnt() == 0);
56
* Map the file in. If we're creating an in-system-memory region,
57
* specify a segment ID (which is never used again) so that the
58
* calling code writes out the REGENV_REF structure to the primary
61
ret = __os_map(dbenv, infop->name, infop, &fh, rp->size,
62
1, is_system, 0, &infop->addr);
63
if (ret == 0 && is_system == 1)
66
(void)__os_closehandle(dbenv, &fh);
73
* Detach from a shared memory region.
76
__os_r_sysdetach(dbenv, infop, destroy)
83
if (infop->wnt_handle != NULL) {
84
(void)CloseHandle(*((HANDLE*)(infop->wnt_handle)));
85
__os_free(dbenv, infop->wnt_handle);
88
ret = !UnmapViewOfFile(infop->addr) ? __os_win32_errno() : 0;
90
__db_err(dbenv, "UnmapViewOfFile: %s", strerror(ret));
92
if (!F_ISSET(dbenv, DB_ENV_SYSTEM_MEM) && destroy) {
93
if (F_ISSET(dbenv, DB_ENV_OVERWRITE))
94
(void)__db_overwrite(dbenv, infop->name);
95
if ((t_ret = __os_unlink(dbenv, infop->name)) != 0 && ret == 0)
104
* Map in a shared memory file.
107
__os_mapfile(dbenv, path, fhp, len, is_rdonly, addr)
115
/* If the user replaced the map call, call through their interface. */
116
if (DB_GLOBAL(j_map) != NULL)
117
return (DB_GLOBAL(j_map)(path, len, 0, is_rdonly, addr));
119
return (__os_map(dbenv, path, NULL, fhp, len, 0, 0, is_rdonly, addr));
124
* Unmap the shared memory file.
127
__os_unmapfile(dbenv, addr, len)
132
/* If the user replaced the map call, call through their interface. */
133
if (DB_GLOBAL(j_unmap) != NULL)
134
return (DB_GLOBAL(j_unmap)(addr, len));
136
return (!UnmapViewOfFile(addr) ? __os_win32_errno() : 0);
140
* __os_unique_name --
141
* Create a unique identifying name from a pathname (may be absolute or
142
* relative) and/or a file descriptor.
144
* The name returned must be unique (different files map to different
145
* names), and repeatable (same files, map to same names). It's not
146
* so easy to do by name. Should handle not only:
148
* foo.bar == ./foo.bar == c:/whatever_path/foo.bar
150
* but also understand that:
152
* foo.bar == Foo.Bar (FAT file system)
153
* foo.bar != Foo.Bar (NTFS)
155
* The best solution is to use the file index, found in the file
156
* information structure (similar to UNIX inode #).
158
* When a file is deleted, its file index may be reused,
159
* but if the unique name has not gone from its namespace,
160
* we may get a conflict. So to ensure some tie in to the
161
* original pathname, we also use the creation time and the
162
* file basename. This is not a perfect system, but it
163
* should work for all but anamolous test cases.
167
__os_unique_name(orig_path, hfile, result_path, result_path_len)
168
char *orig_path, *result_path;
170
size_t result_path_len;
172
BY_HANDLE_FILE_INFORMATION fileinfo;
176
* In Windows, pathname components are delimited by '/' or '\', and
177
* if neither is present, we need to strip off leading drive letter
180
basename = strrchr(orig_path, '/');
181
p = strrchr(orig_path, '\\');
182
if (basename == NULL || (p != NULL && p > basename))
184
if (basename == NULL)
185
basename = strrchr(orig_path, ':');
187
if (basename == NULL)
188
basename = orig_path;
192
if (!GetFileInformationByHandle(hfile, &fileinfo))
193
return (__os_win32_errno());
195
(void)snprintf(result_path, result_path_len,
196
"__db_shmem.%8.8lx.%8.8lx.%8.8lx.%8.8lx.%8.8lx.%s",
197
fileinfo.dwVolumeSerialNumber,
198
fileinfo.nFileIndexHigh,
199
fileinfo.nFileIndexLow,
200
fileinfo.ftCreationTime.dwHighDateTime,
201
fileinfo.ftCreationTime.dwHighDateTime,
209
* The mmap(2) function for Windows.
212
__os_map(dbenv, path, infop, fhp, len, is_region, is_system, is_rdonly, addr)
217
int is_region, is_system, is_rdonly;
223
int ret, use_pagefile;
224
char shmem_name[MAXPATHLEN];
229
infop->wnt_handle = NULL;
231
use_pagefile = is_region && is_system;
234
* If creating a region in system space, get a matching name in the
235
* paging file namespace.
237
if (use_pagefile && (ret = __os_unique_name(
238
path, fhp->handle, shmem_name, sizeof(shmem_name))) != 0)
243
* DB: We have not implemented copy-on-write here.
246
* DB: This code will fail if the library is ever compiled on a 64-bit
250
* If this is an region in system memory, let's try opening using the
251
* OpenFileMapping() first. Why, oh why are we doing this?
253
* Well, we might be asking the OS for a handle to a pre-existing
254
* memory section, or we might be the first to get here and want the
255
* section created. CreateFileMapping() sounds like it will do both
256
* jobs. But, not so. It seems to mess up making the commit charge to
257
* the process. It thinks, incorrectly, that when we want to join a
258
* previously existing section, that it should make a commit charge
259
* for the whole section. In fact, there is no new committed memory
260
* whatever. The call can fail if there is insufficient memory free
261
* to handle the erroneous commit charge. So, we find that the bogus
262
* commit is not made if we call OpenFileMapping(). So we do that
263
* first, and only call CreateFileMapping() if we're really creating
268
hMemory = OpenFileMapping(
269
is_rdonly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
274
hMemory = CreateFileMapping(
275
use_pagefile ? (HANDLE)-1 : fhp->handle,
277
is_rdonly ? PAGE_READONLY : PAGE_READWRITE,
279
use_pagefile ? shmem_name : NULL);
280
if (hMemory == NULL) {
281
ret = __os_win32_errno();
282
__db_err(dbenv, "OpenFileMapping: %s", strerror(ret));
286
pMemory = MapViewOfFile(hMemory,
287
(is_rdonly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS), 0, 0, len);
288
if (pMemory == NULL) {
289
ret = __os_win32_errno();
290
__db_err(dbenv, "MapViewOfFile: %s", strerror(ret));
296
* It turns out that the kernel object underlying the named section
297
* is reference counted, but that the call to MapViewOfFile() above
298
* does NOT increment the reference count! So, if we close the handle
299
* here, the kernel deletes the object from the kernel namespace.
300
* When a second process comes along to join the region, the kernel
301
* happily creates a new object with the same name, but completely
302
* different identity. The two processes then have distinct isolated
303
* mapped sections, not at all what was wanted. Not closing the handle
304
* here fixes this problem. We carry the handle around in the region
305
* structure so we can close it when unmap is called. Ignore malloc
306
* errors, it just means we leak the memory.
308
if (use_pagefile && infop != NULL) {
309
if (__os_malloc(dbenv,
310
sizeof(HANDLE), &infop->wnt_handle) == 0)
311
memcpy(infop->wnt_handle, &hMemory, sizeof(HANDLE));
313
CloseHandle(hMemory);
318
* Windows/95 zeroes anonymous memory regions at last close.
319
* This means that the backing file can exist and reference
320
* the region, but the region itself is no longer initialized.
321
* If the caller is capable of creating the region, update
322
* the REGINFO structure so that they do so.
324
renv = (REGENV *)pMemory;
325
if (renv->magic == 0) {
326
if (F_ISSET(infop, REGION_CREATE_OK))
327
F_SET(infop, REGION_CREATE);
329
(void)UnmapViewOfFile(pMemory);