1 /* Licensed under Apache License v2.0 - see LICENSE file for details */
11 * struct rszshm_scan - parameters for the free region search
12 * @start: first address to test
13 * @len: size of region to test
14 * @hop: offset of the next test
15 * @iter: number of attempts
17 * See rszshm_mk for search details.
31 #define RSZSHM_DFLT_SCAN (struct rszshm_scan) { (void *) (64*TiB), 4*GiB, 1*TiB, 10 }
33 #define RSZSHM_DFLT_SCAN (struct rszshm_scan) { (void *) ((1024+512)*MiB), 256*MiB, 256*MiB, 10 }
37 * struct rszshm_hdr - header describing mapped memory
38 * @flen: length of the shared file mapping
39 * @max: length of the private mapping
40 * @addr: address of the mapping
42 * The shared region is mapped over the private region.
43 * max is the maximum size the shared region can be extended.
44 * addr and max are set at creation time and do not change.
45 * flen is updated each time the file and shared region is grown.
54 * struct rszshm - handle for a mapped region
55 * @fd: file descriptor of the mapped file
56 * @flen: length of the mapped shared file in this process
57 * @fname: path of the mapped file
58 * @hdr: pointer to the mapped region header
59 * @dat: pointer to the usable space after the header
60 * @cap: length of the usable space after the header
62 * flen is updated by rszshm_grow, or by rszshm_up.
64 #define RSZSHM_PATH_MAX 128
65 #define RSZSHM_DFLT_FNAME "/dev/shm/rszshm_XXXXXX/0"
69 char fname[RSZSHM_PATH_MAX];
70 struct rszshm_hdr *hdr;
76 * rszshm_mk - make and mmap a shareable region
77 * @r: pointer to handle
78 * @flen: initial length of shared mapping
79 * @fname: path to file to be created, may be NULL or contain template
80 * @scan: struct specifying search parameters
82 * The handle pointed to by r is populated by rszshm_mk. flen is increased
83 * by the size of struct rszshm_hdr and rounded up to the next multiple of
84 * page size. If the directory portion of fname ends with XXXXXX, mkdtemp(3)
85 * is used. If fname is NULL, a default path with template is used.
87 * If rszshm_mk is called with only three arguments, a default scan struct
88 * is used. To supply a struct via compound literal, wrap the argument in
89 * parenthesis to avoid macro failure.
91 * rszshm_mk attempts to mmap a region of scan.len size at scan.start address.
92 * This is a private anonymous noreserve map used to claim an address space.
93 * If the mapping returns a different address, the region is unmapped, and
94 * another attempt is made at scan.start - scan.hop. If necessary, the next
95 * address tried is scan.start + scan.hop, then scan.start - (2 * scan.hop),
96 * and so on for at most scan.iter iterations. The pattern can be visualized
97 * as a counterclockwise spiral. If no match is found, NULL is returned and
98 * errno is set to ENOSPC.
100 * When an mmap returns an address matching the requested address, that region
101 * is used. If fname contains a template, mkdtemp(3) is called. A file is
102 * created, and extended to flen bytes. It must not already exist. This file
103 * is mmap'd over the region using MAP_FIXED. The mapping may later be extended
104 * by rszshm_grow consuming more of the claimed address space.
106 * The initial portion of the mapped file is populated with a struct rszshm_hdr,
107 * and msync called to write out the header.
110 * struct rszshm r, s, t;
112 * if (!rszshm_mk(&r, 4*MiB, NULL))
113 * err(1, "rszshm_mk");
114 * // map at 0x400000000000
116 * if (!rszshm_mk(&s, 4*MiB, "/var/tmp/dat"))
117 * err(1, "rszshm_mk");
118 * // map at 0x3f0000000000
120 * if (!rszshm_mk(&t, 4*MiB, NULL, ((struct rszshm_scan) { (void *) (48*TiB), 4*GiB, 1*TiB, 10 })))
121 * err(1, "rszshm_mk");
122 * // map at 0x300000000000
124 * Returns: r->dat address on success, NULL on error
126 void *rszshm_mk(struct rszshm *r, size_t flen, const char *fname, struct rszshm_scan scan);
127 #define __4args(a,b,c,d,...) a, b, c, d
128 #define rszshm_mk(...) rszshm_mk(__4args(__VA_ARGS__, RSZSHM_DFLT_SCAN))
130 #if HAVE_STATEMENT_EXPR
132 * rszshm_mkm - malloc handle and run rszshm_mk
133 * @r: pointer to handle
134 * @flen: initial length of shared mapping
135 * @fname: path to file to be created, may be NULL or contain template
140 * if (!rszshm_mkm(r, 4*MiB, NULL))
141 * err(1, "rszshm_mkm");
143 * Returns: result of rszshm_mk
145 #define rszshm_mkm(r, fl, fn) ({ \
147 r = malloc(sizeof(*r)); \
148 if (r && !(__p = rszshm_mk(r, fl, fn))) { \
157 * rszshm_at - mmap ("attach") an existing shared region
158 * @r: pointer to handle
159 * @fname: path to file
161 * rszshm_at lets unrelated processes attach an existing shared region.
162 * fname must name a file previously created by rszshm_mk in another process.
163 * Note, fork'd children of the creating process inherit the mapping and
164 * should *not* call rszshm_at.
166 * rszshm_at opens and reads the header from the file. It makes a private
167 * anonymous noreserve mapping at the address recorded in the header.
168 * If mmap returns an address other than the requested one, munmap
169 * is called, errno is set to ENOSPC, and NULL is returned.
171 * Once the address space is claimed, the file is mmap'd over the region
172 * using MAP_FIXED. The remaining claimed address space will be used by
173 * later calls to rszshm_grow. Finally, the handle is populated and r->dat
179 * if (!rszshm_at(&r, "/dev/shm/rszshm_LAsEvt/0"))
180 * err(1, "rszshm_at");
182 * Returns: r->dat address on success, NULL on error
184 void *rszshm_at(struct rszshm *r, const char *fname);
186 #if HAVE_STATEMENT_EXPR
188 * rszshm_atm - malloc handle and run rszshm_at
189 * @r: pointer to handle
190 * @fname: path to file
195 * if (!rszshm_atm(r, "/dev/shm/rszshm_LAsEvt/0"))
196 * err(1, "rszshm_atm");
198 * Returns: result of rszshm_at
200 #define rszshm_atm(r, f) ({ \
202 r = malloc(sizeof(*r)); \
203 if (r && !(__p = rszshm_at(r, f))) { \
212 * rszshm_dt - unmap ("detach") shared region
213 * @r: pointer to handle
215 * Calls msync, munmap, and close. Resets handle values except fname.
216 * (fname is used by rszshm_rm*.)
218 * Returns: 0 on success, -1 if any call failed
220 int rszshm_dt(struct rszshm *r);
223 * rszshm_up - update mapping of shared region
224 * @r: pointer to handle
226 * Check if flen from the region header matches flen from the handle.
227 * They will diverge when another process runs rszshm_grow.
228 * If they are different, call mmap with the header flen and MAP_FIXED,
231 * Returns: -1 if mmap fails, 0 for no change, 1 is mapping updated
233 int rszshm_up(struct rszshm *r);
234 #define rszshm_up(r) (assert(r), (r)->flen == (r)->hdr->flen ? 0 : rszshm_up(r))
237 * rszshm_grow - double the shared region, conditionally
238 * @r: pointer to handle
240 * If the region is already at capacity, set errno to ENOMEM, and return -1.
242 * rszshm_up is called, to see if another process has already grown the region.
243 * If not, a lock is acquired and the check repeated, to avoid races.
244 * The file is extended, and mmap called with MAP_FIXED. The header and handle
247 * Returns: 1 on success, -1 on error
249 int rszshm_grow(struct rszshm *r);
252 * rszshm_unlink - unlink shared file
253 * @r: pointer to handle
255 * Returns: result of unlink
257 int rszshm_unlink(struct rszshm *r);
260 * rszshm_rmdir - rmdir of fname directory
261 * @r: pointer to handle
263 * Returns: result of rmdir
265 int rszshm_rmdir(struct rszshm *r);
267 #if HAVE_STATEMENT_EXPR
269 * rszshm_rm - remove file and directory
270 * @r: pointer to handle
272 * Calls rszshm_unlink and rszshm_rmdir.
274 * Returns: 0 on success, -1 on error
276 #define rszshm_rm(r) ({ \
279 __ret = rszshm_unlink(r); \
281 __ret = rszshm_rmdir(r); \
286 #if HAVE_STATEMENT_EXPR
288 * rszshm_free - run rszshm_dt and free malloced handle
289 * @r: pointer to handle
291 * Returns: result of rszshm_dt
293 #define rszshm_free(r) ({ \
294 int __i = rszshm_dt(r); \