procmgr_event_notify_add()

Add a request to be notified of system-wide events

Synopsis:

#include <sys/procmgr.h>

int procmgr_event_notify_add (
              unsigned flags,
              const struct sigevent * event );

Arguments:

flags
A bitwise OR of the type of events that you want to be notified of. The event types include:
  • PROCMGR_EVENT_CONFSTR
  • PROCMGR_EVENT_CONTIG_ALLOC_FAIL
  • PROCMGR_EVENT_DAEMON_DEATH
  • PROCMGR_EVENT_PATHSPACE
  • PROCMGR_EVENT_SYNC
  • PROCMGR_EVENT_SYSCONF
  • PROCMGR_EVENT_TOD

For more information, see "Event types," below.

event
A pointer to a sigevent structure that specifies how you want to be notified.

Library:

libc

Use the -l c option to qcc to link against this library. This library is usually included automatically.

Description:

The procmgr_event_notify_add() function adds a request that the process manager notify the caller of the system-wide events identified by the given flags. You can use this function to set up more than one notification request.

To delete a request, call procmgr_event_notify_delete(), passing it the handle returned by procmgr_event_notify_add().

Event types

The following event types are defined in <sys/procmgr.h>:

PROCMGR_EVENT_CONFSTR
A process set a configuration string.
PROCMGR_EVENT_CONTIG_ALLOC_FAIL
(QNX Neutrino 6.6 or later) An attempt to allocate contiguous memory failed.
PROCMGR_EVENT_DAEMON_DEATH
A process in session 1 died. This event is most useful for watching for the death of daemon processes that use procmgr_daemon() to put themselves in session 1 as well as close and redirect file descriptors. As a result of this closing and redirecting, the death of daemons is difficult to detect otherwise.
Note: Notification is via the given event. Before QNX Neutrino 6.6, no information was provided as to which process died. Once you received the event, you had to do something else to find out if processes that you cared about had died. You did this by walking through the list of all processes, looking for specific process IDs or process names. If you didn't find a process, then it had died. The sample code below demonstrates how you can do this.

In QNX Neutrino 6.6 or later, you can specify SIGEV_FLAG_UPDATEABLE as described below, and then the notification includes the process ID of the process that died.

PROCMGR_EVENT_PATHSPACE
(QNX Momentics 6.3.0 SP2 or later) A resource manager added or removed an entry (i.e., mountpoint) to or from the pathname space. This is generally associated with resource manager calls to resmgr_attach() and resmgr_detach(). Terminating a resource manager process also generates this event if the mountpoints haven't been detached.
PROCMGR_EVENT_SYNC
A process called sync() to synchronize the filesystems.
PROCMGR_EVENT_SYSCONF
A process set a system configuration string.
PROCMGR_EVENT_TOD
(QNX Neutrino 6.6 or later) A process changed the time of day by calling ClockTime() or clock_settime().

(QNX Neutrino 6.6 or later) If you set SIGEV_FLAG_UPDATEABLE in the hidden bits in the sigevent structure, the kernel provides some additional information in the sigev_value member:

Event Information
PROCMGR_EVENT_PATHSPACE The hash of the pathname (see below)
PROCMGR_EVENT_DAEMON_DEATH The process ID of the dying process
PROCMGR_EVENT_CONFSTR The value of the confstr() constant
PROCMGR_EVENT_SYSCONF The value of the sysconf() constant

The code for generating the hash of the pathname is as follows:

static unsigned
pathspace_hash(const  char * str ) {

    unsigned hash, x;

    for (x = hash = 0 ; *str ; ++str) {
        hash = (hash << 4) + *str;
        if ((x = hash & 0xf0000000u) != 0) {
            hash ^= (x >> 24);
            hash &= ~x;
        }
    }
    // Modification from standard ELFHash so that client can tell that the
    // sigev_value field contains a hash if it's non-zero
    return hash | 0x80000000u;

}

Returns:

An integer handle that you can pass to procmgr_event_notify_delete(), or -1 if an error occurred (errno is set).

Examples:

