[Libvir] RFC: PATCH 2/5: public & driver API for async jobs

Daniel P. Berrange berrange at redhat.com
Sat Jan 5 01:08:44 UTC 2008


This patch adds the public API for the virJobPtr object, and the
internal driver support code. The new public APIs are:

 - int virJobGetInfo(virJobPtr job, virJobInfoPtr info);

   This gets elapsed time, estimate completion time, completion
   progress percentage, and completion status - success, failed,
   cancelled.

 - virDomainPtr  virJobGetDomain(virJobPtr job);

   If the job was a domain creation attempt, this gets the
   resulting domain object

 - virNetworkPtr virJobGetNetwork(virJobPtr job);

   If the job was a network creation attempt, this gets the
   resulting network object

 - virErrorPtr   virJobGetNetwork(virJobPtr job);

   If the job failed, this gets the associated error

 - int virJobCancel(virJobPtr job);

   Request that the job be cancelled. This is not an immediate
   operation. It merely sets a flag, which background jobs will
   check periodically. So a job may still complete even if it
   was cancelled. It should be responded to within a few seconds
   though.

 - int virJobDestroy(virJobPtr job);

   Once a job has finished running (success, failed, or cancelled)
   this may be called to release all resources associated with
   the job.


As mentioned before, the following variants on existing APis are
added:

 - virDomainCreateLinuxJob
 - virDomainCreateJob
 - virNetworkCreateJob
 - virNetworkCreateXMLJob
 - virDomainSaveJob
 - virDomainRestoreJob
 - virDomainDumpCoreJob

All are no-ops by default, unless the underlying driver supports
async jobs.


Finally, the job.c and job.h files provides a set of internal
routines to authors for the purpose of managing virJobPtr objects.
There is a default impl of the virJobDriver APIs which should be
suitable for all existing the remote driver. The async jobs are
basically run in a background pthread.

This psuedo code illustrates how the 'test' driver might use
these to implement an asynchronous variant of the 'save' method.
It basically stores the parameters in a struct, and then calls
the virJobCreate() method.

    privdata = malloc(sizeof(*privdata));
    if (privdata == NULL)
        return (NULL);
    memset(privdata, 0, sizeof(*privdata));

    privdata->type = TEST_JOB_DOMAIN_SAVE;
    privdata->data.save.domidx = domidx;
    privdata->data.save.path = strdup(path);

    job = virJobCreate(domain->conn,
                       domain->conn->driver->jobDriver,
                       testDomainSaveWorker,
                       NULL,
                       privdata,
                       VIR_JOB_BOUNDED);


The actual work is done in the 'testDomainSaveWorker' method
which is passed in to virJobCreate. The job.h file contains
APIs for it to call to update progress information and detect
cancellation:

  static void testDomainSaveWorker(virJobPtr job, void *data)
  {
      testJobPtr privdata = data;
      /* A 50 second ETA for saving */
      virJobInitialize(job, 50);

      do {
          ... do a unit of work...

          ... Check for cancellation ...
          if (virJobFinishCancel(job))
              return;

          ... update progress, indicating 1 second
              of work complete, remove 1 second from
              the ETA, and add 2% of completion state...
          virJobUpdateRel(job, 1, -1, 2);
      } while (...not done...);

      ... Inform world we're all done ...
      virJobFinishSuccess(job);
  }

The virJobInitialize, virJobFinishCancel, virJobFinishSuccess
and virJobUpdateRel methods all take care to lock the virJobPtr
object to ensure thread safety.



 b/src/job.c                  |  304 ++++++++++++++++++++++++++++
 b/src/job.h                  |  102 +++++++++
 include/libvirt/libvirt.h    |  127 ++++++++++-
 include/libvirt/libvirt.h.in |  127 ++++++++++-
 include/libvirt/virterror.h  |    6 
 src/Makefile.am              |    1 
 src/driver.h                 |   61 +++++
 src/internal.h               |   77 ++++++-
 src/libvirt.c                |  459 ++++++++++++++++++++++++++++++++++++++++++-
 src/libvirt_sym.version      |   16 +
 src/openvz_driver.c          |   50 ----
 src/qemu_driver.c            |    9 
 src/test.c                   |    9 
 src/virterror.c              |  104 ++++-----
 14 files changed, 1304 insertions(+), 148 deletions(-)

Dan


diff -r 9b65842892de include/libvirt/libvirt.h
--- a/include/libvirt/libvirt.h	Fri Jan 04 17:29:33 2008 -0500
+++ b/include/libvirt/libvirt.h	Fri Jan 04 18:00:06 2008 -0500
@@ -51,6 +51,21 @@ typedef struct _virDomain virDomain;
  * type used to reference a Xen domain in the API.
  */
 typedef virDomain *virDomainPtr;
+
+/**
+ * virNetwork:
+ *
+ * a virNetwork is a private structure representing a virtual network.
+ */
+typedef struct _virNetwork virNetwork;
+
+/**
+ * virNetworkPtr:
+ *
+ * a virNetworkPtr is pointer to a virNetwork private structure, this is the
+ * type used to reference a virtual network in the API.
+ */
+typedef virNetwork *virNetworkPtr;
 
 /**
  * virDomainState:
@@ -408,6 +423,88 @@ char *                  virConnectGetCap
 
 unsigned long long	virNodeGetFreeMemory	(virConnectPtr conn);
 
+
+
+/*
+ * Asynchronous background jobs
+ */
+
+
+/**
+ * virJob:
+ *
+ * a virJob is a private structure representing a background job.
+ */
+typedef struct _virJob virJob;
+
+/**
+ * virJobPtr:
+ *
+ * a virJobPtr is pointer to a virJob private structure, this is the
+ * type used to reference a background job in the API.
+ */
+typedef virJob *virJobPtr;
+
+/**
+ * virJobType;
+ *
+ * A job may have a finite bounded progress, or may be
+ * unbounded.
+ */
+typedef enum {
+  VIR_JOB_BOUNDED	= 0, /* finite, 0-> 100 completion */
+  VIR_JOB_UNBOUNDED	= 1, /* unknown completion percent */
+} virJobType;
+
+
+/**
+ * virJobState;
+ *
+ * A job may be in one of several states
+ */
+typedef enum {
+  VIR_JOB_RUNNING = 0,     /* Still active */
+  VIR_JOB_COMPLETE = 1,    /* Completed successfully */
+  VIR_JOB_FAILED = 2,      /* Failed to complete see virJobGetError */
+  VIR_JOB_CANCELLED = 3,   /* User requested cancellation */
+} virJobState;
+
+/**
+ * virJobInfoPtr:
+ *
+ * a virJobInfo is a structure filled by virJobGetInfo() and extracting
+ * runtime informations for a given active Job
+ */
+
+typedef struct _virJobInfo virJobInfo;
+
+struct _virJobInfo {
+  int type;                  /* One of virJobType constants */
+  int state;                 /* One of virJobState constants */
+  unsigned int runningTime;  /* Actual running time in seconds */
+  unsigned int remainingTime;/* Estimated remaining time in seconds */
+  int percentComplete;       /* Completion progress 0 -> 100, if VIR_JOB_BOUNDED */
+};
+
+/**
+ * virJobInfoPtr:
+ *
+ * a virJobInfoPtr is a pointer to a virJobInfo structure.
+ */
+
+typedef virJobInfo *virJobInfoPtr;
+
+int                     virJobGetInfo           (virJobPtr job,
+				                 virJobInfoPtr info);
+
+
+virDomainPtr            virJobGetDomain         (virJobPtr job);
+virNetworkPtr           virJobGetNetwork        (virJobPtr job);
+
+int                     virJobCancel            (virJobPtr job);
+int                     virJobDestroy           (virJobPtr job);
+
+
 /*
  * Gather list of running domains
  */
