There are two relationships that an analysis tool can establish with a target application process in order to affect its execution. The analysis tool can "connect" to the process, and, once connected, can also "attach" itself to the process. Connection (described in detail in Chapter 6, Connecting to or starting the target application processes) establishes a communication channel to the host where the process resides and creates the environment within the process that allows the analysis tool to insert and remove instrumentation probes. Inserting instrumentation probes enables the analysis tool to indirectly influence the execution of a target application process.
An analysis tool can connect to processes either by explicitly connecting (by calling the connect or bconnect function of either the Process or Application class), or by creating them (by calling the create or bcreate function of either the Process or PoeAppl class). The connect and bconnect functions place the process(es) in a connected state represented by the enumeration constant PRC_connected of the Process class' ConnectState enumeration type. The create and bcreate functions place the process(es) in a created state represented by the enumeration constant PRC_created of the Process class' ConnectState enumeration type. A subsequent call to the start or bstart function will move the process(es) into the PRC_connected state. In either case, however, a connection has been established that enables the analysis tool to instrument the target application process(es) with probes.
When a process is connected (in either the PRC_connected or PRC_created state), the analysis tool can attach to the process using the attach or battach function of either the Process or Application class. Attaching to the process enables the analysis tool to control execution of the process directly. This direct process control is exclusive -- no other analysis tool will be able to attach to the process. The following sections describe how an analysis tool can:
The analysis tool can also terminate a process. If the process is in the PRC_created state, the analysis tool does not need to attach to it in order to terminate its execution. If the analysis tool has, on the other hand, not created but merely connected to a remote process, it must attach to the process in order to terminate it. The analysis terminates one or more processes by calling the Process::destroy, Process::bdestroy, Application::destroy, or Application::bdestroy function.
Attaching to a target application process enables an analysis tool to directly control the execution of the process. This includes resuming and suspending execution of the process (as described in Resuming execution of the target application process(es) and Suspending execution of the target application process(es)), as well as terminating the process (as described in Terminating target application processes). Attaching to an application automatically suspends its execution. This enables the analysis tool to install probes in the process (as described in Chapter 9, Executing probes in target application processes) before resuming its execution (as described in Resuming execution of the target application process(es)).
In order to attach itself to one or more target application processes, the analysis tool must be connected to the process(es) as described in Connecting to the target application. In other words, the Process object must be in either the PRC_connected or PRC_created state; the analysis tool can query a Process object's state by calling the Process::query_state function.
To attach to a single process, the analysis tool can use the asynchronous
function Process::attach or its blocking equivalent
Process::battach. To attach to processes on an
application-wide basis (for all Process objects managed by an
Application object), the analysis tool can use the functions
Application::attach or
Application::battach.
Table 31. Attaching to one or more target application processes
To attach: | To a single process (Process object) | To multiple processes (all of the Process objects managed by an Application object) |
---|---|---|
Using the asynchronous function attach |
AisStatus sts = p->attach(attach_cb, (GCBTagType) 0); check_status("p->attach(attach_cb, (GCBTagType) 0)", sts); // // callback to be called after the attach // completes // void attach_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg) { // code within callback routine // can check the status of the // operation and respond to its // completion by, for example, // continuing with other work } |
AisStatus sts = a->attach(attach_cb, tag); check_status("a->attach(attac_cbh, tag)", sts); // // callback to be called after the attach // completes for each Process managed by // this Application object // void attach_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg) { // code within callback routine // can check the status of the // operation and respond to its // completion by, for example, // continuing with other work } |
Using the blocking function battach |
sts = P.battach(); check_status("P.battach()", sts); printf(" %s: attached to pid:%d\n", toolname, P.get_pid()); |
sts = A.battach(); check_status("A.battach()", sts); printf(" %s: attached to A\n", toolname); |
Attaching to a process puts the process in an attached state represented by the enumeration constant PRC_attached of the Process class' ConnectState enumeration type. The analysis tool can query a Process object's state by calling the Process::query_state function.
Once attached to one or more target application processes, the analysis tool can:
Note that only one analysis tool can be attached to a particular process at a time. For this reason, an analysis tool may want to "detach" itself from a particular process when it no longer needs to directly control its execution. To do this, see Detaching from target application processes.
For more information on the Process::attach, Process::battach, Application::attach, and Application::battach functions, refer to their UNIX man pages or their entries in the DPCL Class Reference.
When the analysis tool attaches to one or more target application processes (as described in Attaching to the target application process(es)), execution of the process(es) is temporarily suspended. By suspending a process when the analysis tool attaches to it, the DPCL system enables the analysis tool to perform actions on it before resuming its execution. If the analysis tool were a debugger, for example, this would enable it to examine the processes state. Also, an analysis tool could install probes into the target application (as described in Chapter 9, Executing probes in target application processes) before resuming its execution. Once the analysis tool has resumed execution of a process, it can explicitly suspend its execution again as described in Suspending execution of the target application process(es).
To resume execution of a single suspended process, the analysis tool can
use the asynchronous function Process::resume or its
blocking equivalent Process::bresume. To resume
execution of suspended processes on an application-wide basis (for all
Process objects managed by an Application object), the
analysis tool can use the Application::resume or
Application::bresume functions.
Table 32. Resuming execution of one or more suspended target application processes
To resume execution: | Of a single process (Process object) | Of multiple processes (all of the Process objects managed by an Application object) |
---|---|---|
Using the asynchronous function resume |
AisStatus sts = p->resume(resume_cb, GCBTagType(0)); check_status("p->resume(resume_cb, GCBTagType(0))", sts); // // callback to be called after the resume // completes // void resume_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg) { // code within callback routine // can check the status of the // operation and respond to its // completion by, for example, // continuing with other work } |
AisStatus sts = A.resume( resume_cb, GCBTagType(0) ); if ( sts.status() != ASC_success ) { printf("A.resume(), status: %s\n", sts.status_name()); return sts; } // // this is called after each process // resume request has completed // void resume_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg) { AisStatus *stsp = (AisStatus *)msg; if ( stsp->status() != ASC_success ) printf("resume_cb, status: %s\n", stsp->status_name()); } |
Using the blocking function bresume |
sts = P.bresume(); check_status("P.bresume()", sts); printf(" %s: resumed pid:%d\n", toolname, P.get_pid()); |
AisStatus sts=A.bresume(); return sts; |
Note that the process must be attached in order for the analysis tool to resume its execution. In other words, the Process object must be in the PRC_attached state; the analysis tool can query a Process object's state by calling the Process::query_state function.
For more information on the Process::resume, Process::bresume, Application::resume, or Application::bresume functions, refer to their UNIX man pages, or their entries in the DPCL Class Reference
When the analysis tool attaches to one or more target application processes (as described in Attaching to the target application process(es)), the DPCL system automatically suspends execution of the process(es). This enables the analysis tool to install probes in the process(es) (as described in Chapter 9, Executing probes in target application processes). When desired, the analysis tool then resumes execution of the processes as described in Resuming execution of the target application process(es). After execution of a process has been resumed, the analysis tool can suspend it again.
To suspend execution of a single process, the analysis tool can use the
asynchronous function Process::suspend or its blocking
equivalent Process::bsuspend. To suspend
execution of processes on an application-wide basis (for all
Process objects managed by an Application object), the
analysis tool can use the Application::suspend or
Application::bsuspend functions.
Table 33. Suspending execution of one or more target application processes
To suspend execution of: | A single process (Process object) | Multiple processes (all of the Process objects managed by an Application object) |
---|---|---|
Using the asynchronous function suspend |
AisStatus sts = p->suspend(suspend_cb, GCBTagType(0)); check_status("p->suspend(suspend_cb, GCBTagType(0))", sts); // // callback to be called after the suspend // completes // void suspend_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg) { // code within callback routine // can check the status of the // operation and respond to its // completion by, for example, // continuing with other work } |
AisStatus sts = A.suspend( suspend_cb, GCBTagType(0) ); if ( sts.status() != ASC_success ) return sts; // // this is called after each process's // suspend request is done // void suspend_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg) { Process *pp = (Process *)obj; printf("pid %d suspended\n", pp->get_pid()); } |
Using the blocking function bsuspend |
sts = P.bsuspend(); check_status("P.bsuspend()", sts); printf(" %s: suspended pid:%d\n", toolname, P.get_pid()); |
AisStatus sts=A.bsuspend(); // if app status bad, show status by process if ( sts.status() != ASC_success ) for (int i; i<A.get_count; i++) printf("status for Process[%d]: %s\n", i, status(i).status_name); |
Note that the process must be attached in order for the analysis tool to suspend its execution. In other words, the Process object must be in the PRC_attached state; the analysis tool can query a Process object's state by calling the Process::query_state function.
For more information on the Process::suspend, Process::bsuspend, Application::suspend, and Application::bsuspend functions, refer to their UNIX man pages or their entries in the DPCL Class Reference
When attached to a target application process (in other words, when the
Process is in the PRC_attached state), the analysis tool
can terminate execution of the process. The analysis tool can also
terminate a process if it has created the process (in other words, when the
Process is in the PRC_created state). If it has
created the process, the analysis tool does not need to attach to it in order
to terminate its execution. If the analysis tool has, on the other
hand, merely connected to a running process, it must attach to the process in
order to terminate it. To determine if a process is in one of the
required states (PRC_created or PRC_attached), the
analysis tool can query its state by calling the
Process::query_state function. To terminate a
single target application process, the analysis tool can use the asynchronous
function Process::destroy or its blocking equivalent
Process::bdestroy. To terminate processes on an
application-wide basis (for all Process objects managed by an
Application object), the analysis tool can use the functions
Application::destroy or
Application::bdestroy. When using any of these
functions, however, the analysis tool should exercise the same caution it
would use when calling the UNIX command kill. Killing
selected processes in a message-passing parallel program, for example, could
result in program deadlock among the remaining processes.
Table 34. Terminating one or more target application processes
Destroying a one or more processes as shown in the preceding table places the Process object(s) in a destroyed state. This state is represented by the enumeration constant PRC_destroyed of the Process class' ConnectState enumeration type. The analysis tool can query a Process object's state by calling the Process::query_state function.
For more information on the Process::destroy, Process::bdestroy, Application::destroy, or Application::bdestroy functions, refer to their UNIX man pages or their entries in the DPCL Class Reference.
An analysis tool does not need to explicitly detach itself from the target application process. When either the analysis tool process or the target application process terminates, the attachment will, or course, be broken. However, it is also important to note that only one analysis tool can be attached to a particular process at a time. For this reason, an analysis tool may want to detach itself from the process when it no longer needs to control execution of the process. This enables another analysis tool to attach to the process.
To detach itself from a single process, the analysis tool can use the
asynchronous function Process::detach or its blocking
equivalent Process::bdetach. To detach itself
from processes on an application-wide basis (for all Process
objects managed by an Application object), the analysis tool can
use the functions Application::detach or
Application::bdetach. Naturally the process must
be attached in order for the analysis tool to detach it. In other
words, the Process object must be in the PRC_attached
state; the analysis tool can query a Process object's
state by calling the Process::query_state
function.
Table 35. Detaching from one or more target application processes
To detach: | From a single process (Process object) | From multiple processes (all of the Process objects managed by an Application object) |
---|---|---|
Using the asynchronous function detach |
AisStatus sts = p->detach(detach_cb, GCBTagType(0)); check_status("p->detach(detach_cb, GCBTagType(0))", sts); // // callback to be called after the // detach completes // void detach_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg) // code within callback routine // can check the status of the // operation and respond to its // completion by, for example, // continuing with other work } |
AisStatus sts = A.detach( detach_cb, GCBTagType(0) ); if ( sts.status() != ASC_success ) return sts.status_name(); // // this is called after each detach request is // complete // void detach_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg) { AisStatus *stsp = (AisStatus *) msg; Process *pp = (Process *)obj; if (stsp->status() == ASC_success) printf("pid %d detached\n", pp->get_pid()); else printf("pid %d not detached\n", pp->get_pid()); } |
Using the blocking function bdetach |
sts = P.bdetach(); check_status("P.bdetach()", sts); printf(" %s: detached from pid:%d\n", toolname, P.get_pid()); |
AisStatus sts=A.bdetach(); if ( sts.status() != ASC_success ) return sts; |
For more information on the Process::detach, Process::bdetach, Application::detach, and Application::bdetach functions, refer to their UNIX man pages or their entries in the DPCL Class Reference
Note that detaching from a target application process does not remove the analysis tool's connection to the process. The analysis tool will still be able to install and execute probes within the process.
The following example illustrates how a target application can control execution of target application processes. Specifically, it illustrates the use of the Application::bsuspend, Application::bresume, Application::bdetach, and Application::bdestroy calls. The user passes this analysis tool the host name and process IDs of the target application processes. The analysis tool:
Once execution of the processes resumes, the installed point probes collect information until the user presses a key on the keyboard. The target application then:
// // Example DPCL program for bsuspend, bresume, bdetach // and bdestroy calls. // Compile with -DLET_RUN if you want the application to // continue running after instrumenting it. // #include <stdlib.h> #include <stdio.h> #include <dpcl.h> AisStatus instrument(Application A); void insert_probes(); void remove_probes(); void wait_for_keystroke(); main(int argc, char *argv[]) { Application A; char hostname[128]; int pid_list[128]; int pid_count; if (argc <3) { printf("Usage: %s <hostname> <pid> [pid...]\n", argv[0]); exit(-1); } // get the hostname and pids from argv // strcpy(hostname, argv[1]); pid_count=argc-2; for (int i=0; i<pid_count; i++) { pid_list[i] = atoi(argv[i+2]); } Ais_initialize(); // Call the Process constructor then // add the processes to the application // for (i=0; i<pid_count; i++) { Process p(hostname, pid_list[i]); A.add_process(&p); } // call this routine to instrument the application // AisStatus sts = instrument(A); // very basic error checking // if ( sts.status() != ASC_success ) { // print overall status for application // printf("Failed with overall status: %s\n", sts.status_name()); // print individual status for processes in application // for (int i=0; i<A.get_count(); i++) printf("status for Process[%d]: %s\n", i, A.status(i).status_name()); exit(-1); } } AisStatus instrument(Application A) { // connect to the application // AisStatus sts=A.bconnect(); if ( sts.status() != ASC_success ) return sts; // attach to the application // sts=A.battach(); if ( sts.status() != ASC_success ) return sts; // Instrument the application // insert_probes(); // resume the application // sts=A.bresume(); if ( sts.status() != ASC_success ) return sts; // collect instrumentation until there is user input // wait_for_keystroke(); // suspend the application // sts=A.bsuspend(); if ( sts.status() != ASC_success ) return sts; // remove the instrumentation // remove_probes(); // resume the application // sts=A.bresume(); if ( sts.status() != ASC_success ) return sts; #ifdef LET_RUN // detach from the application // sts=A.bdetach(); if ( sts.status() != ASC_success ) return sts; // let the application go on normally // sts=A.bdisconnect(); if ( sts.status() != ASC_success ) return sts; #else // let the application go on normally // sts=A.bdestroy(); if ( sts.status() != ASC_success ) return sts; #endif // LET_RUN return sts; } // dummy function defs void insert_probes() {} void remove_probes() {} void wait_for_keystroke() {}