Add a request to be notified of system-wide events
#include <sys/procmgr.h>
int procmgr_event_notify_add (
unsigned flags,
const struct sigevent * event );
For more information, see "Event types," below.
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
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>:
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.
(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;
}
An integer handle that you can pass to procmgr_event_notify_delete(), or -1 if an error occurred (errno is set).
/*
* 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;
}
| Safety: | |
|---|---|
| Cancellation point | No |
| Interrupt handler | No |
| Signal handler | Yes |
| Thread | Yes |