LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Notify when a process closes (https://www.linuxquestions.org/questions/programming-9/notify-when-a-process-closes-859236/)

gcubar 01-28-2011 09:21 AM

Notify when a process closes
 
Hi colleagues,

It is possible to know when any process is closed? When I refer to any process, is a process that is not a child of my application.

I thought perhaps pipes in /proc/[pid]/fd/... could helpme, but really I have no idea how it could be.

Any ideas, or is this possible?

Best regards.

orgcandman 01-28-2011 09:31 AM

Have you tried waitpid(PID_T, &status, 0) ?

edit - duh, waitpid is for children.

A few ways you can do this.

#1 - write a small "hook" application to be the parent. All it does is fork() + exec() and waitpid()

#2 - ptrace() attach to the app, and let it continue executing. When it is delivered a signal, you can intercept. If it would exit() normally, your ptrace() call should fail with ESRCH.

#3 - watch a pid file, or /proc/ filesystem.

gcubar 01-28-2011 01:10 PM

Thank you for your quick answer.

Quote:

Originally Posted by orgcandman (Post 4240621)
#1 - write a small "hook" application to be the parent. All it does is fork() + exec() and waitpid()

This sounds a little difficult to implement, or at least to me. Because I don't understand why I need to execute the process any more with fork() + exec(). I repeat that the process is not handled for my applications and it's not a child neither.

Quote:

Originally Posted by orgcandman (Post 4240621)
#2 - ptrace() attach to the app, and let it continue executing. When it is delivered a signal, you can intercept. If it would exit() normally, your ptrace() call should fail with ESRCH.

Ok, I'm a newbie on Linux. I saw that ptrace like this:

Code:

    pid_t pid = 10000;

    long rTrace = ptrace(PTRACE_ATTACH, pid, 0, 0);

    if(rTrace < 0)
      {
        cout << "ERROR: No. " << errno << endl;
      }
    else
      {
        cout << "Process attached!" << endl;
      }

trace any process in Linux, but, how i hope for the process and get the signal that tells me that the process is terminated? I have to use threads too?

Quote:

Originally Posted by orgcandman (Post 4240621)
#3 - watch a pid file, or /proc/ filesystem.

What I look for in /proc/filesystems? However, I do not think that this is a good solution.

Thanks.

Aquarius_Girl 01-29-2011 12:45 AM

Quote:

Originally Posted by orgcandman (Post 4240621)
#1 - write a small "hook" application to be the parent. All it does is fork() + exec() and waitpid()

#2 - ptrace() attach to the app, and let it continue executing. When it is delivered a signal, you can intercept. If it would exit() normally, your ptrace() call should fail with ESRCH.

The man page says:
Quote:

The ptrace() system call provides a means by which a parent process may observe and control the execution of another process,
Does it not mean that ptrace can work on the children of a particular process? If my understanding is wrong, correct me, if not, then OP has specified that he wants to observe unrelated processes too, how will the ptrace work in that case?

Aquarius_Girl 01-29-2011 01:03 AM

Quote:

Originally Posted by gcubar (Post 4240836)
What I look for in /proc/filesystems?

Observe the below outputs, ps -el lists the PID of ALL the running processes and those processes have an entry in /proc.

The way to read and write /proc is shown here: http://tldp.org/LDP/lkmpg/2.6/html/x769.html
Code:

anisha@linux-uitj:~> ps -el
F S  UID  PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S    0    1    0  0  80  0 -  2018 poll_s ?        00:00:00 init
1 S    0    2    0  0  75  -5 -    0 kthrea ?        00:00:00 kthreadd
1 S    0    3    2  0 -40  - -    0 migrat ?        00:00:00 migration/0
1 S    0    4    2  0  75  -5 -    0 ksofti ?        00:00:09 ksoftirqd/0
....
....
0 S  1000 28488    1  0  80  0 -  3107 wait  ?        00:00:00 firefox
....
0 S  1000 30020    1  0  80  0 - 76885 poll_s ?        00:00:03 okular
....

Code:

anisha@linux-uitj:~> cd /proc
anisha@linux-uitj:/proc> ls
1      17179  17240  1942  2334  26293  28502  44        diskstats    kpagecount    slabinfo
11    17180  17263  1943  2367  2634  28506  471        dma          kpageflags    softirqs
1172  17190  17266  1944  2368  267    29    5          dri          latency_stats  splash
1186  17191  17270  19567  2371  27    3      516        driver      loadavg        stat
12    17194  17426  19570  2373  28367  30    52        execdomains  locks          swaps
1215  17197  18    1960  2374  28368  30020  53        fb          mdstat        sys
13    17198  1811  1982  2377  28369  30493  631        filesystems  meminfo        sysrq-trigger
14    17199  1818  1984  24    28370  3071  645        fs          misc          sysvipc
16    17201  1827  2      24732  28371  31    692        ide          modules        timer_list
1622  17203  1828  20    25    28372  32    9          interrupts  mounts        timer_stats
1629  17205  18597  2016  2509  28373  32371  acpi      iomem        mtrr          tty
1646  17210  18598  2072  2522  28374  32583  asound    ioports      net            uptime
16746  17211  18600  21    2527  28375  33    buddyinfo  irq          pagetypeinfo  version
17071  17213  18604  2118  2572  28376  357    bus        kallsyms    partitions    vmallocinfo
17074  17215  19    22438  2578  28377  38    cmdline    kcore        sched_debug    vmstat
17079  17221  1916  2289  2582  28379  39    config.gz  kdb          schedstat      zoneinfo
17080  17225  1919  2298  26    28380  4      cpuinfo    key-users    scsi
17106  17232  1920  23    26261  28488  43    devices    kmsg        self


firstfire 01-29-2011 02:03 AM

Hi.
You can use GDB as a higher-level interface to ptrace() syscall.
For example:
  1. Create couple of files:
    Code:

    # file: eval-on-exit.gdb
    catch syscall exit
    catch syscall exit_group
    commands 1 2        # catchpoints
    shell './script.sh'  # run any program you want
    cont
    end

    cont

    Code:

    #!/bin/bash
    # file: script.sh
    # make it executable: chmod +x script.sh
    echo 'End hook started'

  2. Run the process in question if it is not yet. In this example I assume 'gvim' process is running.
  3. Now attach GDB to a running process (gvim here):
    Code:

    gdb -batch -x eval-on-exit.gdb --quiet  --pid=`pidof gvim`

When `gvim' exits (you type :q) `script.sh' will be executed. Here is a test run
Code:

$ gdb -batch -x eval-on-exit.gdb --quiet --pid=`pidof gvim`
[Thread debugging using libthread_db enabled]
0xb7835424 in __kernel_vsyscall ()
Catchpoint 1 (syscall 'exit' [1])
Catchpoint 2 (syscall 'exit_group' [252])

Catchpoint 2 (call to syscall 'exit_group'), 0xb7835424 in __kernel_vsyscall ()
End hook started

Program exited normally.

In my opinion this approach has a number of drawbacks (slow, do not work if SIGINT recieved etc) and simple polling of /proc should be used if you do not need to make some actions just before the process exit.

P.S. Following command allow gdb to attach to a running process without root priviledges (Ubuntu 10.10 and later):
Code:

# echo 0 > /proc/sys/kernel/yama/ptrace_scope

gcubar 01-30-2011 06:28 PM

Well, this is an approximation of a possible solution to my question and thanks to their answer I can expose there here. This is the code where I put two variants of notification: through the 'sigaction' and through the 'waitpid' within the cycle.

Any comments or corrections are always welcome.

Code:


#include <errno.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <string.h>

#include <iostream>

extern int errno;

using namespace std;

void sa_sigchld_handler(int signum)
  {
    cout << "*** SIGCHLD" << endl;
  }

int main()
  {
    pid_t childPid = 7817;

    // attach process with pid = childPid
    long rTrace = ptrace(PTRACE_ATTACH, childPid, 0, 0);

    if(rTrace < 0)
      {
        cout << "ERROR #" << errno << ": ";
        cout.flush();
        perror("");
      }
    else
      {
        int exitStatus;
        cout << "Process attached!" << endl;

        // wait for child process change the state
        if(waitpid(childPid, &exitStatus, WNOHANG) > 0)
          {
            bool childStopped = WIFSTOPPED(exitStatus);

            if(childStopped)
              {
                // do the process continue
                rTrace = ptrace(PTRACE_CONT, childPid, 0, 0);
                if(rTrace < 0)
                  {
                    cout << "Don't could continue!" << endl;
                    cout << "ERROR #" << errno << ": ";
                    cout.flush();
                    perror("");
                  }
                else
                  {
                    cout << "Process continues!" << endl;
                  }
              }
          }

        // connect sigaction
        struct sigaction action;
        struct sigaction oldAction;
        memset(&action, 0, sizeof(action));
        action.sa_handler = sa_sigchld_handler;
        action.sa_flags = SA_NOCLDSTOP;
        sigaction(SIGCHLD, &action, &oldAction);

        do {
          if(waitpid(childPid, &exitStatus, WNOHANG) > 0)
            {
              bool crashed = !WIFEXITED(exitStatus);
              int exitCode = WEXITSTATUS(exitStatus);
              int signalCode = WIFSIGNALED(exitStatus);
              int stopSignal = WSTOPSIG(exitStatus);
              cout << "This process dead with exitCode " << exitCode
                  << ", crashed? " << bool(crashed)
                  << ", signaled? " << signalCode
                  << ", stopedSignal? " << stopSignal
                  ;

              break;
            }
          else
            {
              //cout << "Process not deaded!" << endl;
            }
        } while(true);
      }

    return 0;
  }

Thanks any more.


All times are GMT -5. The time now is 11:18 PM.