Asynchronous FunctionsAn asynchronous operation is executed in its own thread. An asynchronous function that started the operation returns to the caller immediately without waiting for the operation to complete. The results of the operation can be verified later when needed. Asynchronous functions return
The Callback Function (Event Handler) Asynchronous functions return data to the caller by means of an event handler (or callback function). The callback function could be called at any time, depending on how long the asynchronous function takes to complete. The callback function must have a specific signature. The prototype can be found in typedef PRL_METHOD_PTR(PRL_EVENT_HANDLER_PTR) ( PRL_HANDLE hEvent, PRL_VOID_PTR data ); The following is an example of the callback function implementation: static PRL_RESULT OurCallback(PRL_HANDLE handle, void *pData) { // Event handler code...
// You must always release the handle before exiting. PrlHandle_Free(handle); } A handle received by the callback function can be of type To handle system events within a callback function:
To handle jobs within a callback function:
Note: You must always free the handle that was passed to the callback function before exiting, regardless of whether you actually used it or not. Failure to do so will result in a memory leak. The following skeleton code demonstrates implementation of the above steps. In this example, the objective is to handle events of type static PRL_RESULT OurCallbackFunction(PRL_HANDLE hHandle, PRL_VOID_PTR pUserData) { PRL_JOB_OPERATION_CODE nJobType = PJOC_UNKNOWN; // job type PRL_HANDLE_TYPE nHandleType = PHT_ERROR; // handle type PRL_HANDLE hVm = PRL_INVALID_HANDLE; // virtual machine handle PRL_HANDLE hParam = PRL_INVALID_HANDLE; // event parameter PRL_HANDLE hJobResult = PRL_INVALID_HANDLE; // job result PRL_UINT32 nParamsCount = -1; // parameter count PRL_UINT32 nParamIndex = -1; // parameter index PRL_RESULT err = PRL_ERR_UNINITIALIZED; // error
// Check the type of the received handle. PrlHandle_GetType(hHandle, &nHandleType);
if (nHandleType == PHT_EVENT) // Event handle { PRL_EVENT_TYPE EventType; PrlEvent_GetType(hHandle, &EventType);
// Check if the event type is a statistics update. if (EventType == PET_DSP_EVT_HOST_STATISTICS_UPDATED) { // Get handle to PHT_EVENT_PARAMETER. PRL_HANDLE hEventParameters = PRL_INVALID_HANDLE; PrlEvent_GetParam(hHandle, 0, &hEventParameters);
// Get handle to PHT_SYSTEM_STATISTICS. PRL_HANDLE hServerStatistics = PRL_INVALID_HANDLE; PrlEvtPrm_ToHandle(hEventParameters, &hServerStatistics);
// Code goes here to extract the statistics data // using hServerStatistics.
PrlHandle_Free(hServerStatistics); PrlHandle_Free(hEventParameters); } } else if (nHandleType == PHT_JOB) // Job handle { // Get the job type. PrlJob_GetOpCode(hHandle, &nJobType);
// Check if the job type is PJOC_SRV_GET_VM_LIST. if (nJobType == PJOC_SRV_GET_VM_LIST) { // Check the job return code. PRL_RESULT nJobRetCode; PrlJob_GetRetCode(hHandle, &nJobRetCode); if (PRL_FAILED(nJobRetCode)) { fprintf(stderr, "[B]%.8X: %s\n", nJobRetCode, prl_result_to_string(nJobRetCode)); PrlHandle_Free(hHandle); return nJobRetCode; }
err = PrlJob_GetResult(hHandle, &hJobResult);
// if (err != PRL_ERR_SUCCESS), process the error here.
// Determine the number of parameters in the result. PrlResult_GetParamsCount(hJobResult, &nParamsCount);
// Iterate through the parameter list. for(nParamIndex = 0; nParamIndex < nParamsCount ; nParamIndex++) { // Obtain a virtual machine handle (PHT_VIRTUAL_MACHINE). PrlResult_GetParamByIndex(hJobResult, nParamIndex, &hVm);
// Code goes here to obtain virtual machine info from hVm.
// Free the handle when done using it. PrlHandle_Free(hVm); } PrlHandle_Free(hJobResult); } }
PrlHandle_Free(hHandle); return PRL_ERR_SUCCESS; } Registering / Unregistering an Event Handler The Note: When an event handler is registered, it will receive all of the events/jobs regardless of their origin. It is the responsibility of the program to identify the type of the event and to handle each one accordingly. // Register an event handler. ReturnDataClass rd; // some user-defined class. PrlSrv_RegEventHandler(hServer, OurCallbackFunction, &rd);
// Make a call to an asynchronous function here. // OurCallbackFunction will be called by the background thread // as soon as the job is completed, and code within // OurCallbackFunction can populate the ReturnDataClass instance. // For example, we can make the following call here:
hJob = PrlSrv_GetVmList(hServer); PrlHandle_Free(hJob);
// Please note that we still have to obtain the // job object (hJob above) and free it; otherwise // we will have memory leaks.
// Unregister the event handler when it is no longer needed. PrlSrv_UnregEventHandler(hServer, OurCallbackFunction, &rd); Calling Asynchronous Functions Synchronously It is possible to call an asynchronous function synchronously by using the // Log in (PrlSrv_Login is asynchronous). PRL_HANDLE hJob = PrlSrv_Login( hServer, szHostnameOrIpAddress, szUsername, szPassword, 0, 0, 0, PSL_LOW_SECURITY);
// Wait for a maximum of 10 seconds for // asynchronous function PrlSrv_Login to complete. ret = PrlJob_Wait(hJob, 10000); if (PRL_FAILED(ret)) { fprintf(stderr, "PrlJob_Wait for PrlSrv_Login returned with error: %s\n", prl_result_to_string(ret)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); return -1; }
// Analyse the result of the PrlServer_Login call. PRL_RESULT nJobResult; ret = PrlJob_GetRetCode(hJob, &nJobResult); if (PRL_FAILED(nJobResult)) { PrlHandle_Free(hJob); PrlHandle_Free(hServer); printf("Login job returned with error: %s\n", prl_result_to_string(nJobResult)); return -1; } else { printf("login successfully performed\n"); } |
||||
|