VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/shmem-posix.cpp@ 76553

Last change on this file since 76553 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 KB
Line 
1/* $Id: shmem-posix.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * IPRT - Named shared memory object, POSIX Implementation.
4 */
5
6/*
7 * Copyright (C) 2018-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/shmem.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/cdefs.h>
37#include <iprt/err.h>
38#include <iprt/mem.h>
39#include <iprt/string.h>
40#include "internal/magics.h"
41
42#include <errno.h>
43#include <sys/mman.h>
44#include <sys/stat.h>
45#include <fcntl.h>
46#include <unistd.h>
47#include <limits.h>
48
49/* Workaround on systems which do not provide this. */
50#ifndef NAME_MAX
51# define NAME_MAX 255
52#endif
53
54
55/*********************************************************************************************************************************
56* Structures and Typedefs *
57*********************************************************************************************************************************/
58
59/**
60 * Shared memory object mapping descriptor.
61 */
62typedef struct RTSHMEMMAPPINGDESC
63{
64 /** Number of references held to this mapping, 0 if the descriptor is free. */
65 volatile uint32_t cMappings;
66 /** Pointer to the region mapping. */
67 void *pvMapping;
68 /** Start offset */
69 size_t offRegion;
70 /** Size of the region. */
71 size_t cbRegion;
72 /** Access flags for this region .*/
73 uint32_t fFlags;
74} RTSHMEMMAPPINGDESC;
75/** Pointer to a shared memory object mapping descriptor. */
76typedef RTSHMEMMAPPINGDESC *PRTSHMEMMAPPINGDESC;
77/** Pointer to a constant shared memory object mapping descriptor. */
78typedef const RTSHMEMMAPPINGDESC *PCRTSHMEMMAPPINGDESC;
79
80
81/**
82 * Internal shared memory object state.
83 */
84typedef struct RTSHMEMINT
85{
86 /** Magic value (RTSHMEM_MAGIC). */
87 uint32_t u32Magic;
88 /** File descriptor for the underlying shared memory object. */
89 int iFdShm;
90 /** Pointer to the shared memory object name. */
91 char *pszName;
92 /** Flag whether this instance created the named shared memory object. */
93 bool fCreate;
94 /** Overall number of mappings active for this shared memory object. */
95 volatile uint32_t cMappings;
96 /** Maximum number of mapping descriptors allocated. */
97 uint32_t cMappingDescsMax;
98 /** Number of mapping descriptors used. */
99 volatile uint32_t cMappingDescsUsed;
100 /** Array of mapping descriptors - variable in size. */
101 RTSHMEMMAPPINGDESC aMappingDescs[1];
102} RTSHMEMINT;
103/** Pointer to the internal shared memory object state. */
104typedef RTSHMEMINT *PRTSHMEMINT;
105
106
107
108/**
109 * Returns a mapping descriptor matching the given region properties or NULL if none was found.
110 *
111 * @returns Pointer to the matching mapping descriptor or NULL if not found.
112 * @param pThis Pointer to the shared memory object instance.
113 * @param offRegion Offset into the shared memory object to start mapping at.
114 * @param cbRegion Size of the region to map.
115 * @param fFlags Desired properties of the mapped region, combination of RTSHMEM_MAP_F_* defines.
116 */
117DECLINLINE(PRTSHMEMMAPPINGDESC) rtShMemMappingDescFindByProp(PRTSHMEMINT pThis, size_t offRegion, size_t cbRegion, uint32_t fFlags)
118{
119 for (uint32_t i = 0; i < pThis->cMappingDescsMax; i++)
120 {
121 if ( pThis->aMappingDescs[i].offRegion == offRegion
122 && pThis->aMappingDescs[i].cbRegion == cbRegion
123 && pThis->aMappingDescs[i].fFlags == fFlags)
124 return &pThis->aMappingDescs[i];
125 }
126
127 return NULL;
128}
129
130
131RTDECL(int) RTShMemOpen(PRTSHMEM phShMem, const char *pszName, uint32_t fFlags, size_t cbMax, uint32_t cMappingsHint)
132{
133 AssertPtrReturn(phShMem, VERR_INVALID_PARAMETER);
134 AssertPtrReturn(pszName, VERR_INVALID_PARAMETER);
135 AssertReturn(!(fFlags & ~RTSHMEM_O_F_VALID_MASK), VERR_INVALID_PARAMETER);
136 AssertReturn(cMappingsHint < 64, VERR_OUT_OF_RANGE);
137
138 size_t cchName = strlen(pszName);
139 AssertReturn(cchName, VERR_INVALID_PARAMETER);
140 AssertReturn(cchName < NAME_MAX - 1, VERR_INVALID_PARAMETER); /* account for the / we add later on. */
141 cMappingsHint = cMappingsHint == 0 ? 5 : cMappingsHint;
142 int rc = VINF_SUCCESS;
143 PRTSHMEMINT pThis = (PRTSHMEMINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTSHMEMINT, aMappingDescs[cMappingsHint]) + cchName + 2); /* '/' + terminator. */
144 if (RT_LIKELY(pThis))
145 {
146 pThis->u32Magic = RTSHMEM_MAGIC;
147 pThis->pszName = (char *)&pThis->aMappingDescs[cMappingsHint];
148 /*pThis->fCreate = false; */
149 /*pThis->cMappings = 0; */
150 pThis->cMappingDescsMax = cMappingsHint;
151 /*pThis->cMappingDescsUsed = 0; */
152 pThis->pszName[0] = '/';
153 memcpy(&pThis->pszName[1], pszName, cchName);
154 int fShmFlags = 0;
155 if (fFlags & RTSHMEM_O_F_CREATE)
156 {
157 fShmFlags |= O_CREAT;
158 pThis->fCreate = true;
159 }
160 if ((fFlags & RTSHMEM_O_F_CREATE_EXCL) == RTSHMEM_O_F_CREATE_EXCL)
161 fShmFlags |= O_EXCL;
162 if ( (fFlags & RTSHMEM_O_F_READWRITE) == RTSHMEM_O_F_READWRITE
163 || (fFlags & RTSHMEM_O_F_WRITE))
164 fShmFlags |= O_RDWR;
165 else
166 fShmFlags |= O_RDONLY;
167 if (fFlags & RTSHMEM_O_F_TRUNCATE)
168 fShmFlags |= O_TRUNC;
169 pThis->iFdShm = shm_open(pThis->pszName, fShmFlags , 0600);
170 if (pThis->iFdShm > 0)
171 {
172 if (cbMax)
173 rc = RTShMemSetSize(pThis, cbMax);
174 if (RT_SUCCESS(rc))
175 {
176 *phShMem = pThis;
177 return VINF_SUCCESS;
178 }
179
180 close(pThis->iFdShm);
181 }
182 else
183 rc = RTErrConvertFromErrno(errno);
184
185 RTMemFree(pThis);
186 }
187 else
188 rc = VERR_NO_MEMORY;
189
190 return rc;
191}
192
193
194RTDECL(int) RTShMemClose(RTSHMEM hShMem)
195{
196 PRTSHMEMINT pThis = hShMem;
197 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
198 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
199 AssertReturn(!pThis->cMappings, VERR_INVALID_STATE);
200
201 int rc = VINF_SUCCESS;
202 if (!close(pThis->iFdShm))
203 {
204 if (pThis->fCreate)
205 shm_unlink(pThis->pszName); /* Ignore any error here. */
206 pThis->u32Magic = RTSHMEM_MAGIC_DEAD;
207 RTMemFree(pThis);
208 }
209 else
210 rc = RTErrConvertFromErrno(errno);
211
212 return rc;
213}
214
215
216RTDECL(uint32_t) RTShMemRefCount(RTSHMEM hShMem)
217{
218 PRTSHMEMINT pThis = hShMem;
219 AssertPtrReturn(pThis, 0);
220 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, 0);
221
222 return pThis->cMappings;
223}
224
225
226RTDECL(int) RTShMemSetSize(RTSHMEM hShMem, size_t cbMem)
227{
228 PRTSHMEMINT pThis = hShMem;
229 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
230 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
231 AssertReturn(!pThis->cMappings, VERR_INVALID_STATE);
232
233 int rc = VINF_SUCCESS;
234 if (ftruncate(pThis->iFdShm, (off_t)cbMem))
235 rc = RTErrConvertFromErrno(errno);
236
237 return rc;
238}
239
240
241RTDECL(int) RTShMemQuerySize(RTSHMEM hShMem, size_t *pcbMem)
242{
243 PRTSHMEMINT pThis = hShMem;
244 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
245 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
246 AssertPtrReturn(pcbMem, VERR_INVALID_PARAMETER);
247
248 struct stat st;
249 if (!fstat(pThis->iFdShm, &st))
250 {
251 *pcbMem = st.st_size;
252 return VINF_SUCCESS;
253 }
254 return RTErrConvertFromErrno(errno);
255}
256
257
258RTDECL(int) RTShMemMapRegion(RTSHMEM hShMem, size_t offRegion, size_t cbRegion, uint32_t fFlags, void **ppv)
259{
260 PRTSHMEMINT pThis = hShMem;
261 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
262 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
263 AssertPtrReturn(ppv, VERR_INVALID_PARAMETER);
264 AssertReturn(!(fFlags & ~RTSHMEM_MAP_F_VALID_MASK), VERR_INVALID_PARAMETER);
265
266 /* Try to find a mapping with compatible parameters first. */
267 PRTSHMEMMAPPINGDESC pMappingDesc = NULL;
268 for (uint32_t iTry = 0; iTry < 10; iTry++)
269 {
270 pMappingDesc = rtShMemMappingDescFindByProp(pThis, offRegion, cbRegion, fFlags);
271 if (!pMappingDesc)
272 break;
273
274 /* Increase the mapping count and check that the region is still accessible by us. */
275 if ( ASMAtomicIncU32(&pMappingDesc->cMappings) > 1
276 && pMappingDesc->offRegion == offRegion
277 && pMappingDesc->cbRegion == cbRegion
278 && pMappingDesc->fFlags == fFlags)
279 break;
280 /* Mapping was freed inbetween, next round. */
281 }
282
283 int rc = VINF_SUCCESS;
284 if (!pMappingDesc)
285 {
286 /* Find an empty region descriptor and map the region. */
287 for (uint32_t i = 0; i < pThis->cMappingDescsMax && !pMappingDesc; i++)
288 {
289 if (!pThis->aMappingDescs[i].cMappings)
290 {
291 pMappingDesc = &pThis->aMappingDescs[i];
292
293 /* Try to grab this one. */
294 if (ASMAtomicIncU32(&pMappingDesc->cMappings) == 1)
295 break;
296
297 /* Somebody raced us, drop reference and continue. */
298 ASMAtomicDecU32(&pMappingDesc->cMappings);
299 pMappingDesc = NULL;
300 }
301 }
302
303 if (RT_LIKELY(pMappingDesc))
304 {
305 /* Try to map it. */
306 int fMmapFlags = 0;
307 int fProt = 0;
308 if (fFlags & RTSHMEM_MAP_F_READ)
309 fProt |= PROT_READ;
310 if (fFlags & RTSHMEM_MAP_F_WRITE)
311 fProt |= PROT_WRITE;
312 if (fFlags & RTSHMEM_MAP_F_EXEC)
313 fProt |= PROT_EXEC;
314 if (fFlags & RTSHMEM_MAP_F_COW)
315 fMmapFlags |= MAP_PRIVATE;
316 else
317 fMmapFlags |= MAP_SHARED;
318
319 void *pv = mmap(NULL, cbRegion, fProt, fMmapFlags, pThis->iFdShm, (off_t)offRegion);
320 if (pv != MAP_FAILED)
321 {
322 pMappingDesc->pvMapping = pv;
323 pMappingDesc->offRegion = offRegion;
324 pMappingDesc->cbRegion = cbRegion;
325 pMappingDesc->fFlags = fFlags;
326 }
327 else
328 {
329 rc = RTErrConvertFromErrno(errno);
330 ASMAtomicDecU32(&pMappingDesc->cMappings);
331 }
332 }
333 else
334 rc = VERR_SHMEM_MAXIMUM_MAPPINGS_REACHED;
335 }
336
337 if (RT_SUCCESS(rc))
338 {
339 *ppv = pMappingDesc->pvMapping;
340 ASMAtomicIncU32(&pThis->cMappings);
341 }
342
343 return rc;
344}
345
346
347RTDECL(int) RTShMemUnmapRegion(RTSHMEM hShMem, void *pv)
348{
349 PRTSHMEMINT pThis = hShMem;
350 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
351 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
352 AssertPtrReturn(pv, VERR_INVALID_PARAMETER);
353
354 /* Find the mapping descriptor by the given region address. */
355 PRTSHMEMMAPPINGDESC pMappingDesc = NULL;
356 for (uint32_t i = 0; i < pThis->cMappingDescsMax && !pMappingDesc; i++)
357 {
358 if (pThis->aMappingDescs[i].pvMapping == pv)
359 {
360 pMappingDesc = &pThis->aMappingDescs[i];
361 break;
362 }
363 }
364
365 AssertPtrReturn(pMappingDesc, VERR_INVALID_PARAMETER);
366
367 int rc = VINF_SUCCESS;
368 size_t cbRegion = pMappingDesc->cMappings;
369 if (!ASMAtomicDecU32(&pMappingDesc->cMappings))
370 {
371 /* Last mapping of this region was unmapped, so do the real unmapping now. */
372 if (munmap(pv, cbRegion))
373 {
374 ASMAtomicIncU32(&pMappingDesc->cMappings);
375 rc = RTErrConvertFromErrno(errno);
376 }
377 else
378 {
379 ASMAtomicDecU32(&pThis->cMappingDescsUsed);
380 ASMAtomicDecU32(&pThis->cMappings);
381 }
382 }
383
384 return rc;
385}
386
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette