Dynamic Probe Class Library

Dynamic Probe Class Library Programming Guide


Chapter 4. Performing status error checking

Before we describe such standard DPCL programming tasks as initializing the analysis tool and connecting to a target application, a general discussion of DPCL error checking is in order. While many of the code examples in this book are for illustration only and therefore do not perform rigorous error checking, any real-world DPCL application will need to check the return status of each DPCL function it calls. As with any kind of error-checking situation, if the status returned by a DPCL function call indicates an error condition, the analysis tool should respond to the condition in some way. For example, if the returned status for a Process::bconnect call indicates that if was unable to connect to the process because of an invalid process ID, the analysis tool could respond by displaying the invalid process ID to the analysis tool user and prompt the user to supply a valid one. If error checking were not performed in this example, then subsequent DPCL calls made by the analysis tool (for, say, probe installation) would also fail since a connection to the process was never established.

As described in What is the AisStatus class?, status is returned by DPCL functions in the form of AisStatus objects which store status and severity codes. In some cases, the AisStatus object also contains data associated with the status. For example, in the situation described above in which the AisStatus object indicated that the process ID was invalid, the AisStatus object would also contain a data string to show the invalid process ID.

The following example code shows a single error checking routine that examines an AisStatus object and reports error conditions to the analysis-tool user. This simple function first calls the AisStatus::status function to see if it indicates the successful completion of whatever service was requested. If it does not, the function then calls the AisStatus::status_name function to get the name of the status code that was returned, and prints this name to standard output. Since the AisStatus object might also contain data associated with the error condition, the following example function also calls the AisStatus::data_count and AisStatus::data_value functions to get this information if it is available. The AisStatus::data_count function returns the number of data values associated with the AisStatus object and is used here to initialize a loop. The AisStatus::data_value function copies a particular data value associated with the AisStatus object into a specified buffer -- in this case the buffer buf. For more information on the AisStatus::status, AisStatus::data_count, and AisStatus::data_value functions, refer to their UNIX man pages or the DPCL Class Reference.







#include <stdio.h>

#include <stdlib.h>

#include "dpcl.h"

 

#define BUFLEN 128

 

void check_status(AisStatus &sts, char *name) {

  char buf[BUFLEN];

  int i, dc;

 

  if (sts.status() != ASC_success) {

    printf("error from %s: %s\n", name, sts.status_name());

    dc = sts.data_count();

    for (i=0; i<dc; ++i) {

      sts.data_value(i, buf, BUFLEN);

      printf("  '%s'\n", buf);

    }

  }

}

 

main(int argc, char *argv[]) {

  AisStatus sts;

  char hostname[BUFLEN];

  int apppid;

 

  if (argc < 3) {

    printf("need two args\n");

    return 0;

  }

 

  strcpy(hostname, argv[1]);

  apppid = atoi(argv[2]);

  

  Process P(hostname, apppid);

 

  Ais_initialize();

 

  sts = P.bconnect();

  if (sts.status() != ASC_success) {

    check_status(sts, "bconnect");

  }

 

  return 0;

}

Asynchronous DPCL calls and Application class calls that perform operations for each process managed by the Application object introduce additional complexity to DPCL status error checking. Calls to asynchronous functions return immediately, but the returned AisStatus object will indicate only whether or not the DPCL service requested by the function was successfully sent, and not whether or not it succeeded. To determine the status of the operation when it actually succeeds or fails, the analysis tool can specify an acknowledgment callback routine when calling the asynchronous function. When the service requested by the asynchronous function either succeeds or fails, the DPCL system will trigger execution of the specified callback and will pass it the AisStatus object and a pointer to the Process object for which the requested service either succeeded or failed. When calling an asynchronous function, the analysis tool can also specify a tag value which will also be passed by the DPCL system to the acknowledgment callback.

The function prototype for a callback is:

void callback (

     GCBSysType sys,

     GCBTagType tag,

     GCBObjType obj,

     GCBMsgType msg);

 

Where:
is:

sys
a data structure defined as
struct GCBSysType {

     int msg_socket;

     int msg_type;

     int msg_size;

};

 

Where
Is

msg_socket
the socket or file descriptor from which the message was received.

msg_type
a message key or type value that represents the protocol or purpose behind the message. This is provided and used by the DPCL system in order to determine the callback routine to execute.

msg_size
the size of the message in bytes.

tag
a value, large enough to contain a pointer, that is supplied by the analysis tool when the acknowledgment callback is identified. (In other words, when the asynchronous function is called.)

The tag parameter allows the analysis tool to use the acknowledgement callback routine for more than one purpose. For example, the analysis tool could create a general-purpose acknowledgment callback that could be used when calling any asynchronous function. The tag value in that case could contain information about which asynchronous function was called.

obj
a pointer to the object that issued the request. In the case of the Application object, the requesting object will be the Process object managed by the Application object. The DPCL system supplies this information because, if an asynchronous Application function was called, the same acknowledgment callback will be triggered for each Process object managed by the Application object. By supplying a pointer to the invoking object, the DPCL system enables the callback to ascertain the Process for which status is being returned.

msg
the AisStatus object.

Acknowledgment callback routines are particularly useful when error checking asynchronous Application class functions. Since these functions perform the requested operation on each Process object managed by the Application object, the DPCL system will trigger the callback routine for each Process object in turn. Since the operation may succeed on some processes while failing on others, the acknowledgment callback routine enables the analysis tool to check the status for each process.

