DCMD_PROC_TIMERS

We can find out about the timers that are associated with a process.

We use the DCMD_PROC_TIMERS command, and expect to get back zero or more data structures, as we did in the DCMD_PROC_PAGEDATA and DCMD_PROC_MAPINFO examples above. The structure is defined for 64-bit architectures as follows:

typedef struct _debug_timer64 {
  timer_t               id;
  unsigned              spare;
  struct _timer_info32  __info32;
  struct _timer_info64  info;
} debug_timer64_t;

This structure relies on the struct _timer_info type (defined in <sys/platform.h>, and paraphrased slightly):

struct _timer_info {
  struct _itimer      itime;
  struct _itimer      otime;
  uint32_t            flags;
  int32_t             tid;
  int32_t             notify;
  clockid_t           clockid;
  uint32_t            overruns;
  struct sigevent     event;
};

This data type, struct _timer_info is used with the TimerInfo() function call.

To fetch the data, we utilize code that's almost identical to that used for the memory segments (above):

#define MAX_TIMERS  512

static void
dump_procfs_timer (int fd, int pid)
{
  procfs_timer  timers [MAX_TIMERS];
  int           ntimers;
  int           i;
  int           sts;

  // fetch information about the timers for this pid
  sts = devctl (fd, DCMD_PROC_TIMERS, timers, sizeof (timers), &ntimers);
  if (sts != EOK) {
    fprintf (stderr, "%s: TIMERS err, proc %d, error %d (%s)\n",
             progname, pid, sts, strerror (sts));
    exit (EXIT_FAILURE);
  }

  if (ntimers > MAX_TIMERS) {
    fprintf (stderr, "%s: proc %d has > %d timers (%d) !!!\n",
             progname, pid, MAX_TIMERS, ntimers);
    exit (EXIT_FAILURE);
  }

  printf ("Info from DCMD_PROC_TIMERS\n");
  for (i = 0; i < ntimers; i++) {
    // print information here
  }
  printf ("\n");
}

Since our pipe command doesn't use timers, let's look at the devb-eide driver instead. It has four timers; I've selected just one:

  Buffer   2 timer ID 2
    itime    1063180.652506618 s,      0.250000000 interval s
    otime          0.225003825 s,      0.250000000 interval s
    flags     0x00000001
    tid       0
    notify    196612 (0x30004)
    clockid   0
    overruns  0
    event (sigev_notify type 4)
      SIGEV_PULSE (sigev_coid 1073741832,
                   sigev_value.sival_int 0,
                   sigev_priority -1, sigev_code 1)

The fields are as follows:

itime
This represents the time when the timer will fire, if it is active (i.e., the flags member has the bit _NTO_TI_ACTIVE set). If the timer is not active, but has been active in the past, then this will contain the time that it fired last, or was going to fire (in case the timer was canceled before firing).
otime
Time remaining before the timer expires.
flags
One or more of these flags (defined in <sys/neutrino.h>):
  • _NTO_TI_ABSOLUTE (the timer is waiting for an absolute time to occur; otherwise, the timer is considered relative)
  • _NTO_TI_ACTIVE (the timer is active)
  • _NTO_TI_EXPIRED (the timer has expired)
  • _NTO_TI_PRECISE (the timer is precise, and excludes any default tolerance that was set for the process—see procmgr_timer_tolerance())
  • _NTO_TI_PROCESS_TOLERANT (the timer is using the process's default tolerance)
  • _NTO_TI_TARGET_PROCESS (the timer targets the process, not a specific thread)
  • _NTO_TI_TOD_BASED (the timer is based relative to the beginning of the world (January 1, 1970, 00:00:00 GMT); otherwise, the timer is based relative to the time that QNX Neutrino was started on the machine—see the system page qtime boot_time member)
  • _NTO_TI_TOLERANT (the timer has a nonzero tolerance, which could be the process's default tolerance).

The header file also defines _NTO_TI_REPORT_TOLERANCE, which you use in the flags argument to TimerInfo(), and _NTO_TI_WAKEUP, which is only emitted into trace events. You won't find either of them set here.

tid
The thread to which the timer is directed (or the value 0 if it's directed to the process).
notify
The notification type (only the bottom 16 bits are interesting; the rest are used internally).
clockid
This is the clock ID (e.g., CLOCK_REALTIME).
overruns
This is a count of the number of timer overruns.
event
This is a struct sigevent that indicates the type of event that should be delivered when the timer fires. For the example above, it's a SIGEV_PULSE, meaning that a pulse is sent. The fields listed after the SIGEV_PULSE pertain to the pulse delivery type (e.g., connection ID, etc.).

In the example above, the flags member has only the bit _NTO_TI_ACTIVE (the value 0x0001) set, which means that the timer is active. Since the _NTO_TI_TOD_BASED flag is not set, however, it indicates that the timer is relative to the time that the machine was booted. So the next time the timer will fire is 1063180.652506618 seconds past the time that the machine was booted (or 12 days, 7 hours, 19 minutes, and 40.652506618 seconds past the boot time). This timer might be used for flushing the write cache—at the time the snapshot was taken, the machine had already been up for 12 days, 7 hours, 19 minutes, and some number of seconds.

The notify type (when examined in hexadecimal) shows 0x0004 as the bottom 16 bits, which is a notification type of SIGEV_PULSE (which agrees with the data in the event structure).