VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServicePropCache.cpp@ 28983

Last change on this file since 28983 was 28983, checked in by vboxsync, 15 years ago

VBoxService/PropCache: Make it thread safe (for a global cache later).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.9 KB
Line 
1/* $Id: VBoxServicePropCache.cpp 28983 2010-05-03 14:55:34Z vboxsync $ */
2/** @file
3 * VBoxServicePropCache - Guest property cache.
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <iprt/assert.h>
23#include <iprt/list.h>
24#include <iprt/mem.h>
25#include <iprt/string.h>
26
27#include <VBox/VBoxGuestLib.h>
28#include "VBoxServiceInternal.h"
29#include "VBoxServiceUtils.h"
30#include "VBoxServicePropCache.h"
31
32#ifdef VBOX_WITH_GUEST_PROPS
33
34/** @todo Docs */
35int VBoxServicePropCacheInit(PVBOXSERVICEVEPROPCACHE pCache, uint32_t u32ClientId)
36{
37 AssertPtr(pCache);
38 /** @todo Prevent init the cache twice! */
39 RTListInit(&pCache->Node);
40 pCache->uClientID = u32ClientId;
41 return RTSemMutexCreate(&pCache->Mutex);
42}
43
44
45/** @todo Docs */
46PVBOXSERVICEVEPROPCACHEENTRY VBoxServicePropCacheFind(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName, uint32_t uFlags)
47{
48 AssertPtr(pCache);
49 AssertPtr(pszName);
50 /* This is a O(n) lookup, maybe improve this later to O(1) using a map. */
51 PVBOXSERVICEVEPROPCACHEENTRY pNodeIt, pNode = NULL;
52 if (RT_SUCCESS(RTSemMutexRequest(pCache->Mutex, RT_INDEFINITE_WAIT)))
53 {
54 RTListForEach(&pCache->Node, pNodeIt, VBOXSERVICEVEPROPCACHEENTRY, Node)
55 {
56 if (strcmp(pNodeIt->pszName, pszName) == 0)
57 {
58 pNode = pNodeIt;
59 break;
60 }
61 }
62 RTSemMutexRelease(pCache->Mutex);
63 }
64 return pNode;
65}
66
67
68/** @todo Docs */
69int VBoxServicePropCacheUpdateEntry(PVBOXSERVICEVEPROPCACHE pCache,
70 const char *pszName, uint32_t u32Flags, const char *pszValueReset)
71{
72 AssertPtr(pCache);
73 AssertPtr(pszName);
74 PVBOXSERVICEVEPROPCACHEENTRY pNode = VBoxServicePropCacheFind(pCache, pszName, 0);
75 int rc;
76 if (pNode != NULL)
77 {
78 rc = RTSemMutexRequest(pCache->Mutex, RT_INDEFINITE_WAIT);
79 if (RT_SUCCESS(rc))
80 {
81 pNode->uFlags = u32Flags;
82 if (pszValueReset)
83 {
84 if (pszValueReset)
85 RTStrFree(pNode->pszValueReset);
86 pNode->pszValueReset = RTStrDup(pszValueReset);
87 }
88 rc = RTSemMutexRelease(pCache->Mutex);
89 }
90 }
91 else
92 rc = VERR_NOT_FOUND;
93 return rc;
94}
95
96
97/**
98 * Updates the local guest property cache and writes it to HGCM if outdated.
99 *
100 * @returns VBox status code. Errors will be logged.
101 *
102 * @param u32ClientId The HGCM client ID for the guest property session.
103 * @param pszName The property name.
104 * @param pszValueFormat The property format string. If this is NULL then
105 * the property will be deleted (if possible).
106 * @param ... Format arguments.
107 */
108int VBoxServicePropCacheUpdate(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName, const char *pszValueFormat, ...)
109{
110 char *pszValue = NULL;
111 int rc;
112 if (pszValueFormat)
113 {
114 va_list va;
115 va_start(va, pszValueFormat);
116 RTStrAPrintfV(&pszValue, pszValueFormat, va);
117 va_end(va);
118 }
119 rc = VBoxServicePropCacheUpdateEx(pCache, pszName, 0 /* Not used */, NULL /* Not used */, pszValue);
120 if (pszValue)
121 RTStrFree(pszValue);
122 return rc;
123}
124
125
126/**
127 * Updates the local guest property cache and writes it to HGCM if outdated.
128 *
129 * @returns VBox status code. Errors will be logged.
130 *
131 * @param u32ClientId The HGCM client ID for the guest property session.
132 * @param pszName The property name.
133 * @param pszValueFormat The property format string. If this is NULL then
134 * the property will be deleted (if possible).
135 * @param ... Format arguments.
136 */
137int VBoxServicePropCacheUpdateEx(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName, uint32_t u32Flags, const char *pszValueReset, const char *pszValueFormat, ...)
138{
139 AssertPtr(pCache);
140 Assert(pCache->uClientID);
141 AssertPtr(pszName);
142
143 char *pszValue = NULL;
144 if (pszValueFormat)
145 {
146 va_list va;
147 va_start(va, pszValueFormat);
148 RTStrAPrintfV(&pszValue, pszValueFormat, va);
149 va_end(va);
150 }
151
152 PVBOXSERVICEVEPROPCACHEENTRY pNode = VBoxServicePropCacheFind(pCache, pszName, 0);
153
154 /* Lock the cache. */
155 int rc = RTSemMutexRequest(pCache->Mutex, RT_INDEFINITE_WAIT);
156 if (RT_SUCCESS(rc))
157 {
158
159 if (pNode == NULL)
160 {
161 pNode = (PVBOXSERVICEVEPROPCACHEENTRY)RTMemAlloc(sizeof(VBOXSERVICEVEPROPCACHEENTRY));
162 AssertPtrReturn(pNode, VERR_NO_MEMORY);
163
164 pNode->pszName = RTStrDup(pszName);
165 pNode->pszValue = NULL;
166 pNode->uFlags = 0;
167 pNode->pszValueReset = NULL;
168
169 /*rc =*/ RTListAppend(&pCache->Node, &pNode->Node);
170 }
171
172 AssertPtr(pNode);
173 if (pszValue) /* Do we have a value to check for? */
174 {
175 bool fUpdate = false;
176 /* Always update this property, no matter what? */
177 if (pNode->uFlags & VBOXSERVICEPROPCACHEFLAG_ALWAYS_UPDATE)
178 fUpdate = true;
179 /* Did the value change so we have to update? */
180 else if (pNode->pszValue && strcmp(pNode->pszValue, pszValue) != 0)
181 fUpdate = true;
182 /* No value stored at the moment but we have a value now? */
183 else if (pNode->pszValue == NULL)
184 fUpdate = true;
185
186 if (fUpdate)
187 {
188 /* Write the update. */
189 rc = VBoxServiceWritePropF(pCache->uClientID, pNode->pszName, pszValue);
190 if (pNode->pszValue)
191 RTStrFree(pNode->pszValue);
192 pNode->pszValue = RTStrDup(pszValue);
193 }
194 else
195 rc = VINF_ALREADY_INITIALIZED; /* No update needed. */
196 }
197 else
198 {
199 /* No value specified. Deletion (or no action required). */
200 if (pNode->pszValue) /* Did we have a value before? Then the value needs to be deleted. */
201 {
202 /* Delete property (but do not remove from cache) if not deleted yet. */
203 rc = VBoxServiceWritePropF(pCache->uClientID, pNode->pszName, NULL);
204 RTStrFree(pNode->pszValue);
205 pNode->pszValue = NULL;
206 }
207 else
208 rc = VINF_ALREADY_INITIALIZED; /* No update needed. */
209 }
210
211 /* Update rest of the fields. */
212 if (pszValueReset)
213 {
214 if (pNode->pszValueReset)
215 RTStrFree(pNode->pszValueReset);
216 pNode->pszValueReset = RTStrDup(pszValueReset);
217 }
218 if (u32Flags)
219 pNode->uFlags = u32Flags;
220
221 /* Delete temp stuff. */
222 if (pszValue)
223 RTStrFree(pszValue);
224
225 /* Release cache. */
226 int rc2 = RTSemMutexRelease(pCache->Mutex);
227 if (RT_SUCCESS(rc))
228 rc2 = rc;
229 }
230 return rc;
231}
232
233
234/** @todo Docs */
235void VBoxServicePropCacheDestroy(PVBOXSERVICEVEPROPCACHE pCache)
236{
237 AssertPtr(pCache);
238 Assert(pCache->uClientID);
239 PVBOXSERVICEVEPROPCACHEENTRY pNode;
240 RTListForEach(&pCache->Node, pNode, VBOXSERVICEVEPROPCACHEENTRY, Node)
241 {
242 if ((pNode->uFlags & VBOXSERVICEPROPCACHEFLAG_TEMPORARY) == 0)
243 {
244 if (pNode->pszValueReset) /* Write reset value? */
245 {
246 /* rc = */VBoxServiceWritePropF(pCache->uClientID, pNode->pszName, pNode->pszValueReset);
247 }
248 else /* Delete value. */
249 /* rc = */VBoxServiceWritePropF(pCache->uClientID, pNode->pszName, NULL);
250 }
251
252 AssertPtr(pNode->pszName);
253 RTStrFree(pNode->pszName);
254 if (pNode->pszValue)
255 RTStrFree(pNode->pszValue);
256 if (pNode->pszValueReset)
257 RTStrFree(pNode->pszValueReset);
258 pNode->uFlags = 0;
259 }
260
261 pNode = RTListNodeGetFirst(&pCache->Node, VBOXSERVICEVEPROPCACHEENTRY, Node);
262 while (pNode)
263 {
264 PVBOXSERVICEVEPROPCACHEENTRY pNext = RTListNodeGetNext(&pNode->Node, VBOXSERVICEVEPROPCACHEENTRY, Node);
265 RTListNodeRemove(&pNode->Node);
266 if (pNext && RTListNodeIsLast(&pCache->Node, &pNext->Node))
267 break;
268 pNode = pNext;
269 }
270 /* Destroy mutex. */
271 RTSemMutexDestroy(pCache->Mutex);
272}
273#endif /* VBOX_WITH_GUEST_PROPS */
Note: See TracBrowser for help on using the repository browser.

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