VIX API Concepts

######

# VIX API Concepts

######

This chapter contains the following topics:

- Objects and Handles
- Reference Counting on Handles
- Error Codes
- Multithreading
- Handle Properties
- Property Lists
- Asynchronous Operations and Job Objects
- Callback Functions
- Event Models
- Using the Event Pump
- Local and Remote Host Handles

## Objects and Handles

The Vix API is object-based. Most API functions either create objects or operate on the properties of existing objects.

Client applications reference Vix objects with handles. Handles are opaque identifiers (actually integers) that can be passed as parameters to functions. Handles are run-time only and are unique only within a client's address space.

Most functions in the C-language API take a handle as a parameter. Because a handle value represents an object to the API, this document uses the terms "handle" and "object" interchangeably.

There are several handle types, but a few of the key types are:

- Virtual Machine – A single virtual machine, which might or might not be powered on.
- Host – A single host computer, either the local host or a remote host.
- Job – An object used in managing asynchronous operations.
- Snapshot – A snapshot of a virtual machine.

## Reference Counting on Handles

Handles are reference counted, so you must call a "release" function on the handle when you are done using it. A handle remains valid until you call the `Vix_ReleaseHandle()` function. The `Vix_ReleaseHandle()` function releases any type of handle:

    void Vix_ReleaseHandle(VixHandle handle);

For example, consider the following code to open and release a handle:

###### Example 2-1.

    VixHandle handle1;
    handle1 = MyOpenVMWrapper(...various parameters...);
    // handle1 is assigned a unique integer value.

    // Now you can perform various operations on handle1.

    Vix_ReleaseHandle(handle1);
    handle1 = VIX_INVALID_HANDLE;
    // handle1 has been released and should no longer be used.

### Handle Independence

Generally, you can have any number of handles active at one time. Each handle represents a different object, and handles can be created and destroyed independently. Consider the following example:

###### Example 2-2.

    VixHandle handle1;
    VixHandle handle2;

    handle1 = MyOpenVMWrapper(... parameters for virtual machine 1...);
    // handle1 is assigned a unique value - for example, 11.

    handle2 = MyOpenVMWrapper(... parameters for virtual machine 2...);
    // handle2 is assigned a unique value - for example, 12.

    // Now you can perform various operations on handle1 or handle2.

    Vix_ReleaseHandle(handle1);
    handle1 = VIX_INVALID_HANDLE;
    // handle1 has been released and should no longer be used.

    // You can still perform operations on handle 2.

    Vix_ReleaseHandle(handle2);
    handle2 = VIX_INVALID_HANDLE;
    // handle2 has been released and should no longer be used.

### Deleting Handles

Clients must still call the release function even when the data stored in that handle has been deleted by another function. For example, to delete a virtual machine, you first call a delete function on the virtual machine's handle, and then you call the release function on the handle itself. This design avoids confusion over which functions do and do not release handles; only the release function can release a handle.

The client application is responsible for calling the release function on every handle. In the case of releasing a handle after deleting a virtual machine, the delete function updates the internal handle state, so most functions except the release function will recognize that the virtual machine has been deleted and will immediately return an error.

### Opening Handles

If you open a handle to the same virtual machine twice, without releasing the first handle, the open function will return the same handle both times. The handle reference count is incremented each time the open function returns, so you must call the release function twice, once for each time you open the handle. Consider the following example:

###### Example 2-3.

    VixHandle handle1;
    VixHandle handle2;

    handle1 = MyOpenVMWrapper(...various parameters...);
    // handle1 is assigned a unique value.
    // handle1 has reference count 1.

    // Now you can perform various operations on handle1.

    handle2 = MyOpenVMWrapper(...the SAME parameters identifying the SAME virtual machine...);
    // handle2 has the same value as handle1.
    // handle1 has reference count 2.
    ASSERT(handle1 == handle2);

    Vix_ReleaseHandle(handle1);
    // handle1 has reference count 1.

    // The handle still can be safely used here.

    Vix_ReleaseHandle(handle1);
    handle1 = handle2 = VIX_INVALID_HANDLE;
    // The handle has been released and should no longer be used.

