mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
Thread local error reporting
This commit is contained in:
parent
c790f6d25e
commit
ead04dcbe8
17
ChangeLog
17
ChangeLog
@ -1,3 +1,20 @@
|
|||||||
|
Tue Jan 20 12:01:53 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
|
Thread local error handling
|
||||||
|
* src/datatypes.c: Don't reference global error object directly
|
||||||
|
now that it is thread-local. Avoid passing 'conn' arg to error
|
||||||
|
routines if we just determined that the pointer is invalid
|
||||||
|
* src/datatypes.h: Add note about rules for locking when using
|
||||||
|
virConnectPtr members
|
||||||
|
* src/libvirt.c: Initialize error handling routines at startup.
|
||||||
|
Adapt driver API methods to reset last error upon entry, and
|
||||||
|
copy the global thread local error to the per-connection error
|
||||||
|
upon exit
|
||||||
|
* src/virterror.c, src/virterror_internal.h: Store the global
|
||||||
|
error object in a thread local variable. Provide a API to copy
|
||||||
|
the global error into a per-connection error object. Add an
|
||||||
|
initialization routine to setup the thread local
|
||||||
|
|
||||||
Tue Jan 20 11:43:53 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
|
Tue Jan 20 11:43:53 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
* src/remote_internal.c: Disable event watch when doing an
|
* src/remote_internal.c: Disable event watch when doing an
|
||||||
|
@ -195,8 +195,6 @@ virReleaseConnect(virConnectPtr conn) {
|
|||||||
virHashFree(conn->nodeDevices, (virHashDeallocator) virNodeDeviceFree);
|
virHashFree(conn->nodeDevices, (virHashDeallocator) virNodeDeviceFree);
|
||||||
|
|
||||||
virResetError(&conn->err);
|
virResetError(&conn->err);
|
||||||
if (virLastErr.conn == conn)
|
|
||||||
virLastErr.conn = NULL;
|
|
||||||
|
|
||||||
xmlFreeURI(conn->uri);
|
xmlFreeURI(conn->uri);
|
||||||
|
|
||||||
@ -219,7 +217,7 @@ virUnrefConnect(virConnectPtr conn) {
|
|||||||
int refs;
|
int refs;
|
||||||
|
|
||||||
if ((!VIR_IS_CONNECT(conn))) {
|
if ((!VIR_IS_CONNECT(conn))) {
|
||||||
virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
virMutexLock(&conn->lock);
|
virMutexLock(&conn->lock);
|
||||||
@ -253,7 +251,7 @@ virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) {
|
|||||||
virDomainPtr ret = NULL;
|
virDomainPtr ret = NULL;
|
||||||
|
|
||||||
if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) {
|
if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) {
|
||||||
virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
virMutexLock(&conn->lock);
|
virMutexLock(&conn->lock);
|
||||||
@ -323,10 +321,6 @@ virReleaseDomain(virDomainPtr domain) {
|
|||||||
virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
|
virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
_("domain missing from connection hash table"));
|
_("domain missing from connection hash table"));
|
||||||
|
|
||||||
if (conn->err.dom == domain)
|
|
||||||
conn->err.dom = NULL;
|
|
||||||
if (virLastErr.dom == domain)
|
|
||||||
virLastErr.dom = NULL;
|
|
||||||
domain->magic = -1;
|
domain->magic = -1;
|
||||||
domain->id = -1;
|
domain->id = -1;
|
||||||
VIR_FREE(domain->name);
|
VIR_FREE(domain->name);
|
||||||
@ -358,7 +352,7 @@ virUnrefDomain(virDomainPtr domain) {
|
|||||||
int refs;
|
int refs;
|
||||||
|
|
||||||
if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
|
if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
|
||||||
virLibConnError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
virMutexLock(&domain->conn->lock);
|
virMutexLock(&domain->conn->lock);
|
||||||
@ -393,7 +387,7 @@ virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) {
|
|||||||
virNetworkPtr ret = NULL;
|
virNetworkPtr ret = NULL;
|
||||||
|
|
||||||
if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) {
|
if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) {
|
||||||
virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
virMutexLock(&conn->lock);
|
virMutexLock(&conn->lock);
|
||||||
@ -459,11 +453,6 @@ virReleaseNetwork(virNetworkPtr network) {
|
|||||||
virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
|
virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
_("network missing from connection hash table"));
|
_("network missing from connection hash table"));
|
||||||
|
|
||||||
if (conn->err.net == network)
|
|
||||||
conn->err.net = NULL;
|
|
||||||
if (virLastErr.net == network)
|
|
||||||
virLastErr.net = NULL;
|
|
||||||
|
|
||||||
network->magic = -1;
|
network->magic = -1;
|
||||||
VIR_FREE(network->name);
|
VIR_FREE(network->name);
|
||||||
VIR_FREE(network);
|
VIR_FREE(network);
|
||||||
@ -494,7 +483,7 @@ virUnrefNetwork(virNetworkPtr network) {
|
|||||||
int refs;
|
int refs;
|
||||||
|
|
||||||
if (!VIR_IS_CONNECTED_NETWORK(network)) {
|
if (!VIR_IS_CONNECTED_NETWORK(network)) {
|
||||||
virLibConnError(network->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
virMutexLock(&network->conn->lock);
|
virMutexLock(&network->conn->lock);
|
||||||
@ -530,7 +519,7 @@ virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *uui
|
|||||||
virStoragePoolPtr ret = NULL;
|
virStoragePoolPtr ret = NULL;
|
||||||
|
|
||||||
if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) {
|
if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) {
|
||||||
virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
virMutexLock(&conn->lock);
|
virMutexLock(&conn->lock);
|
||||||
@ -627,7 +616,7 @@ virUnrefStoragePool(virStoragePoolPtr pool) {
|
|||||||
int refs;
|
int refs;
|
||||||
|
|
||||||
if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
|
if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
|
||||||
virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
virMutexLock(&pool->conn->lock);
|
virMutexLock(&pool->conn->lock);
|
||||||
@ -664,7 +653,7 @@ virGetStorageVol(virConnectPtr conn, const char *pool, const char *name, const c
|
|||||||
virStorageVolPtr ret = NULL;
|
virStorageVolPtr ret = NULL;
|
||||||
|
|
||||||
if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (key == NULL)) {
|
if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (key == NULL)) {
|
||||||
virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
virMutexLock(&conn->lock);
|
virMutexLock(&conn->lock);
|
||||||
@ -765,7 +754,7 @@ virUnrefStorageVol(virStorageVolPtr vol) {
|
|||||||
int refs;
|
int refs;
|
||||||
|
|
||||||
if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) {
|
if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) {
|
||||||
virLibConnError(vol->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
virMutexLock(&vol->conn->lock);
|
virMutexLock(&vol->conn->lock);
|
||||||
@ -801,7 +790,7 @@ virGetNodeDevice(virConnectPtr conn, const char *name)
|
|||||||
virNodeDevicePtr ret = NULL;
|
virNodeDevicePtr ret = NULL;
|
||||||
|
|
||||||
if ((!VIR_IS_CONNECT(conn)) || (name == NULL)) {
|
if ((!VIR_IS_CONNECT(conn)) || (name == NULL)) {
|
||||||
virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
virMutexLock(&conn->lock);
|
virMutexLock(&conn->lock);
|
||||||
|
@ -95,6 +95,10 @@
|
|||||||
* Internal structure associated to a connection
|
* Internal structure associated to a connection
|
||||||
*/
|
*/
|
||||||
struct _virConnect {
|
struct _virConnect {
|
||||||
|
/* All the variables from here, until the 'lock' declaration
|
||||||
|
* are setup at time of connection open, and never changed
|
||||||
|
* since. Thus no need to lock when accessing them
|
||||||
|
*/
|
||||||
unsigned int magic; /* specific value to check */
|
unsigned int magic; /* specific value to check */
|
||||||
int flags; /* a set of connection flags */
|
int flags; /* a set of connection flags */
|
||||||
xmlURIPtr uri; /* connection URI */
|
xmlURIPtr uri; /* connection URI */
|
||||||
@ -114,11 +118,6 @@ struct _virConnect {
|
|||||||
void * storagePrivateData;
|
void * storagePrivateData;
|
||||||
void * devMonPrivateData;
|
void * devMonPrivateData;
|
||||||
|
|
||||||
/* Per-connection error. */
|
|
||||||
virError err; /* the last error */
|
|
||||||
virErrorFunc handler; /* associated handlet */
|
|
||||||
void *userData; /* the user data */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The lock mutex must be acquired before accessing/changing
|
* The lock mutex must be acquired before accessing/changing
|
||||||
* any of members following this point, or changing the ref
|
* any of members following this point, or changing the ref
|
||||||
@ -126,6 +125,12 @@ struct _virConnect {
|
|||||||
* this connection
|
* this connection
|
||||||
*/
|
*/
|
||||||
virMutex lock;
|
virMutex lock;
|
||||||
|
|
||||||
|
/* Per-connection error. */
|
||||||
|
virError err; /* the last error */
|
||||||
|
virErrorFunc handler; /* associated handlet */
|
||||||
|
void *userData; /* the user data */
|
||||||
|
|
||||||
virHashTablePtr domains; /* hash table for known domains */
|
virHashTablePtr domains; /* hash table for known domains */
|
||||||
virHashTablePtr networks; /* hash table for known domains */
|
virHashTablePtr networks; /* hash table for known domains */
|
||||||
virHashTablePtr storagePools;/* hash table for known storage pools */
|
virHashTablePtr storagePools;/* hash table for known storage pools */
|
||||||
|
2118
src/libvirt.c
2118
src/libvirt.c
File diff suppressed because it is too large
Load Diff
258
src/virterror.c
258
src/virterror.c
@ -18,11 +18,11 @@
|
|||||||
#include "virterror_internal.h"
|
#include "virterror_internal.h"
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "threads.h"
|
||||||
|
|
||||||
|
virThreadLocal virLastErr;
|
||||||
|
|
||||||
virError virLastErr = /* the last error */
|
|
||||||
{ .code = 0, .domain = 0, .message = NULL, .level = VIR_ERR_NONE,
|
|
||||||
.conn = NULL, .dom = NULL, .str1 = NULL, .str2 = NULL, .str3 = NULL,
|
|
||||||
.int1 = 0, .int2 = 0, .net = NULL };
|
|
||||||
virErrorFunc virErrorHandler = NULL; /* global error handler */
|
virErrorFunc virErrorHandler = NULL; /* global error handler */
|
||||||
void *virUserData = NULL; /* associated data */
|
void *virUserData = NULL; /* associated data */
|
||||||
|
|
||||||
@ -154,28 +154,118 @@ static const char *virErrorDomainName(virErrorDomain domain) {
|
|||||||
return(dom);
|
return(dom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* Internal helper that is called when a thread exits, to
|
||||||
|
* release the error object stored in the thread local
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
virLastErrFreeData(void *data)
|
||||||
|
{
|
||||||
|
virErrorPtr err = data;
|
||||||
|
if (!err)
|
||||||
|
return;
|
||||||
|
virResetError(err);
|
||||||
|
VIR_FREE(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
virErrorInitialize(void)
|
||||||
|
{
|
||||||
|
return virThreadLocalInit(&virLastErr, virLastErrFreeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal helper to ensure a generic error code is stored
|
||||||
|
* in case where API returns failure, but forgot to set an
|
||||||
|
* error
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
virErrorGenericFailure(virErrorPtr err)
|
||||||
|
{
|
||||||
|
err->code = VIR_ERR_INTERNAL_ERROR;
|
||||||
|
err->domain = VIR_FROM_NONE;
|
||||||
|
err->level = VIR_ERR_ERROR;
|
||||||
|
err->message = strdup(_("Unknown failure"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal helper to perform a deep copy of the an error
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
virCopyError(virErrorPtr from,
|
||||||
|
virErrorPtr to)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
if (!to)
|
||||||
|
return 0;
|
||||||
|
virResetError(to);
|
||||||
|
if (!from)
|
||||||
|
return 0;
|
||||||
|
to->code = from->code;
|
||||||
|
to->domain = from->domain;
|
||||||
|
to->level = from->level;
|
||||||
|
if (from->message && !(to->message = strdup(from->message)))
|
||||||
|
ret = -1;
|
||||||
|
if (from->str1 && !(to->str1 = strdup(from->str1)))
|
||||||
|
ret = -1;
|
||||||
|
if (from->str2 && !(to->str2 = strdup(from->str2)))
|
||||||
|
ret = -1;
|
||||||
|
if (from->str3 && !(to->str3 = strdup(from->str3)))
|
||||||
|
ret = -1;
|
||||||
|
to->int1 = from->int1;
|
||||||
|
to->int2 = from->int2;
|
||||||
|
/*
|
||||||
|
* Delibrately not setting 'conn', 'dom', 'net' references
|
||||||
|
*/
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static virErrorPtr
|
||||||
|
virLastErrorObject(void)
|
||||||
|
{
|
||||||
|
virErrorPtr err;
|
||||||
|
err = virThreadLocalGet(&virLastErr);
|
||||||
|
if (!err) {
|
||||||
|
if (VIR_ALLOC(err) < 0)
|
||||||
|
return NULL;
|
||||||
|
virThreadLocalSet(&virLastErr, err);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
* virGetLastError:
|
* virGetLastError:
|
||||||
*
|
*
|
||||||
* Provide a pointer to the last error caught at the library level
|
* Provide a pointer to the last error caught at the library level
|
||||||
* Simpler but may not be suitable for multithreaded accesses, in which
|
*
|
||||||
* case use virCopyLastError()
|
* The error object is kept in thread local storage, so separate
|
||||||
|
* threads can safely access this concurrently.
|
||||||
*
|
*
|
||||||
* Returns a pointer to the last error or NULL if none occurred.
|
* Returns a pointer to the last error or NULL if none occurred.
|
||||||
*/
|
*/
|
||||||
virErrorPtr
|
virErrorPtr
|
||||||
virGetLastError(void)
|
virGetLastError(void)
|
||||||
{
|
{
|
||||||
if (virLastErr.code == VIR_ERR_OK)
|
virErrorPtr err = virLastErrorObject();
|
||||||
return (NULL);
|
if (!err || err->code == VIR_ERR_OK)
|
||||||
return (&virLastErr);
|
return NULL;
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* virCopyLastError:
|
* virCopyLastError:
|
||||||
* @to: target to receive the copy
|
* @to: target to receive the copy
|
||||||
*
|
*
|
||||||
* Copy the content of the last error caught at the library level
|
* Copy the content of the last error caught at the library level
|
||||||
|
*
|
||||||
|
* The error object is kept in thread local storage, so separate
|
||||||
|
* threads can safely access this concurrently.
|
||||||
|
*
|
||||||
* One will need to free the result with virResetError()
|
* One will need to free the result with virResetError()
|
||||||
*
|
*
|
||||||
* Returns 0 if no error was found and the error code otherwise and -1 in case
|
* Returns 0 if no error was found and the error code otherwise and -1 in case
|
||||||
@ -184,12 +274,14 @@ virGetLastError(void)
|
|||||||
int
|
int
|
||||||
virCopyLastError(virErrorPtr to)
|
virCopyLastError(virErrorPtr to)
|
||||||
{
|
{
|
||||||
if (to == NULL)
|
virErrorPtr err = virLastErrorObject();
|
||||||
return (-1);
|
/* We can't guarentee caller has initialized it to zero */
|
||||||
if (virLastErr.code == VIR_ERR_OK)
|
memset(to, 0, sizeof(*to));
|
||||||
return (0);
|
if (err)
|
||||||
memcpy(to, &virLastErr, sizeof(virError));
|
virCopyError(err, to);
|
||||||
return (virLastErr.code);
|
else
|
||||||
|
virResetError(to);
|
||||||
|
return to->code;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -210,15 +302,22 @@ virResetError(virErrorPtr err)
|
|||||||
memset(err, 0, sizeof(virError));
|
memset(err, 0, sizeof(virError));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virResetLastError:
|
* virResetLastError:
|
||||||
*
|
*
|
||||||
* Reset the last error caught at the library level.
|
* Reset the last error caught at the library level.
|
||||||
|
*
|
||||||
|
* The error object is kept in thread local storage, so separate
|
||||||
|
* threads can safely access this concurrently, only resetting
|
||||||
|
* their own error object.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
virResetLastError(void)
|
virResetLastError(void)
|
||||||
{
|
{
|
||||||
virResetError(&virLastErr);
|
virErrorPtr err = virLastErrorObject();
|
||||||
|
if (err)
|
||||||
|
virResetError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -226,8 +325,20 @@ virResetLastError(void)
|
|||||||
* @conn: pointer to the hypervisor connection
|
* @conn: pointer to the hypervisor connection
|
||||||
*
|
*
|
||||||
* Provide a pointer to the last error caught on that connection
|
* Provide a pointer to the last error caught on that connection
|
||||||
* Simpler but may not be suitable for multithreaded accesses, in which
|
*
|
||||||
* case use virConnCopyLastError()
|
* This method is not protected against access from multiple
|
||||||
|
* threads. In a multi-threaded application, always use the
|
||||||
|
* global virGetLastError() API which is backed by thread
|
||||||
|
* local storage.
|
||||||
|
*
|
||||||
|
* If the connection object was discovered to be invalid by
|
||||||
|
* an API call, then the error will be reported against the
|
||||||
|
* global error object.
|
||||||
|
*
|
||||||
|
* Since 0.6.0, all errors reported in the per-connection object
|
||||||
|
* are also duplicated in the global error object. As such an
|
||||||
|
* application can always use virGetLastError(). This method
|
||||||
|
* remains for backwards compatability.
|
||||||
*
|
*
|
||||||
* Returns a pointer to the last error or NULL if none occurred.
|
* Returns a pointer to the last error or NULL if none occurred.
|
||||||
*/
|
*/
|
||||||
@ -235,8 +346,8 @@ virErrorPtr
|
|||||||
virConnGetLastError(virConnectPtr conn)
|
virConnGetLastError(virConnectPtr conn)
|
||||||
{
|
{
|
||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return (NULL);
|
return NULL;
|
||||||
return (&conn->err);
|
return &conn->err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -245,6 +356,21 @@ virConnGetLastError(virConnectPtr conn)
|
|||||||
* @to: target to receive the copy
|
* @to: target to receive the copy
|
||||||
*
|
*
|
||||||
* Copy the content of the last error caught on that connection
|
* Copy the content of the last error caught on that connection
|
||||||
|
*
|
||||||
|
* This method is not protected against access from multiple
|
||||||
|
* threads. In a multi-threaded application, always use the
|
||||||
|
* global virGetLastError() API which is backed by thread
|
||||||
|
* local storage.
|
||||||
|
*
|
||||||
|
* If the connection object was discovered to be invalid by
|
||||||
|
* an API call, then the error will be reported against the
|
||||||
|
* global error object.
|
||||||
|
*
|
||||||
|
* Since 0.6.0, all errors reported in the per-connection object
|
||||||
|
* are also duplicated in the global error object. As such an
|
||||||
|
* application can always use virGetLastError(). This method
|
||||||
|
* remains for backwards compatability.
|
||||||
|
*
|
||||||
* One will need to free the result with virResetError()
|
* One will need to free the result with virResetError()
|
||||||
*
|
*
|
||||||
* Returns 0 if no error was found and the error code otherwise and -1 in case
|
* Returns 0 if no error was found and the error code otherwise and -1 in case
|
||||||
@ -253,20 +379,27 @@ virConnGetLastError(virConnectPtr conn)
|
|||||||
int
|
int
|
||||||
virConnCopyLastError(virConnectPtr conn, virErrorPtr to)
|
virConnCopyLastError(virConnectPtr conn, virErrorPtr to)
|
||||||
{
|
{
|
||||||
|
/* We can't guarentee caller has initialized it to zero */
|
||||||
|
memset(to, 0, sizeof(*to));
|
||||||
|
|
||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return (-1);
|
return -1;
|
||||||
if (to == NULL)
|
virMutexLock(&conn->lock);
|
||||||
return (-1);
|
|
||||||
if (conn->err.code == VIR_ERR_OK)
|
if (conn->err.code == VIR_ERR_OK)
|
||||||
return (0);
|
virResetError(to);
|
||||||
memcpy(to, &conn->err, sizeof(virError));
|
else
|
||||||
return (conn->err.code);
|
virCopyError(&conn->err, to);
|
||||||
|
virMutexUnlock(&conn->lock);
|
||||||
|
return to->code;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virConnResetLastError:
|
* virConnResetLastError:
|
||||||
* @conn: pointer to the hypervisor connection
|
* @conn: pointer to the hypervisor connection
|
||||||
*
|
*
|
||||||
|
* The error object is kept in thread local storage, so separate
|
||||||
|
* threads can safely access this concurrently.
|
||||||
|
*
|
||||||
* Reset the last error caught on that connection
|
* Reset the last error caught on that connection
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@ -274,7 +407,9 @@ virConnResetLastError(virConnectPtr conn)
|
|||||||
{
|
{
|
||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return;
|
return;
|
||||||
|
virMutexLock(&conn->lock);
|
||||||
virResetError(&conn->err);
|
virResetError(&conn->err);
|
||||||
|
virMutexUnlock(&conn->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -309,8 +444,10 @@ virConnSetErrorFunc(virConnectPtr conn, void *userData,
|
|||||||
{
|
{
|
||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return;
|
return;
|
||||||
|
virMutexLock(&conn->lock);
|
||||||
conn->handler = handler;
|
conn->handler = handler;
|
||||||
conn->userData = userData;
|
conn->userData = userData;
|
||||||
|
virMutexUnlock(&conn->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -357,6 +494,44 @@ virDefaultErrorFunc(virErrorPtr err)
|
|||||||
dom, lvl, domain, network, err->message);
|
dom, lvl, domain, network, err->message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal helper to ensure the global error object
|
||||||
|
* is initialized with a generic message if not already
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
virSetGlobalError(void)
|
||||||
|
{
|
||||||
|
virErrorPtr err = virLastErrorObject();
|
||||||
|
|
||||||
|
if (err && err->code == VIR_ERR_OK)
|
||||||
|
virErrorGenericFailure(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal helper to ensure the connection error object
|
||||||
|
* is initialized from the global object.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
virSetConnError(virConnectPtr conn)
|
||||||
|
{
|
||||||
|
virErrorPtr err = virLastErrorObject();
|
||||||
|
|
||||||
|
if (err && err->code == VIR_ERR_OK)
|
||||||
|
virErrorGenericFailure(err);
|
||||||
|
|
||||||
|
if (conn) {
|
||||||
|
virMutexLock(&conn->lock);
|
||||||
|
if (err)
|
||||||
|
virCopyError(err, &conn->err);
|
||||||
|
else
|
||||||
|
virErrorGenericFailure(&conn->err);
|
||||||
|
virMutexUnlock(&conn->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virRaiseError:
|
* virRaiseError:
|
||||||
* @conn: the connection to the hypervisor if available
|
* @conn: the connection to the hypervisor if available
|
||||||
@ -377,16 +552,29 @@ virDefaultErrorFunc(virErrorPtr err)
|
|||||||
* immediately if a callback is found and store it for later handling.
|
* immediately if a callback is found and store it for later handling.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
virRaiseError(virConnectPtr conn, virDomainPtr dom, virNetworkPtr net,
|
virRaiseError(virConnectPtr conn,
|
||||||
|
virDomainPtr dom ATTRIBUTE_UNUSED,
|
||||||
|
virNetworkPtr net ATTRIBUTE_UNUSED,
|
||||||
int domain, int code, virErrorLevel level,
|
int domain, int code, virErrorLevel level,
|
||||||
const char *str1, const char *str2, const char *str3,
|
const char *str1, const char *str2, const char *str3,
|
||||||
int int1, int int2, const char *msg, ...)
|
int int1, int int2, const char *msg, ...)
|
||||||
{
|
{
|
||||||
virErrorPtr to = &virLastErr;
|
virErrorPtr to;
|
||||||
void *userData = virUserData;
|
void *userData = virUserData;
|
||||||
virErrorFunc handler = virErrorHandler;
|
virErrorFunc handler = virErrorHandler;
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All errors are recorded in thread local storage
|
||||||
|
* For compatability, public API calls will copy them
|
||||||
|
* to the per-connection error object when neccessary
|
||||||
|
*/
|
||||||
|
to = virLastErrorObject();
|
||||||
|
if (!to)
|
||||||
|
return; /* Hit OOM allocating thread error object, sod all we can do now */
|
||||||
|
|
||||||
|
virResetError(to);
|
||||||
|
|
||||||
if (code == VIR_ERR_OK)
|
if (code == VIR_ERR_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -394,11 +582,12 @@ virRaiseError(virConnectPtr conn, virDomainPtr dom, virNetworkPtr net,
|
|||||||
* try to find the best place to save and report the error
|
* try to find the best place to save and report the error
|
||||||
*/
|
*/
|
||||||
if (conn != NULL) {
|
if (conn != NULL) {
|
||||||
to = &conn->err;
|
virMutexLock(&conn->lock);
|
||||||
if (conn->handler != NULL) {
|
if (conn->handler != NULL) {
|
||||||
handler = conn->handler;
|
handler = conn->handler;
|
||||||
userData = conn->userData;
|
userData = conn->userData;
|
||||||
}
|
}
|
||||||
|
virMutexUnlock(&conn->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -421,9 +610,10 @@ virRaiseError(virConnectPtr conn, virDomainPtr dom, virNetworkPtr net,
|
|||||||
* Save the information about the error
|
* Save the information about the error
|
||||||
*/
|
*/
|
||||||
virResetError(to);
|
virResetError(to);
|
||||||
to->conn = conn;
|
/*
|
||||||
to->dom = dom;
|
* Delibrately not setting conn, dom & net fields since
|
||||||
to->net = net;
|
* they're utterly unsafe
|
||||||
|
*/
|
||||||
to->domain = domain;
|
to->domain = domain;
|
||||||
to->code = code;
|
to->code = code;
|
||||||
to->message = str;
|
to->message = str;
|
||||||
@ -813,3 +1003,5 @@ void virReportErrorHelper(virConnectPtr conn, int domcode, int errcode,
|
|||||||
virerr, errorMessage, NULL, -1, -1, virerr, errorMessage);
|
virerr, errorMessage, NULL, -1, -1, virerr, errorMessage);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
extern virError virLastErr;
|
|
||||||
extern virErrorFunc virErrorHandler;
|
extern virErrorFunc virErrorHandler;
|
||||||
extern void *virUserData;
|
extern void *virUserData;
|
||||||
|
|
||||||
@ -33,6 +32,7 @@ extern void *virUserData;
|
|||||||
* API for error handling *
|
* API for error handling *
|
||||||
* *
|
* *
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
|
int virErrorInitialize(void);
|
||||||
void virRaiseError(virConnectPtr conn,
|
void virRaiseError(virConnectPtr conn,
|
||||||
virDomainPtr dom,
|
virDomainPtr dom,
|
||||||
virNetworkPtr net,
|
virNetworkPtr net,
|
||||||
@ -53,4 +53,7 @@ void virReportErrorHelper(virConnectPtr conn, int domcode, int errcode,
|
|||||||
ATTRIBUTE_FORMAT(printf, 7, 8);
|
ATTRIBUTE_FORMAT(printf, 7, 8);
|
||||||
|
|
||||||
|
|
||||||
|
void virSetGlobalError(void);
|
||||||
|
void virSetConnError(virConnectPtr conn);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user