DCMD_DUMPER_NOTIFYEVENT

Updated: April 19, 2023

Register for dump notifications

Synopsis:

#include <sys/dcmd_dumper.h>

#define DCMD_DUMPER_NOTIFYEVENT __DIOT(_DCMD_MISC, DUMPER_NOTIFYEVENT, struct sigevent)

Arguments to devctl():

Argument Value
filedes A file descriptor for the dumper that you obtained by opening /proc/dumper
dcmd DCMD_DUMPER_NOTIFYEVENT
dev_data_ptr A pointer to a struct sigevent
n_bytes sizeof(struct sigevent)
dev_info_ptr NULL

Description:

This command registers a program for dump notifications.

Input:

A struct sigevent that's filled in to indicate what type of notification you want.

Output:

None.

Example:

 
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dcmd_dumper.h>
#include <fcntl.h>
#include <unistd.h>
#include <devctl.h>
#include <errno.h>
#include <string.h>
#include <sys/neutrino.h>
#include <sys/procfs.h>

#ifndef NOFD
  #define NOFD -1
#endif

int dumper_notify_attach(struct sigevent *devent)
{
    int dumper_fd;
    dumper_fd = open("/proc/dumper",O_RDONLY);
    
    /* Only registered events can be used by default. */    
    if (MsgRegisterEvent(devent, dumper_fd) == -1) {
        perror("MsgRegisterEvent");
    }
    
    if (dumper_fd >= 0) {
        devctl(dumper_fd, DCMD_DUMPER_NOTIFYEVENT, devent, sizeof(*devent), NULL);
        fcntl(dumper_fd, F_SETFD, FD_CLOEXEC);
    } else {
        dumper_fd = -1;
    }
    
    return dumper_fd;
}

#ifndef ARRAY_SIZE
  #define ARRAY_SIZE(x) ((sizeof(x))/sizeof(*(x)))
#endif

#define DUMP_PULSE_CODE 0x50

int dumper_get_dumppath(char *buf, size_t buf_len, int fd, int pid)
{
    dump_info_t dinfo;
    iov_t in_iov[1], out_iov[1];
    if (buf==NULL || buf_len==0 || fd==NOFD) {
        errno=EINVAL;
        return -1;
    }
    dinfo.i.pid = pid;
    SETIOV(in_iov+0, &dinfo.i, sizeof(dinfo.i));
    SETIOV(out_iov+0, buf, buf_len);
    return devctlv(fd, DCMD_DUMPER_GETPATH, ARRAY_SIZE(in_iov), ARRAY_SIZE(out_iov), 
                   in_iov, out_iov, NULL);
}

int main(int argc, const char *argv[], const char *envp[])
{
    int dp_chid=-1;
    int dp_coid=-1;
    struct sigevent devent;
    struct _pulse gpulse;
    int dumper_fd=-1;
    int rcvid;
    pid_t pid;

    // Create death pulses channel
    dp_chid = ChannelCreate(_NTO_CHF_FIXED_PRIORITY);
    if (dp_chid==-1) {
        perror("ERROR: ChannelCreate");
        exit( -1 );
    }
    dp_coid = ConnectAttach(0, 0, dp_chid, _NTO_SIDE_CHANNEL, _NTO_COF_CLOEXEC);
    if (dp_coid==-1) {
        perror("ERROR: ConnectAttach");
        exit( -1 );
    }
    SIGEV_PULSE_INIT(&devent, dp_coid, sched_get_priority_max(SCHED_RR), 
                     DUMP_PULSE_CODE, -1);
    
    // Make this event updateable to allow the dumper to put pid data 
    // into 'value.sival_int' field of the pulse structure. 
    SIGEV_MAKE_UPDATEABLE(&devent);
    
    dumper_fd=dumper_notify_attach(&devent);
    if (dumper_fd==-1) {
        perror("ERROR: opening /proc/dumper");
        exit( -1 );
    }
    for (;;) {
        char buf[PATH_MAX];
        int ret;
        
        // Blocks waiting for a pulse
        rcvid = MsgReceivePulse(dp_chid, &gpulse, sizeof(gpulse), NULL);
        if(rcvid < 0){
            perror("MsgReceivePulse");
            continue;   
        }
        switch (gpulse.code) {
            case DUMP_PULSE_CODE:          // something died
                pid = gpulse.value.sival_int;
                ret=dumper_get_dumppath(buf, sizeof(buf), dumper_fd, pid);
                if (ret != EOK) {
                    fprintf(stderr, "devctl(DCMD_DUMPER_GETPATH) : %s\n", 
                            strerror(ret));
                    buf[0]='\0';
                }
                fprintf(stderr, "Received Dump Pulse code %"PRId8"\n", 
                        gpulse.code);
                fprintf(stderr, "Process Pid %d dumped to %s\n",
                        pid, buf);

                break;
            default:
                fprintf(stderr, "Unknown pulse code: %"PRId8"\n", 
                        gpulse.code);
                break;
        }
    }
    if (dumper_fd >=0)
    {
        devctl(dumper_fd, DCMD_DUMPER_REMOVEALL, NULL, 0, NULL);

        /* This would have worked too, because we attached only one event:
        devctl(dumper_fd, DCMD_DUMPER_REMOVEEVENT, NULL, 0, NULL);
        */
        close(dumper_fd);
    }
    if (dp_coid >=0)
        ConnectDetach(dp_coid);
    if (dp_chid >=0)
        ChannelDestroy(dp_chid);
    exit(0);
}

See also:

DCMD_DUMPER_GETPATH, DCMD_DUMPER_REMOVEALL, DCMD_DUMPER_REMOVEEVENT

devctl() in the QNX Neutrino C Library Reference

dumper in the Utilities Reference