In general, every function that returns a handle increments the handle's reference count. This means a client application should call the release function once for every time the handle has been returned by a Vix function.

### Internal Handle References

Some handles keep an internal reference to another handle. For example, a device keeps a reference to its virtual machine, and a virtual machine keeps references to all its devices. As a result of these internal references, some handles might not be deleted when the client is done with them. This situation should not impact the client, because the internal reference counting is always correctly maintained. When an internal reference keeps a handle open, the client receives the same handle value when it opens the same object again after releasing its handle.

## Error Codes

All synchronous Vix functions return an error code, which is an integer value defined by a global type. Asynchronous Vix functions (described below) report an error code when the function eventually completes.

Some Vix functions can return an internally defined error code value, such as an integer value that is not part of the public type. This is unusual; it indicates an internal error that cannot be translated to a public error code.

The error code type is `VixError`. It is defined in the public Vix header. Error codes are listed in the VIX API Reference Guide.

A Vix error is a 64-bit value. A value of `VIX_OK` indicates success, but if there is an error then several bit regions in the 64-bit value might be set. The least significant 16 bits are set to the error code described for Vix errors. More significant bit fields might be set to other values.

### Error Code Functions

Vix provides the following defines for working with error codes:

- `VIX_ERROR_CODE(err)`

  Use this to mask off bit fields not used by the Vix API.

  ###### Example 2-4.

      VixError err;
      err = VixJob_GetError(jobHandle);
      if (VIX_E_FILE_NOT_FOUND == VIX_ERROR_CODE(err)) {
         // Handle error case...
      }

- `VIX_SUCCEEDED(err)`

  Use this to test for the absence of an error.

  ###### Example 2-5.

      VixError err;
      err = VixJob_GetError(jobHandle);
      if (VIX_SUCCEEDED(err)) {
         // Handle success case...
      }

- `VIX_FAILED(err)`

  Use this to test for the presence of an error.

  ###### Example 2-6.

      VixError err;
      err = VixJob_GetError(jobHandle);
      if (VIX_FAILED(err)) {
         // Handle failure case...
      }

### Error Code Bit Masking

If you prefer to do your own bit masking on error codes, here are some examples:

###### Example 2-7.

    VixError err;

    err = VixJob_GetError(jobHandle);

    // CORRECT!
    // This is legal. Success is always indicated with VIX_OK.
    if (VIX_OK == err) {
       // Handle success case...
    }

    // CORRECT!
    // This is legal. Success is always indicated with VIX_OK (all zeroes).
    // Anything else is an error.
    if (VIX_OK != err) {
       // Handle error case...
    }

    // WRONG!
    // If an error code is not VIX_OK, several bit fields may be set.
    if (VIX_E_FILE_NOT_FOUND == err) {
       // This will not work...
    }

    // CORRECT!
    // If an error code is not VIX_OK, the least significant 16 bits
    // will be the Vix error code.
    if (VIX_E_FILE_NOT_FOUND == (err & 0xFFFF)) {
       // Handle error case...
    }

## Multithreading

The Vix library is intended for use by multi-threaded clients. Vix shared objects are managed by the Vix library to avoid conflicts between threads. Clients need only be responsible for protecting user-defined shared data.

### Thread Safety of Handles

All Vix objects are thread safe so they may be used from several threads at the same time.

The Vix library handles locking of objects when they are modified. As a result, client code does not need to be concerned with the protection of objects when they are used from multiple threads.

### Performance Implications

Locking shared objects implies some performance degradation in certain situations. For example, when you power on a virtual machine, the Vix library needs to modify both the virtual machine handle and the host's list of running virtual machines. If two clients power on two virtual machines at the same time, the Vix library needs to lock the list of running virtual machines on behalf of one client, causing a small delay for the second client.