@@ -432,6 +529,10 @@ virDomainPtr		virDomainCreateLinux	(virC
 virDomainPtr		virDomainCreateLinux	(virConnectPtr conn,
 						 const char *xmlDesc,
 						 unsigned int flags);
+virJobPtr               virDomainCreateLinuxJob (virConnectPtr conn,
+						 const char *xmlDesc,
+						 unsigned int flags);
+
 virDomainPtr		virDomainLookupByName	(virConnectPtr conn,
 						 const char *name);
 virDomainPtr		virDomainLookupByID	(virConnectPtr conn,
@@ -458,13 +559,20 @@ int			virDomainResume		(virDomainPtr dom
  */
 int			virDomainSave		(virDomainPtr domain,
 						 const char *to);
+virJobPtr      		virDomainSaveJob       	(virDomainPtr domain,
+						 const char *to);
 int			virDomainRestore	(virConnectPtr conn,
 						 const char *from);
+virJobPtr      		virDomainRestoreJob	(virConnectPtr conn,
+						 const char *from);
 
 /*
  * Domain core dump
  */
 int			virDomainCoreDump	(virDomainPtr domain,
+						 const char *to,
+						 int flags);
+virJobPtr      		virDomainCoreDumpJob	(virDomainPtr domain,
 						 const char *to,
 						 int flags);
 
@@ -535,6 +643,8 @@ int			virConnectListDefinedDomains (virC
 						 char **const names,
 						 int maxnames);
 int			virDomainCreate		(virDomainPtr domain);
+virJobPtr      		virDomainCreateJob     	(virDomainPtr domain,
+						 unsigned int flags);
 
 int			virDomainGetAutostart	(virDomainPtr domain,
 						 int *autostart);
@@ -669,20 +779,6 @@ int			 virNodeGetCellsFreeMemory(virConn
  * Virtual Networks API
  */
 
-/**
- * virNetwork:
- *
- * a virNetwork is a private structure representing a virtual network.
- */
-typedef struct _virNetwork virNetwork;
-
-/**
- * virNetworkPtr:
- *
- * a virNetworkPtr is pointer to a virNetwork private structure, this is the
- * type used to reference a virtual network in the API.
- */
-typedef virNetwork *virNetworkPtr;
 
 /*
  * Get connection from network.
@@ -720,6 +816,8 @@ virNetworkPtr		virNetworkLookupByUUIDStr
  */
 virNetworkPtr		virNetworkCreateXML	(virConnectPtr conn,
 						 const char *xmlDesc);
+virJobPtr		virNetworkCreateXMLJob	(virConnectPtr conn,
+						 const char *xmlDesc);
 
 /*
  * Define inactive persistent network
@@ -736,6 +834,7 @@ int			virNetworkUndefine	(virNetworkPtr 
  * Activate persistent network
  */
 int			virNetworkCreate	(virNetworkPtr network);
+virJobPtr      		virNetworkCreateJob	(virNetworkPtr network);
 
 /*
  * Network destroy/free
diff -r 9b65842892de include/libvirt/libvirt.h.in
--- a/include/libvirt/libvirt.h.in	Fri Jan 04 17:29:33 2008 -0500
+++ b/include/libvirt/libvirt.h.in	Fri Jan 04 18:00:06 2008 -0500
@@ -51,6 +51,21 @@ typedef struct _virDomain virDomain;
  * type used to reference a Xen domain in the API.
  */
 typedef virDomain *virDomainPtr;
+
+/**
+ * virNetwork:
+ *
+ * a virNetwork is a private structure representing a virtual network.
+ */
+typedef struct _virNetwork virNetwork;
+
+/**
+ * virNetworkPtr:
+ *
+ * a virNetworkPtr is pointer to a virNetwork private structure, this is the
+ * type used to reference a virtual network in the API.
+ */
+typedef virNetwork *virNetworkPtr;
 
 /**
  * virDomainState:
@@ -408,6 +423,88 @@ char *                  virConnectGetCap
 
 unsigned long long	virNodeGetFreeMemory	(virConnectPtr conn);
 
+
+
+/*
+ * Asynchronous background jobs
+ */
+
+
+/**
+ * virJob:
+ *
+ * a virJob is a private structure representing a background job.
+ */
+typedef struct _virJob virJob;
+
+/**
+ * virJobPtr:
+ *
+ * a virJobPtr is pointer to a virJob private structure, this is the
+ * type used to reference a background job in the API.
+ */
+typedef virJob *virJobPtr;
+
+/**
+ * virJobType;
+ *
+ * A job may have a finite bounded progress, or may be
+ * unbounded.
+ */
+typedef enum {
+  VIR_JOB_BOUNDED	= 0, /* finite, 0-> 100 completion */
+  VIR_JOB_UNBOUNDED	= 1, /* unknown completion percent */
+} virJobType;
+
+
+/**
+ * virJobState;
+ *
+ * A job may be in one of several states
+ */
+typedef enum {
+  VIR_JOB_RUNNING = 0,     /* Still active */
+  VIR_JOB_COMPLETE = 1,    /* Completed successfully */
+  VIR_JOB_FAILED = 2,      /* Failed to complete see virJobGetError */
+  VIR_JOB_CANCELLED = 3,   /* User requested cancellation */
+} virJobState;
+
+/**
+ * virJobInfoPtr:
+ *
+ * a virJobInfo is a structure filled by virJobGetInfo() and extracting
+ * runtime informations for a given active Job
+ */
+
+typedef struct _virJobInfo virJobInfo;
+
+struct _virJobInfo {
+  int type;                  /* One of virJobType constants */
+  int state;                 /* One of virJobState constants */
+  unsigned int runningTime;  /* Actual running time in seconds */
+  unsigned int remainingTime;/* Estimated remaining time in seconds */
+  int percentComplete;       /* Completion progress 0 -> 100, if VIR_JOB_BOUNDED */
+};
+
+/**
+ * virJobInfoPtr:
+ *
+ * a virJobInfoPtr is a pointer to a virJobInfo structure.
+ */
+
+typedef virJobInfo *virJobInfoPtr;
+
+int                     virJobGetInfo           (virJobPtr job,
+				                 virJobInfoPtr info);
+
+
+virDomainPtr            virJobGetDomain         (virJobPtr job);
+virNetworkPtr           virJobGetNetwork        (virJobPtr job);
+
+int                     virJobCancel            (virJobPtr job);
+int                     virJobDestroy           (virJobPtr job);
+
+
 /*
  * Gather list of running domains
  */
@@ -432,6 +529,10 @@ virDomainPtr		virDomainCreateLinux	(virC
 virDomainPtr		virDomainCreateLinux	(virConnectPtr conn,
 						 const char *xmlDesc,
 						 unsigned int flags);
+virJobPtr               virDomainCreateLinuxJob (virConnectPtr conn,
+						 const char *xmlDesc,
+						 unsigned int flags);
+
 virDomainPtr		virDomainLookupByName	(virConnectPtr conn,
 						 const char *name);
 virDomainPtr		virDomainLookupByID	(virConnectPtr conn,
@@ -458,13 +559,20 @@ int			virDomainResume		(virDomainPtr dom
  */
 int			virDomainSave		(virDomainPtr domain,
 						 const char *to);
+virJobPtr      		virDomainSaveJob       	(virDomainPtr domain,
+						 const char *to);
 int			virDomainRestore	(virConnectPtr conn,
 						 const char *from);
+virJobPtr      		virDomainRestoreJob	(virConnectPtr conn,
+						 const char *from);
 
 /*
  * Domain core dump
  */
 int			virDomainCoreDump	(virDomainPtr domain,
+						 const char *to,
+						 int flags);
+virJobPtr      		virDomainCoreDumpJob	(virDomainPtr domain,
 						 const char *to,
 						 int flags);
 
@@ -535,6 +643,8 @@ int			virConnectListDefinedDomains (virC
 						 char **const names,
 						 int maxnames);
 int			virDomainCreate		(virDomainPtr domain);
+virJobPtr      		virDomainCreateJob     	(virDomainPtr domain,
+						 unsigned int flags);
 
 int			virDomainGetAutostart	(virDomainPtr domain,
 						 int *autostart);
@@ -669,20 +779,6 @@ int			 virNodeGetCellsFreeMemory(virConn
  * Virtual Networks API
  */
 
-/**
- * virNetwork:
- *
- * a virNetwork is a private structure representing a virtual network.
- */
-typedef struct _virNetwork virNetwork;
-
-/**
- * virNetworkPtr:
- *
- * a virNetworkPtr is pointer to a virNetwork private structure, this is the
- * type used to reference a virtual network in the API.
- */
-typedef virNetwork *virNetworkPtr;
 
 /*
  * Get connection from network.
@@ -720,6 +816,8 @@ virNetworkPtr		virNetworkLookupByUUIDStr
  */
 virNetworkPtr		virNetworkCreateXML	(virConnectPtr conn,
 						 const char *xmlDesc);
+virJobPtr		virNetworkCreateXMLJob	(virConnectPtr conn,
+						 const char *xmlDesc);
 
 /*
  * Define inactive persistent network
@@ -736,6 +834,7 @@ int			virNetworkUndefine	(virNetworkPtr 
  * Activate persistent network
  */
 int			virNetworkCreate	(virNetworkPtr network);
+virJobPtr      		virNetworkCreateJob	(virNetworkPtr network);
 
 /*
  * Network destroy/free
diff -r 9b65842892de include/libvirt/virterror.h
--- a/include/libvirt/virterror.h	Fri Jan 04 17:29:33 2008 -0500
+++ b/include/libvirt/virterror.h	Fri Jan 04 18:00:06 2008 -0500
@@ -165,6 +165,12 @@ void			virConnSetErrorFunc	(virConnectPt
 						 virErrorFunc handler);
 int			virConnCopyLastError	(virConnectPtr conn,
 						 virErrorPtr to);
+
+virErrorPtr		virJobGetError	        (virJobPtr job);
+int			virJobCopyLastError	(virJobPtr job,
+						 virErrorPtr to);
+
+
 #ifdef __cplusplus
 }
 #endif
diff -r 9b65842892de src/Makefile.am
--- a/src/Makefile.am	Fri Jan 04 17:29:33 2008 -0500
+++ b/src/Makefile.am	Fri Jan 04 18:00:06 2008 -0500
@@ -32,6 +32,7 @@ CLIENT_SOURCES =						\
 		libvirt.c internal.h				\
 		gnutls_1_0_compat.h				\
 		hash.c hash.h					\
+		job.c job.h                                     \
 		test.c test.h                                   \
                 buf.c buf.h					\
 		xml.c xml.h					\
diff -r 9b65842892de src/driver.h
--- a/src/driver.h	Fri Jan 04 17:29:33 2008 -0500
+++ b/src/driver.h	Fri Jan 04 18:00:06 2008 -0500
@@ -95,6 +95,23 @@ typedef int
 					 virNodeInfoPtr info);
 typedef char *
 	(*virDrvGetCapabilities) (virConnectPtr conn);
+
+typedef int
+    (*virDrvJobGetInfo)          (virJobPtr job,
+                                  virJobInfoPtr info);
+typedef virDomainPtr
+    (*virDrvJobGetDomain)          (virJobPtr job);
+typedef virNetworkPtr
+    (*virDrvJobGetNetwork)          (virJobPtr job);
+typedef virErrorPtr
+    (*virDrvJobGetError)           (virJobPtr job);
+
+typedef int
+    (*virDrvJobCancel)           (virJobPtr job);
+typedef int
+    (*virDrvJobDestroy)          (virJobPtr job);
+
+
 typedef int
 	(*virDrvListDomains)		(virConnectPtr conn,
 					 int *ids,
@@ -105,6 +122,10 @@ typedef virDomainPtr
 	(*virDrvDomainCreateLinux)	(virConnectPtr conn,
 					 const char *xmlDesc,
 					 unsigned int flags);
+typedef virJobPtr
+	(*virDrvDomainCreateLinuxJob)	(virConnectPtr conn,
+					 const char *xmlDesc,
+					 unsigned int flags);
 typedef virDomainPtr
 	(*virDrvDomainLookupByID)	(virConnectPtr conn,
 					 int id);
@@ -141,13 +162,23 @@ typedef int
 typedef int
 	(*virDrvDomainSave)		(virDomainPtr domain,
 					 const char *to);
+typedef virJobPtr
+	(*virDrvDomainSaveJob)	(virDomainPtr domain,
+					 const char *to);
 typedef int
 	(*virDrvDomainRestore)		(virConnectPtr conn,
+					 const char *from);
+typedef virJobPtr
+	(*virDrvDomainRestoreJob)	(virConnectPtr conn,
 					 const char *from);
 typedef int
 	(*virDrvDomainCoreDump)		(virDomainPtr domain,
 					 const char *to,
 					 int flags);
+typedef virJobPtr
+	(*virDrvDomainCoreDumpJob)	(virDomainPtr domain,
+					 const char *to,
+					 int flags);
 typedef char *
 	(*virDrvDomainDumpXML)		(virDomainPtr dom,
 					 int flags);
@@ -159,6 +190,9 @@ typedef int
 	(*virDrvNumOfDefinedDomains)	(virConnectPtr conn);
 typedef int
 	(*virDrvDomainCreate)		(virDomainPtr dom);
+typedef virJobPtr
+    (*virDrvDomainCreateJob)	(virDomainPtr dom,
+                                 unsigned int flags);
 typedef virDomainPtr
 	(*virDrvDomainDefineXML)	(virConnectPtr conn,
 					 const char *xml);
@@ -264,6 +298,19 @@ typedef unsigned long long
     (*virDrvNodeGetFreeMemory)
 		    (virConnectPtr conn);
 
+
+typedef struct _virJobDriver virJobDriver;
+typedef virJobDriver *virJobDriverPtr;
+
+struct _virJobDriver {
+    virDrvJobGetInfo getInfo;
+    virDrvJobGetDomain getDomain;
+    virDrvJobGetNetwork getNetwork;
+    virDrvJobGetError getError;
+    virDrvJobCancel cancel;
+    virDrvJobDestroy destroy;
+};
+
 /**
  * _virDriver:
  *
@@ -280,6 +327,7 @@ struct _virDriver {
 	int	       no;	/* the number virDrvNo */
 	const char * name;	/* the name of the driver */
 	unsigned long ver;	/* the version of the backend */
+    virJobDriverPtr  jobDriver;
 	virDrvOpen			open;
 	virDrvClose			close;
     virDrvSupportsFeature   supports_feature;
@@ -293,6 +341,7 @@ struct _virDriver {
 	virDrvListDomains		listDomains;
 	virDrvNumOfDomains		numOfDomains;
 	virDrvDomainCreateLinux		domainCreateLinux;
+	virDrvDomainCreateLinuxJob	domainCreateLinuxJob;
 	virDrvDomainLookupByID		domainLookupByID;
 	virDrvDomainLookupByUUID	domainLookupByUUID;
 	virDrvDomainLookupByName	domainLookupByName;
@@ -307,8 +356,11 @@ struct _virDriver {
 	virDrvDomainSetMemory		domainSetMemory;
 	virDrvDomainGetInfo		domainGetInfo;
 	virDrvDomainSave		domainSave;
+	virDrvDomainSaveJob		domainSaveJob;
 	virDrvDomainRestore		domainRestore;
+	virDrvDomainRestoreJob		domainRestoreJob;
 	virDrvDomainCoreDump		domainCoreDump;
+	virDrvDomainCoreDumpJob		domainCoreDumpJob;
 	virDrvDomainSetVcpus		domainSetVcpus;
 	virDrvDomainPinVcpu		domainPinVcpu;
 	virDrvDomainGetVcpus		domainGetVcpus;
@@ -317,6 +369,7 @@ struct _virDriver {
 	virDrvListDefinedDomains	listDefinedDomains;
 	virDrvNumOfDefinedDomains	numOfDefinedDomains;
 	virDrvDomainCreate		domainCreate;
+	virDrvDomainCreateJob		domainCreateJob;
 	virDrvDomainDefineXML           domainDefineXML;
 	virDrvDomainUndefine            domainUndefine;
 	virDrvDomainAttachDevice	domainAttachDevice;
@@ -356,6 +409,9 @@ typedef virNetworkPtr
 typedef virNetworkPtr
 	(*virDrvNetworkCreateXML)	(virConnectPtr conn,
 					 const char *xmlDesc);
+typedef virJobPtr
+	(*virDrvNetworkCreateXMLJob)	(virConnectPtr conn,
+					 const char *xmlDesc);
 typedef virNetworkPtr
 	(*virDrvNetworkDefineXML)	(virConnectPtr conn,
 					 const char *xml);
@@ -363,6 +419,8 @@ typedef int
 	(*virDrvNetworkUndefine)	(virNetworkPtr network);
 typedef int
 	(*virDrvNetworkCreate)		(virNetworkPtr network);
+typedef virJobPtr
+	(*virDrvNetworkCreateJob)		(virNetworkPtr network);
 typedef int
 	(*virDrvNetworkDestroy)		(virNetworkPtr network);
 typedef char *
@@ -393,6 +451,7 @@ typedef virNetworkDriver *virNetworkDriv
  */
 struct _virNetworkDriver {
 	const char * name;	/* the name of the driver */
+    virJobDriverPtr  jobDriver;
 	virDrvOpen			open;
 	virDrvClose			close;
 	virDrvNumOfNetworks		numOfNetworks;
@@ -402,9 +461,11 @@ struct _virNetworkDriver {
 	virDrvNetworkLookupByUUID	networkLookupByUUID;
 	virDrvNetworkLookupByName	networkLookupByName;
 	virDrvNetworkCreateXML		networkCreateXML;
+	virDrvNetworkCreateXMLJob		networkCreateXMLJob;
 	virDrvNetworkDefineXML		networkDefineXML;
 	virDrvNetworkUndefine		networkUndefine;
 	virDrvNetworkCreate		networkCreate;
+	virDrvNetworkCreateJob		networkCreateJob;
 	virDrvNetworkDestroy		networkDestroy;
 	virDrvNetworkDumpXML		networkDumpXML;
 	virDrvNetworkGetBridgeName	networkGetBridgeName;
diff -r 9b65842892de src/internal.h
--- a/src/internal.h	Fri Jan 04 17:29:33 2008 -0500
+++ b/src/internal.h	Fri Jan 04 18:00:06 2008 -0500
@@ -100,6 +100,16 @@ extern "C" {
 
 
 /**
+ * VIR_JOB_MAGIC:
+ *
+ * magic value used to protect the API when pointers to job structures
+ * are passed down by the users.
+ */
+#define VIR_JOB_MAGIC		0x99DEAD11
+#define VIR_IS_JOB(obj)		((obj) && (obj)->magic==VIR_JOB_MAGIC)
+#define VIR_IS_CONNECTED_JOB(obj)	(VIR_IS_JOB(obj) && VIR_IS_CONNECT((obj)->conn))
+
+/**
  * VIR_DOMAIN_MAGIC:
  *
  * magic value used to protect the API when pointers to domain structures
@@ -160,6 +170,7 @@ struct _virConnect {
     pthread_mutex_t lock;
     virHashTablePtr domains;  /* hash table for known domains */
     virHashTablePtr networks; /* hash table for known domains */
+    virJobPtr jobs;           /* list of active background jobs */
     int refs;                 /* reference count */
 };
 
@@ -196,17 +207,28 @@ struct _virNetwork {
  *		API for error handling					*
  *									*
  ************************************************************************/
+void __virSetError(virErrorPtr err,
+                   virConnectPtr conn,
+                   virDomainPtr dom,
+                   virNetworkPtr net,
+                   int domain,
+                   int code,
+                   virErrorLevel level,
+                   const char *str1,
+                   const char *str2,
+                   const char *str3,
+                   int int1, int int2, const char *message);
 void __virRaiseError(virConnectPtr conn,
-		     virDomainPtr dom,
-		     virNetworkPtr net,
-		     int domain,
-		     int code,
-		     virErrorLevel level,
-		     const char *str1,
-		     const char *str2,
-		     const char *str3,
-		     int int1, int int2, const char *msg, ...)
-  ATTRIBUTE_FORMAT(printf, 12, 13);
+                     virDomainPtr dom,
+                     virNetworkPtr net,
+                     int domain,
+                     int code,
+                     virErrorLevel level,
+                     const char *str1,
+                     const char *str2,
+                     const char *str3,
+                     int int1, int int2, const char *msg, ...)
+    ATTRIBUTE_FORMAT(printf, 12, 13);
 const char *__virErrorMsg(virErrorNumber error, const char *info);
 
 /************************************************************************
@@ -290,6 +312,41 @@ xstrtol_ui(char const *s, char **end_ptr
     return 0;
 }
 
+/*
+ * Macro used to format the message as a string in __virRaiseError
+ * and borrowed from libxml2.
+ */
+#define VIR_GET_VAR_STR(msg, str) {				\
+        int       size = 150, prev_size = -1;   \
+        int       chars;						\
+        char      *larger;						\
+        va_list   ap;                           \
+                                                \
+        str = (char *) malloc(size);            \
+        if (str != NULL) {						\
+            while (1) {                                                 \
+                va_start(ap, msg);                                      \
+                chars = vsnprintf(str, size, msg, ap);                  \
+                va_end(ap);                                             \
+                if ((chars > -1) && (chars < size)) {                   \
+                    if (prev_size == chars) {                           \
+                        break;                                          \
+                    } else {                                            \
+                        prev_size = chars;                              \
+                    }                                                   \
+                }                                                       \
+                if (chars > -1)                                         \
+                    size += chars + 1;                                  \
+                else                                                    \
+                    size += 100;                                        \
+                if ((larger = (char *) realloc(str, size)) == NULL) {	\
+                    break;                                              \
+                }                                                       \
+                str = larger;                                           \
+            }                                                           \
+        }                                                               \
+    }
+
 #ifdef __cplusplus
 }
 #endif                          /* __cplusplus */
diff -r 9b65842892de src/job.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/job.c	Fri Jan 04 18:00:06 2008 -0500
@@ -0,0 +1,304 @@
+/*
+ * job.h: asynchronous background jobs
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Daniel Berrange <berrange at redhat.com>
+ */
+
+#include "job.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+
+/*
+ * Threading rules
+ *  1. Thou shalt lock the virConnectPtr before virJobPtr
+ *  2. Thou shalt not delete the virJobPtr while the thread is running
+ *
+ */
+
+static void *virJobStartFunc(void *data)
+{
+    virJobPtr job = data;
+
+    (*job->worker)(job, job->funcData);
+
+    return NULL;
+}
+
+virJobPtr virJobCreate(virConnectPtr conn,
+                       virJobDriverPtr driver,
+                       virJobWorkerFunc worker,
+                       virJobCleanupFunc cleanup,
+                       void *funcData,
+                       int type)
+{
+    virJobPtr job = malloc(sizeof(*job));
+    if (!job) {
+        if (cleanup)
+            (*cleanup)(funcData);
+        return NULL;
+    }
+    memset(job, 0, sizeof(*job));
+
+    pthread_mutex_lock(&conn->lock);
+
+    pthread_mutex_init(&job->lock, NULL);
+    job->magic = VIR_JOB_MAGIC;
+    job->conn = conn;
+    job->driver = driver;
+    job->info.type = type;
+    job->worker = worker;
+    job->cleanup = cleanup;
+    job->funcData = funcData;
+
+    job->next = conn->jobs;
+    conn->jobs = job;
+    conn->refs++;
+
+    pthread_mutex_lock(&job->lock);
+    job->info.state = VIR_JOB_RUNNING;
+    if (pthread_create(&job->thread, NULL,
+                       virJobStartFunc, job) != 0) {
+        job->info.state = VIR_JOB_FAILED;
+        pthread_mutex_unlock(&job->lock);
+        pthread_mutex_unlock(&conn->lock);
+        virJobFree(conn, job);
+        return NULL;
+    }
+
+    pthread_mutex_unlock(&job->lock);
+    pthread_mutex_unlock(&conn->lock);
+
+    return job;
+}
+
+
+int virJobFree(virConnectPtr conn,
+               virJobPtr job) {
+    virJobPtr tmp, prev = NULL;
+
+    pthread_mutex_lock(&conn->lock);
+    pthread_mutex_lock(&job->lock);
+    if (job->info.state == VIR_JOB_RUNNING) {
+        pthread_mutex_unlock(&job->lock);
+        pthread_mutex_unlock(&conn->lock);
+        return -1;
+    }
+    pthread_mutex_unlock(&job->lock);
+
+    pthread_join(job->thread, NULL);
+
+    tmp = conn->jobs;
+    while (tmp) {
+        if (tmp == job) {
+            if (prev)
+                prev->next = job->next;
+            else
+                conn->jobs = job->next;
+            break;
+        }
+        prev = tmp;
+        tmp = tmp->next;
+    }
+    if (job->cleanup)
+        (*job->cleanup)(job->funcData);
+    if (virUnrefConnect(conn) > 0)
+        pthread_mutex_unlock(&conn->lock);
+    free(job);
+    return 0;
+}
+
+
+void virJobInitialize(virJobPtr job,
+                      int remaining) {
+    pthread_mutex_lock(&job->conn->lock);
+    pthread_mutex_lock(&job->lock);
+    pthread_mutex_unlock(&job->conn->lock);
+
+    job->info.remainingTime = remaining;
+
+    pthread_mutex_unlock(&job->lock);
+}
+
+void virJobUpdateAbs(virJobPtr job,
+                     int running,
+                     int remaining,
+                     int complete) {
+    pthread_mutex_lock(&job->conn->lock);
+    pthread_mutex_lock(&job->lock);
+    pthread_mutex_unlock(&job->conn->lock);
+
+    job->info.remainingTime = remaining;
+    job->info.runningTime = running;
+    job->info.percentComplete = complete;
+
+    pthread_mutex_unlock(&job->lock);
+}
+
+void virJobUpdateRel(virJobPtr job,
+                     int running,
+                     int remaining,
+                     int complete) {
+    pthread_mutex_lock(&job->conn->lock);
+    pthread_mutex_lock(&job->lock);
+    pthread_mutex_unlock(&job->conn->lock);
+
+    job->info.remainingTime += remaining;
+    job->info.runningTime += running;
+    job->info.percentComplete += complete;
+
+    pthread_mutex_unlock(&job->lock);
+}
+
+void virJobFinishSuccess(virJobPtr job) {
+    pthread_mutex_lock(&job->conn->lock);
+    pthread_mutex_lock(&job->lock);
+    pthread_mutex_unlock(&job->conn->lock);
+
+    job->info.remainingTime = 0;
+    job->info.state = VIR_JOB_COMPLETE;
+
+    pthread_mutex_unlock(&job->lock);
+}
+
+int virJobFinishCancel(virJobPtr job) {
+    int ret = 0;
+
+    pthread_mutex_lock(&job->conn->lock);
+    pthread_mutex_lock(&job->lock);
+    pthread_mutex_unlock(&job->conn->lock);
+
+    if (job->cancelled) {
+        ret = 1;
+        job->info.remainingTime = 0;
+        job->info.state = VIR_JOB_CANCELLED;
+    }
+
+    pthread_mutex_unlock(&job->lock);
+
+    return ret;
+}
+
+void virJobFinishFailed(virJobPtr job,
+                        int domain, int code, int level,
+                        const char *str1, const char *str2, const char *str3,
+                        int int1, int int2,
+                        char *msg, ...) {
+    char *str;
+    pthread_mutex_lock(&job->conn->lock);
+    pthread_mutex_lock(&job->lock);
+    pthread_mutex_unlock(&job->conn->lock);
+
+    job->info.remainingTime = 0;
+    job->info.state = VIR_JOB_FAILED;
+
+    if (msg == NULL) {
+        str = strdup(_("No error message provided"));
+    } else {
+        VIR_GET_VAR_STR(msg, str);
+    }
+
+    __virSetError(&job->err, job->conn, NULL, NULL,
+                  domain, code, level,
+                  str1, str2, str3, int1, int2,
+                  str);
+
+    free(str);
+
+    pthread_mutex_unlock(&job->lock);
+}
+
+static int virJobDefaultGetInfo(virJobPtr job,
+                                virJobInfoPtr info) {
+    pthread_mutex_lock(&job->conn->lock);
+    pthread_mutex_lock(&job->lock);
+    pthread_mutex_unlock(&job->conn->lock);
+
+    memcpy(info, &job->info, sizeof(*info));
+
+    pthread_mutex_unlock(&job->lock);
+
+    return 0;
+}
+
+static virErrorPtr virJobDefaultGetError(virJobPtr job) {
+    virErrorPtr err;
+
+    pthread_mutex_lock(&job->conn->lock);
+    pthread_mutex_lock(&job->lock);
+    pthread_mutex_unlock(&job->conn->lock);
+
+    if (job->info.state == VIR_JOB_RUNNING ||
+        job->err.code == VIR_ERR_OK) {
+        pthread_mutex_unlock(&job->lock);
+        return NULL;
+    }
+
+    err = &job->err;
+    pthread_mutex_unlock(&job->lock);
+
+    return err;
+}
+
+
+static int virJobDefaultCancel(virJobPtr job) {
+    pthread_mutex_lock(&job->conn->lock);
+    pthread_mutex_lock(&job->lock);
+    pthread_mutex_unlock(&job->conn->lock);
+
+    if (job->info.state != VIR_JOB_RUNNING) {
+        pthread_mutex_unlock(&job->lock);
+        return -1;
+    }
+
+    job->cancelled = 1;
+    pthread_mutex_unlock(&job->lock);
+    return 0;
+}
+
+static int virJobDefaultDestroy(virJobPtr job) {
+    return virJobFree(job->conn, job);
+}
+
+
+virJobDriver defaultJobDriver = {
+    virJobDefaultGetInfo,
+    NULL,
+    NULL,
+    virJobDefaultGetError,
+    virJobDefaultCancel,
+    virJobDefaultDestroy,
+};
+
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -r 9b65842892de src/job.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/job.h	Fri Jan 04 18:00:06 2008 -0500
@@ -0,0 +1,102 @@
+/*
+ * job.h: asynchronous background jobs
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Daniel Berrange <berrange at redhat.com>
+ */
+
+#include "config.h"
+
+#include "internal.h"
+#include "driver.h"
+
+extern virJobDriver defaultJobDriver;
+
+typedef void (*virJobWorkerFunc)(virJobPtr job, void *data);
+typedef void (*virJobCleanupFunc)(void *data);
+
+struct _virJob {
+    int magic;
+    virJobDriverPtr driver;
+    virConnectPtr conn;
+
+    virJobInfo info;
+    int cancelled;
+    virError err;
+
+    pthread_mutex_t lock;
+    pthread_t thread;
+    virJobWorkerFunc worker;
+    virJobCleanupFunc cleanup;
+    void *funcData;
+
+    virJobPtr next;
+};
+
+
+virJobPtr virJobCreate(virConnectPtr conn,
+                       virJobDriverPtr driver,
+                       virJobWorkerFunc worker,
+                       virJobCleanupFunc cleanup,
+                       void *funcData,
+                       int type);
+
+int virJobFree(virConnectPtr conn,
+               virJobPtr job);
+
+
+
+/* Following methods can be called from the worker
+   thread to update the job status. They automatically
+   lock the job */
+
+void virJobInitialize(virJobPtr job,
+                      int remaining);
+
+void virJobUpdateAbs(virJobPtr job,
+                     int running,
+                     int remaining,
+                     int complete);
+
+void virJobUpdateRel(virJobPtr job,
+                     int running,
+                     int remaining,
+                     int complete);
+
+void virJobFinishSuccess(virJobPtr job);
+int virJobFinishCancel(virJobPtr job);
+void virJobFinishFailed(virJobPtr job,
+                        int domain, int code, int level,
+                        const char *str1, const char *str2, const char *str3,
+                        int int1, int int2,
+                        char *msg, ...)
+    ATTRIBUTE_FORMAT(printf, 10, 11);
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -r 9b65842892de src/libvirt.c
--- a/src/libvirt.c	Fri Jan 04 17:29:33 2008 -0500
+++ b/src/libvirt.c	Fri Jan 04 18:00:06 2008 -0500
@@ -26,6 +26,7 @@
 
 #include "internal.h"
 #include "driver.h"
+#include "job.h"
 
 #include "uuid.h"
 #include "test.h"
@@ -865,6 +866,141 @@ virConnectGetMaxVcpus(virConnectPtr conn
     return -1;
 }
 
+
+int
+virJobGetInfo(virJobPtr job,
+              virJobInfoPtr info)
+{
+    DEBUG("job=%p, info=%p", job, info);
+
+    if (!VIR_IS_JOB(job)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return (-1);
+    }
+
+    if (info == NULL) {
+        virLibConnError(job->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return (-1);
+    }
+
+    if (job->driver->getInfo)
+        return job->driver->getInfo (job, info);
+
+    virLibConnError (job->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return -1;
+}
+
+
+virDomainPtr
+virJobGetDomain(virJobPtr job)
+{
+    DEBUG("job=%p", job);
+
+    if (!VIR_IS_JOB(job)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return (NULL);
+    }
+
+    if (job->driver->getDomain)
+        return job->driver->getDomain (job);
+
+    virLibConnError (job->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return NULL;
+}
+
+virNetworkPtr
+virJobGetNetwork(virJobPtr job)
+{
+    DEBUG("job=%p", job);
+
+    if (!VIR_IS_JOB(job)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return (NULL);
+    }
+
+    if (job->driver->getNetwork)
+        return job->driver->getNetwork (job);
+
+    virLibConnError (job->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return NULL;
+}
+
+virErrorPtr
+virJobGetError(virJobPtr job)
+{
+    DEBUG("job=%p", job);
+
+    if (!VIR_IS_JOB(job)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return (NULL);
+    }
+
+    if (job->driver->getError)
+        return job->driver->getError (job);
+
+    virLibConnError (job->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return NULL;
+}
+
+int
+virJobCopyLastError	(virJobPtr job,
+                     virErrorPtr to)
+{
+    virErrorPtr err;
+    DEBUG("job=%p", job);
+
+    if (!VIR_IS_JOB(job)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return (-1);
+    }
+    if (to == NULL) {
+        virLibConnError(job->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return (-1);
+    }
+
+    err = virJobGetError(job);
+    if (err == NULL)
+        return (0);
+    if (err->code == VIR_ERR_OK)
+        return (0);
+    memcpy(to, err, sizeof(virError));
+    return (err->code);
+}
+
+int
+virJobCancel(virJobPtr job)
+{
+    DEBUG("job=%p", job);
+
+    if (!VIR_IS_JOB(job)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return (-1);
+    }
+
+    if (job->driver->cancel)
+        return job->driver->cancel (job);
+
+    virLibConnError (job->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return -1;
+}
+
+int
+virJobDestroy(virJobPtr job)
+{
+    DEBUG("job=%p", job);
+
+    if (!VIR_IS_JOB(job)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return (-1);
+    }
+
+    if (job->driver->destroy)
+        return job->driver->destroy (job);
+
+    virLibConnError (job->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return -1;
+}
+
 /**
  * virConnectListDomains:
  * @conn: pointer to the hypervisor connection
@@ -981,6 +1117,45 @@ virDomainCreateLinux(virConnectPtr conn,
 
     if (conn->driver->domainCreateLinux)
         return conn->driver->domainCreateLinux (conn, xmlDesc, flags);
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return NULL;
+}
+
+/**
+ * virDomainCreateLinuxJob:
+ * @conn: pointer to the hypervisor connection
+ * @xmlDesc: an XML description of the domain
+ * @flags: an optional set of virDomainFlags
+ *
+ * Launch a new Linux guest domain, based on an XML description similar
+ * to the one returned by virDomainGetXMLDesc()
+ * This function may requires priviledged access to the hypervisor.
+ * 
+ * Returns a new job object for monitoring progress of the creation
+ * attempt or NULL in case of failure
+ */
+virJobPtr
+virDomainCreateLinuxJob(virConnectPtr conn, const char *xmlDesc,
+                        unsigned int flags)
+{
+    DEBUG("conn=%p, xmlDesc=%s, flags=%d", conn, xmlDesc, flags);
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return (NULL);
+    }
+    if (xmlDesc == NULL) {
+        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return (NULL);
+    }
+    if (conn->flags & VIR_CONNECT_RO) {
+        virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        return (NULL);
+    }
+
+    if (conn->driver->domainCreateLinuxJob)
+        return conn->driver->domainCreateLinuxJob (conn, xmlDesc, flags);
 
     virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
     return NULL;
@@ -1323,6 +1498,66 @@ virDomainSave(virDomainPtr domain, const
 }
 
 /**
+ * virDomainSaveJob:
+ * @domain: a domain object
+ * @to: path for the output file
+ *
+ * This method will suspend a domain and save its memory contents to
+ * a file on disk. After the call, if successful, the domain is not
+ * listed as running anymore (this may be a problem).
+ * Use virDomainRestore() to restore a domain after saving.
+ *
+ * Returns a new job for monitoring save progress, and NULL in case of failure.
+ */
+virJobPtr
+virDomainSaveJob(virDomainPtr domain, const char *to)
+{
+    char filepath[4096];
+    virConnectPtr conn;
+    DEBUG("domain=%p, to=%s", domain, to);
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        return (NULL);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        return (NULL);
+    }
+    conn = domain->conn;
+    if (to == NULL) {
+        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return (NULL);
+    }
+
+    /*
+     * We must absolutize the file path as the save is done out of process
+     * TODO: check for URI when libxml2 is linked in.
+     */
+    if (to[0] != '/') {
+        unsigned int len, t;
+
+        t = strlen(to);
+        if (getcwd(filepath, sizeof(filepath) - (t + 3)) == NULL)
+            return (NULL);
+        len = strlen(filepath);
+        /* that should be covered by getcwd() semantic, but be 100% sure */
+        if (len > sizeof(filepath) - (t + 3))
+            return (NULL);
+        filepath[len] = '/';
+        strcpy(&filepath[len + 1], to);
+        to = &filepath[0];
+
+    }
+
+    if (conn->driver->domainSaveJob)
+        return conn->driver->domainSaveJob (domain, to);
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return (NULL);
+}
+
+/**
  * virDomainRestore:
  * @conn: pointer to the hypervisor connection
  * @from: path to the 
@@ -1377,6 +1612,60 @@ virDomainRestore(virConnectPtr conn, con
 }
 
 /**
+ * virDomainRestoreJob:
+ * @conn: pointer to the hypervisor connection
+ * @from: path to the 
+ *
+ * This method will restore a domain saved to disk by virDomainSave().
+ *
+ * Returns a new job for monitoring restore progress and NULL in case of failure.
+ */
+virJobPtr
+virDomainRestoreJob(virConnectPtr conn, const char *from)
+{
+    char filepath[4096];
+    DEBUG("conn=%p, from=%s", conn, from);
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return (NULL);
+    }
+    if (conn->flags & VIR_CONNECT_RO) {
+        virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        return (NULL);
+    }
+    if (from == NULL) {
+        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return (NULL);
+    }
+
+    /*
+     * We must absolutize the file path as the restore is done out of process
+     * TODO: check for URI when libxml2 is linked in.
+     */
+    if (from[0] != '/') {
+        unsigned int len, t;
+
+        t = strlen(from);
+        if (getcwd(filepath, sizeof(filepath) - (t + 3)) == NULL)
+            return (NULL);
+        len = strlen(filepath);
+        /* that should be covered by getcwd() semantic, but be 100% sure */
+        if (len > sizeof(filepath) - (t + 3))
+            return (NULL);
+        filepath[len] = '/';
+        strcpy(&filepath[len + 1], from);
+        from = &filepath[0];
+    }
+
+    if (conn->driver->domainRestoreJob)
+        return conn->driver->domainRestoreJob (conn, from);
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return (NULL);
+}
+
+/**
  * virDomainCoreDump:
  * @domain: a domain object
  * @to: path for the core file
@@ -1434,6 +1723,66 @@ virDomainCoreDump(virDomainPtr domain, c
 
     virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
     return -1;
+}
+
+/**
+ * virDomainCoreDumpJob:
+ * @domain: a domain object
+ * @to: path for the core file
+ * @flags: extra flags, currently unused
+ *
+ * This method will dump the core of a domain on a given file for analysis.
+ * Note that for remote Xen Daemon the file path will be interpreted in
+ * the remote host.
+ *
+ * Returns a new job for monitoring dump progress and NULL in case of failure.
+ */
+virJobPtr
+virDomainCoreDumpJob(virDomainPtr domain, const char *to, int flags)
+{
+    char filepath[4096];
+    virConnectPtr conn;
+    DEBUG("domain=%p, to=%s, flags=%d", domain, to, flags);
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        return (NULL);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        return (NULL);
+    }
+    conn = domain->conn;
+    if (to == NULL) {
+        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return (NULL);
+    }
+
+    /*
+     * We must absolutize the file path as the save is done out of process
+     * TODO: check for URI when libxml2 is linked in.
+     */
+    if (to[0] != '/') {
+        unsigned int len, t;
+
+        t = strlen(to);
+        if (getcwd(filepath, sizeof(filepath) - (t + 3)) == NULL)
+            return (NULL);
+        len = strlen(filepath);
+        /* that should be covered by getcwd() semantic, but be 100% sure */
+        if (len > sizeof(filepath) - (t + 3))
+            return (NULL);
+        filepath[len] = '/';
+        strcpy(&filepath[len + 1], to);
+        to = &filepath[0];
+
+    }
+
+    if (conn->driver->domainCoreDumpJob)
+        return conn->driver->domainCoreDumpJob (domain, to, flags);
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return (NULL);
 }
 
 /**
@@ -2477,10 +2826,6 @@ virDomainCreate(virDomainPtr domain) {
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
-    if (domain == NULL) {
-        TODO
-	return (-1);
-    }
     if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (-1);
@@ -2495,7 +2840,40 @@ virDomainCreate(virDomainPtr domain) {
         return conn->driver->domainCreate (domain);
 
     virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-    return -1;
+    return (-1);
+}
+
+/**
+ * virDomainCreateJob:
+ * @domain: pointer to a defined domain
+ *
+ * launch a defined domain. If the call succeed the domain moves from the
+ * defined to the running domains pools.
+ *
+ * Returns a new job object for monitoring progress of
+ * creation attempt, NULL in case of error
+ */
+virJobPtr
+virDomainCreateJob(virDomainPtr domain,
+                   unsigned int flags) {
+    virConnectPtr conn;
+    DEBUG("domain=%p", domain);
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        return (NULL);
+    }
+    conn = domain->conn;
+    if (conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        return (NULL);
+    }
+
+    if (conn->driver->domainCreateJob)
+        return conn->driver->domainCreateJob (domain, flags);
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return (NULL);
 }
 
 /**
@@ -3147,6 +3525,41 @@ virNetworkCreateXML(virConnectPtr conn, 
 }
 
 /**
+ * virNetworkCreateXMLJob:
+ * @conn: pointer to the hypervisor connection
+ * @xmlDesc: an XML description of the network
+ *
+ * Create and start a new virtual network, based on an XML description
+ * similar to the one returned by virNetworkGetXMLDesc()
+ *
+ * Returns a new job object or NULL in case of failure
+ */
+virJobPtr
+virNetworkCreateXMLJob(virConnectPtr conn, const char *xmlDesc)
+{
+    DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc);
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return (NULL);
+    }
+    if (xmlDesc == NULL) {
+        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return (NULL);
+    }
+    if (conn->flags & VIR_CONNECT_RO) {
+        virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        return (NULL);
+    }
+
+    if (conn->networkDriver && conn->networkDriver->networkCreateXMLJob)
+        return conn->networkDriver->networkCreateXMLJob (conn, xmlDesc);
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return NULL;
+}
+
+/**
  * virNetworkDefineXML:
  * @conn: pointer to the hypervisor connection
  * @xml: the XML description for the network, preferably in UTF-8
@@ -3225,10 +3638,6 @@ virNetworkCreate(virNetworkPtr network)
     virConnectPtr conn;
     DEBUG("network=%p", network);
 
-    if (network == NULL) {
-        TODO
-	return (-1);
-    }
     if (!VIR_IS_CONNECTED_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         return (-1);
@@ -3244,6 +3653,38 @@ virNetworkCreate(virNetworkPtr network)
 
     virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
     return -1;
+}
+
+/**
+ * virNetworkCreateJob:
+ * @network: pointer to a defined network
+ *
+ * Create and start a defined network. If the call succeed the network
+ * moves from the defined to the running networks pools.
+ *
+ * Returns a job object for monitoring progress, NULL in case of error
+ */
+virJobPtr
+virNetworkCreateJob(virNetworkPtr network)
+{
+    virConnectPtr conn;
+    DEBUG("network=%p", network);
+
+    if (!VIR_IS_CONNECTED_NETWORK(network)) {
+        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        return (NULL);
+    }
+    conn = network->conn;
+    if (conn->flags & VIR_CONNECT_RO) {
+        virLibNetworkError(network, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        return (NULL);
+    }
+
+    if (conn->networkDriver && conn->networkDriver->networkCreateJob)
+        return conn->networkDriver->networkCreateJob (network);
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return (NULL);
 }
 
 /**
diff -r 9b65842892de src/libvirt_sym.version
--- a/src/libvirt_sym.version	Fri Jan 04 17:29:33 2008 -0500
+++ b/src/libvirt_sym.version	Fri Jan 04 18:00:06 2008 -0500
@@ -11,11 +11,22 @@
 	virConnectGetVersion;
 	virConnectGetHostname;
 	virConnectGetURI;
+
+        virJobGetInfo;
+        virJobGetDomain;
+        virJobGetNetwork;
+        virJobGetError;
+        virJobCopyError;
+        virJobCancel;
+        virJobDestroy;
+
 	virDomainGetConnect;
 	virConnectListDomains;
 	virConnectNumOfDomains;
         virDomainCreate;
+        virDomainCreateJob;
 	virDomainCreateLinux;
+	virDomainCreateLinuxJob;
         virDomainDefineXML;
 	virDomainDestroy;
 	virDomainFree;
@@ -33,9 +44,12 @@
 	virDomainLookupByUUID;
 	virDomainLookupByUUIDString;
 	virDomainRestore;
+	virDomainRestoreJob;
 	virDomainResume;
 	virDomainSave;
+	virDomainSaveJob;
 	virDomainCoreDump;
+	virDomainCoreDumpJob;
         virDomainSetMemory;
 	virDomainSetMaxMemory;
 	virDomainShutdown;
@@ -87,9 +101,11 @@
 	virNetworkLookupByUUID;
 	virNetworkLookupByUUIDString;
 	virNetworkCreateXML;
+	virNetworkCreateXMLJob;
 	virNetworkDefineXML;
 	virNetworkUndefine;
 	virNetworkCreate;
+	virNetworkCreateJob;
 	virNetworkDestroy;
 	virNetworkFree;
 	virNetworkGetName;
diff -r 9b65842892de src/openvz_driver.c
--- a/src/openvz_driver.c	Fri Jan 04 17:29:33 2008 -0500
+++ b/src/openvz_driver.c	Fri Jan 04 18:00:06 2008 -0500
@@ -85,14 +85,6 @@ static int openvzShutdown(void);
 static int openvzShutdown(void);
 static int openvzReload(void);
 static int openvzActive(void);
-static int openvzCloseNetwork(virConnectPtr conn);
-static virDrvOpenStatus openvzOpenNetwork(virConnectPtr conn, 
-                                          const char *name ATTRIBUTE_UNUSED,
-                                          int *credtype ATTRIBUTE_UNUSED,
-                                          int ncredtype ATTRIBUTE_UNUSED,
-                                          virConnectAuthCallbackPtr cb ATTRIBUTE_UNUSED,
-                                          void *cbdata ATTRIBUTE_UNUSED,
-                                          int flags ATTRIBUTE_UNUSED);
 
 static virDomainPtr openvzDomainDefineXML(virConnectPtr conn, const char *xml);
 static virDomainPtr openvzDomainCreateLinux(virConnectPtr conn, const char *xml, 
@@ -695,24 +687,11 @@ static int openvzActive(void) {
     return 1;
 }
 
-static int openvzCloseNetwork(virConnectPtr conn ATTRIBUTE_UNUSED) {
-    return 0;
-}
-
-static virDrvOpenStatus openvzOpenNetwork(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                          const char *name ATTRIBUTE_UNUSED,
-                                          int *credtype ATTRIBUTE_UNUSED,
-                                          int ncredtype ATTRIBUTE_UNUSED,
-                                          virConnectAuthCallbackPtr cb ATTRIBUTE_UNUSED,
-                                          void *cbdata ATTRIBUTE_UNUSED,
-                                          int flags ATTRIBUTE_UNUSED) {
-    return VIR_DRV_OPEN_SUCCESS;
-}
-
 static virDriver openvzDriver = {
     VIR_DRV_OPENVZ,
     "OPENVZ",
     LIBVIR_VERSION_NUMBER,
+    NULL, /* jobDriver */
     openvzOpen, /* open */
     openvzClose, /* close */
     NULL, /* supports_feature */
@@ -726,6 +705,7 @@ static virDriver openvzDriver = {
     openvzListDomains, /* listDomains */
     openvzNumDomains, /* numOfDomains */
     openvzDomainCreateLinux, /* domainCreateLinux */
+    NULL, /* domainCreateLinuxJob */
     openvzDomainLookupByID, /* domainLookupByID */
     openvzDomainLookupByUUID, /* domainLookupByUUID */
     openvzDomainLookupByName, /* domainLookupByName */
@@ -740,8 +720,11 @@ static virDriver openvzDriver = {
     NULL, /* domainSetMemory */
     openvzDomainGetInfo, /* domainGetInfo */
     NULL, /* domainSave */
+    NULL, /* domainSaveJob */
     NULL, /* domainRestore */
+    NULL, /* domainRestoreJob */
     NULL, /* domainCoreDump */
+    NULL, /* domainCoreDumpJob */
     NULL, /* domainSetVcpus */
     NULL, /* domainPinVcpu */
     NULL, /* domainGetVcpus */
@@ -750,6 +733,7 @@ static virDriver openvzDriver = {
     openvzListDefinedDomains, /* listDomains */
     openvzNumDefinedDomains, /* numOfDomains */
     openvzDomainCreate, /* domainCreate */
+    NULL, /* domainCreateJob */
     openvzDomainDefineXML, /* domainDefineXML */
     openvzDomainUndefine, /* domainUndefine */
     NULL, /* domainAttachDevice */
@@ -768,27 +752,6 @@ static virDriver openvzDriver = {
     NULL, /* nodeGetFreeMemory */
 };
 
-static virNetworkDriver openvzNetworkDriver = {
-    NULL, /* name */	
-    openvzOpenNetwork, /* open */
-    openvzCloseNetwork, /* close */
-    NULL, /* numOfNetworks */
-    NULL, /* listNetworks */
-    NULL, /* numOfDefinedNetworks */
-    NULL, /* listDefinedNetworks */
-    NULL, /* networkLookupByUUID */
-    NULL, /* networkLookupByName */
-    NULL, /* networkCreateXML */
-    NULL, /* networkDefineXML */
-    NULL, /* networkUndefine */
-    NULL, /* networkCreate */
-    NULL, /* networkDestroy */
-    NULL, /* networkDumpXML */
-    NULL, /* networkGetBridgeName */
-    NULL, /* networkGetAutostart */
-    NULL, /* networkSetAutostart */
-};
-
 static virStateDriver openvzStateDriver = {
     openvzStartup,
     openvzShutdown,
@@ -798,7 +761,6 @@ static virStateDriver openvzStateDriver 
 
 int openvzRegister(void) {
     virRegisterDriver(&openvzDriver);
-    virRegisterNetworkDriver(&openvzNetworkDriver);
     virRegisterStateDriver(&openvzStateDriver);
     return 0;
 }
diff -r 9b65842892de src/qemu_driver.c
--- a/src/qemu_driver.c	Fri Jan 04 17:29:33 2008 -0500
+++ b/src/qemu_driver.c	Fri Jan 04 18:00:06 2008 -0500
@@ -2837,6 +2837,7 @@ static virDriver qemuDriver = {
     VIR_DRV_QEMU,
     "QEMU",
     LIBVIR_VERSION_NUMBER,
+    NULL, /* jobDriver */
     qemudOpen, /* open */
     qemudClose, /* close */
     NULL, /* supports_feature */
@@ -2850,6 +2851,7 @@ static virDriver qemuDriver = {
     qemudListDomains, /* listDomains */
     qemudNumDomains, /* numOfDomains */
     qemudDomainCreate, /* domainCreateLinux */
+    NULL, /* domainCreateLinuxJob */
     qemudDomainLookupByID, /* domainLookupByID */
     qemudDomainLookupByUUID, /* domainLookupByUUID */
     qemudDomainLookupByName, /* domainLookupByName */
@@ -2864,8 +2866,11 @@ static virDriver qemuDriver = {
     NULL, /* domainSetMemory */
     qemudDomainGetInfo, /* domainGetInfo */
     qemudDomainSave, /* domainSave */
+    NULL, /* domainSaveJob */
     qemudDomainRestore, /* domainRestore */
+    NULL, /* domainRestoreJob */
     NULL, /* domainCoreDump */
+    NULL, /* domainCoreDumpJob */
     NULL, /* domainSetVcpus */
     NULL, /* domainPinVcpu */
     NULL, /* domainGetVcpus */
@@ -2874,6 +2879,7 @@ static virDriver qemuDriver = {
     qemudListDefinedDomains, /* listDomains */
     qemudNumDefinedDomains, /* numOfDomains */
     qemudDomainStart, /* domainCreate */
+    NULL, /* domainCreateJob */
     qemudDomainDefine, /* domainDefineXML */
     qemudDomainUndefine, /* domainUndefine */
     qemudDomainAttachDevice, /* domainAttachDevice */
@@ -2894,6 +2900,7 @@ static virDriver qemuDriver = {
 
 static virNetworkDriver qemuNetworkDriver = {
     "QEMU",
+    NULL, /* jobDriver */
     qemudOpenNetwork, /* open */
     qemudCloseNetwork, /* close */
     qemudNumNetworks, /* numOfNetworks */
@@ -2903,9 +2910,11 @@ static virNetworkDriver qemuNetworkDrive
     qemudNetworkLookupByUUID, /* networkLookupByUUID */
     qemudNetworkLookupByName, /* networkLookupByName */
     qemudNetworkCreate, /* networkCreateXML */
+    NULL, /* networkCreateXMLJob */
     qemudNetworkDefine, /* networkDefineXML */
     qemudNetworkUndefine, /* networkUndefine */
     qemudNetworkStart, /* networkCreate */
+    NULL, /* networkCreateJob */
     qemudNetworkDestroy, /* networkDestroy */
     qemudNetworkDumpXML, /* networkDumpXML */
     qemudNetworkGetBridgeName, /* networkGetBridgeName */
diff -r 9b65842892de src/test.c
--- a/src/test.c	Fri Jan 04 17:29:33 2008 -0500
+++ b/src/test.c	Fri Jan 04 18:00:06 2008 -0500
@@ -1915,6 +1915,7 @@ static virDriver testDriver = {
     VIR_DRV_TEST,
     "Test",
     LIBVIR_VERSION_NUMBER,
+    NULL, /* jobDriver */
     testOpen, /* open */
     testClose, /* close */
     NULL, /* supports_feature */
@@ -1928,6 +1929,7 @@ static virDriver testDriver = {
     testListDomains, /* listDomains */
     testNumOfDomains, /* numOfDomains */
     testDomainCreateLinux, /* domainCreateLinux */
+    NULL, /* domainCreateLinuxJob */
     testLookupDomainByID, /* domainLookupByID */
     testLookupDomainByUUID, /* domainLookupByUUID */
     testLookupDomainByName, /* domainLookupByName */
@@ -1942,8 +1944,11 @@ static virDriver testDriver = {
     testSetMemory, /* domainSetMemory */
     testGetDomainInfo, /* domainGetInfo */
     testDomainSave, /* domainSave */
+    NULL, /* domainSaveJob */
     testDomainRestore, /* domainRestore */
+    NULL, /* domainRestoreJob */
     testDomainCoreDump, /* domainCoreDump */
+    NULL, /* domainCoreDumpJob */
     testSetVcpus, /* domainSetVcpus */
     NULL, /* domainPinVcpu */
     NULL, /* domainGetVcpus */
@@ -1952,6 +1957,7 @@ static virDriver testDriver = {
     testListDefinedDomains, /* listDefinedDomains */
     testNumOfDefinedDomains, /* numOfDefinedDomains */
     testDomainCreate, /* domainCreate */
+    NULL, /* domainCreateJob */
     testDomainDefineXML, /* domainDefineXML */
     testDomainUndefine, /* domainUndefine */
     NULL, /* domainAttachDevice */
@@ -1972,6 +1978,7 @@ static virDriver testDriver = {
 
 static virNetworkDriver testNetworkDriver = {
     "Test",
+    NULL, /* jobDriver */
     testOpenNetwork, /* open */
     testCloseNetwork, /* close */
     testNumNetworks, /* numOfNetworks */
@@ -1981,9 +1988,11 @@ static virNetworkDriver testNetworkDrive
     testLookupNetworkByUUID, /* networkLookupByUUID */
     testLookupNetworkByName, /* networkLookupByName */
     testNetworkCreate, /* networkCreateXML */
+    NULL, /* networkCreateXMLJob */
     testNetworkDefine, /* networkDefineXML */
     testNetworkUndefine, /* networkUndefine */
     testNetworkStart, /* networkCreate */
+    NULL, /* networkCreateJob */
     testNetworkDestroy, /* networkDestroy */
     testNetworkDumpXML, /* networkDumpXML */
     testNetworkGetBridgeName, /* networkGetBridgeName */
diff -r 9b65842892de src/virterror.c
--- a/src/virterror.c	Fri Jan 04 17:29:33 2008 -0500
+++ b/src/virterror.c	Fri Jan 04 18:00:06 2008 -0500
@@ -22,43 +22,6 @@ static virError lastErr =       /* the l
 { 0, 0, NULL, VIR_ERR_NONE, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL };
 static virErrorFunc virErrorHandler = NULL;     /* global error handlet */
 static void *virUserData = NULL;        /* associated data */
-
-/*
- * Macro used to format the message as a string in __virRaiseError
- * and borrowed from libxml2.
- */
-#define VIR_GET_VAR_STR(msg, str) {				\
-    int       size, prev_size = -1;				\
-    int       chars;						\
-    char      *larger;						\
-    va_list   ap;						\
-								\
-    str = (char *) malloc(150);					\
-    if (str != NULL) {						\
-								\
-    size = 150;							\
-								\
-    while (1) {							\
-	va_start(ap, msg);					\
-  	chars = vsnprintf(str, size, msg, ap);			\
-	va_end(ap);						\
-	if ((chars > -1) && (chars < size)) {			\
-	    if (prev_size == chars) {				\
-		break;						\
-	    } else {						\
-		prev_size = chars;				\
-	    }							\
-	}							\
-	if (chars > -1)						\
-	    size += chars + 1;					\
-	else							\
-	    size += 100;					\
-	if ((larger = (char *) realloc(str, size)) == NULL) {	\
-	    break;						\
-	}							\
-	str = larger;						\
-    }}								\
-}
 
 /*
  * virGetLastError:
@@ -318,6 +281,49 @@ virDefaultErrorFunc(virErrorPtr err)
     else
         fprintf(stderr, "libvir: %s%s %s%s: %s",
                 dom, lvl, domain, network, err->message);
+}
+
+/**
+ * __virSetError:
+ * @err: the error object to set
+ * @conn: the connection to the hypervisor if available
+ * @dom: the domain if available
+ * @net: the network if available
+ * @domain: the virErrorDomain indicating where it's coming from
+ * @code: the virErrorNumber code for the error
+ * @level: the virErrorLevel for the error
+ * @str1: extra string info
+ * @str2: extra string info
+ * @str3: extra string info
+ * @int1: extra int info
+ * @int2: extra int info
+ * @msg:  the message to display/transmit
+ *
+ * Internal routine called when an error is detected.
+ */
+void
+__virSetError(virErrorPtr err,
+              virConnectPtr conn, virDomainPtr dom, virNetworkPtr net,
+              int domain, int code, virErrorLevel level,
+              const char *str1, const char *str2, const char *str3,
+              int int1, int int2, const char *message)
+{
+    virResetError(err);
+    err->conn = conn;
+    err->dom = dom;
+    err->net = net;
+    err->domain = domain;
+    err->code = code;
+    err->message = strdup(message);
+    err->level = level;
+    if (str1 != NULL)
+        err->str1 = strdup(str1);
+    if (str2 != NULL)
+        err->str2 = strdup(str2);
+    if (str3 != NULL)
+        err->str3 = strdup(str3);
+    err->int1 = int1;
+    err->int2 = int2;
 }
 
 /**
@@ -373,26 +379,10 @@ __virRaiseError(virConnectPtr conn, virD
         VIR_GET_VAR_STR(msg, str);
     }
 
-    /*
-     * Save the information about the error
-     */
-    virResetError(to);
-    to->conn = conn;
-    to->dom = dom;
-    to->net = net;
-    to->domain = domain;
-    to->code = code;
-    to->message = str;
-    to->level = level;
-    if (str1 != NULL)
-        to->str1 = strdup(str1);
-    if (str2 != NULL)
-        to->str2 = strdup(str2);
-    if (str3 != NULL)
-        to->str3 = strdup(str3);
-    to->int1 = int1;
-    to->int2 = int2;
-
+    __virSetError(to, conn, dom, net, domain, code, level,
+                  str1, str2, str3, int1, int2, str);
+
+    free(str);
     /*
      * now, report it
      */

-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 




More information about the libvir-list mailing list