Example: Sample flight recorder output from a Pthread program

This example shows a Pthread program that uses the flight recorder or tracing interfaces that are provided by the system.

Note: By using the code examples, you agree to the terms of the Code license and disclaimer information.
/*
Filename: ATEST23.QCSRC
Use CL command DMPUSRTRC to output the following tracing
information that this example traces.

This information is put into a file QTEMP/QAP0ZDMP or to
standard output.

The trace records are indented and labeled based on thread id,
and millisecond timestamp of the time the tracepoint was cut.

The following trace output occurs when the optional parameter
'PTHREAD_TRACING' is NOT specified when calling this program.

If the optional parameter 'PTHREAD_TRACING' is specified, many
more tracepoints describing pthread library processing will occur.

Use the Pthread library tracepoints to debug incorrect calls to the
Pthreads library from your application.

Trace output ---------
User Trace Dump for job 096932/MYLIB/PTHREADT. Size: 300K, Wrapped 0 times.

--- 11/06/1998 11:06:57 ---
0000000D:133520 Create/start a thread
0000000D:293104 Wait for the thread to complete, and release their resources
0000000E:294072 Thread Entered
0000000E:294272 DB51A4C80A:001CD0 L:0008 Global Data
0000000E:294416  DB51A4C80A:001CD0  00000000 00000002                       *................*
0000000E:294496 foo(), threadSpecific data=0 2
0000000E:294568 bar(), threadSpecific data=0 2
0000000E:294624 bar(): This is an error tracepoint
0000000E:294680 Stack Dump For Current Thread
0000000E:294736 Stack:  This thread's stack at time of error in bar()
0000000E:333872 Stack:  Library    / Program     Module      Stmt    Procedure
0000000E:367488 Stack:  QSYS       / QLESPI      QLECRTTH    774   : LE_Create_Thread2__FP12crtth_parm_t
0000000E:371704 Stack:  QSYS       / QP0WPTHR    QP0WPTHR    1008  : pthread_create_part2
0000000E:371872 Stack:  MYLIB      / PTHREADT    PTHREADT    19    : theThread__FPv
0000000E:371944 Stack:  MYLIB      / PTHREADT    PTHREADT    29    : foo__Fv
0000000E:372016 Stack:  MYLIB      / PTHREADT    PTHREADT    46    : bar__Fv
0000000E:372104 Stack:  QSYS       / QP0ZCPA     QP0ZUDBG    87    : Qp0zDumpStack
0000000E:379248 Stack:  QSYS       / QP0ZSCPA    QP0ZSCPA    276   : Qp0zSUDumpStack
0000000E:379400 Stack:  QSYS       / QP0ZSCPA    QP0ZSCPA    287   : Qp0zSUDumpTargetStack
0000000E:379440 Stack:  Completed
0000000E:379560 foo(): This is an error tracepoint
0000000E:379656 dataDestructor: Free data
0000000D:413816 Create/start a thread
0000000D:414408 Wait for the thread to complete, and release their resources
0000000F:415672 Thread Entered
0000000F:415872 DB51A4C80A:001CD0 L:0008 Global Data
0000000F:416024  DB51A4C80A:001CD0  00000001 00000004                       *................*
0000000F:416104 foo(), threadSpecific data=1 4
0000000F:416176 bar(), threadSpecific data=1 4
0000000F:416232 bar(): This is an error tracepoint
0000000F:416288 Stack Dump For Current Thread
0000000F:416344 Stack:  This thread's stack at time of error in bar()
0000000F:416552 Stack:  Library    / Program     Module      Stmt    Procedure
0000000F:416696 Stack:  QSYS       / QLESPI      QLECRTTH    774   : LE_Create_Thread2__FP12crtth_parm_t
0000000F:416784 Stack:  QSYS       / QP0WPTHR    QP0WPTHR    1008  : pthread_create_part2
0000000F:416872 Stack:  MYLIB      / PTHREADT    PTHREADT    19    : theThread__FPv
0000000F:416952 Stack:  MYLIB      / PTHREADT    PTHREADT    29    : foo__Fv
0000000F:531432 Stack:  MYLIB      / PTHREADT    PTHREADT    46    : bar__Fv
0000000F:531544 Stack:  QSYS       / QP0ZCPA     QP0ZUDBG    87    : Qp0zDumpStack
0000000F:531632 Stack:  QSYS       / QP0ZSCPA    QP0ZSCPA    276   : Qp0zSUDumpStack
0000000F:531704 Stack:  QSYS       / QP0ZSCPA    QP0ZSCPA    287   : Qp0zSUDumpTargetStack
0000000F:531744 Stack:  Completed
0000000F:531856 foo(): This is an error tracepoint
0000000F:531952 dataDestructor: Free data
0000000D:532528 Main completed
*/
#define _MULTI_THREADED
#include <pthread.h> 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <qp0ztrc.h>
#define checkResults(string, val) {             \
 if (val) {                                     \
   printf("Failed with %d at %s", val, string); \
   exit(1);                                     \
 }                                              \
}