## Handle Properties

The Vix API defines a set of properties for each type of handle. A property is a typed name/value pair. A type name is a unique integer ID and the type may be one of the following:

- 32-bit Integer
- 64-bit Integer
- String
- Boolean
- Handle

Vix defines a different set of properties for each handle type. For example, a virtual machine handle has a string property that stores the file path name of the virtual machine, but a job handle does not. The complete set of handle properties for each type is defined in the VIX API Reference Guide.

If a property is defined for a particular handle type, all handles of that type always have some value for that property. For example, every virtual machine has a property that stores its file path name, whether the virtual machine is powered on or not, or whether it is stored on the local host or not.

Clients can modify handle properties only by invoking functions on the handle. For example, the function `VixVM_PowerOn()` modifies the `VIX_PROPERTY_VM_IS_RUNNING` of the virtual machine handle.

Properties are the main mechanism for reading both the persistent configuration state and the runtime status of handles. Properties allow Vix to be language independent and backward compatible.

### GetProperties() Function

Vix provides one function that can get properties from any handle. This function has a varargs signature, which means you can use it to retrieve any number of properties by passing in sufficient parameters. The argument list must be terminated with a special property, `VIX_PROPERTY_NONE`.

    VixError Vix_GetProperties(VixHandle handle,
                               VixPropertyID firstPropertyID,
                               ...);

Here is an example of retrieving properties from a virtual machine handle:

###### Example 2-8.

    VixError err;
    VixHandle handle1;
    int vmPowerState;
    char *vmVmxPathName;

    handle1 = MyOpenVMWrapper(...various parameters...);

    err = Vix_GetProperties(handle1,
                            VIX_PROPERTY_VM_VMX_PATHNAME,
                            &vmVmxPathName,
                            VIX_PROPERTY_VM_POWER_STATE,
                            &vmPowerState,
                            VIX_PROPERTY_NONE);

## Property Lists

Vix defines a special runtime data structure, the property list, as a convenient way to store properties and pass them as arguments. Property lists are runtime-only data structures, and they behave as Vix objects. You can reference a property list with a handle and you can pass the handle to functions such as `Vix_GetProperties()`.

Here is an example of a callback function that retrieves a value from a property list.

###### Example 2-9.

    void MyFunction(VixHandle propertyListHandle)
    {
       char *url = NULL;

       err = Vix_GetProperties(propertyListHandle,
                               VIX_PROPERTY_VM_VMX_PATHNAME,
                               &url,
                               VIX_PROPERTY_NONE);
       if (VIX_OK != err) {
          // ...Handle the error...
       }
       // ... Use the url property, then release the buffer ...
       Vix_FreeBuffer(url);
    }

## Asynchronous Operations and Job Objects

Many Vix functions are synchronous, which makes them easy to use. Some functions, however, such as powering on a virtual machine, are asynchronous. These asynchronous functions either implement time-consuming operations or interact with the persistent virtual machine state, which can be on a remote host.

All asynchronous Vix functions allocate and return a "job" handle, which is a Vix object that represents the execution of an asynchronous operation. A job handle can be used to signal when the asynchronous operation has completed, and also to retrieve the results of a completed asynchronous function. A job has a single "completed" state, which indicates when the job has finished. Additionally, a job may have several result properties that are set when the job has completed. These result properties contain information returned by a completed job. Different kinds of jobs have different return values.

A new job object is created for each active asynchronous call. For example, if you invoke three asynchronous calls, they all might complete at different times and they each have a different job object. Vix always creates a job handle for every asynchronous call. Even if you do not use the handle, you are still responsible for releasing it.

### Monitoring a Job Object

Currently, a client application can use several mechanisms to detect when a job object has been signaled:

- Poll the job, by calling a non-blocking function that checks whether it has been signaled. This is described in Polling the Job Object for Completion.
- Block until the job is signaled, by calling the `VixJob_Wait()` function. This is described in Using the Job Object to Block Calls.
- Register a callback function that is called when the job is signaled. This is described in Using a Callback Function.

