2014-04-09 70 views
1

我開發了一個用Qt(C++)和Objective-C編寫的OSX守護進程應用程序。我監視其他應用程序和進程何時啓動,並使用內核擴展,但需要知道它們何時終止。當進程退出時得到通知

有沒有辦法接受其他進程,終止的通知,而無需不斷查詢目標進程的PID或馬赫的任務嗎?

+0

對於應用程序,這可能幫助:如何分開,如果一個應用程序已經關閉(http://stackoverflow.com/questions/22947393/how-如果某個應用程序已關閉,則將其分離)?我不知道它是否可以從守護進程中使用。 –

+0

我不知道OSX,但因爲我相信它是基於* nix的,所以您應該可以使用'signal()'來捕獲當子進程死亡時發送的'SIG_CHILD'信號。 – TripeHound

+0

謝謝你們,我會研究他們並報告回來。 – TheDarkKnight

回答

2

你可以做到這一點的kqueue/KEVENT。我篡改了一個控制檯應用程序,然後重構了一些控制檯應用程序,以便明確發生了什麼,並添加了一個輔助函數,以便更輕鬆地調用它。只是幾乎沒有測試過,但希望它可以讓你前進的方式...

哦,是的,請注意,這段代碼假設主要運行循環在應用程序中運行...並且它將調用該塊內runloop ...足夠簡單,可以用另一個運行循環替換它...或者,如果您不使用任何CF運行循環,則必須將kq文件描述符添加到您正在使用的任何通知機制中。

編輯

修正了重新啓用,因爲文件描述符回調回調必須在每次射擊後重新啓用。另外,制定的參數需要多個PID來演示監控多個PID。

當然,你可以很容易地使用調用委託方法,而不是使用塊,但是這並不是真正的點... ...

哎呀....修復資源泄漏...我可能無法修復了。 ..因爲它是被攻擊的例子,但我每次回去讀它的時候,我發現不對勁......也許我就停止閱讀它:-)

// main.c 

#include <CoreFoundation/CoreFoundation.h> 
#include <sys/types.h> 
#include <sys/event.h> 
#include <sys/time.h> 

static void 
kqueueCallbackOnExit(CFFileDescriptorRef fileDescriptor, 
        CFOptionFlags flags, 
        void *info) 
{ 
    int fd = CFFileDescriptorGetNativeDescriptor(fileDescriptor); 
    struct kevent event; 
    if (kevent(fd, NULL, 0, &event, 1, NULL) == 1 && event.udata) { 
    void (^cb)(pid_t) = event.udata; 
    cb((pid_t)event.ident); 
    Block_release(cb); 
    } 
    CFFileDescriptorEnableCallBacks(
     fileDescriptor, kCFFileDescriptorReadCallBack); 
} 

static int 
createOnProcessExitQueue() 
{ 
    int kq = kqueue(); 
    if (kq < 0) return -1; 

    CFFileDescriptorContext context = { 
    .version = 0, 
    .info = NULL, 
    .retain = NULL, 
    .release = NULL, 
    .copyDescription = NULL 
    }; 
    CFFileDescriptorRef kqFileDescriptor = CFFileDescriptorCreate(
     NULL, kq, true, kqueueCallbackOnExit, &context); 
    if (kqFileDescriptor == NULL) { 
    close(kq); 
    kq = -1; 
    return -1; 
    } 

    CFRunLoopSourceRef runLoopSource = CFFileDescriptorCreateRunLoopSource(
     NULL, kqFileDescriptor, 0); 
    CFRunLoopAddSource(CFRunLoopGetMain(), 
     runLoopSource, kCFRunLoopDefaultMode); 
    CFRelease(runLoopSource); 

    CFFileDescriptorEnableCallBacks(
     kqFileDescriptor, kCFFileDescriptorReadCallBack); 
    CFRelease(kqFileDescriptor); 

    return kq; 
} 

static int 
onProcessExit(pid_t pid, void (^callback)(pid_t pid)) 
{ 
    static int kq; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
    kq = createOnProcessExitQueue(); 
    }); 

    void (^cb)(pid_t) = Block_copy(callback); 
    struct kevent event = { 
    .ident = pid, 
    .filter = EVFILT_PROC, 
    .flags = EV_ADD | EV_ONESHOT, 
    .fflags = NOTE_EXIT, 
    .data = 0, 
    .udata = (void*)cb 
    }; 

    if (kevent(kq, &event, 1, NULL, 0, NULL) != 1) { 
    Block_release(cb); 
    return -1; 
    } 
    return 0; 
} 

int main(int argc, const char * argv[]) 
{ 
    for (int i = 0; i < argc; ++i) { 
    pid_t pid = atoi(argv[i]); 
    printf("watching pid: %d\n", pid); 
    fflush(stdout); 
    onProcessExit(pid, ^(pid_t pid) { 
     printf("process %d just died\n", (int)pid); 
     fflush(stdout); 
    }); 
    } 

    CFRunLoopRun(); 
    return 0; 
} 
+0

謝謝,這種方法非常好,並使我使用GCD更簡單的方法。 – TheDarkKnight

0

由於@JodyHagins,研究我做了kqueue,kevent帶我到this blog,它顯示瞭如何使用GCD監視文件和an example by Apple here。與作爲一個模板,我想出了這個: -

struct ProcessInfo 
{ 
    int pid; 
    dispatch_source_t source; 
}; 

// function called back on event 
void pid_event(struct ProcessInfo* procinfo) 
{ 
    printf("****** Application exited: %d ******\n", procinfo->pid); 
    dispatch_source_cancel(procinfo->source); 
} 

// function called back when the dispatch source is cancelled 
void pid_finalize(struct ProcessInfo* procinfo) 
{ 
    dispatch_release(procinfo->source); 
    printf(">>>> Finished with %d <<<<\n", procinfo->pid); 
    delete procinfo; 
} 

// Monitor a process by pid, for termination 
void DispatchMonitorProcess(int pid, ProcessInfo* procinfo) 
{ 
    procinfo->pid = pid; 

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_source_t dsp = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, queue); 

    dispatch_source_set_event_handler_f(dsp, (dispatch_function_t)pid_event); 
    dispatch_source_set_cancel_handler_f(dsp, (dispatch_function_t)pid_finalize); 

    procinfo->source = dsp; 
    dispatch_set_context(dsp, procinfo); 

    dispatch_resume(dsp); 
} 

// Monitors the termination of a process with the given pid 
void MonitorTermination(int pid) 
{   
    DispatchMonitorProcess(pid, new ProcessInfo); 
} 
相關問題