Macos 如何检测内核扩展Mac OS X中的应用程序终止

Macos 如何检测内核扩展Mac OS X中的应用程序终止,macos,kernel,signals,exit,Macos,Kernel,Signals,Exit,我正在寻找一种方法来检测内核空间中的应用程序退出(例如cmd-q),以便在网络内核扩展中进行处理 更准确地说: 当进程(例如,终端ping)保持在iolockleep(…THREAD_ABORTSAFE)中时,ctrl-c能够释放锁。 询问proc_issignal(),它会响应sigmask(SIGINT) 现在我正在寻找一种检测另一个进程退出的方法,例如firefox(菜单栏:Application quit(cmd-q)) 以下是我尝试过的: #define FLAG(X) ((dispa

我正在寻找一种方法来检测内核空间中的应用程序退出(例如cmd-q),以便在网络内核扩展中进行处理

更准确地说: 当进程(例如,终端ping)保持在iolockleep(…THREAD_ABORTSAFE)中时,ctrl-c能够释放锁。 询问proc_issignal(),它会响应sigmask(SIGINT)

现在我正在寻找一种检测另一个进程退出的方法,例如firefox(菜单栏:Application quit(cmd-q))

以下是我尝试过的:

#define FLAG(X) ((dispatch_source_get_data(src) & DISPATCH_PROC_##X) ? #X" " : "")

struct ProcessInfo {
    int pid;
    dispatch_source_t source;
};

// function called back on event
void process_termination_event(struct ProcessInfo* procinfo) {
    dispatch_source_t src = procinfo->source;
    printf("process_termination_event: %d \n", procinfo->pid);
    printf("flags: %s%s\n", FLAG(EXIT), FLAG(SIGNAL));
    dispatch_source_cancel(procinfo->source);
}

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

// Monitor a process by pid, for termination
void MonitorTermination(int pid) {
    struct ProcessInfo* procinfo = (struct ProcessInfo*)malloc(sizeof(struct ProcessInfo));

    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|DISPATCH_PROC_SIGNAL, queue);

    procinfo->pid = pid;
    procinfo->source = dsp;

    dispatch_source_set_event_handler_f(procinfo->source, (dispatch_function_t)process_termination_event);
    dispatch_source_set_cancel_handler_f(procinfo->source, (dispatch_function_t)process_termination_finalize);
    dispatch_set_context(procinfo->source, procinfo);
    dispatch_resume(procinfo->source);
}

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

        MonitorTermination(pid);
    }

    CFRunLoopRun();
    return 0;
}
#define FLAG(X)((dispatch_source_get_data(src)&dispatch_PROC_#X)?#X“”:“”)
结构进程信息{
int-pid;
调度来源;
};
//事件时回调函数
无效进程\终止\事件(结构进程信息*procinfo){
dispatch\u source\u t src=procinfo->source;
printf(“进程\终止\事件:%d\n”,procinfo->pid);
printf(“标志:%s%s\n”、标志(退出)、标志(信号));
调度\来源\取消(procinfo->source);
}
//取消分派源时回调函数
作废进程\终止\最终确定(结构进程信息*procinfo){
printf(“进程\u终止\u完成:%d\n”,procinfo->pid);
调度发布(procinfo->source);
}
//通过pid监控一个进程,以便终止
无效监视终止(int pid){
struct ProcessInfo*procinfo=(struct ProcessInfo*)malloc(sizeof(struct ProcessInfo));
调度队列=调度获取全局队列(调度队列优先级默认为0);
调度源dsp=调度源创建(调度源类型进程、pid、调度进程退出、调度进程信号、队列);
procinfo->pid=pid;
procinfo->source=dsp;
调度\u源\u集\u事件\u处理程序\u f(procinfo->source,(调度功能\u t)处理\u终止\u事件);
调度源设置取消处理程序(procinfo->source,(调度功能)处理终止完成);
调度设置上下文(procinfo->source,procinfo);
发送简历(procinfo->source);
}
int main(int argc,const char*argv[]
{
对于(int i=0;i
如上所述,在cmd-q之后不会调用process_termination_事件。即使在武力退出之后

进程本身保存在网络内核扩展函数内的一个循环中:

errno_t KEXT::data_out(void *cookie, socket_t so, const struct sockaddr *to, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags)
{
    // at this point I would like to detect the app quit/termination signal.
    while(PROCESS_IS_NOT_TEMINATING); // <-- pseudo code, actually held with IOLockSleep...
    return 0;
}
errno\u t KEXT::data\u out(void*cookie、socket\u t so、const struct sockaddr*to、mbuf\u t*数据、mbuf\u t*控件、sflt\u data\u标志)
{
//此时,我想检测应用程序退出/终止信号。

虽然(PROCESS_IS_NOT_temining);//这可能不是您一直以来的想法,但是如果您在内核空间,那么我假设您正在编写内核扩展(kext)。使用内核扩展,您可以执行应用程序。您可以改为使用文件范围

kext与用户级应用程序(守护程序)一起通知守护程序进程已开始执行,然后使用函数从用户级守护程序监视已启动应用程序的终止。如果需要,用户应用程序可以将已终止的应用程序通知kext

要监视用户级应用程序的终止,当收到正在执行的应用程序的通知时,可以执行以下操作:-

// pid and path provided from vNode scope kext...
void UserLevelApp::MonitorProcessTermination(int pid, const QString &path)
{    
    ProcessInfo* procinfo = new ProcessInfo;

    procinfo->pid = pid;
    procinfo->path = path;
    procinfo->context = this;

    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)process_termination_event);
    dispatch_source_set_cancel_handler_f(dsp,  (dispatch_function_t)process_termination_finalize);

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

    dispatch_resume(dsp);
}

// app terminated call-back function
void UserLevelApp::process_termination_event(struct ProcessInfo* procinfo)
{
    dispatch_source_cancel(procinfo->source);

    // example of how to use the context to call a class function
    procinfo->context->SomeClassFunction(procinfo->pid, procinfo->path);

    qDebug("App Terminated: %d, %s\n", procinfo->pid, procinfo->path.toUtf8().data());
}

// finalize callback function
void UserLevelApp::process_termination_finalize(struct ProcessInfo* procinfo)
{
   dispatch_release(procinfo->source);
   delete procinfo;
}
因此,由kext通知的每个启动的应用程序都有一个与之关联的事件处理程序,当应用程序终止时,您将在注册函数process_termination_event和process_termination_finalize中被回调


虽然这种方法需要一个与kext关联的用户级守护程序应用程序,但从安全性和稳定性的角度来看,这并不是一件坏事。

这种方法很好。但我一直坚持“应用程序将终止”问题。因为kext函数使应用程序保持活动状态。在kext完成处理之前,应用程序无法终止。如果您实现了我所描述的,应用程序终止应该没有问题-我一直在使用它。内核扩展只不过是通知进程活动的守护进程,它不应该这样做保留进程的任何资源。我想我是按照描述实现的。现在我添加了更详细的描述和守护程序代码。可能是某些错误或kext处理(while loop/lock)根本不符合目的?我不确定您试图在内核扩展中使用while循环做什么。无论如何,如果您有Amit Singh的书,Mac OS X Internals,它有一个完整的示例,说明如何编写用于监视VNode活动的内核扩展,这与我提供的答案相符。我建议您看看。如果你没有它,而且你正在编写任何低级OS X代码,我建议你购买它;虽然有点过时,但它是非常宝贵的。Merlin069,你能想象一下帮我编写代码吗?我不想免费!但我想到了那个问题,我头发变白了…我创建了一个完整的示例项目,标有问题的位置。。。