A typical asynchronous call looks similar to `VixVM_Open()`, and there are several common patterns shared by all asynchronous Vix calls. For reference, the following code shows the signature of `VixVM_Open()`.

    VixHandle VixVM_Open(VixHandle hostHandle,
                         const char *vmxFilePathName,
                         VixEventProc *callbackProc,
                         void *clientData);

This function creates a Vix job object and returns a `VixHandle` for this new job object. The caller is responsible for releasing this job object, even if the job object is not used for anything else.

### Polling the Job Object for Completion

The job object tracks the status of an asynchronous operation. You can interrogate the completion status of a job object using the function `VixJob_CheckCompletion()`. This is a non-blocking function that returns a Boolean value representing the completion state of the asynchronous operation. The following example shows the use of `VixJob_CheckCompletion()` in a polling loop.

###### Example 2-10.

    Bool OpenVMWithPolling(const VixHandle hostHandle,
                           const char *vmName,
                           VixHandle *vmHandle)
    {
       VixError err = VIX_OK;
       VixHandle jobHandle = VIX_INVALID_HANDLE;
       Bool completed = FALSE;

       if (!vmHandle) {
          return FALSE;
       }
       *vmHandle = VIX_INVALID_HANDLE;

       // Start asynchronous operation.
       jobHandle = VixVM_Open(hostHandle,
                              vmName,
                              NULL, // callbackProc,
                              NULL); // clientData

       // Poll the job object for completion of asynchronous operation.
       while ( !completed ) {
          sleep(1);

          err = VixJob_CheckCompletion(jobHandle, &completed);
          if (VIX_OK != err) {
             Vix_ReleaseHandle(jobHandle);
             return FALSE;
          }
       }

       err = Vix_GetProperties(jobHandle,
                               VIX_PROPERTY_JOB_RESULT_HANDLE,
                               vmHandle,
                               VIX_PROPERTY_NONE);
       if (VIX_OK != err) {
          Vix_ReleaseHandle(jobHandle);
          *vmHandle = VIX_INVALID_HANDLE;
          return FALSE;
       }

       Vix_ReleaseHandle(jobHandle);
       return TRUE;
       // Caller must release vmHandle.
    }

### Using the Job Object to Block Calls

The job object allows a client to block until an asynchronous call completes. This achieves the same result as if the asynchronous call were a synchronous call. Here is an example of how this can be done, using the `VixJob_Wait()` function.

###### Example 2-11.

    VixHandle hostHandle = VIX_INVALID_HANDLE;
    VixHandle jobHandle = VIX_INVALID_HANDLE;
    VixHandle vmHandle = VIX_INVALID_HANDLE;

    jobHandle = VixHost_Connect(VIX_API_VERSION,
                                VIX_SERVICEPROVIDER_VMWARE_VI_SERVER,
                                "server2.example.com", // hostName
                                0, // hostPort
                                "root", // username
                                "secretpw", // password
                                0, // options
                                VIX_INVALID_HANDLE, // propertyListHandle
                                NULL, // callbackProc
                                NULL); // clientData

    // Wait for completion of operation.
    err = VixJob_Wait(jobHandle, VIX_PROPERTY_NONE);
    if (VIX_OK != err) {
       goto abort;
    }

    // Release handle when done.
    Vix_ReleaseHandle(jobHandle);
    jobHandle = VIX_INVALID_HANDLE;

### Retrieving Results from Job Object Properties

The job object can also be used to retrieve results from an asynchronous operation once the asynchronous operation has completed. You can get these properties by calling `Vix_GetProperties()` on the job handle. The following example shows how this is done.