The following example code calls the Application::connect function to connect to each process managed by the Application object. In this example, a generic error checking routine (check_status) is called to check the initial status returned by the Application::connect call, and is also called within the acknowledgment callback to check the status for each Process. Remember that the AisStatus object returned by the initial Application::connect call indicates only whether or not the request to connect was successfully sent; it does not indicate whether or not any of the connect operations actually succeeded. As the connect request succeeds or fails for each particular Process object, the callback connect_cb is invoked and passed the AisStatus object, a pointer to the Process object, and, in this example, a pointer to the Application object (passed as the callback's tag value). Note that each time the callback is invoked, it increments the value of the integer count. The code uses this for comparison with the constant integer NUM_PROCS (defined outside the code shown) which indicates the number of Process objects managed by the Application object. When count is equal to NUM_PROCS, then all the processes managed by the Application object are connected, and the callback can continue with the next piece of work (in this case, calling the Application::attach function to attach to the processes).

//

// connect to the application

//

sts = A.connect(connect_cb, (GCBTagType) &A);

       check_status("A.connect(connect_cb, (GCBTagType) &A)", sts);

 

 

NUM_PROCS = A.get_count();

//

// callback to be called after the connect completes

//

void connect_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg)

{

         static int count = 0;

         count++;

	

    //

    // get the status from the msg parm

    //

    AisStatus *stsp = (AisStatus *)msg;

    check_status("connect_cb()", *stsp);

 

    //

    // get ptr to the process object from the obj parm

	 //

    Process *p = (Process *)obj;

         printf("  %s: connect to pid: %d of Application\n", toolname, p->get_pid());

 

         if ( count >= NUM_PROCS) {

                  //

                  // get ptr to app object from the tag parm

                  //

    	Application *a = (Application *)tag;

                  printf("  %s: connected to entire Application A\n", toolname);

	

    	//

    	// attach to the application

    	//

    	AisStatus sts = a->attach(attach_cb, tag);

	               check_status("a->attach(attach_cb, tag)", sts);

      }

}

 

//

// generic status-checking routine

// print status and exit when status is not success

//

void check_status (char *str, AisStatus sts)

{

    static char buf[256];

 

    if (sts.status() == ASC_success) {

        return;

    } else {

    	printf("%s: Status for %s: %d, %s\n",  toolname, str, sts.status(), sts.status_name());

    	for (int i=0; i<sts.data_count(); i++) {

        	printf("  %s: data_value[%d]: %s\n",  toolname, i, sts.data_value(i, buf, sizeof(buf)));

    	   }

	   }

	printf("  %s: exiting\n", toolname);

   fflush(stdout);

	exit(-1);

}

 

The preceding example illustrates how, when calling an asynchronous Application function, the analysis tool can use an acknowledgment callback to check the return status for each Process object managed by the Application object. When calling a blocking Application function, however, the analysis tool is not able to specify an acknowledgment callback. For blocking Application functions, acknowledgment callback routines are not necessary since the blocking calls do not return until the requested operation has either succeeded or failed for all of the Process objects managed by the Application object. To perform error status checking for a blocking Application function, the analysis tool should first examine the AisStatus object returned by the function -- the AisStatus object will indicate whether or not the operation succeeded for all processes managed by the Application object. If it did not succeed for all processes, the analysis tool can call the Application::status function to determine the processes on which the operation failed. The Application::status function has one parameter -- an index value that identifies the Process within the collection of those managed by the Application object. The Application::get_count function returns the number of Process objects managed by the Application object, and so can be used by the analysis tool to initialize a loop that calls the Application::status function to check each Process object's status in turn.

In the following example, a generic error checking routine (check_status) is called to check the status returned by the Application::bconnect call. If the returned status indicates that the connect operation failed on one or more processes, the same error checking routine is called to check the return status for each individual process.

#include <stdio.h>

#include <stdlib.h>

#include "dpcl.h"

 

#define BUFLEN 128

 

void check_status(AisStatus &sts, char *name) {

  char buf[BUFLEN];

  int i, dc;

 

  if (sts.status() != ASC_success) {

    printf("error from %s: %s\n", name, sts.status_name());

    dc = sts.data_count();

    for (i=0; i<dc; ++i) {

      sts.data_value(i, buf, BUFLEN);

      printf("  '%s'\n", buf);

    }

  }

}

 

main(int argc, char *argv[]) {

  AisStatus sts;

  char hostname[BUFLEN];

  char msg[BUFLEN];

  int i, pc;

    .

    .

    .

    // Code here to initialize application, create Process objects, organize

    // them under an Application object, and so on.

    .

    .

    .

  sts = A.bconnect();

  if (sts.status() != ASC_success) {

    check_status(sts, "A.bconnect");

 

    pc = A.get_count();

    for (i=0; i<pc; i++) {

      Process P = A.get_process(i);

      int tasknum = P.get_task();

      sprintf(msg, "bconnect on task %d", tasknum);

      sts = A.status(i);

      check_status(sts, msg);

    }

 

    return 0;

  }

 

  // rest of program

}


[ Top of Page | Previous Page | Next Page | Table of Contents | Index ]