// ChildWatcher.h #ifndef dial_ChildWatcher_H #define dial_ChildWatcher_H // August 2002 // David Adams // // Class to monitor the deaths of child processes. // // Catches end of child signals and records them for later // inspection. It also provides mean to register a function to be // called when such signals are received. A separate function may // be registered for each process ID. // // The signal-catching function is very simple to avoid deadlock. // Registered signal handling functions should observe the same // care. In particular, any use of STL can be dangerous. It is // probably best to query the child watcher rather than make use // of such functions. // // The child watcher may be compiled with or without threads by // setting a flag in the sourcxe file. The threaded version uses // a separate thread to watch for end of child signals. // // The threaded version does not work with RH7.3 presumably because // threads within a process have different PID's and so the thread // waiting for SIGCHLD never receives it. #include #ifndef __CINT__ #include #else typedef int pid_t; #endif #include "dial_job/ProcessStatus.h" namespace dial { class ChildWatcher { public: // typedefs // Process ID. typedef pid_t Pid; // Function called when a child dies. // First agument is the PID of the child that died. // Second argument is the return status (0-255). // This is called automatically during C++ initialization. typedef void (*FunPtr) (Pid, int); public: // static methods // Return if child watcher has already been initialized. static bool is_initialized(); // Initialize the child watcher. // No action if this has already been done. // Returns 0 if initialization is (or was) successful. // The signal indicating the death of a child process is blocked // until check() is called. static int initialize(); // Close the child watcher. // Causes the watcher to give up signal handling. // This is called auotmatically during C++ closeout. // It should be called earlier. // It may be called multiple times. // Returns 0 for success. static int close(); // Record the birth of a child process. // Initialization must be done in advance. // This PID must // The function fun is called when child process pid dies. // Returns 0 for success. static int watch(Pid pid, FunPtr fun =0); // Block the end-of-child signal. // Block signals before starting a new process and unblock // when prepared to handle the signal, i.e. after setting // watch and any associated actions. // Or call update to unblock, handle and reset block. // Return the initial block status. static bool block(); // Unblock end of child. // Return the initial block status. static bool unblock(); // Update. // Unblocks the end-of-child signal. // Handles all children that have ended calling their // recorded function and marking them as killed. // Returns the number of live processes remaining. // Returns negative for error. static long update(); // Return if the Child watcher is blocked, i.e. if the // end-of-child signal is blocked. static bool is_blocked(); // Return the number of live child processes. // Returns negative for error. static long live_count(); // Return the number of child processes that have died. // Returns negative for error. static long dead_count(); // Return the number of processes that died without being born. static long unborn_count(); // Return the number of processes which were registered or handled // in an invalid state. static long error_count(); // Return true if the OS reports any completed child processes // pending. static bool pending(); // Print status. // Level > 0 for more info. static std::ostream& print(std::ostream& str, int level =0); // Has a PID been registered? // is_registered = is_live || is_done static bool is_registered(Pid pid); // Has a PID been registered and not yet ended? static bool is_live(Pid pid); // Has a PID been registered and ended? static bool is_done(Pid pid); // Return the status of a process. static ProcessStatus status(Pid pid); }; } // end namespace dial #endif