###### Example 2-12.

    VixHandle hostHandle = VIX_INVALID_HANDLE;
    VixHandle jobHandle = VIX_INVALID_HANDLE;
    VixHandle vmHandle = VIX_INVALID_HANDLE;

    jobHandle = VixHost_Connect(VIX_API_VERSION,
                                VIX_SERVICEPROVIDER_VMWARE_VI_SERVER,
                                "server2.example.com", // hostName
                                0, // hostPort
                                "root", // username
                                "secretpw", // password
                                0, // options
                                VIX_INVALID_HANDLE, // propertyListHandle
                                NULL, // callbackProc
                                NULL); // clientData

    // Wait for completion of operation.
    err = VixJob_Wait(jobHandle, VIX_PROPERTY_NONE);
    if (VIX_OK != err) {
       goto abort;
    }

    // Collect desired result of operation.
    err = Vix_GetProperties(jobHandle,
                            VIX_PROPERTY_JOB_RESULT_HANDLE,
                            &hostHandle,
                            VIX_PROPERTY_NONE);

    // Release handle when done.
    Vix_ReleaseHandle(jobHandle);
    jobHandle = VIX_INVALID_HANDLE;

For convenience, you can also extract properties from the job object with the `VixJob_Wait()` function. The following example shows how this is done.

###### Example 2-13.

    // Start asynchronous operation.
    jobHandle = VixVM_Open(hostHandle,
                           "[standard] WindowsXP/WindowsXP.vmx",
                           NULL, // callbackProc
                           NULL); // clientData

    // Wait for completion of operation. Collect result handle.
    err = VixJob_Wait(jobHandle,
                      VIX_PROPERTY_JOB_RESULT_HANDLE,
                      &vmHandle,
                      VIX_PROPERTY_NONE);

    // Release handle when done.
    Vix_ReleaseHandle(jobHandle);
    jobHandle = VIX_INVALID_HANDLE;

For simplicity, most of the examples in this document use the approach of calling `VixJob_Wait()` and requesting the desired properties at the same time. Some kinds of applications might increase responsiveness by using callback functions in a multithreaded client.

## Callback Functions

All asynchronous Vix functions, such as `VixVM_Open()`, include a parameter for a callback procedure and a parameter that is passed to the callback procedure. These parameters are optional, so a caller can pass `NULL` for either. The prototype of this callback procedure parameter is:

    typedef void (VixEventProc)(VixHandle handle,
                                VixEventType eventType,
                                VixHandle moreEventInfo,
                                void *clientData);

### Using a Callback Function

If the caller provides a callback procedure, that procedure is registered with the job object and is invoked when the job object is signaled. For example, if a caller passes a callback procedure to `VixVM_Open()`, that callback procedure is invoked when the virtual machine has been opened. This situation could happen either before or after `VixVM_Open()` returns. It also can happen on any thread.

This mechanism allows Vix functions to run asynchronously. Asynchronous Vix functions should complete their work quickly and then return from the callback. Asynchronous functions must not block, and Vix applications should never call `VixJob_Wait()` while using a callback function.

When a callback procedure is invoked, it is passed the `clientData` parameter that was passed in the original call to the asynchronous function. This allows a callback procedure to associate some context with an outstanding asynchronous call.

