2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
11 static const char sccsid
[] = "@(#)os_map.c 10.19 (Sleepycat) 5/3/98";
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
30 #include "common_ext.h"
33 static int __os_map
__P((char *, int, size_t, int, int, int, void **));
36 static int __os_shmget
__P((char *, REGINFO
*));
41 * Return if this OS can support anonymous memory regions.
43 * PUBLIC: int __db_mapanon_ok __P((int));
46 __db_mapanon_ok(need_names
)
54 * If we don't have spinlocks, we have to have a file descriptor
55 * for fcntl(2) locking, which implies using mmap(2) to map in a
56 * regular file. Theoretically, we could probably find ways to
57 * get a file descriptor to lock other types of shared regions,
58 * but I don't see any reason to do so.
60 * If need_names is set, the application wants to share anonymous
61 * memory among multiple processes, so we have to have a way to
62 * name it. This requires shmget(2), on UNIX systems.
78 COMPQUIET(need_names
, 0);
79 #endif /* HAVE_MMAP */
80 #endif /* HAVE_SPINLOCKS */
87 * Return if shared regions need to be initialized.
89 * PUBLIC: int __db_mapinit __P((void));
95 * Historically, some systems required that all of the bytes of the
96 * region be written before it could be mmapped and accessed randomly.
97 * We have the option of setting REGION_INIT_NEEDED at configuration
98 * time if we're running on one of those systems.
100 #ifdef REGION_INIT_NEEDED
109 * Attach to a shared memory region.
111 * PUBLIC: int __db_mapregion __P((char *, REGINFO *));
114 __db_mapregion(path
, infop
)
123 /* If the user replaces the map call, call through their interface. */
124 if (__db_jump
.j_map
!= NULL
) {
125 F_SET(infop
, REGION_HOLDINGSYS
);
126 return (__db_jump
.j_map(path
, infop
->fd
, infop
->size
,
127 1, F_ISSET(infop
, REGION_ANONYMOUS
), 0, &infop
->addr
));
130 if (F_ISSET(infop
, REGION_ANONYMOUS
)) {
133 * If we're creating anonymous regions:
135 * If it's private, we use mmap(2). The problem with using
136 * shmget(2) is that we may be creating a region of which the
137 * application isn't aware, and if the application crashes
138 * we'll have no way to remove the system resources for the
141 * If it's not private, we use the shmget(2) interface if it's
142 * available, because it allows us to name anonymous memory.
143 * If shmget(2) isn't available, use the mmap(2) calls.
145 * In the case of anonymous memory, using mmap(2) means the
146 * memory isn't named and only the single process and its
147 * threads can access the region.
151 #define HAVE_MMAP_ANONYMOUS 1
154 #define HAVE_MMAP_ANONYMOUS 1
158 #ifdef HAVE_MMAP_ANONYMOUS
159 if (!called
&& F_ISSET(infop
, REGION_PRIVATE
)) {
162 infop
->fd
, infop
->size
, 1, 1, 0, &infop
->addr
);
168 ret
= __os_shmget(path
, infop
);
173 * If we're trying to join an unnamed anonymous region, fail --
174 * that's not possible.
179 if (!F_ISSET(infop
, REGION_CREATED
)) {
180 __db_err(infop
->dbenv
,
181 "cannot join region in unnamed anonymous memory");
186 infop
->fd
, infop
->size
, 1, 1, 0, &infop
->addr
);
192 * If we're creating normal regions, we use the mmap(2)
193 * interface if it's available because it's POSIX 1003.1
194 * standard and we trust it more than we do shmget(2).
200 /* Mmap(2) regions that aren't anonymous can grow. */
201 F_SET(infop
, REGION_CANGROW
);
204 infop
->fd
, infop
->size
, 1, 0, 0, &infop
->addr
);
210 ret
= __os_shmget(path
, infop
);
218 * __db_unmapregion --
219 * Detach from the shared memory region.
221 * PUBLIC: int __db_unmapregion __P((REGINFO *));
224 __db_unmapregion(infop
)
232 if (__db_jump
.j_unmap
!= NULL
)
233 return (__db_jump
.j_unmap(infop
->addr
, infop
->size
));
236 if (infop
->segid
!= INVALID_SEGID
) {
238 ret
= shmdt(infop
->addr
) ? errno
: 0;
244 ret
= munmap(infop
->addr
, infop
->size
) ? errno
: 0;
251 * __db_unlinkregion --
252 * Remove the shared memory region.
254 * PUBLIC: int __db_unlinkregion __P((char *, REGINFO *));
257 __db_unlinkregion(name
, infop
)
266 if (__db_jump
.j_runlink
!= NULL
)
267 return (__db_jump
.j_runlink(name
));
270 if (infop
->segid
!= INVALID_SEGID
) {
272 ret
= shmctl(infop
->segid
, IPC_RMID
, NULL
) ? errno
: 0;
275 COMPQUIET(infop
, NULL
);
288 * Map in a shared memory file.
290 * PUBLIC: int __db_mapfile __P((char *, int, size_t, int, void **));
293 __db_mapfile(path
, fd
, len
, is_rdonly
, addr
)
299 if (__db_jump
.j_map
!= NULL
)
300 return (__db_jump
.j_map(path
, fd
, len
, 0, 0, is_rdonly
, addr
));
303 return (__os_map(path
, fd
, len
, 0, 0, is_rdonly
, addr
));
311 * Unmap the shared memory file.
313 * PUBLIC: int __db_unmapfile __P((void *, size_t));
316 __db_unmapfile(addr
, len
)
320 if (__db_jump
.j_unmap
!= NULL
)
321 return (__db_jump
.j_unmap(addr
, len
));
324 return (munmap(addr
, len
) ? errno
: 0);
333 * Call the mmap(2) function.
336 __os_map(path
, fd
, len
, is_region
, is_anonymous
, is_rdonly
, addr
)
338 int fd
, is_region
, is_anonymous
, is_rdonly
;
345 COMPQUIET(path
, NULL
);
348 * If it's read-only, it's private, and if it's not, it's shared.
349 * Don't bother with an additional parameter.
351 flags
= is_rdonly
? MAP_PRIVATE
: MAP_SHARED
;
353 if (is_region
&& is_anonymous
) {
355 * BSD derived systems use MAP_ANON; Digital Unix and HP/UX
362 flags
|= MAP_ANONYMOUS
;
367 if (!is_region
|| !is_anonymous
) {
369 * Historically, MAP_FILE was required for mapping regular
370 * files, even though it was the default. Some systems have
371 * it, some don't, some that have it set it to 0.
378 * I know of no systems that implement the flag to tell the system
379 * that the region contains semaphores, but it's not an unreasonable
380 * thing to do, and has been part of the design since forever. I
381 * don't think anyone will object, but don't set it for read-only
382 * files, it doesn't make sense.
384 #ifdef MAP_HASSEMAPHORE
386 flags
|= MAP_HASSEMAPHORE
;
389 prot
= PROT_READ
| (is_rdonly
? 0 : PROT_WRITE
);
391 /* MAP_FAILED was not defined in early mmap implementations. */
393 #define MAP_FAILED -1
396 mmap(NULL
, len
, prot
, flags
, fd
, (off_t
)0)) == (void *)MAP_FAILED
)
407 * Call the shmget(2) family of functions.
410 __os_shmget(path
, infop
)
417 if (F_ISSET(infop
, REGION_CREATED
)) {
419 * The return key from ftok(3) is not guaranteed to be unique.
420 * The nice thing about the shmget(2) interface is that it
421 * allows you to name anonymous pieces of memory. The evil
422 * thing about it is that the name space is separate from the
426 {char mpe_path
[MAXPATHLEN
];
428 * MPE ftok() is broken as of 5.5pp4. If the file path does
429 * not start with '/' or '.', then ftok() tries to interpret
430 * the file path in MPE syntax instead of POSIX HFS syntax.
431 * The workaround is to prepend "./" to these paths. See HP
432 * SR 5003416081 for details.
434 if (*path
!= '/' && *path
!= '.') {
435 if (strlen(path
) + strlen("./") + 1 > sizeof(mpe_path
))
436 return (ENAMETOOLONG
);
439 (void)strcpy(mpe_path
+ 2, path
);
444 if ((key
= ftok(path
, 1)) == (key_t
)-1)
447 shmflg
= IPC_CREAT
| 0600;
448 if ((infop
->segid
= shmget(key
, infop
->size
, shmflg
)) == -1)
452 if ((infop
->addr
= shmat(infop
->segid
, NULL
, 0)) == (void *)-1) {
454 * If we're trying to join the region and failing, assume
455 * that there was a reboot and the region no longer exists.
457 if (!F_ISSET(infop
, REGION_CREATED
))
462 F_SET(infop
, REGION_HOLDINGSYS
);