HP OpenVMS Systems Documentation | 
	
HP OpenVMS Debugger Manual
 15.16.5 Setting Watchpoints in Global Sections (Alpha and I64 Only)On Alpha and I64, you can set watchpoints in global sections. A global section is a region of memory that is shared among all processes of a multiprocess program. A watchpoint that is set on a location in a global section (a global section watchpoint) triggers when any process modifies the contents of that location. When setting watchpoints on arrays or records, note that performance is improved if you specify individual elements rather than the entire structure with the SET WATCH command. If you set a watchpoint on a location that is not yet mapped to a global section, the watchpoint is treated as a conventional static watchpoint. For example: 
 
 When ARR is subsequently mapped to a global section, the watchpoint is automatically treated as a global section watchpoint and an informational message is issued. For example: 
 
 After the watched location is mapped to a global section, the watchpoint is visible from each process. For example: 
 
 15.16.6 System Requirements for DebuggingSeveral users debugging programs simultaneously can place a load on a system. This section describes the resources used by the debugger, so that you or your system manager can tune your system for this activity. 
Note that the discussion covers only the resources used by the
debugger. You might also have to tune your system to support the
programs themselves.
 Each user needs a PRCLM quota sufficient to create an additional process for the debugger, beyond the number of processes needed by the program. BYTLM, ENQLM, FILLM, and PGFLQUOTA are pooled quotas. They may need to be increased to account for the debugger process as follows: 
 15.16.6.2 System Resources
The kernel debugger and main debugger communicate through global
sections. Each main debugger, regardless of platform, uses at least one
64 Kbyte global section. On VAX and ALPHA, the main debugger can
communicate with up to six kernel debuggers. On I64, it can only
communicate with up to 2 kernel debuggers.
 Example 15-4 and Example 15-5 contain the C code for the server and client programs used in examples throughout this chapter. 
 
 
 
 
 
 The header file included in Example 15-4 and Example 15-5, mbxtest.h is shown below. 
 
 
 Chapter 16
 | 
Within the debugger, the terms task and thread are synonyms. When you are debugging programs linked with PTHREAD$RTL Version 7.1 or greater, you can directly access the Compaq POSIX Threads debugger with the PTHREAD command.  | 
  
In this chapter, any language-specific information or information specific to POSIX Threads is identified as such. Section 16.1 provides a cross-reference between POSIX Threads terminology and Ada tasking terminology.
The features described in this chapter enable you to perform functions such as:
When using these features, remember that the debugger might alter the behavior of a tasking program from run to run. For example, while you are suspending execution of the currently active task at a breakpoint, the delivery of an asynchronous system trap (AST) or a POSIX signal as some input/output (I/O) completes might make some other task eligible to run as soon as you allow execution to continue.
For more information about POSIX Threads, see the Guide to the POSIX Threads Library. For more information about Ada tasks, see the Compaq Ada documentation.
The debugging of multiprocess programs (programs that run in more than
one process) is described in Chapter 15.
16.1 Comparison of  POSIX Threads  and Ada Terminology
Table 16-1 compares POSIX Threads and Ada terminology and concepts.
| POSIX Threads Terminology | Ada Terminology | Description | 
|---|---|---|
| Thread | Task | The flow of control within a process | 
| Thread object | Task object | The data item that represents the flow of control | 
| Object name or expression | Task name or expression | The data item that represents the flow of control | 
| Start routine | Task body | The code that is executed by the flow of control | 
| Not applicable | Master task | A parent flow of control | 
| Not applicable | Dependent task | A child flow of control that is controlled by some parent | 
| Synchronization object (mutex, condition variable) | Rendezvous construct such as an entry call or accept statement | Method of synchronizing flows of control | 
| Scheduling policy and scheduling priority | Task priority | Method of scheduling execution | 
| Alert operation | Abort statement | Method of canceling a flow of control | 
| Thread state | Task state | Execution state (waiting, ready, running, terminated) | 
| Thread creation attribute (priority, scheduling policy, and so on) | Pragma | Attributes of the parallel entity | 
The following sections present sample tasking programs with common errors that you might encounter when debugging tasking programs:
Some other examples in this chapter are derived from these programs.
16.2.1 Sample C Multithread Program
Example 16-1 is a multithread C program that shows incorrect use of condition variables, which results in blocking.
Explanatory notes are included after the example. Following these notes are instructions showing how to use the debugger to diagnose the blocking by controlling the relative execution of the threads.
In Example 16-1, the initial thread creates two worker threads that do some computational work. After the worker threads are created, a SHOW TASK/ALL command will show three tasks, each corresponding to a thread ( Section 16.4 explains how to use the SHOW TASK command).
In Example 16-1, a synchronization point (a condition wait) has been placed in the workers' path at line 3893. (The comment starting at line 3877 indicates that a straight call such as this one is incorrect programming and shows the correct code.)
When the program executes, the worker threads are busy computing when the initial thread broadcasts on the condition variable. The first thread to wait on the condition variable detects the initial thread's broadcast and clears it, which leaves any remaining threads stranded. Execution is blocked and the program cannot terminate.
| Example 16-1 Sample C Multithread Program | 
|---|
      