###### Example 2-14.

    void myCallback(VixHandle jobHandle,
                    VixEventType eventType,
                    VixHandle moreEventInfo,
                    void *clientData)
    {
       VixError err;
       VixError asyncErr;
       VixHandle vmHandle = VIX_INVALID_HANDLE;

       /*
        * Ignore progress callbacks. Check only for final signal.
        */
       if (VIX_EVENTTYPE_JOB_COMPLETED != eventType) {
          return;
       }

       err = Vix_GetProperties(jobHandle,
                               VIX_PROPERTY_JOB_RESULT_HANDLE,
                               &vmHandle,
                               VIX_PROPERTY_JOB_RESULT_ERROR_CODE,
                               &asyncErr,
                               VIX_PROPERTY_NONE);

       if (VIX_OK != asyncErr) {
          /*
           * The open failed.
           */
       }
    }

    int main()
    {
       VixError err = VIX_OK;
       VixHandle hostHandle = VIX_INVALID_HANDLE;
       VixHandle jobHandle = VIX_INVALID_HANDLE;
       VixHandle vmHandle = VIX_INVALID_HANDLE;
       char *contextData = "Hello, Vix";

       jobHandle = VixHost_Connect(VIX_API_VERSION,
                                   VIX_SERVICEPROVIDER_VMWARE_VI_SERVER,
                                   "server2.example.com", // hostName
                                   0, // hostPort
                                   "root", // username
                                   "secretpw", // password
                                   0, // options
                                   VIX_INVALID_HANDLE, // propertyListHandle
                                   NULL, // callbackProc
                                   NULL); // clientData

       // Block for host connection to complete.
       err = VixJob_Wait(jobHandle,
                         VIX_PROPERTY_JOB_RESULT_HANDLE,
                         &hostHandle,
                         VIX_PROPERTY_NONE);
       Vix_ReleaseHandle(jobHandle);
       jobHandle = VIX_INVALID_HANDLE;
       if (VIX_OK != err) {
          goto abort;
       }

       // Use callback function to capture completion of virtual machine open.
       jobHandle = VixVM_Open(hostHandle,
                              "[standard] WindowsXP/WindowsXP.vmx",
                              myCallback,
                              contextData);
       /*
        * Do something, like pump a message pump.
        * Later, myCallback will be invoked on another thread.
        */

    abort:
       Vix_ReleaseHandle(jobHandle);
       jobHandle = VIX_INVALID_HANDLE;
    }

### Callback Events

Note that a callback might be called several times, for several different reasons. For example, it might be called for periodic progress updates. The `eventType` parameter indicates why the callback is being called. The supported event types are:

- `VIX_EVENTTYPE_JOB_COMPLETED` – Indicates that the asynchronous action has completed, whether successfully or not.
- `VIX_EVENTTYPE_JOB_PROGRESS` – This event may be passed several times to report progress on an asynchronous action.
- `VIX_EVENTTYPE_FIND_ITEM` – This event is used by `VixHost_FindItems()`.
- `VIX_EVENTTYPE_HOST_INITIALIZED` – This event is used by `VixHost_Connect()`.

## Event Models

The Vix API provides the flexibility to handle events in different ways, depending on the needs of the client. The "event pump" mechanism allows you to process asynchronous operations in single-threaded clients. This section discusses both ways to manage asynchronous operations.

### Multi-Threaded Event Model

The multi-threaded event model is the default model for Vix clients. Its use is described in detail in the section above called Callback Functions. This model is the easiest to use, if your client code is thread-safe.

Using this model, the Vix library creates worker threads as needed to process asynchronous operations in parallel. Callback functions are invoked on the worker threads under the control of the Vix library.

### Single-Threaded Event Model

Using the single-threaded model, all asynchronous processing and all event reporting is deferred until the thread calls `Vix_PumpEvents()`. Each call to `Vix_PumpEvents()` does more work on an asynchronous operation. At appropriate times during the operation, control is transferred to the callback routine, if one was specified in the call to the asynchronous function that began the operation.

The single-threaded event model is useful for clients that are not thread safe, or that depend on libraries that are not thread-safe. All processing is done in a single thread. You have to write extra code for a polling loop, but you need not be concerned with synchronizing multiple threads.

## Using the Event Pump

To use the event pump:

