VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/shmem-win.cpp@ 75883

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

IPRT/shmem: Make doxygen and scm happy.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.3 KB
Line 
1/* $Id: shmem-win.cpp 75883 2018-12-02 20:58:27Z vboxsync $ */
2/** @file
3 * IPRT - Named shared memory object, Windows Implementation.
4 */
5
6/*
7 * Copyright (C) 2018 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/nt/nt-and-windows.h>
32
33#include <iprt/shmem.h>
34#include "internal/iprt.h"
35
36#include <iprt/asm.h>
37#include <iprt/assert.h>
38#include <iprt/cdefs.h>
39#include <iprt/err.h>
40#include <iprt/mem.h>
41#include <iprt/string.h>
42#include "internal/magics.h"
43#include "internal/path.h"
44#include "internal-r3-win.h" /* For g_enmWinVer + kRTWinOSType_XXX */
45
46/*
47 * Define values ourselves in case the compiling host is too old.
48 * See https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createfilemappinga
49 * for when these were introduced.
50 */
51#ifndef PAGE_EXECUTE_READ
52# define PAGE_EXECUTE_READ 0x20
53#endif
54#ifndef PAGE_EXECUTE_READWRITE
55# define PAGE_EXECUTE_READWRITE 0x40
56#endif
57#ifndef PAGE_EXECUTE_WRITECOPY
58# define PAGE_EXECUTE_WRITECOPY 0x80
59#endif
60#ifndef FILE_MAP_EXECUTE
61# define FILE_MAP_EXECUTE 0x20
62#endif
63
64
65/*********************************************************************************************************************************
66* Structures and Typedefs *
67*********************************************************************************************************************************/
68
69/**
70 * Shared memory object mapping descriptor.
71 */
72typedef struct RTSHMEMMAPPINGDESC
73{
74 /** Number of references held to this mapping, 0 if the descriptor is free. */
75 volatile uint32_t cMappings;
76 /** Pointer to the region mapping. */
77 void *pvMapping;
78 /** Start offset */
79 size_t offRegion;
80 /** Size of the region. */
81 size_t cbRegion;
82 /** Access flags for this region .*/
83 uint32_t fFlags;
84} RTSHMEMMAPPINGDESC;
85/** Pointer to a shared memory object mapping descriptor. */
86typedef RTSHMEMMAPPINGDESC *PRTSHMEMMAPPINGDESC;
87/** Pointer to a constant shared memory object mapping descriptor. */
88typedef const RTSHMEMMAPPINGDESC *PCRTSHMEMMAPPINGDESC;
89
90
91/**
92 * Internal shared memory object state.
93 */
94typedef struct RTSHMEMINT
95{
96 /** Magic value (RTSHMEM_MAGIC). */
97 uint32_t u32Magic;
98 /** Flag whether this instance created the named shared memory object. */
99 bool fCreate;
100 /** Handle to the underlying mapping object. */
101 HANDLE hShmObj;
102 /** Size of the mapping object in bytes. */
103 size_t cbMax;
104 /** Overall number of mappings active for this shared memory object. */
105 volatile uint32_t cMappings;
106 /** Maximum number of mapping descriptors allocated. */
107 uint32_t cMappingDescsMax;
108 /** Number of mapping descriptors used. */
109 volatile uint32_t cMappingDescsUsed;
110 /** Array of mapping descriptors - variable in size. */
111 RTSHMEMMAPPINGDESC aMappingDescs[1];
112} RTSHMEMINT;
113/** Pointer to the internal shared memory object state. */
114typedef RTSHMEMINT *PRTSHMEMINT;
115
116
117
118
119/**
120 * Returns a mapping descriptor matching the given region properties or NULL if none was found.
121 *
122 * @returns Pointer to the matching mapping descriptor or NULL if not found.
123 * @param pThis Pointer to the shared memory object instance.
124 * @param offRegion Offset into the shared memory object to start mapping at.
125 * @param cbRegion Size of the region to map.
126 * @param fFlags Desired properties of the mapped region, combination of RTSHMEM_MAP_F_* defines.
127 */
128DECLINLINE(PRTSHMEMMAPPINGDESC) rtShMemMappingDescFindByProp(PRTSHMEMINT pThis, size_t offRegion, size_t cbRegion, uint32_t fFlags)
129{
130 for (uint32_t i = 0; i < pThis->cMappingDescsMax; i++)
131 {
132 if ( pThis->aMappingDescs[i].offRegion == offRegion
133 && pThis->aMappingDescs[i].cbRegion == cbRegion
134 && pThis->aMappingDescs[i].fFlags == fFlags)
135 return &pThis->aMappingDescs[i];
136 }
137
138 return NULL;
139}
140
141
142RTDECL(int) RTShMemOpen(PRTSHMEM phShMem, const char *pszName, uint32_t fFlags, size_t cbMax, uint32_t cMappingsHint)
143{
144 AssertPtrReturn(phShMem, VERR_INVALID_PARAMETER);
145 AssertPtrReturn(pszName, VERR_INVALID_PARAMETER);
146 AssertReturn(!(fFlags & ~RTSHMEM_O_F_VALID_MASK), VERR_INVALID_PARAMETER);
147 AssertReturn(cMappingsHint < 64, VERR_OUT_OF_RANGE);
148 AssertReturn(cbMax > 0 || !(fFlags & RTSHMEM_O_F_CREATE), VERR_NOT_SUPPORTED);
149
150 if (fFlags & RTSHMEM_O_F_TRUNCATE)
151 return VERR_NOT_SUPPORTED;
152
153 /*
154 * The executable access was introduced with Windows XP SP2 and Windows Server 2003 SP1,
155 * PAGE_EXECUTE_WRITECOPY was not available until Windows Vista SP1.
156 * Allow execute mappings only starting from Windows 7 to keep the checks simple here (lazy coder).
157 */
158 if ( (fFlags & RTSHMEM_O_F_MAYBE_EXEC)
159 && g_enmWinVer < kRTWinOSType_7)
160 return VERR_NOT_SUPPORTED;
161
162 cMappingsHint = cMappingsHint == 0 ? 5 : cMappingsHint;
163 int rc = VINF_SUCCESS;
164 PRTSHMEMINT pThis = (PRTSHMEMINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTSHMEMINT, aMappingDescs[cMappingsHint]));
165 if (RT_LIKELY(pThis))
166 {
167 pThis->u32Magic = RTSHMEM_MAGIC;
168 /*pThis->fCreate = false; */
169 /*pThis->cMappings = 0; */
170 pThis->cMappingDescsMax = cMappingsHint;
171 /*pThis->cMappingDescsUsed = 0; */
172 /* Construct the filename, always use the local namespace, global requires special privileges. */
173 char szName[RTPATH_MAX];
174 ssize_t cch = RTStrPrintf2(&szName[0], sizeof(szName), "Local\\%s", pszName);
175 if (cch > 0)
176 {
177 PRTUTF16 pwszName = NULL;
178 rc = RTStrToUtf16Ex(&szName[0], RTSTR_MAX, &pwszName, 0, NULL);
179 if (RT_SUCCESS(rc))
180 {
181 if (fFlags & RTSHMEM_O_F_CREATE)
182 {
183#if HC_ARCH_BITS == 64
184 DWORD dwSzMaxHigh = cbMax >> 32;
185#elif HC_ARCH_BITS == 32
186 DWORD dwSzMaxHigh = 0;
187#else
188# error "Port me"
189#endif
190 DWORD dwSzMaxLow = cbMax & UINT32_C(0xffffffff);
191 DWORD fProt = 0;
192
193 if (fFlags & RTSHMEM_O_F_MAYBE_EXEC)
194 {
195 if ((fFlags & RTSHMEM_O_F_READWRITE) == RTSHMEM_O_F_READ)
196 fProt |= PAGE_EXECUTE_READ;
197 else
198 fProt |= PAGE_EXECUTE_READWRITE;
199 }
200 else
201 {
202 if ((fFlags & RTSHMEM_O_F_READWRITE) == RTSHMEM_O_F_READ)
203 fProt |= PAGE_READONLY;
204 else
205 fProt |= PAGE_READWRITE;
206 }
207 pThis->hShmObj = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, fProt,
208 dwSzMaxHigh, dwSzMaxLow, pwszName);
209 }
210 else
211 {
212 DWORD fProt = SECTION_QUERY;
213 if (fFlags & RTSHMEM_O_F_MAYBE_EXEC)
214 fProt |= FILE_MAP_EXECUTE;
215 if (fFlags & RTSHMEM_O_F_READ)
216 fProt |= FILE_MAP_READ;
217 if (fFlags & RTSHMEM_O_F_WRITE)
218 fProt |= FILE_MAP_WRITE;
219
220 pThis->hShmObj = OpenFileMappingW(fProt, FALSE, pwszName);
221 }
222 RTUtf16Free(pwszName);
223 if (pThis->hShmObj != NULL)
224 {
225 *phShMem = pThis;
226 return VINF_SUCCESS;
227 }
228 else
229 rc = RTErrConvertFromWin32(GetLastError());
230 }
231 }
232 else
233 rc = VERR_BUFFER_OVERFLOW;
234
235 RTMemFree(pThis);
236 }
237 else
238 rc = VERR_NO_MEMORY;
239
240 return rc;
241}
242
243
244RTDECL(int) RTShMemClose(RTSHMEM hShMem)
245{
246 PRTSHMEMINT pThis = hShMem;
247 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
248 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
249 AssertReturn(!pThis->cMappings, VERR_INVALID_STATE);
250
251 int rc = VINF_SUCCESS;
252 if (CloseHandle(pThis->hShmObj))
253 {
254 pThis->u32Magic = RTSHMEM_MAGIC_DEAD;
255 RTMemFree(pThis);
256 }
257 else
258 rc = RTErrConvertFromWin32(GetLastError());
259
260 return rc;
261}
262
263
264RTDECL(uint32_t) RTShMemRefCount(RTSHMEM hShMem)
265{
266 PRTSHMEMINT pThis = hShMem;
267 AssertPtrReturn(pThis, 0);
268 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, 0);
269
270 return pThis->cMappings;
271}
272
273
274RTDECL(int) RTShMemSetSize(RTSHMEM hShMem, size_t cbMem)
275{
276 PRTSHMEMINT pThis = hShMem;
277 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
278 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
279 AssertReturn(!pThis->cMappings, VERR_INVALID_STATE);
280 AssertReturn(cbMem, VERR_NOT_SUPPORTED);
281
282 return VERR_NOT_SUPPORTED;
283}
284
285
286RTDECL(int) RTShMemQuerySize(RTSHMEM hShMem, size_t *pcbMem)
287{
288 PRTSHMEMINT pThis = hShMem;
289 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
290 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
291 AssertPtrReturn(pcbMem, VERR_INVALID_PARAMETER);
292
293 int rc = VINF_SUCCESS;
294 SECTION_BASIC_INFORMATION SecInf;
295 SIZE_T cbRet;
296 NTSTATUS rcNt = NtQuerySection(pThis->hShmObj, SectionBasicInformation, &SecInf, sizeof(SecInf), &cbRet);
297 if (NT_SUCCESS(rcNt))
298 {
299 AssertReturn(cbRet == sizeof(SecInf), VERR_INTERNAL_ERROR);
300#if HC_ARCH_BITS == 32
301 AssertReturn(SecInf.MaximumSize.HighPart == 0, VERR_INTERNAL_ERROR_2);
302 *pcbMem = SecInf.MaximumSize.LowPart;
303#elif HC_ARCH_BITS == 64
304 *pcbMem = SecInf.MaximumSize.QuadPart;
305#else
306# error "Port me"
307#endif
308 }
309 else
310 rc = RTErrConvertFromNtStatus(rcNt);
311
312 return rc;
313}
314
315
316RTDECL(int) RTShMemMapRegion(RTSHMEM hShMem, size_t offRegion, size_t cbRegion, uint32_t fFlags, void **ppv)
317{
318 PRTSHMEMINT pThis = hShMem;
319 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
320 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
321 AssertPtrReturn(ppv, VERR_INVALID_PARAMETER);
322 AssertReturn(!(fFlags & ~RTSHMEM_MAP_F_VALID_MASK), VERR_INVALID_PARAMETER);
323
324 /* See comment in RTShMemOpen(). */
325 if ( (fFlags & RTSHMEM_MAP_F_EXEC)
326 && g_enmWinVer < kRTWinOSType_7)
327 return VERR_NOT_SUPPORTED;
328
329 /* Try to find a mapping with compatible parameters first. */
330 PRTSHMEMMAPPINGDESC pMappingDesc = NULL;
331 for (uint32_t iTry = 0; iTry < 10; iTry++)
332 {
333 pMappingDesc = rtShMemMappingDescFindByProp(pThis, offRegion, cbRegion, fFlags);
334 if (!pMappingDesc)
335 break;
336
337 /* Increase the mapping count and check that the region is still accessible by us. */
338 if ( ASMAtomicIncU32(&pMappingDesc->cMappings) > 1
339 && pMappingDesc->offRegion == offRegion
340 && pMappingDesc->cbRegion == cbRegion
341 && pMappingDesc->fFlags == fFlags)
342 break;
343 /* Mapping was freed inbetween, next round. */
344 }
345
346 int rc = VINF_SUCCESS;
347 if (!pMappingDesc)
348 {
349 /* Find an empty region descriptor and map the region. */
350 for (uint32_t i = 0; i < pThis->cMappingDescsMax && !pMappingDesc; i++)
351 {
352 if (!pThis->aMappingDescs[i].cMappings)
353 {
354 pMappingDesc = &pThis->aMappingDescs[i];
355
356 /* Try to grab this one. */
357 if (ASMAtomicIncU32(&pMappingDesc->cMappings) == 1)
358 break;
359
360 /* Somebody raced us, drop reference and continue. */
361 ASMAtomicDecU32(&pMappingDesc->cMappings);
362 pMappingDesc = NULL;
363 }
364 }
365
366 if (RT_LIKELY(pMappingDesc))
367 {
368 /* Try to map it. */
369 DWORD fProt = 0;
370 DWORD offLow = offRegion & UINT32_C(0xffffffff);
371#if HC_ARCH_BITS == 64
372 DWORD offHigh = offRegion >> 32;
373#elif HC_ARCH_BITS == 32
374 DWORD offHigh = 0;
375#else
376# error "Port me"
377#endif
378 if (fFlags & RTSHMEM_MAP_F_READ)
379 fProt |= FILE_MAP_READ;
380 if (fFlags & RTSHMEM_MAP_F_WRITE)
381 fProt |= FILE_MAP_WRITE;
382 if (fFlags & RTSHMEM_MAP_F_EXEC)
383 fProt |= FILE_MAP_EXECUTE;
384 if (fFlags & RTSHMEM_MAP_F_COW)
385 fProt |= FILE_MAP_COPY;
386
387 void *pv = MapViewOfFile(pThis->hShmObj, fProt, offHigh, offLow, cbRegion);
388 if (pv != NULL)
389 {
390 pMappingDesc->pvMapping = pv;
391 pMappingDesc->offRegion = offRegion;
392 pMappingDesc->cbRegion = cbRegion;
393 pMappingDesc->fFlags = fFlags;
394 }
395 else
396 {
397 rc = RTErrConvertFromWin32(GetLastError());
398 ASMAtomicDecU32(&pMappingDesc->cMappings);
399 }
400 }
401 else
402 rc = VERR_SHMEM_MAXIMUM_MAPPINGS_REACHED;
403 }
404
405 if (RT_SUCCESS(rc))
406 {
407 *ppv = pMappingDesc->pvMapping;
408 ASMAtomicIncU32(&pThis->cMappings);
409 }
410
411 return rc;
412}
413
414
415RTDECL(int) RTShMemUnmapRegion(RTSHMEM hShMem, void *pv)
416{
417 PRTSHMEMINT pThis = hShMem;
418 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
419 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
420 AssertPtrReturn(pv, VERR_INVALID_PARAMETER);
421
422 /* Find the mapping descriptor by the given region address. */
423 PRTSHMEMMAPPINGDESC pMappingDesc = NULL;
424 for (uint32_t i = 0; i < pThis->cMappingDescsMax && !pMappingDesc; i++)
425 {
426 if (pThis->aMappingDescs[i].pvMapping == pv)
427 {
428 pMappingDesc = &pThis->aMappingDescs[i];
429 break;
430 }
431 }
432
433 AssertPtrReturn(pMappingDesc, VERR_INVALID_PARAMETER);
434
435 int rc = VINF_SUCCESS;
436 if (!ASMAtomicDecU32(&pMappingDesc->cMappings))
437 {
438 /* Last mapping of this region was unmapped, so do the real unmapping now. */
439 if (UnmapViewOfFile(pv))
440 {
441 ASMAtomicDecU32(&pThis->cMappingDescsUsed);
442 ASMAtomicDecU32(&pThis->cMappings);
443 }
444 else
445 {
446 ASMAtomicIncU32(&pMappingDesc->cMappings);
447 rc = RTErrConvertFromWin32(GetLastError());
448 }
449 }
450
451 return rc;
452}
453
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