typedef struct {
   int          threadSpecific1;
   int          threadSpecific2;
} threadSpecific_data_t;

#define                 NUMTHREADS   2
pthread_key_t           threadSpecificKey;

void foo(void);
void bar(void);
void dataDestructor(void *);

void *theThread(void *parm) {
   int                     rc;
   threadSpecific_data_t  *gData;
   PTHREAD_TRACE_NP({
                    Qp0zUprintf("Thread Entered\n");
                   Qp0zDump("Global Data", parm, sizeof(threadSpecific_data_t));},
                   PTHREAD_TRACE_INFO_NP);
   gData = (threadSpecific_data_t *)parm;
   rc = pthread_setspecific(threadSpecificKey, gData);
   checkResults("pthread_setspecific()\n", rc);
   foo();
   return NULL;
}

void foo() {
   threadSpecific_data_t *gData =
      (threadSpecific_data_t *)pthread_getspecific(threadSpecificKey);
   PTHREAD_TRACE_NP(Qp0zUprintf("foo(), threadSpecific data=%d %d\n",
                                gData->threadSpecific1, gData->threadSpecific2);,
                   PTHREAD_TRACE_INFO_NP);
   bar();
   PTHREAD_TRACE_NP(Qp0zUprintf("foo(): This is an error tracepoint\n");,
                   PTHREAD_TRACE_ERROR_NP);
}

void bar() {
   threadSpecific_data_t *gData =
      (threadSpecific_data_t *)pthread_getspecific(threadSpecificKey);
   PTHREAD_TRACE_NP(Qp0zUprintf("bar(), threadSpecific data=%d %d\n",
                                gData->threadSpecific1, gData->threadSpecific2);,
                   PTHREAD_TRACE_INFO_NP);
   PTHREAD_TRACE_NP(Qp0zUprintf("bar(): This is an error tracepoint\n");
                   Qp0zDumpStack("This thread's stack at time of error in bar()");,
                   PTHREAD_TRACE_ERROR_NP);
   return;
}

void dataDestructor(void *data) {
   PTHREAD_TRACE_NP(Qp0zUprintf("dataDestructor: Free data\n");,
                   PTHREAD_TRACE_INFO_NP);
   pthread_setspecific(threadSpecificKey, NULL);   free(data);
   /* If doing verbose tracing we will even write a message to the job log */
   PTHREAD_TRACE_NP(Qp0zLprintf("Free'd the thread specific data\n");,
                   PTHREAD_TRACE_VERBOSE_NP);
}

/* Call this testcase with an optional parameter 'PTHREAD_TRACING' */
/* If the PTHREAD_TRACING parameter is specified, then the         */
/* Pthread tracing environment variable will be set, and the       */
/* pthread tracing will be re initialized from its previous value. */
/* NOTE: We set the trace level to informational, tracepoints cut  */
/*       using PTHREAD_TRACE_NP at a VERBOSE level will NOT show up*/
int main(int argc, char **argv) {
   pthread_t              thread[NUMTHREADS];
   int                    rc=0;
   int                    i;
   threadSpecific_data_t *gData;
   char                   buffer[50];

   PTHREAD_TRACE_NP(Qp0zUprintf("Enter Testcase - %s\n", argv[0]);,
                   PTHREAD_TRACE_INFO_NP);
   if (argc == 2 && !strcmp("PTHREAD_TRACING", argv[1])) {
      /* Turn on internal pthread function tracing support          */
      /* Or, use ADDENVVAR, CHGENVVAR CL commands to set this envvar*/
      sprintf(buffer, "QIBM_PTHREAD_TRACE_LEVEL=%d", PTHREAD_TRACE_INFO_NP);
      putenv(buffer);
      /* Refresh the Pthreads internal tracing with the environment */
      /* variables value.                                           */
      pthread_trace_init_np();
   }
   else {
      /* Trace only our application, not the Pthread code           */
      Qp0wTraceLevel = PTHREAD_TRACE_INFO_NP;
   }

   rc = pthread_key_create(&threadSpecificKey, dataDestructor);
   checkResults("pthread_key_create()\n", rc);

   for (i=0; i <NUMTHREADS; ++i) {
      /* Create per-thread threadSpecific data and pass it to the thread */
      gData = (threadSpecific_data_t *)malloc(sizeof(threadSpecific_data_t));
      gData->threadSpecific1 = i;
      gData->threadSpecific2 = (i+1)*2;
      rc = pthread_create( &thread[i], NULL, theThread, gData);
      checkResults("pthread_create()\n", rc);
      PTHREAD_TRACE_NP(Qp0zUprintf("Wait for the thread to complete, "
                                   "and release their resources\n");,
                      PTHREAD_TRACE_INFO_NP);
      rc = pthread_join(thread[i], NULL);
      checkResults("pthread_join()\n", rc);
   }

   pthread_key_delete(threadSpecificKey);
   PTHREAD_TRACE_NP(Qp0zUprintf("Main completed\n");,
                   PTHREAD_TRACE_INFO_NP);
   return 0;
}