/*
 * This demonstrates procmgr_event_notify_add() with the 
 * PROCMGR_DAEMON_DEATH flag. This flag allows you to 
 * be notified if any process in session 1 dies.  
 * Daemons are processes that do things that make
 * their death hard to detect (they become daemons by calling
 * procmgr_daemon()).  One of the things that happens is that
 * daemons end up in session 1.  Hence, the usefulness of the
 * PROCMGR_DAEMON_DEATH flag.
 *
 * When you are notified, you're not told who died.
 * It's up to you to know who should be running.  Once notified,
 * you could then walk through the list of which processes are
 * still running and see if all the expected processes are still
 * running. If you know the process id of the processes you
 * are watching out for then this is easiest.  If you don't know
 * the process id then your next option may be by process name.
 * The code below does a lookup by process name.
 *
 * This is easier in QNX Neutrino 6.6 or later, thanks to the
 * SIGEV_FLAG_UPDATEABLE flag.
 */

#include <devctl.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/neutrino.h>
#include <sys/procfs.h>
#include <sys/procmgr.h>

static int check_if_running( char *process );

#define DAEMON_DIED_CODE   (_PULSE_CODE_MINAVAIL)

struct dinfo_s {
    procfs_debuginfo    info;
    char                pathbuffer[PATH_MAX];
};

int
main( int argc, char **argv )
{
    char            *daemon_to_watch;
    int             chid, coid, rcvid, handle;
    struct sigevent event;
    struct _pulse   msg;
    
    if (argc != 2) {
        printf( "use: %s process_to_watch_for\n", argv[0] );
        exit( EXIT_FAILURE );
    }
    
    daemon_to_watch = argv[1];   /* the process to watch for */
    
    chid = ChannelCreate( 0 );
    coid = ConnectAttach( 0, 0, chid, _NTO_SIDE_CHANNEL, 0 );
    SIGEV_PULSE_INIT( &event, coid, SIGEV_PULSE_PRIO_INHERIT,
                      DAEMON_DIED_CODE, 0 );

    /*
     * Ask to be notified via a pulse whenever a 
     * daemon process dies
     */
     
    handle = procmgr_event_notify_add( PROCMGR_EVENT_DAEMON_DEATH, &event );
    if (handle == -1) {
        fprintf( stderr, "procmgr_event_notify_add() failed" );
        exit( EXIT_FAILURE );
    }

    while (1) {
        rcvid = MsgReceive( chid, &msg, sizeof(msg), NULL );
        if (rcvid != 0) {
            /* not a pulse; could be an unexpected message or
               error */
            exit( EXIT_FAILURE );
        }
        
        if (check_if_running( daemon_to_watch ) == 0)
            printf( "%s is no longer running\n", daemon_to_watch);
    }    

    procmgr_event_notify_delete (handle);

    return 0;
}

/*
 * check_if_running - This will walk through all processes 
 * to see if this particular one is still running.
 */
 
static int
check_if_running( char *process )
{
    DIR             *dirp;
    struct dirent   *dire;
    char            buffer[20];
    int             fd, status;
    pid_t           pid;
    struct dinfo_s  dinfo;
    
    if ((dirp = opendir( "/proc" )) == NULL) {
        perror( "Could not open '/proc'" );
        return -1;
    }
    while (1) {
        if ((dire = readdir( dirp )) == NULL)
            break;
        if (isdigit( dire->d_name[0] )) {
            pid = strtoul( dire->d_name, NULL, 0 );
    
            sprintf( buffer, "/proc/%d/as", pid );
            if ((fd = open( buffer, O_RDONLY )) != NULL) {
                status = devctl( fd, DCMD_PROC_MAPDEBUG_BASE,
                                 &dinfo, sizeof(dinfo), NULL );
                if (status == EOK) {
                    if (!strcmp( process,
                                 basename( dinfo.info.path ) ))
                    {
                        closedir (dirp);

                        /* You should close fd to prevent memory
                           leaking */
                        close(fd); 
                       
                        return 1;
                    }
                } /* else some errors are expected, e.g. procnto
                     has no MAPDEBUG info and there is a timing
                     issue  with getting info on the process
                     that died, ignore errors */
                close( fd );
            }
        }
    }
    closedir( dirp );
    return 0;
}

Classification:

QNX Neutrino

Safety:  
Cancellation point No
Interrupt handler No
Signal handler Yes
Thread Yes