xref: /illumos-gate/usr/src/cmd/sendmail/db/mp/mp_open.c (revision 71269a2275bf5a143dad6461eee2710a344e7261)
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 1997, 1998
5  *	Sleepycat Software.  All rights reserved.
6  */
7 #include "config.h"
8 
9 #ifndef lint
10 static const char sccsid[] = "@(#)mp_open.c	10.27 (Sleepycat) 10/1/98";
11 #endif /* not lint */
12 
13 #ifndef NO_SYSTEM_INCLUDES
14 #include <sys/types.h>
15 
16 #include <errno.h>
17 #include <string.h>
18 #endif
19 
20 #include "db_int.h"
21 #include "shqueue.h"
22 #include "db_shash.h"
23 #include "mp.h"
24 #include "common_ext.h"
25 
26 /*
27  * memp_open --
28  *	Initialize and/or join a memory pool.
29  */
30 int
31 memp_open(path, flags, mode, dbenv, retp)
32 	const char *path;
33 	u_int32_t flags;
34 	int mode;
35 	DB_ENV *dbenv;
36 	DB_MPOOL **retp;
37 {
38 	DB_MPOOL *dbmp;
39 	size_t cachesize;
40 	int is_private, ret;
41 
42 	/* Validate arguments. */
43 #ifdef HAVE_SPINLOCKS
44 #define	OKFLAGS	(DB_CREATE | DB_MPOOL_PRIVATE | DB_NOMMAP | DB_THREAD)
45 #else
46 #define	OKFLAGS	(DB_CREATE | DB_MPOOL_PRIVATE | DB_NOMMAP)
47 #endif
48 	if ((ret = __db_fchk(dbenv, "memp_open", flags, OKFLAGS)) != 0)
49 		return (ret);
50 
51 	/* Extract fields from DB_ENV structure. */
52 	cachesize = dbenv == NULL ? 0 : dbenv->mp_size;
53 
54 	/* Create and initialize the DB_MPOOL structure. */
55 	if ((ret = __os_calloc(1, sizeof(DB_MPOOL), &dbmp)) != 0)
56 		return (ret);
57 	LIST_INIT(&dbmp->dbregq);
58 	TAILQ_INIT(&dbmp->dbmfq);
59 
60 	dbmp->dbenv = dbenv;
61 
62 	/* Decide if it's possible for anyone else to access the pool. */
63 	is_private =
64 	    (dbenv == NULL && path == NULL) || LF_ISSET(DB_MPOOL_PRIVATE);
65 
66 	/*
67 	 * Map in the region.  We do locking regardless, as portions of it are
68 	 * implemented in common code (if we put the region in a file, that is).
69 	 */
70 	F_SET(dbmp, MP_LOCKREGION);
71 	if ((ret = __memp_ropen(dbmp,
72 	    path, cachesize, mode, is_private, LF_ISSET(DB_CREATE))) != 0)
73 		goto err;
74 	F_CLR(dbmp, MP_LOCKREGION);
75 
76 	/*
77 	 * If there's concurrent access, then we have to lock the region.
78 	 * If it's threaded, then we have to lock both the handles and the
79 	 * region, and we need to allocate a mutex for that purpose.
80 	 */
81 	if (!is_private)
82 		F_SET(dbmp, MP_LOCKREGION);
83 	if (LF_ISSET(DB_THREAD)) {
84 		F_SET(dbmp, MP_LOCKHANDLE | MP_LOCKREGION);
85 		LOCKREGION(dbmp);
86 		ret = __memp_alloc(dbmp,
87 		    sizeof(db_mutex_t), NULL, &dbmp->mutexp);
88 		UNLOCKREGION(dbmp);
89 		if (ret != 0) {
90 			(void)memp_close(dbmp);
91 			goto err;
92 		}
93 		LOCKINIT(dbmp, dbmp->mutexp);
94 	}
95 
96 	*retp = dbmp;
97 	return (0);
98 
99 err:	if (dbmp != NULL)
100 		__os_free(dbmp, sizeof(DB_MPOOL));
101 	return (ret);
102 }
103 
104 /*
105  * memp_close --
106  *	Close a memory pool.
107  */
108 int
109 memp_close(dbmp)
110 	DB_MPOOL *dbmp;
111 {
112 	DB_MPOOLFILE *dbmfp;
113 	DB_MPREG *mpreg;
114 	int ret, t_ret;
115 
116 	ret = 0;
117 
118 	MP_PANIC_CHECK(dbmp);
119 
120 	/* Discard DB_MPREGs. */
121 	while ((mpreg = LIST_FIRST(&dbmp->dbregq)) != NULL) {
122 		LIST_REMOVE(mpreg, q);
123 		__os_free(mpreg, sizeof(DB_MPREG));
124 	}
125 
126 	/* Discard DB_MPOOLFILEs. */
127 	while ((dbmfp = TAILQ_FIRST(&dbmp->dbmfq)) != NULL)
128 		if ((t_ret = memp_fclose(dbmfp)) != 0 && ret == 0)
129 			ret = t_ret;
130 
131 	/* Discard thread mutex. */
132 	if (F_ISSET(dbmp, MP_LOCKHANDLE)) {
133 		LOCKREGION(dbmp);
134 		__db_shalloc_free(dbmp->addr, dbmp->mutexp);
135 		UNLOCKREGION(dbmp);
136 	}
137 
138 	/* Close the region. */
139 	if ((t_ret = __db_rdetach(&dbmp->reginfo)) != 0 && ret == 0)
140 		ret = t_ret;
141 
142 	if (dbmp->reginfo.path != NULL)
143 		__os_freestr(dbmp->reginfo.path);
144 	__os_free(dbmp, sizeof(DB_MPOOL));
145 
146 	return (ret);
147 }
148 
149 /*
150  * __memp_panic --
151  *	Panic a memory pool.
152  *
153  * PUBLIC: void __memp_panic __P((DB_ENV *));
154  */
155 void
156 __memp_panic(dbenv)
157 	DB_ENV *dbenv;
158 {
159 	if (dbenv->mp_info != NULL)
160 		dbenv->mp_info->mp->rlayout.panic = 1;
161 }
162 
163 /*
164  * memp_unlink --
165  *	Exit a memory pool.
166  */
167 int
168 memp_unlink(path, force, dbenv)
169 	const char *path;
170 	int force;
171 	DB_ENV *dbenv;
172 {
173 	REGINFO reginfo;
174 	int ret;
175 
176 	memset(&reginfo, 0, sizeof(reginfo));
177 	reginfo.dbenv = dbenv;
178 	reginfo.appname = DB_APP_NONE;
179 	if (path != NULL && (ret = __os_strdup(path, &reginfo.path)) != 0)
180 		return (ret);
181 	reginfo.file = DB_DEFAULT_MPOOL_FILE;
182 	ret = __db_runlink(&reginfo, force);
183 	if (reginfo.path != NULL)
184 		__os_freestr(reginfo.path);
185 	return (ret);
186 }
187 
188 /*
189  * memp_register --
190  *	Register a file type's pgin, pgout routines.
191  */
192 int
193 memp_register(dbmp, ftype, pgin, pgout)
194 	DB_MPOOL *dbmp;
195 	int ftype;
196 	int (*pgin) __P((db_pgno_t, void *, DBT *));
197 	int (*pgout) __P((db_pgno_t, void *, DBT *));
198 {
199 	DB_MPREG *mpr;
200 	int ret;
201 
202 	MP_PANIC_CHECK(dbmp);
203 
204 	if ((ret = __os_malloc(sizeof(DB_MPREG), NULL, &mpr)) != 0)
205 		return (ret);
206 
207 	mpr->ftype = ftype;
208 	mpr->pgin = pgin;
209 	mpr->pgout = pgout;
210 
211 	/*
212 	 * Insert at the head.  Because we do a linear walk, we'll find
213 	 * the most recent registry in the case of multiple entries, so
214 	 * we don't have to check for multiple registries.
215 	 */
216 	LOCKHANDLE(dbmp, dbmp->mutexp);
217 	LIST_INSERT_HEAD(&dbmp->dbregq, mpr, q);
218 	UNLOCKHANDLE(dbmp, dbmp->mutexp);
219 
220 	return (0);
221 }
222