VirtualBox

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

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

VBoxServiceVMInfo/PropCache: r=bird: todos in the code. Fixed two odd semaphore exit bugs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.5 KB
Line 
1/* $Id: VBoxServicePropCache.cpp 29026 2010-05-04 14:18:27Z 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
33/**
34 * Initializes the property cache.
35 *
36 * @returns IPRT status code.
37 * @param pCache Pointer to the cache.
38 * @param uClientId The HGCM handle of to the guest property service.
39 */
40int VBoxServicePropCacheInit(PVBOXSERVICEVEPROPCACHE pCache, uint32_t uClientId)
41{
42 AssertPtr(pCache);
43 /** @todo Prevent init the cache twice!
44 * r=bird: Use a magic, or/and abstract the whole cache by rename this function
45 * VBoxServicePropCacheCreate(). */
46 RTListInit(&pCache->Node);
47 pCache->uClientID = uClientId;
48 return RTSemMutexCreate(&pCache->Mutex);
49}
50
51
52/** @todo Docs
53 * @todo this looks internal to me, nobody should need to access the
54 * structures directly here. */
55PVBOXSERVICEVEPROPCACHEENTRY VBoxServicePropCacheFind(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName, uint32_t uFlags)
56{
57 AssertPtr(pCache);
58 AssertPtr(pszName);
59 /** @todo This is a O(n) lookup, maybe improve this later to O(1) using a
60 * map.
61 * r=bird: Use a string space (RTstrSpace*). That is O(log n) in its current
62 * implementation (AVL tree). However, this is not important at the
63 * moment. */
64 PVBOXSERVICEVEPROPCACHEENTRY pNodeIt, pNode = NULL;
65 if (RT_SUCCESS(RTSemMutexRequest(pCache->Mutex, RT_INDEFINITE_WAIT)))
66 {
67 RTListForEach(&pCache->Node, pNodeIt, VBOXSERVICEVEPROPCACHEENTRY, Node)
68 {
69 if (strcmp(pNodeIt->pszName, pszName) == 0)
70 {
71 pNode = pNodeIt;
72 break;
73 }
74 }
75 RTSemMutexRelease(pCache->Mutex);
76 }
77 return pNode;
78}
79
80
81/** @todo Docs */
82int VBoxServicePropCacheUpdateEntry(PVBOXSERVICEVEPROPCACHE pCache,
83 const char *pszName, uint32_t fFlags, const char *pszValueReset)
84{
85 AssertPtr(pCache);
86 AssertPtr(pszName);
87 PVBOXSERVICEVEPROPCACHEENTRY pNode = VBoxServicePropCacheFind(pCache, pszName, 0);
88 int rc;
89 if (pNode != NULL)
90 {
91 rc = RTSemMutexRequest(pCache->Mutex, RT_INDEFINITE_WAIT);
92 if (RT_SUCCESS(rc))
93 {
94 pNode->fFlags = fFlags;
95 if (pszValueReset)
96 {
97 if (pszValueReset)
98 RTStrFree(pNode->pszValueReset);
99 pNode->pszValueReset = RTStrDup(pszValueReset);
100 }
101 rc = RTSemMutexRelease(pCache->Mutex);
102 }
103 }
104 else
105 rc = VERR_NOT_FOUND;
106 return rc;
107}
108
109
110/**
111 * Updates the local guest property cache and writes it to HGCM if outdated.
112 *
113 * @returns VBox status code. Errors will be logged.
114 *
115 * @param pCache The property cache.
116 * @param pszName The property name.
117 * @param pszValueFormat The property format string. If this is NULL then
118 * the property will be deleted (if possible).
119 * @param ... Format arguments.
120 */
121int VBoxServicePropCacheUpdate(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName, const char *pszValueFormat, ...)
122{
123 char *pszValue = NULL;
124 int rc;
125 if (pszValueFormat)
126 {
127 va_list va;
128 va_start(va, pszValueFormat);
129 RTStrAPrintfV(&pszValue, pszValueFormat, va);
130 va_end(va);
131 }
132 rc = VBoxServicePropCacheUpdateEx(pCache, pszName, 0 /* Not used */, NULL /* Not used */, pszValue);
133 if (pszValue)
134 RTStrFree(pszValue);
135 return rc;
136}
137
138
139/**
140 * Updates the local guest property cache and writes it to HGCM if outdated.
141 *
142 * @returns VBox status code. Errors will be logged.
143 *
144 * @param pCache The property cache.
145 * @param pszName The property name.
146 * @param pszValueFormat The property format string. If this is NULL then
147 * the property will be deleted (if possible).
148 * @param ... Format arguments.
149 */
150int VBoxServicePropCacheUpdateEx(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName, uint32_t fFlags,
151 const char *pszValueReset, const char *pszValueFormat, ...)
152{
153 AssertPtr(pCache);
154 Assert(pCache->uClientID);
155 AssertPtr(pszName);
156
157 /*
158 * Format the value first.
159 */
160 char *pszValue = NULL;
161 if (pszValueFormat)
162 {
163 va_list va;
164 va_start(va, pszValueFormat);
165 RTStrAPrintfV(&pszValue, pszValueFormat, va);
166 va_end(va);
167 if (!pszValue)
168 return VERR_NO_STR_MEMORY;
169 }
170
171 PVBOXSERVICEVEPROPCACHEENTRY pNode = VBoxServicePropCacheFind(pCache, pszName, 0);
172
173 /* Lock the cache. */
174 int rc = RTSemMutexRequest(pCache->Mutex, RT_INDEFINITE_WAIT);
175 if (RT_SUCCESS(rc))
176 {
177
178 if (pNode == NULL)
179 {
180 pNode = (PVBOXSERVICEVEPROPCACHEENTRY)RTMemAlloc(sizeof(VBOXSERVICEVEPROPCACHEENTRY));
181 if (RT_UNLIKELY(!pNode))
182 {
183 RTSemMutexRelease(pCache->Mutex);
184 return VERR_NO_MEMORY;
185 }
186
187 pNode->pszName = RTStrDup(pszName);
188 pNode->pszValue = NULL;
189 pNode->fFlags = 0;
190 pNode->pszValueReset = NULL;
191
192 /*rc =*/ RTListAppend(&pCache->Node, &pNode->Node);
193 }
194
195 AssertPtr(pNode);
196 if (pszValue) /* Do we have a value to check for? */
197 {
198 bool fUpdate = false;
199 /* Always update this property, no matter what? */
200 if (pNode->fFlags & VBOXSERVICEPROPCACHEFLAG_ALWAYS_UPDATE)
201 fUpdate = true;
202 /* Did the value change so we have to update? */
203 else if (pNode->pszValue && strcmp(pNode->pszValue, pszValue) != 0)
204 fUpdate = true;
205 /* No value stored at the moment but we have a value now? */
206 else if (pNode->pszValue == NULL)
207 fUpdate = true;
208
209 if (fUpdate)
210 {
211 /* Write the update. */
212 rc = VBoxServiceWritePropF(pCache->uClientID, pNode->pszName, pszValue);
213 RTStrFree(pNode->pszValue);
214 pNode->pszValue = RTStrDup(pszValue);
215 }
216 else
217 /** @todo r=bird: Add a VINF_NO_CHANGE status code to iprt/err.h and use it. */
218 rc = VINF_ALREADY_INITIALIZED; /* No update needed. */
219 }
220 else
221 {
222 /* No value specified. Deletion (or no action required). */
223 if (pNode->pszValue) /* Did we have a value before? Then the value needs to be deleted. */
224 {
225 /* Delete property (but do not remove from cache) if not deleted yet. */
226 RTStrFree(pNode->pszValue);
227 pNode->pszValue = NULL;
228 rc = VBoxServiceWritePropF(pCache->uClientID, pNode->pszName, NULL);
229 }
230 else
231 /** @todo r=bird: Use VINF_NO_CHANGE. */
232 rc = VINF_ALREADY_INITIALIZED; /* No update needed. */
233 }
234
235 /* Update rest of the fields. */
236 if (pszValueReset)
237 {
238 if (pNode->pszValueReset)
239 RTStrFree(pNode->pszValueReset);
240 pNode->pszValueReset = RTStrDup(pszValueReset);
241 }
242 if (fFlags)
243 pNode->fFlags = fFlags;
244
245 /* Release cache. */
246 int rc2 = RTSemMutexRelease(pCache->Mutex);
247 if (RT_SUCCESS(rc))
248 rc2 = rc;
249 }
250
251 /* Delete temp stuff. */
252 RTStrFree(pszValue);
253
254 return rc;
255}
256
257
258/**
259 * Reset all temporary properties and destroy the cache.
260 *
261 * @param pCache The property cache.
262 */
263void VBoxServicePropCacheDestroy(PVBOXSERVICEVEPROPCACHE pCache)
264{
265 AssertPtr(pCache);
266 Assert(pCache->uClientID);
267 PVBOXSERVICEVEPROPCACHEENTRY pNode;
268 RTListForEach(&pCache->Node, pNode, VBOXSERVICEVEPROPCACHEENTRY, Node)
269 {
270 if ((pNode->fFlags & VBOXSERVICEPROPCACHEFLAG_TEMPORARY) == 0)
271 VBoxServiceWritePropF(pCache->uClientID, pNode->pszName, pNode->pszValueReset);
272
273 AssertPtr(pNode->pszName);
274 RTStrFree(pNode->pszName);
275 RTStrFree(pNode->pszValue);
276 RTStrFree(pNode->pszValueReset);
277 pNode->fFlags = 0;
278 }
279
280 pNode = RTListNodeGetFirst(&pCache->Node, VBOXSERVICEVEPROPCACHEENTRY, Node);
281 while (pNode)
282 {
283 PVBOXSERVICEVEPROPCACHEENTRY pNext = RTListNodeGetNext(&pNode->Node, VBOXSERVICEVEPROPCACHEENTRY, Node);
284 RTListNodeRemove(&pNode->Node);
285 /** @todo r=bird: hrm. missing RTMemFree(pNode)? Why don't you just combine the
286 * two loops? */
287
288 if (pNext && RTListNodeIsLast(&pCache->Node, &pNext->Node))
289 break;
290 pNode = pNext;
291 }
292
293 /* Destroy mutex. */
294 RTSemMutexDestroy(pCache->Mutex);
295}
296
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