summaryrefslogtreecommitdiff
path: root/db/os/os_region.c
blob: ea9cde3a5dce85072ed665bf41d980c2cfb702aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*-
 * See the file LICENSE for redistribution information.
 *
 * Copyright (c) 1996-2006
 *	Oracle Corporation.  All rights reserved.
 *
 * $Id: os_region.c,v 12.9 2006/08/24 14:46:18 bostic Exp $
 */

#include "db_config.h"

#include "db_int.h"

/*
 * __os_r_attach --
 *	Attach to a shared memory region.
 *
 * PUBLIC: int __os_r_attach __P((DB_ENV *, REGINFO *, REGION *));
 */
int
__os_r_attach(dbenv, infop, rp)
	DB_ENV *dbenv;
	REGINFO *infop;
	REGION *rp;
{
	int ret;

	/*
	 * All regions are created on 8K boundaries out of sheer paranoia,
	 * so we don't make some underlying VM unhappy. Make sure we don't
	 * overflow or underflow.
	 */
#define	OS_VMPAGESIZE		(8 * 1024)
#define	OS_VMROUNDOFF(i) {						\
	if ((i) <							\
	    (UINT32_MAX - OS_VMPAGESIZE) + 1 || (i) < OS_VMPAGESIZE)	\
		(i) += OS_VMPAGESIZE - 1;				\
	(i) -= (i) % OS_VMPAGESIZE;					\
}
	OS_VMROUNDOFF(rp->size);

#ifdef DB_REGIONSIZE_MAX
	/* Some architectures have hard limits on the maximum region size. */
	if (rp->size > DB_REGIONSIZE_MAX) {
		__db_errx(dbenv, "region size %lu is too large; maximum is %lu",
		    (u_long)rp->size, (u_long)DB_REGIONSIZE_MAX);
		return (EINVAL);
	}
#endif

	/*
	 * If a region is private, malloc the memory.
	 *
	 * !!!
	 * If this fails because the region is too large to malloc, mmap(2)
	 * using the MAP_ANON or MAP_ANONYMOUS flags would be an alternative.
	 * I don't know of any architectures (yet!) where malloc is a problem.
	 */
	if (F_ISSET(dbenv, DB_ENV_PRIVATE)) {
#if defined(HAVE_MUTEX_HPPA_MSEM_INIT)
		/*
		 * !!!
		 * There exist spinlocks that don't work in malloc memory, e.g.,
		 * the HP/UX msemaphore interface.  If we don't have locks that
		 * will work in malloc memory, we better not be private or not
		 * be threaded.
		 */
		if (F_ISSET(dbenv, DB_ENV_THREAD)) {
			__db_errx(dbenv, "%s",
    "architecture does not support locks inside process-local (malloc) memory");
			__db_errx(dbenv, "%s",
    "application may not specify both DB_PRIVATE and DB_THREAD");
			return (EINVAL);
		}
#endif
		if ((ret = __os_malloc(
		    dbenv, sizeof(REGENV), &infop->addr)) != 0)
			return (ret);

		infop->max_alloc = rp->size;
	} else {
		/*
		 * If the user replaced the map call, call through their
		 * interface.
		 */
		if (DB_GLOBAL(j_map) != NULL && (ret = DB_GLOBAL(j_map)
		    (infop->name, rp->size, 1, 0, &infop->addr)) != 0)
			return (ret);

		/* Get some space from the underlying system. */
		if ((ret = __os_r_sysattach(dbenv, infop, rp)) != 0)
			return (ret);
	}

	/*
	 * We may require alignment the underlying system or heap allocation
	 * library doesn't supply.  Align the address if necessary, saving
	 * the original values for restoration when the region is discarded.
	 */
	infop->addr_orig = infop->addr;
	infop->addr = ALIGNP_INC(infop->addr_orig, sizeof(size_t));

	rp->size_orig = rp->size;
	if (infop->addr != infop->addr_orig)
		rp->size -= (roff_t)
		    ((u_int8_t *)infop->addr - (u_int8_t *)infop->addr_orig);

	return (0);
}

/*
 * __os_r_detach --
 *	Detach from a shared memory region.
 *
 * PUBLIC: int __os_r_detach __P((DB_ENV *, REGINFO *, int));
 */
int
__os_r_detach(dbenv, infop, destroy)
	DB_ENV *dbenv;
	REGINFO *infop;
	int destroy;
{
	REGION *rp;

	rp = infop->rp;

	/* Restore any address/size altered for alignment reasons. */
	if (infop->addr != infop->addr_orig) {
		infop->addr = infop->addr_orig;
		rp->size = rp->size_orig;
	}

	/* If a region is private, free the memory. */
	if (F_ISSET(dbenv, DB_ENV_PRIVATE)) {
		__os_free(dbenv, infop->addr);
		return (0);
	}

	/* If the user replaced the map call, call through their interface. */
	if (DB_GLOBAL(j_unmap) != NULL)
		return (DB_GLOBAL(j_unmap)(infop->addr, rp->size));

	return (__os_r_sysdetach(dbenv, infop, destroy));
}