add packaging
[platform/upstream/db4.git] / os_vxworks / os_vx_map.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1998-2009 Oracle.  All rights reserved.
5  *
6  * This code is derived from software contributed to Sleepycat Software by
7  * Frederick G.M. Roeber of Netscape Communications Corp.
8  *
9  * $Id$
10  */
11
12 #include "db_config.h"
13
14 #include "db_int.h"
15
16 /*
17  * DB uses memory-mapped files for two things:
18  *      faster access of read-only databases, and
19  *      shared memory for process synchronization and locking.
20  * The code carefully does not mix the two uses.  The first-case uses are
21  * actually written such that memory-mapping isn't really required -- it's
22  * merely a convenience -- so we don't have to worry much about it.  In the
23  * second case, it's solely used as a shared memory mechanism, so that's
24  * all we have to replace.
25  *
26  * All memory in VxWorks is shared, and a task can allocate memory and keep
27  * notes.  So I merely have to allocate memory, remember the "filename" for
28  * that memory, and issue small-integer segment IDs which index the list of
29  * these shared-memory segments. Subsequent opens are checked against the
30  * list of already open segments.
31  */
32 typedef struct {
33         void *segment;                  /* Segment address. */
34         u_int32_t size;                 /* Segment size. */
35         char *name;                     /* Segment name. */
36         long segid;                     /* Segment ID. */
37 } os_segdata_t;
38
39 static os_segdata_t *__os_segdata;      /* Segment table. */
40 static int __os_segdata_size;           /* Segment table size. */
41
42 #define OS_SEGDATA_STARTING_SIZE 16
43 #define OS_SEGDATA_INCREMENT     16
44
45 static int __os_segdata_allocate
46                __P((ENV *, const char *, REGINFO *, REGION *));
47 static int __os_segdata_find_byname
48                __P((ENV *, const char *, REGINFO *, REGION *));
49 static int __os_segdata_init __P((ENV *));
50 static int __os_segdata_new __P((ENV *, int *));
51 static int __os_segdata_release __P((ENV *, REGION *, int));
52
53 /*
54  * __os_attach --
55  *      Create/join a shared memory region.
56  */
57 int
58 __os_attach(env, infop, rp)
59         ENV *env;
60         REGINFO *infop;
61         REGION *rp;
62 {
63         DB_ENV *dbenv;
64         int ret;
65
66         dbenv = env->dbenv;
67
68         if (__os_segdata == NULL)
69                 __os_segdata_init(env);
70
71         DB_BEGIN_SINGLE_THREAD;
72
73         /* Try to find an already existing segment. */
74         ret = __os_segdata_find_byname(env, infop->name, infop, rp);
75
76         /*
77          * If we are trying to join a region, it is easy, either we
78          * found it and we return, or we didn't find it and we return
79          * an error that it doesn't exist.
80          */
81         if (!F_ISSET(infop, REGION_CREATE)) {
82                 if (ret != 0) {
83                         __db_errx(env, "segment %s does not exist",
84                             infop->name);
85                         ret = EAGAIN;
86                 }
87                 goto out;
88         }
89
90         /*
91          * If we get here, we are trying to create the region.
92          * There are several things to consider:
93          * - if we have an error (not a found or not-found value), return.
94          * - they better have shm_key set.
95          * - if the region is already there (ret == 0 from above),
96          * assume the application crashed and we're restarting.
97          * Delete the old region.
98          * - try to create the region.
99          */
100         if (ret != 0 && ret != ENOENT)
101                 goto out;
102
103         if (dbenv->shm_key == INVALID_REGION_SEGID) {
104                 __db_errx(env, "no base shared memory ID specified");
105                 ret = EAGAIN;
106                 goto out;
107         }
108         if (ret == 0 && __os_segdata_release(env, rp, 1) != 0) {
109                 __db_errx(env,
110                     "key: %ld: shared memory region already exists",
111                     dbenv->shm_key + (infop->id - 1));
112                 ret = EAGAIN;
113                 goto out;
114         }
115
116         ret = __os_segdata_allocate(env, infop->name, infop, rp);
117 out:
118         DB_END_SINGLE_THREAD;
119         return (ret);
120 }
121
122 /*
123  * __os_detach --
124  *      Detach from a shared region.
125  */
126 int
127 __os_detach(env, infop, destroy)
128         ENV *env;
129         REGINFO *infop;
130         int destroy;
131 {
132         /*
133          * If just detaching, there is no mapping to discard.
134          * If destroying, remove the region.
135          */
136         if (destroy)
137                 return (__os_segdata_release(env, infop->rp, 0));
138         return (0);
139 }
140
141 /*
142  * __os_mapfile --
143  *      Map in a shared memory file.
144  */
145 int
146 __os_mapfile(env, path, fhp, len, is_rdonly, addrp)
147         ENV *env;
148         char *path;
149         DB_FH *fhp;
150         int is_rdonly;
151         size_t len;
152         void **addrp;
153 {
154         /* We cannot map in regular files in VxWorks. */
155         COMPQUIET(env, NULL);
156         COMPQUIET(path, NULL);
157         COMPQUIET(fhp, NULL);
158         COMPQUIET(is_rdonly, 0);
159         COMPQUIET(len, 0);
160         COMPQUIET(addrp, NULL);
161         return (DB_OPNOTSUP);
162 }
163
164 /*
165  * __os_unmapfile --
166  *      Unmap the shared memory file.
167  */
168 int
169 __os_unmapfile(env, addr, len)
170         ENV *env;
171         void *addr;
172         size_t len;
173 {
174         /* We cannot map in regular files in VxWorks. */
175         COMPQUIET(env, NULL);
176         COMPQUIET(addr, NULL);
177         COMPQUIET(len, 0);
178         return (DB_OPNOTSUP);
179 }
180
181 /*
182  * __os_segdata_init --
183  *      Initializes the library's table of shared memory segments.
184  *      Called once on the first time through __os_segdata_new().
185  */
186 static int
187 __os_segdata_init(env)
188         ENV *env;
189 {
190         int ret;
191
192         if (__os_segdata != NULL) {
193                 __db_errx(env, "shared memory segment already exists");
194                 return (EEXIST);
195         }
196
197         /*
198          * The lock init call returns a locked lock.
199          */
200         DB_BEGIN_SINGLE_THREAD;
201         __os_segdata_size = OS_SEGDATA_STARTING_SIZE;
202         ret = __os_calloc(env,
203             __os_segdata_size, sizeof(os_segdata_t), &__os_segdata);
204         DB_END_SINGLE_THREAD;
205         return (ret);
206 }
207
208 /*
209  * __os_segdata_destroy --
210  *      Destroys the library's table of shared memory segments.  It also
211  *      frees all linked data: the segments themselves, and their names.
212  *      Currently not called.  This function should be called if the
213  *      user creates a function to unload or shutdown.
214  */
215 int
216 __os_segdata_destroy(env)
217         ENV *env;
218 {
219         os_segdata_t *p;
220         int i;
221
222         if (__os_segdata == NULL)
223                 return (0);
224
225         DB_BEGIN_SINGLE_THREAD;
226         for (i = 0; i < __os_segdata_size; i++) {
227                 p = &__os_segdata[i];
228                 if (p->name != NULL) {
229                         __os_free(env, p->name);
230                         p->name = NULL;
231                 }
232                 if (p->segment != NULL) {
233                         __os_free(env, p->segment);
234                         p->segment = NULL;
235                 }
236                 p->size = 0;
237         }
238
239         __os_free(env, __os_segdata);
240         __os_segdata = NULL;
241         __os_segdata_size = 0;
242         DB_END_SINGLE_THREAD;
243
244         return (0);
245 }
246
247 /*
248  * __os_segdata_allocate --
249  *      Creates a new segment of the specified size, optionally with the
250  *      specified name.
251  *
252  * Assumes it is called with the SEGDATA lock taken.
253  */
254 static int
255 __os_segdata_allocate(env, name, infop, rp)
256         ENV *env;
257         const char *name;
258         REGINFO *infop;
259         REGION *rp;
260 {
261         DB_ENV *dbenv;
262         os_segdata_t *p;
263         int id, ret;
264
265         dbenv = env->dbenv;
266
267         if ((ret = __os_segdata_new(env, &id)) != 0)
268                 return (ret);
269
270         p = &__os_segdata[id];
271         if ((ret = __os_calloc(env, 1, rp->size, &p->segment)) != 0)
272                 return (ret);
273         if ((ret = __os_strdup(env, name, &p->name)) != 0) {
274                 __os_free(env, p->segment);
275                 p->segment = NULL;
276                 return (ret);
277         }
278         p->size = rp->size;
279         p->segid = dbenv->shm_key + infop->id - 1;
280
281         infop->addr = p->segment;
282         rp->segid = id;
283
284         return (0);
285 }
286
287 /*
288  * __os_segdata_new --
289  *      Finds a new segdata slot.  Does not initialise it, so the fd returned
290  *      is only valid until you call this again.
291  *
292  * Assumes it is called with the SEGDATA lock taken.
293  */
294 static int
295 __os_segdata_new(env, segidp)
296         ENV *env;
297         int *segidp;
298 {
299         os_segdata_t *p;
300         int i, newsize, ret;
301
302         if (__os_segdata == NULL) {
303                 __db_errx(env, "shared memory segment not initialized");
304                 return (EAGAIN);
305         }
306
307         for (i = 0; i < __os_segdata_size; i++) {
308                 p = &__os_segdata[i];
309                 if (p->segment == NULL) {
310                         *segidp = i;
311                         return (0);
312                 }
313         }
314
315         /*
316          * No more free slots, expand.
317          */
318         newsize = __os_segdata_size + OS_SEGDATA_INCREMENT;
319         if ((ret = __os_realloc(env, newsize * sizeof(os_segdata_t),
320             &__os_segdata)) != 0)
321                 return (ret);
322         memset(&__os_segdata[__os_segdata_size],
323             0, OS_SEGDATA_INCREMENT * sizeof(os_segdata_t));
324
325         *segidp = __os_segdata_size;
326         __os_segdata_size = newsize;
327
328         return (0);
329 }
330
331 /*
332  * __os_segdata_find_byname --
333  *      Finds a segment by its name and shm_key.
334  *
335  * Assumes it is called with the SEGDATA lock taken.
336  */
337 static int
338 __os_segdata_find_byname(env, name, infop, rp)
339         ENV *env;
340         const char *name;
341         REGINFO *infop;
342         REGION *rp;
343 {
344         DB_ENV *dbenv;
345         os_segdata_t *p;
346         long segid;
347         int i;
348
349         dbenv = env->dbenv;
350
351         if (__os_segdata == NULL) {
352                 __db_errx(env, "shared memory segment not initialized");
353                 return (EAGAIN);
354         }
355
356         if (name == NULL) {
357                 __db_errx(env, "no segment name given");
358                 return (EAGAIN);
359         }
360
361         /*
362          * If we are creating the region, compute the segid.
363          * If we are joining the region, we use the segid in the
364          * index we are given.
365          */
366         if (F_ISSET(infop, REGION_CREATE))
367                 segid = dbenv->shm_key + (infop->id - 1);
368         else {
369                 if (rp->segid >= __os_segdata_size ||
370                     rp->segid == INVALID_REGION_SEGID) {
371                         __db_errx(env, "Invalid segment id given");
372                         return (EAGAIN);
373                 }
374                 segid = __os_segdata[rp->segid].segid;
375         }
376         for (i = 0; i < __os_segdata_size; i++) {
377                 p = &__os_segdata[i];
378                 if (p->name != NULL && strcmp(name, p->name) == 0 &&
379                     p->segid == segid) {
380                         infop->addr = p->segment;
381                         rp->segid = i;
382                         return (0);
383                 }
384         }
385         return (ENOENT);
386 }
387
388 /*
389  * __os_segdata_release --
390  *      Free a segdata entry.
391  */
392 static int
393 __os_segdata_release(env, rp, is_locked)
394         ENV *env;
395         REGION *rp;
396         int is_locked;
397 {
398         os_segdata_t *p;
399
400         if (__os_segdata == NULL) {
401                 __db_errx(env, "shared memory segment not initialized");
402                 return (EAGAIN);
403         }
404
405         if (rp->segid < 0 || rp->segid >= __os_segdata_size) {
406                 __db_errx(env, "segment id %ld out of range", rp->segid);
407                 return (EINVAL);
408         }
409
410         if (is_locked == 0)
411                 DB_BEGIN_SINGLE_THREAD;
412         p = &__os_segdata[rp->segid];
413         if (p->name != NULL) {
414                 __os_free(env, p->name);
415                 p->name = NULL;
416         }
417         if (p->segment != NULL) {
418                 __os_free(env, p->segment);
419                 p->segment = NULL;
420         }
421         p->size = 0;
422         if (is_locked == 0)
423                 DB_END_SINGLE_THREAD;
424
425         /* Any shrink-table logic could go here */
426
427         return (0);
428 }