Changeset 18645 in vbox for trunk/src/VBox/VMM/VMMAll
- Timestamp:
- Apr 2, 2009 3:38:31 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/VMAll.cpp
r13832 r18645 30 30 #include <VBox/vm.h> 31 31 #include <VBox/err.h> 32 #include <VBox/log.h> 32 33 33 34 #include <iprt/assert.h> 34 35 #include <iprt/string.h> 36 #ifndef IN_RC 37 # include <iprt/thread.h> 38 #endif 35 39 36 40 … … 184 188 /** 185 189 * Sets the runtime error message. 190 * 186 191 * As opposed VMSetError(), this method is intended to inform the VM user about 187 192 * errors and error-like conditions that happen at an arbitrary point during VM 188 193 * execution (like "host memory low" or "out of host disk space"). 189 194 * 190 * The @a fFatal parameter defines whether the error is fatal or not. If it is 191 * true, then it is expected that the caller has already paused the VM execution 192 * before calling this method. The VM user is supposed to power off the VM 193 * immediately after it has received the runtime error notification via the 194 * FNVMATRUNTIMEERROR callback. 195 * 196 * If @a fFatal is false, then the paused state of the VM defines the kind of 197 * the error. If the VM is paused before calling this method, it means that 198 * the VM user may try to fix the error condition (i.e. free more host memory) 199 * and then resume the VM execution. If the VM is not paused before calling 200 * this method, it means that the given error is a warning about an error 201 * condition that may happen soon but that doesn't directly affect the 202 * VM execution by the time of the call. 203 * 204 * The @a pszErrorID parameter defines an unique error identificator. 205 * It is used by the front-ends to show a proper message to the end user 206 * containig possible actions (for example, Retry/Ignore). For this reason, 207 * an error ID assigned once to some particular error condition should not 208 * change in the future. The format of this parameter is "someErrorCondition". 209 * 210 * @param pVM VM handle. Must be non-NULL. 211 * @param fFatal Whether it is a fatal error or not. 212 * @param pszErrorID Error ID string. 195 * @returns VBox status code. For some flags the status code needs to be 196 * propagated up the stack, but this may depend on where the call was 197 * made. 198 * 199 * @param pVM The VM handle. 200 * 201 * @param fFlags Flags indicating which actions to take. 202 * See VMSETRTERR_FLAGS_* for details on each flag. 203 * 204 * @param pszErrorId Unique error identificator string. This is used by 205 * the frontends and maybe other devices or drivers, so 206 * once an ID has been selected it's essentially 207 * unchangable. Employ camelcase when constructing the 208 * string, leave out spaces. 209 * 210 * The registered runtime error callbacks should string 211 * switch on this and handle the ones it knows 212 * specifically and the unknown ones generically. 213 * 213 214 * @param pszFormat Error message format string. 214 215 * @param ... Error message arguments. 215 216 * 216 * @return VBox status code (whether the error has been successfully set217 * and delivered to callbacks or not).218 *219 217 * @thread Any 220 * @todo r=bird: The pausing/suspending of the VM should be done here, we'll just end 221 * up duplicating code all over the place otherwise. In the case of 222 * devices/drivers/etc they might not be trusted to pause/suspend the 223 * vm even. Change fFatal to fFlags and define action flags and a fatal flag. 224 * 225 * Also, why a string ID and not an enum? 226 */ 227 VMMDECL(int) VMSetRuntimeError(PVM pVM, bool fFatal, const char *pszErrorID, 228 const char *pszFormat, ...) 229 { 230 va_list args; 231 va_start(args, pszFormat); 232 int rc = VMSetRuntimeErrorV(pVM, fFatal, pszErrorID, pszFormat, args); 233 va_end(args); 218 */ 219 VMMDECL(int) VMSetRuntimeError(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...) 220 { 221 va_list va; 222 va_start(va, pszFormat); 223 int rc = VMSetRuntimeErrorV(pVM, fFlags, pszErrorId, pszFormat, va); 224 va_end(va); 234 225 return rc; 235 226 } … … 239 230 * va_list version of VMSetRuntimeError. 240 231 * 241 * @param pVM VM handle. Must be non-NULL. 242 * @param fFatal Whether it is a fatal error or not. 243 * @param pszErrorID Error ID string. 244 * @param pszFormat Error message format string. 245 * @param args Error message arguments. 246 * 247 * @return VBox status code (whether the error has been successfully set 248 * and delivered to callbacks or not). 232 * @returns VBox status code. For some flags the status code needs to be 233 * propagated up the stack, but this may depend on where the call was 234 * made. For most actions, there is a force action flag mopping up if 235 * the status code can't be propagated. 236 * 237 * @param pVM The VM handle. 238 * @param fFlags Flags indicating which actions to take. See 239 * VMSETRTERR_FLAGS_*. 240 * @param pszErrorId Error ID string. 241 * @param pszFormat Error message format string. 242 * @param va Error message arguments. 249 243 * 250 244 * @thread Any 251 245 */ 252 VMMDECL(int) VMSetRuntimeErrorV(PVM pVM, bool fFatal, const char *pszErrorID, 253 const char *pszFormat, va_list args) 254 { 246 VMMDECL(int) VMSetRuntimeErrorV(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va) 247 { 248 Log(("VMSetRuntimeErrorV: fFlags=%#x pszErrorId=%s\n", fFlags, pszErrorId)); 249 250 /* 251 * Relaxed parameter validation. 252 */ 253 AssertPtr(pVM); 254 AssertMsg(fFlags & ~(VMSETRTERR_FLAGS_NO_WAIT | VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_FATAL), ("%#x\n", fFlags)); 255 Assert(!(fFlags & VMSETRTERR_FLAGS_NO_WAIT) || !VM_IS_EMT(pVM)); 256 Assert(!(fFlags & VMSETRTERR_FLAGS_SUSPEND) || !(fFlags & VMSETRTERR_FLAGS_FATAL)); 257 AssertPtr(pszErrorId); 258 Assert(*pszErrorId); 259 Assert(memchr(pszErrorId, '\0', 128) != NULL); 260 AssertPtr(pszFormat); 261 Assert(memchr(pszFormat, '\0', 512) != NULL); 262 255 263 #ifdef IN_RING3 256 264 /* … … 258 266 */ 259 267 va_list va2; 260 va_copy(va2, args); /* Have to make a copy here or GCC will break. */ 268 va_copy(va2, va); /* Have to make a copy here or GCC will break. */ 269 int rc; 261 270 PVMREQ pReq; 262 VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3SetRuntimeErrorV, 5, 263 pVM, fFatal, pszErrorID, pszFormat, &va2); 271 if ( !(fFlags & VMSETRTERR_FLAGS_NO_WAIT) 272 || VM_IS_EMT(pVM)) 273 { 274 rc = VMR3ReqCallU(pVM->pUVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, VMREQFLAGS_VBOX_STATUS, 275 (PFNRT)vmR3SetRuntimeErrorV, 5, pVM, fFlags, pszErrorId, pszFormat, &va2); 276 if (RT_SUCCESS(rc)) 277 rc = pReq->iStatus; 278 } 279 else 280 rc = VMR3ReqCallU(pVM->pUVM, VMREQDEST_ANY, &pReq, 0, VMREQFLAGS_VBOX_STATUS | VMREQFLAGS_NO_WAIT, 281 (PFNRT)vmR3SetRuntimeErrorV, 5, pVM, fFlags, pszErrorId, pszFormat, &va2); 264 282 VMR3ReqFree(pReq); 265 283 va_end(va2); … … 267 285 #else 268 286 /* 269 * We're already on the EMT thread and can safely create a VMRUNTIMEERROR chunk. 270 */ 271 vmSetRuntimeErrorCopy(pVM, fFatal, pszErrorID, pszFormat, args); 287 * We're already on the EMT and can safely create a VMRUNTIMEERROR chunk. 288 */ 289 AssertReleaseMsgFailed(("Congratulations! You will have the pleasure of debugging the RC/R0 path.\n")); 290 vmSetRuntimeErrorCopy(pVM, fFlags, pszErrorId, pszFormat, va); 272 291 273 292 # ifdef IN_RC 274 VMMGCCallHost(pVM, VMMCALLHOST_VM_SET_RUNTIME_ERROR, 0); 275 # elif defined(IN_RING0) 276 VMMR0CallHost(pVM, VMMCALLHOST_VM_SET_RUNTIME_ERROR, 0); 293 int rc = VMMGCCallHost(pVM, VMMCALLHOST_VM_SET_RUNTIME_ERROR, 0); 277 294 # else 295 int rc = VMMR0CallHost(pVM, VMMCALLHOST_VM_SET_RUNTIME_ERROR, 0); 278 296 # endif 279 297 #endif 280 return VINF_SUCCESS; 298 299 Log(("VMSetRuntimeErrorV: returns %Rrc (pszErrorId=%s)\n", rc, pszErrorId)); 300 return rc; 281 301 } 282 302 … … 285 305 * Copies the error to a VMRUNTIMEERROR structure. 286 306 * 287 * This is mainly intended for Ring-0 and GC where the error must be copied to307 * This is mainly intended for Ring-0 and RC where the error must be copied to 288 308 * memory accessible from ring-3. But it's just possible that we might add 289 309 * APIs for retrieving the VMRUNTIMEERROR copy later. 290 310 * 291 311 * @param pVM VM handle. Must be non-NULL. 292 * @param fFatal Whether it is a fatal error or not. 293 * @param pszErrorID Error ID string. 294 * @param pszFormat Error message format string. 295 * @param args Error message arguments. 312 * @param fFlags The error flags. 313 * @param pszErrorId Error ID string. 314 * @param pszFormat Error message format string. 315 * @param va Error message arguments. This is of course spoiled 316 * by this call. 296 317 * @thread EMT 297 318 */ 298 void vmSetRuntimeErrorCopy(PVM pVM, bool fFatal, const char *pszErrorID, 299 const char *pszFormat, va_list args) 319 void vmSetRuntimeErrorCopy(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va) 300 320 { 301 321 #if 0 /// @todo implement Ring-0 and GC VMSetError … … 308 328 309 329 /* calc reasonable start size. */ 310 size_t cchErrorID = pszErrorI D ? strlen(pszErrorID) : 0;330 size_t cchErrorID = pszErrorId ? strlen(pszErrorId) : 0; 311 331 size_t cchFormat = strlen(pszFormat); 312 332 size_t cb = sizeof(VMRUNTIMEERROR) … … 322 342 PVMRUNTIMEERROR pErr = (PVMRUNTIMEERROR)pv; 323 343 pErr->cbAllocated = cb; 344 pErr->fFlags = fFlags; 324 345 pErr->off = sizeof(PVMRUNTIMEERROR); 325 pErr->offErrorID = =0;346 pErr->offErrorID = 0; 326 347 327 348 if (cchErrorID) 328 349 { 329 350 pErr->offErrorID = pErr->off; 330 memcpy((uint8_t *)pErr + pErr->off, pszErrorI D, cchErrorID + 1);351 memcpy((uint8_t *)pErr + pErr->off, pszErrorId, cchErrorID + 1); 331 352 pErr->off += cchErrorID + 1; 332 353 }
Note:
See TracChangeset
for help on using the changeset viewer.