1. Connect to the host with a flag indicating that events are to be triggered by `Vix_PumpEvents()` and received by a callback function on the same thread. Otherwise, events are reported asynchronously and callback functions are invoked on a pool of Vix worker threads.

   The flag is a value of `VIX_HOSTOPTION_USE_EVENT_PUMP` passed in the `options` parameter to the `VixHost_Connect()` function.

   ###### Example 2-15.

       VixHandle hostHandle = VIX_INVALID_HANDLE;
       VixHandle jobHandle = VIX_INVALID_HANDLE;
       VixError err;

       jobHandle = VixHost_Connect(VIX_API_VERSION,
                                   VIX_SERVICEPROVIDER_VMWARE_WORKSTATION,
                                   NULL, // hostName
                                   0, // hostPort
                                   NULL, // userName
                                   NULL, // password,
                                   VIX_HOSTOPTION_USE_EVENT_PUMP, // options
                                   VIX_INVALID_HANDLE, // propertyListHandle
                                   NULL, // callbackProc
                                   NULL); // clientData
       err = VixJob_Wait(jobHandle,
                         VIX_PROPERTY_JOB_RESULT_HANDLE,
                         &hostHandle,
                         VIX_PROPERTY_NONE);
       if (VIX_OK != err) {
          // Handle the error...
          goto abort;
       }

2. Call `Vix_PumpEvents()` at appropriate times to advance processing of the asynchronous operation.

       Vix_PumpEvents(hostHandle, VIX_PUMPEVENTOPTION_NONE);

   If your application is multithreaded, you can call this function from a separate thread. You can never call `VixJob_Wait()` on the same thread that also calls `Vix_PumpEvents()`. However, you can call `Vix_PumpEvents()` on one thread and `VixJob_Wait()` on another thread.

3. Check the results of the asynchronous operation, either by polling or by callback. The polling method is explained in Polling for Completion in a Single-Threaded Client. The callback method is explained in Using a Callback Function in a Single-Threaded Client.

### Polling for Completion in a Single-Threaded Client

Single-threaded clients must share the thread between the main logic of the program and the processing that takes place as a result of calling an asynchronous function. In a single-threaded client, the processing can only take place during a call to `Vix_PumpEvents()`.

That fact implies that the single-threaded client cannot call `VixJob_Wait()`. In a multi-threaded client, a call to `VixJob_Wait()` returns when the asynchronous operation is completed by another thread. However, in a single-threaded client, `VixJob_Wait()` never returns because there is no processing happening on any thread during the call to `VixJob_Wait()`.

One solution is to poll for completion using `VixJob_CheckCompletion()` instead of calling `VixJob_Wait()`. You alternate pumping with polling, as in the following example.

###### Example 2-16.

    // Function to poll for completion.
    // Returns TRUE if successful; otherwise returns FALSE.
    Bool CheckCompletion(VixHandle hostHandle,
                         VixHandle jobHandle,
                         int timeOut)
    {
       Bool completed = FALSE;
       VixError err = VIX_OK;
       int secondCount = 0;

       while (!completed && secondCount < timeOut) {
          Vix_PumpEvents(hostHandle, VIX_PUMPEVENTOPTION_NONE);

          err = VixJob_CheckCompletion(jobHandle, &completed);
          if (VIX_OK != err) {
             return FALSE;
          }

          secondCount++;
          sleep(1);
       }

       if ((!completed) && (secondCount == ONE_MINUTE)) {
          return FALSE;
       }

       return TRUE;
    }

    // Part of virtual machine processing below.
    VixError err = VIX_OK;
    VixHandle jobHandle = VIX_INVALID_HANDLE;
    VixPowerState powerState = 0;

    // Suspend the virtual machine.
    jobHandle = VixVM_Suspend(vmHandle,
                              0, // powerOnOptions,
                              VIX_INVALID_HANDLE, // propertyListHandle,
                              NULL, // callbackProc,
                              NULL); // clientData

    // The powerState may be VIX_POWERSTATE_SUSPENDING for a few seconds.
    // Wait for completion.
    if (CheckCompletion(hostHandle, jobHandle, 30)) {
       // Now the powerState should be ready.
       err = Vix_GetProperties(vmHandle,
                               VIX_PROPERTY_VM_POWER_STATE,
                               &powerState,
                               VIX_PROPERTY_NONE);
       if (VIX_OK != err) {
          // Handle the error...
          goto abort;
       }
    } // CheckCompletion

