os_map.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:11k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: os_map.c,v 11.44 2002/07/12 18:56:51 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #ifdef HAVE_MMAP
  14. #include <sys/mman.h>
  15. #endif
  16. #ifdef HAVE_SHMGET
  17. #include <sys/ipc.h>
  18. #include <sys/shm.h>
  19. #endif
  20. #include <string.h>
  21. #endif
  22. #include "db_int.h"
  23. #ifdef HAVE_MMAP
  24. static int __os_map __P((DB_ENV *, char *, DB_FH *, size_t, int, int, void **));
  25. #endif
  26. #ifndef HAVE_SHMGET
  27. static int __db_nosystemmem __P((DB_ENV *));
  28. #endif
  29. /*
  30.  * __os_r_sysattach --
  31.  * Create/join a shared memory region.
  32.  *
  33.  * PUBLIC: int __os_r_sysattach __P((DB_ENV *, REGINFO *, REGION *));
  34.  */
  35. int
  36. __os_r_sysattach(dbenv, infop, rp)
  37. DB_ENV *dbenv;
  38. REGINFO *infop;
  39. REGION *rp;
  40. {
  41. if (F_ISSET(dbenv, DB_ENV_SYSTEM_MEM)) {
  42. /*
  43.  * If the region is in system memory on UNIX, we use shmget(2).
  44.  *
  45.  * !!!
  46.  * There exist spinlocks that don't work in shmget memory, e.g.,
  47.  * the HP/UX msemaphore interface.  If we don't have locks that
  48.  * will work in shmget memory, we better be private and not be
  49.  * threaded.  If we reach this point, we know we're public, so
  50.  * it's an error.
  51.  */
  52. #if defined(MUTEX_NO_SHMGET_LOCKS)
  53. __db_err(dbenv,
  54.     "architecture does not support locks inside system shared memory");
  55. return (EINVAL);
  56. #endif
  57. #if defined(HAVE_SHMGET)
  58. {
  59. key_t segid;
  60. int id, ret;
  61. /*
  62.  * We could potentially create based on REGION_CREATE_OK, but
  63.  * that's dangerous -- we might get crammed in sideways if
  64.  * some of the expected regions exist but others do not.  Also,
  65.  * if the requested size differs from an existing region's
  66.  * actual size, then all sorts of nasty things can happen.
  67.  * Basing create solely on REGION_CREATE is much safer -- a
  68.  * recovery will get us straightened out.
  69.  */
  70. if (F_ISSET(infop, REGION_CREATE)) {
  71. /*
  72.  * The application must give us a base System V IPC key
  73.  * value.  Adjust that value based on the region's ID,
  74.  * and correct so the user's original value appears in
  75.  * the ipcs output.
  76.  */
  77. if (dbenv->shm_key == INVALID_REGION_SEGID) {
  78. __db_err(dbenv,
  79.     "no base system shared memory ID specified");
  80. return (EINVAL);
  81. }
  82. segid = (key_t)(dbenv->shm_key + (infop->id - 1));
  83. /*
  84.  * If map to an existing region, assume the application
  85.  * crashed and we're restarting.  Delete the old region
  86.  * and re-try.  If that fails, return an error, the
  87.  * application will have to select a different segment
  88.  * ID or clean up some other way.
  89.  */
  90. if ((id = shmget(segid, 0, 0)) != -1) {
  91. (void)shmctl(id, IPC_RMID, NULL);
  92. if ((id = shmget(segid, 0, 0)) != -1) {
  93. __db_err(dbenv,
  94. "shmget: key: %ld: shared system memory region already exists",
  95.     (long)segid);
  96. return (EAGAIN);
  97. }
  98. }
  99. if ((id =
  100.     shmget(segid, rp->size, IPC_CREAT | 0600)) == -1) {
  101. ret = __os_get_errno();
  102. __db_err(dbenv,
  103. "shmget: key: %ld: unable to create shared system memory region: %s",
  104.     (long)segid, strerror(ret));
  105. return (ret);
  106. }
  107. rp->segid = id;
  108. } else
  109. id = rp->segid;
  110. if ((infop->addr = shmat(id, NULL, 0)) == (void *)-1) {
  111. infop->addr = NULL;
  112. ret = __os_get_errno();
  113. __db_err(dbenv,
  114. "shmat: id %d: unable to attach to shared system memory region: %s",
  115.     id, strerror(ret));
  116. return (ret);
  117. }
  118. return (0);
  119. }
  120. #else
  121. return (__db_nosystemmem(dbenv));
  122. #endif
  123. }
  124. #ifdef HAVE_MMAP
  125. {
  126. DB_FH fh;
  127. int ret;
  128. /*
  129.  * Try to open/create the shared region file.  We DO NOT need to ensure
  130.  * that multiple threads/processes attempting to simultaneously create
  131.  * the region are properly ordered, our caller has already taken care
  132.  * of that.
  133.  */
  134. if ((ret = __os_open(dbenv, infop->name,
  135.     DB_OSO_REGION | DB_OSO_DIRECT |
  136.     (F_ISSET(infop, REGION_CREATE_OK) ? DB_OSO_CREATE : 0),
  137.     infop->mode, &fh)) != 0)
  138. __db_err(dbenv, "%s: %s", infop->name, db_strerror(ret));
  139. /*
  140.  * If we created the file, grow it to its full size before mapping
  141.  * it in.  We really want to avoid touching the buffer cache after
  142.  * mmap(2) is called, doing anything else confuses the hell out of
  143.  * systems without merged VM/buffer cache systems, or, more to the
  144.  * point, *badly* merged VM/buffer cache systems.
  145.  */
  146. if (ret == 0 && F_ISSET(infop, REGION_CREATE))
  147. ret = __db_fileinit(dbenv,
  148.     &fh, rp->size, F_ISSET(dbenv, DB_ENV_REGION_INIT) ? 1 : 0);
  149. /* Map the file in. */
  150. if (ret == 0)
  151. ret = __os_map(dbenv,
  152.     infop->name, &fh, rp->size, 1, 0, &infop->addr);
  153. if (F_ISSET(&fh, DB_FH_VALID))
  154. (void)__os_closehandle(dbenv, &fh);
  155. return (ret);
  156. }
  157. #else
  158. COMPQUIET(infop, NULL);
  159. COMPQUIET(rp, NULL);
  160. __db_err(dbenv,
  161.     "architecture lacks mmap(2), shared environments not possible");
  162. return (__db_eopnotsup(dbenv));
  163. #endif
  164. }
  165. /*
  166.  * __os_r_sysdetach --
  167.  * Detach from a shared memory region.
  168.  *
  169.  * PUBLIC: int __os_r_sysdetach __P((DB_ENV *, REGINFO *, int));
  170.  */
  171. int
  172. __os_r_sysdetach(dbenv, infop, destroy)
  173. DB_ENV *dbenv;
  174. REGINFO *infop;
  175. int destroy;
  176. {
  177. REGION *rp;
  178. rp = infop->rp;
  179. if (F_ISSET(dbenv, DB_ENV_SYSTEM_MEM)) {
  180. #ifdef HAVE_SHMGET
  181. int ret, segid;
  182. /*
  183.  * We may be about to remove the memory referenced by rp,
  184.  * save the segment ID, and (optionally) wipe the original.
  185.  */
  186. segid = rp->segid;
  187. if (destroy)
  188. rp->segid = INVALID_REGION_SEGID;
  189. if (shmdt(infop->addr) != 0) {
  190. ret = __os_get_errno();
  191. __db_err(dbenv, "shmdt: %s", strerror(ret));
  192. return (ret);
  193. }
  194. if (destroy && shmctl(segid, IPC_RMID,
  195.     NULL) != 0 && (ret = __os_get_errno()) != EINVAL) {
  196. __db_err(dbenv,
  197.     "shmctl: id %ld: unable to delete system shared memory region: %s",
  198.     segid, strerror(ret));
  199. return (ret);
  200. }
  201. return (0);
  202. #else
  203. return (__db_nosystemmem(dbenv));
  204. #endif
  205. }
  206. #ifdef HAVE_MMAP
  207. #ifdef HAVE_MUNLOCK
  208. if (F_ISSET(dbenv, DB_ENV_LOCKDOWN))
  209. (void)munlock(infop->addr, rp->size);
  210. #endif
  211. if (munmap(infop->addr, rp->size) != 0) {
  212. int ret;
  213. ret = __os_get_errno();
  214. __db_err(dbenv, "munmap: %s", strerror(ret));
  215. return (ret);
  216. }
  217. if (destroy && __os_region_unlink(dbenv, infop->name) != 0)
  218. return (__os_get_errno());
  219. return (0);
  220. #else
  221. COMPQUIET(destroy, 0);
  222. return (EINVAL);
  223. #endif
  224. }
  225. /*
  226.  * __os_mapfile --
  227.  * Map in a shared memory file.
  228.  *
  229.  * PUBLIC: int __os_mapfile __P((DB_ENV *,
  230.  * PUBLIC:     char *, DB_FH *, size_t, int, void **));
  231.  */
  232. int
  233. __os_mapfile(dbenv, path, fhp, len, is_rdonly, addrp)
  234. DB_ENV *dbenv;
  235. char *path;
  236. DB_FH *fhp;
  237. int is_rdonly;
  238. size_t len;
  239. void **addrp;
  240. {
  241. #if defined(HAVE_MMAP) && !defined(HAVE_QNX)
  242. return (__os_map(dbenv, path, fhp, len, 0, is_rdonly, addrp));
  243. #else
  244. COMPQUIET(dbenv, NULL);
  245. COMPQUIET(path, NULL);
  246. COMPQUIET(fhp, NULL);
  247. COMPQUIET(is_rdonly, 0);
  248. COMPQUIET(len, 0);
  249. COMPQUIET(addrp, NULL);
  250. return (EINVAL);
  251. #endif
  252. }
  253. /*
  254.  * __os_unmapfile --
  255.  * Unmap the shared memory file.
  256.  *
  257.  * PUBLIC: int __os_unmapfile __P((DB_ENV *, void *, size_t));
  258.  */
  259. int
  260. __os_unmapfile(dbenv, addr, len)
  261. DB_ENV *dbenv;
  262. void *addr;
  263. size_t len;
  264. {
  265. /* If the user replaced the map call, call through their interface. */
  266. if (DB_GLOBAL(j_unmap) != NULL)
  267. return (DB_GLOBAL(j_unmap)(addr, len));
  268. #ifdef HAVE_MMAP
  269. #ifdef HAVE_MUNLOCK
  270. if (F_ISSET(dbenv, DB_ENV_LOCKDOWN))
  271. while (munlock(addr, len) != 0 && __os_get_errno() == EINTR)
  272. ;
  273. #else
  274. COMPQUIET(dbenv, NULL);
  275. #endif
  276. {
  277. int ret;
  278. while ((ret = munmap(addr, len)) != 0 &&
  279.     __os_get_errno() == EINTR)
  280. ;
  281. return (ret ? __os_get_errno() : 0);
  282. }
  283. #else
  284. COMPQUIET(dbenv, NULL);
  285. return (EINVAL);
  286. #endif
  287. }
  288. #ifdef HAVE_MMAP
  289. /*
  290.  * __os_map --
  291.  * Call the mmap(2) function.
  292.  */
  293. static int
  294. __os_map(dbenv, path, fhp, len, is_region, is_rdonly, addrp)
  295. DB_ENV *dbenv;
  296. char *path;
  297. DB_FH *fhp;
  298. int is_region, is_rdonly;
  299. size_t len;
  300. void **addrp;
  301. {
  302. void *p;
  303. int flags, prot, ret;
  304. /* If the user replaced the map call, call through their interface. */
  305. if (DB_GLOBAL(j_map) != NULL)
  306. return (DB_GLOBAL(j_map)
  307.     (path, len, is_region, is_rdonly, addrp));
  308. /*
  309.  * If it's read-only, it's private, and if it's not, it's shared.
  310.  * Don't bother with an additional parameter.
  311.  */
  312. flags = is_rdonly ? MAP_PRIVATE : MAP_SHARED;
  313. #ifdef MAP_FILE
  314. /*
  315.  * Historically, MAP_FILE was required for mapping regular files,
  316.  * even though it was the default.  Some systems have it, some
  317.  * don't, some that have it set it to 0.
  318.  */
  319. flags |= MAP_FILE;
  320. #endif
  321. /*
  322.  * I know of no systems that implement the flag to tell the system
  323.  * that the region contains semaphores, but it's not an unreasonable
  324.  * thing to do, and has been part of the design since forever.  I
  325.  * don't think anyone will object, but don't set it for read-only
  326.  * files, it doesn't make sense.
  327.  */
  328. #ifdef MAP_HASSEMAPHORE
  329. if (is_region && !is_rdonly)
  330. flags |= MAP_HASSEMAPHORE;
  331. #else
  332. COMPQUIET(is_region, 0);
  333. #endif
  334. prot = PROT_READ | (is_rdonly ? 0 : PROT_WRITE);
  335. /*
  336.  * XXX
  337.  * Work around a bug in the VMS V7.1 mmap() implementation.  To map
  338.  * a file into memory on VMS it needs to be opened in a certain way,
  339.  * originally.  To get the file opened in that certain way, the VMS
  340.  * mmap() closes the file and re-opens it.  When it does this, it
  341.  * doesn't flush any caches out to disk before closing.  The problem
  342.  * this causes us is that when the memory cache doesn't get written
  343.  * out, the file isn't big enough to match the memory chunk and the
  344.  * mmap() call fails.  This call to fsync() fixes the problem.  DEC
  345.  * thinks this isn't a bug because of language in XPG5 discussing user
  346.  * responsibility for on-disk and in-memory synchronization.
  347.  */
  348. #ifdef VMS
  349. if (__os_fsync(dbenv, fhp) == -1)
  350. return (__os_get_errno());
  351. #endif
  352. /* MAP_FAILED was not defined in early mmap implementations. */
  353. #ifndef MAP_FAILED
  354. #define MAP_FAILED -1
  355. #endif
  356. if ((p = mmap(NULL,
  357.     len, prot, flags, fhp->fd, (off_t)0)) == (void *)MAP_FAILED) {
  358. ret = __os_get_errno();
  359. __db_err(dbenv, "mmap: %s", strerror(ret));
  360. return (ret);
  361. }
  362. #ifdef HAVE_MLOCK
  363. /*
  364.  * If it's a region, we want to make sure that the memory isn't paged.
  365.  * For example, Solaris will page large mpools because it thinks that
  366.  * I/O buffer memory is more important than we are.  The mlock system
  367.  * call may or may not succeed (mlock is restricted to the super-user
  368.  * on some systems).  Currently, the only other use of mmap in DB is
  369.  * to map read-only databases -- we don't want them paged, either, so
  370.  * the call isn't conditional.
  371.  */
  372. if (F_ISSET(dbenv, DB_ENV_LOCKDOWN) && mlock(p, len) != 0) {
  373. ret = __os_get_errno();
  374. (void)munmap(p, len);
  375. __db_err(dbenv, "mlock: %s", strerror(ret));
  376. return (ret);
  377. }
  378. #else
  379. COMPQUIET(dbenv, NULL);
  380. #endif
  381. *addrp = p;
  382. return (0);
  383. }
  384. #endif
  385. #ifndef HAVE_SHMGET
  386. /*
  387.  * __db_nosystemmem --
  388.  * No system memory environments error message.
  389.  */
  390. static int
  391. __db_nosystemmem(dbenv)
  392. DB_ENV *dbenv;
  393. {
  394. __db_err(dbenv,
  395.     "architecture doesn't support environments in system memory");
  396. return (__db_eopnotsup(dbenv));
  397. }
  398. #endif