VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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