3777  /* DEFINES  */
3778  #define NUM_WORKERS 2           /* Number of worker threads    */
3779
3780  /* MACROS                                                      */
3781  #define check(status,string) \
3782      if (status == -1) perror (string); \
3783
3784  /* GLOBALS                                                     */
3785  int              cv_pred1;     /* Condition Variable predicate */
3786  pthread_mutex_t  cv_mutex;     /* Condition Variable mutex     */
3787  pthread_cond_t   cv;           /* Condition Variable           */
3788  pthread_mutex_t  print_mutex;  /* Print mutex                  */
3799
3790  /* ROUTINES                                                    */
3791  static pthread_startroutine_t
3792  worker_routine (pthread_addr_t  arg);
3793
3794  main ()
3795     {
3796     pthread_t  threads[NUM_WORKERS];  /* Worker threads         */
3787     int        status;                /* Return statuses        */
3798     int        exit;                  /* Join exit status       */
3799     int        result;                /* Join result value      */
3800     int        i;                     /* Loop index             */
3801
3802     /* Initialize mutexes                                       */
3803     status = pthread_mutex_init (&cv_mutex, pthread_mutexattr_default);
3804     check (status, "cv_mutex initialization bad status");
3805     status = pthread_mutex_init (&print_mutex, pthread_mutexattr_default);
3806     check (status, "print_mutex intialization bad status");
3807
3808     /* Initialize condition variable                            */
3809     status = pthread_cond_init (&cv, pthread_condattr_default);
3810     check (status, "cv condition init bad status");
3811
3812     /* Initialize condition variable predicate.                 */
3813     cv_pred1 = 1;                                            (1)
3814
3815     /* Create worker threads                                    */
3816     for (i = 0; i < NUM_WORKERS; i++) {                      (2)
3817         status = pthread_create (
3818                         &threads[i],
3819                         pthread_attr_default,
3820                         worker_routine,
3821                         0);
3822         check (status, "threads create bad status");
3823         }
3824
3825     /* Set cv_pred1 to false; do this inside the lock to insure visibility. */
3826
3827     status = pthread_mutex_lock (&cv_mutex);
3828     check (status, "cv_mutex lock bad status");
3829
3830     cv_pred1 = 0;                                            (3)
3831
3832     status = pthread_mutex_unlock (&cv_mutex);
3833     check (status, "cv_mutex unlock bad status");
3834
3835     /* Broadcast. */
3836     status = pthread_cond_broadcast (&cv);                   (4)
3837     check (status, "cv broadcast bad status");
3838
3839     /* Attempt to join both of the worker threads. */
3840     for (i = 0; i < NUM_WORKERS; i++) {                      (5)
3841         exit = pthread_join (threads[i], (pthread_addr_t*)&result);
3842         check (exit, "threads join bad status");
3843         }
3844     }
3845
3846  static pthread_startroutine_t
3847  worker_routine(arg)
3848     pthread_addr_t   arg;                                    (6)
3849     {
3850     int   sum;
3851     int   iterations;
3852     int   count;
3853     int   status;
3854
3855     /* Do many calculations                        */
3856     for (iterations = 1; iterations < 10001; iterations++) {
3857         sum = 1;
3858         for (count = 1; count < 10001; count++) {
3859             sum = sum + count;
3860             }
3861         }
3862
3863     /* Printf may not be reentrant, so allow 1 thread at a time */
3864
3865     status = pthread_mutex_lock (&print_mutex);
3866     check (status, "print_mutex lock bad status");
3867     printf (" The sum is %d \n", sum);
3868     status = pthread_mutex_unlock (&print_mutex);
3869     check (status, "print_mutex unlock bad status");
3870
3871     /* Lock the mutex associated with this condition variable. pthread_cond_wait will */
3872     /* unlock the mutex if the thread blocks on the condition variable.               */
3873
3874     status = pthread_mutex_lock (&cv_mutex);
3875     check (status, "cv_mutex lock bad status");
3876
3877     /* In the next statement, the correct condition-wait syntax would be to loop      */
3878     /* around the condition-wait call, checking the predicate associated with the     */
3879     /* condition variable.  This would guard against condition waiting on a condition */
3880     /* variable that may have already been broadcast upon, as well as spurious wake   */
3881     /* ups. Execution would resume when the thread is woken AND the predicate is      */
3882     /* false.  The call would look like this:                                         */
3883     /*                                                                                */
3884     /*    while (cv_pred1) {                                                          */
3885     /*      status = pthread_cond_wait (&cv, &cv_mutex);                              */
3886     /*      check (status, "cv condition wait bad status");                           */
3887     /*    }                                                                           */
3888     /*                                                                                */
3888     /* A straight call, as used in the following code, might cause a thread to       */
3890     /* wake up when it should not (spurious) or become permanently blocked, as        */
3891     /* should one of the worker threads here.                                         */
3892
3893     status = pthread_cond_wait (&cv, &cv_mutex);             (7)
3894     check (status, "cv condition wait bad status");
3895
3896     /* While blocking in the condition wait, the routine lets go of the mutex, but    */
3897     /* it retrieves it upon return.                                                   */
3898
3899     status = pthread_mutex_unlock (&cv_mutex);
3900     check (status, "cv_mutex unlock bad status");
3901
3902     return (int)arg;
3903     }
 | 
Key to Example 16-1:
The debugger enables you to control the relative execution of threads to diagnose problems of the kind shown in Example 16-1. In this case, you can suspend the execution of the initial thread and let the worker threads complete their computations so that they will be waiting on the condition variable at the time of broadcast. The following procedure explains how:
| Previous | Next | Contents | Index |