~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to libdb/os/os_map.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

Show diffs side-by-side

added added

removed removed

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