### Using a Callback Function in a Single-Threaded Client

Single-threaded clients also have the option to use callback functions that handle completion. Because the callback has to share the single thread, it cannot happen asynchronously. As with the polling method of completion described in Polling for Completion in a Single-Threaded Client, the client cannot call `VixJob_Wait()`.

In the single-threaded client, processing takes place only during calls to `Vix_PumpEvents()`. Each call does more work on the operation. If a callback was specified in the call to the asynchronous function that began the operation, the Vix library invokes the callback function during one of the calls to `Vix_PumpEvents()`.

The code to use this method looks like the following example. The main function initiates a host connection operation (specifying a callback function) and then enters a loop to pump events. When the operation has completed, the callback function returns a handle to the host (or an invalid value in case of failure).

###### Example 2-17.

    Bool handleCallbackDone = FALSE;

    void handleCallback(VixHandle jobHandle,
                        VixEventType eventType,
                        VixHandle moreEventInfo,
                        void *clientData)
    {
       /*
        * This function is invoked on completion of an asynchronous operation.
        * If the operation succeeded, this function returns a handle
        * that resulted from the asynchronous operation.
        */
       VixError err;
       VixError asyncErr;
       VixHandle resultHandle = VIX_INVALID_HANDLE;

       /*
        * Ignore progress callbacks. Check only for final signal.
       */
       if (VIX_EVENTTYPE_JOB_COMPLETED != eventType) {
          return;
       }

       err = Vix_GetProperties(jobHandle,
                               VIX_PROPERTY_JOB_RESULT_HANDLE,
                               &resultHandle,
                               VIX_PROPERTY_JOB_RESULT_ERROR_CODE,
                               &asyncErr,
                               VIX_PROPERTY_NONE);
       if (VIX_OK != err) {
          // Failed to get properties. Bail.
          *clientData = VIX_INVALID_HANDLE;
          handleCallbackDone = TRUE;
          return;
       }

       if (VIX_OK == asyncErr) {
          *clientData = (void) resultHandle;
       } else {
          // The asynchronous operation failed. Bail.
          *clientData = VIX_INVALID_HANDLE;
       }

       handleCallbackDone = TRUE;
    } // end handleCallback

    int main()
    {
       VixHandle hostHandle = VIX_INVALID_HANDLE;
       VixHandle jobHandle = VIX_INVALID_HANDLE;
       char *contextData = "Hello, Vix";

       jobHandle = VixHost_Connect(VIX_API_VERSION,
                                   VIX_SERVICEPROVIDER_VMWARE_VI_SERVER,
                                   "server2.example.com", // hostName
                                   0, // hostPort
                                   "root", // username
                                   "secretpw", // password
                                   VIX_HOSTOPTION_USE_EVENT_PUMP, // options
                                   VIX_INVALID_HANDLE, // propertyListHandle
                                   handleCallback,
                                   (void *) &hostHandle);

       // Release handle, if not using it.
       Vix_ReleaseHandle(jobHandle);
       jobHandle = VIX_INVALID_HANDLE;

       // Pump events and wait for callback.
       handleCallbackDone = FALSE;
       while (!handleCallbackDone) {
          Vix_PumpEvents();
       }

       if (VIX_INVALID_HANDLE == hostHandle) {
          printf(":-(\n");
       } else {
          printf(":-)\n");
       }
    } // end main

## Local and Remote Host Handles

Vix defines a "host" object (identified by a handle) that allows access to virtual machines. Typically, a Vix application begins by getting a handle to a host object, and then passing that host handle to other functions. A host handle can represent either a local or remote machine.

Vix provides a single API function to open any host. To open an arbitrary host, the function requires a machine name and password authentication.

When you have a host object, you pass it as a parameter to several Vix functions, such as the function that opens a handle to a virtual machine. When the client completes all operations, it releases the host handle with a call to `VixHost_Disconect()`. All handles and all states associated with that host are erased by the call.