Changeset 30313 for trunk/base


Ignore:
Timestamp:
Oct 24, 2007, 12:58:54 PM (12 years ago)
Author:
jberry@…
Message:

Improve Daemondo to use kqueue/kevent to watch for the death of the target
process. Previously Daemondo relied on child death signals, which are given
only for direct offspring, and not grandchildren, etc. The use of the kevents
now gives notice when the targetted process is not direct offspring.

Note: these changes may introduce compatibility issues for Panther, or even
Tiger, since I have not yet tested in those environments. They may also introduce
compilation problems on platforms for which there is no kqueue support at all.
Bug reports are welcome.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/base/src/programs/daemondo/main.c

    r26569 r30313  
    6868#include <stdarg.h>
    6969#include <time.h>
     70#include <sys/types.h>
     71#include <sys/event.h>
     72#include <sys/time.h>
    7073#include <sys/wait.h>
    7174#include <mach/mach.h>
     
    105108int                                     terminating                     = 0;            // TRUE if we're terminating
    106109pid_t                           runningPid                      = 0;            // Current running pid (0 while stopped, -1 if we don't know pid)
     110
     111int                                     kqfd                            = 0;            // Kqueue file descriptor
    107112
    108113mach_port_t                     sigChild_m_port         = 0;            // Mach port to send signals through
     
    164169DoVersion(void)
    165170{
    166         printf("daemondo, version 1.0d3\n\n");
     171        printf("daemondo, version 1.1\n\n");
    167172}
    168173
     
    334339        while ((pid = CheckForValidPidFile()) == -1 && (patience - CFAbsoluteTimeGetCurrent() > 0))
    335340                sleep(1);
     341               
     342        if (verbosity >= 3)
     343                LogMessage("Discovered pid %d from pidfile %s\n", pid, pidFile);
    336344
    337345        return pid;
     346}
     347
     348
     349
     350void
     351MonitorChild(pid_t childPid)
     352{
     353        runningPid = childPid;
     354       
     355        if (runningPid != 0 && runningPid != -1) {
     356                if (verbosity >=3 )
     357                        LogMessage("Start monitoring of pid %d via kevent\n", runningPid);
     358               
     359                // Monitor the process deaths for that pid
     360                struct kevent ke;
     361                EV_SET(&ke, childPid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, NULL);
     362                if (-1 == kevent(kqfd, &ke, 1, NULL, 0, NULL))
     363                        LogMessage("Could not monitor kevent for pid %d (%d)\n", runningPid, errno);
     364        }
     365}
     366
     367
     368void
     369UnmonitorChild()
     370{
     371        runningPid = 0;
     372}
     373
     374
     375int
     376MonitoringChild()
     377{
     378        return runningPid != 0;
    338379}
    339380
     
    346387        {
    347388                if (verbosity >= 3)
    348                         LogMessage("Running process id %d has died.\n", childPid);
    349                        
     389                        LogMessage("Target process id %d has died.\n", childPid);
     390                       
     391                UnmonitorChild();
    350392                DestroyPidFile();
    351 
    352                 runningPid = 0;
     393               
    353394                CFRunLoopStop(CFRunLoopGetCurrent());
    354395        }
     
    510551       
    511552        // If we have a pid, then begin tracking it
    512         runningPid = pid;
     553        MonitorChild(pid);
    513554        if (pid != 0 && pid != -1)
    514555        {
    515556                if (verbosity >= 1)
    516                         LogMessage("process id %d\n", pid);
     557                        LogMessage("Target process id is %d\n", pid);
    517558
    518559                // Create a pid file if we need to             
     
    570611
    571612                // We've executed stop-cmd, so we assume any runningPid process is gone
    572                 runningPid = 0;
     613                UnmonitorChild();
    573614                DestroyPidFile();
    574615        }
     
    768809
    769810
     811void KQueueCallBack (CFSocketRef socketRef, CFSocketCallBackType type,
     812             CFDataRef address, const void *data, void *context)
     813{
     814        int fd = CFSocketGetNative(socketRef);
     815       
     816    struct kevent event;
     817        memset(&event, 0x00, sizeof(struct kevent));
     818       
     819    if (kevent(fd, NULL, 0, &event, 1, NULL) == -1) {
     820        LogMessage("Couldn't get kevent.  Error %d/%s\n", errno, strerror(errno));
     821    } else {
     822        if (event.fflags & NOTE_EXIT) {
     823       
     824                pid_t pid = event.ident;
     825               
     826                        if (verbosity >= 3)
     827                                LogMessage("Received kevent: pid %d has exited\n", pid);
     828                               
     829                        ProcessChildDeath(pid);
     830        } else
     831                LogMessage("Unexpected kevent received: %d\n", event.fflags);
     832    }
     833
     834}
     835
     836
    770837void
    771838AddNotificationToCenter(const void* value, void* context)
     
    823890        int status = 0;
    824891       
     892        if (verbosity >= 3)
     893                LogMessage("Initializing; daemondo pid is %d\n", getpid());
    825894       
    826895        // === Setup Notifications of Changes to System Configuration ===
     
    859928        CFRunLoopSourceRef      sigGenericSrc   = CFMachPortCreateRunLoopSource(NULL, sigGenericPort, 0);
    860929       
    861         // Add only the child signal source to the childwatch mode
     930       
     931        // === Setup kevent notifications of process death
     932        kqfd = kqueue();
     933    CFSocketRef kqSocket                                = CFSocketCreateWithNative(NULL,  kqfd,
     934                                                                kCFSocketReadCallBack, KQueueCallBack, NULL);
     935    CFRunLoopSourceRef  kqueueSrc               = CFSocketCreateRunLoopSource(NULL, kqSocket, 0);       
     936       
     937       
     938        // Add only the child signal sources to the childwatch mode
    862939        CFRunLoopAddSource(CFRunLoopGetCurrent(), sigChildSrc, kChildWatchMode);
    863 
     940        CFRunLoopAddSource(CFRunLoopGetCurrent(), kqueueSrc, kChildWatchMode);
     941       
    864942        // Add both child and generic signal sources to the default mode
    865943        CFRunLoopAddSource(CFRunLoopGetCurrent(), sigChildSrc, kCFRunLoopDefaultMode);
     944        CFRunLoopAddSource(CFRunLoopGetCurrent(), kqueueSrc, kCFRunLoopDefaultMode);
    866945        CFRunLoopAddSource(CFRunLoopGetCurrent(), sigGenericSrc, kCFRunLoopDefaultMode);
    867946       
     
    879958        status = Start();
    880959       
     960        if (verbosity >= 3)
     961                LogMessage("Start event loop\n");
     962       
    881963        // Run the run loop until we stop it, or until the process we're tracking stops
    882         while (status == 0 && !terminating && runningPid != 0)
     964        while (status == 0 && !terminating && MonitoringChild())
    883965                CFRunLoopRunInMode(kCFRunLoopDefaultMode, 99999999.0, true);
    884966               
    885                
    886         // === Tear Down ==
     967        if (verbosity >= 3)
     968                LogMessage("End event loop\n");
     969       
     970               
     971        // === Tear Down (we don't really need to do all of this) ===
    887972        // The daemon should by now have either been stopped, or stopped of its own accord
    888973               
     
    895980        sigGeneric_m_port = 0;
    896981       
     982        // Remove run loop sources
     983        CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sigChildSrc, kChildWatchMode);
     984        CFRunLoopRemoveSource(CFRunLoopGetCurrent(), kqueueSrc, kChildWatchMode);
     985       
     986        CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sigChildSrc, kCFRunLoopDefaultMode);
     987        CFRunLoopRemoveSource(CFRunLoopGetCurrent(), kqueueSrc, kCFRunLoopDefaultMode);
     988        CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sigGenericSrc, kCFRunLoopDefaultMode);
     989       
    897990        // Tear down signal handling infrastructure
    898         CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sigChildSrc, kChildWatchMode);
    899         CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sigChildSrc, kCFRunLoopDefaultMode);
    900         CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sigGenericSrc, kCFRunLoopDefaultMode);
    901        
    902991        CFRelease(sigChildSrc);
    903992        CFRelease(sigGenericSrc);
     
    905994        CFRelease(sigChildPort);
    906995        CFRelease(sigGenericPort);
     996       
     997        // Tear down kqueue infrastructure
     998        CFRelease(kqueueSrc);
     999        CFRelease(kqSocket);
     1000        close(kqfd);
    9071001
    9081002        // Tear down DynamicStore stuff
     
    9191013        CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(powerRef), kCFRunLoopDefaultMode);
    9201014        IODeregisterForSystemPower(&pwrNotifier);
     1015       
     1016        if (verbosity >= 3)
     1017                LogMessage("Terminating\n");
    9211018       
    9221019        return status; 
     
    10561153                int optindex = 0;
    10571154                int ret = getopt_long(argc, argv, ":s:k:r:l:hvV", longopts, &optindex);
    1058                 int opt = (ret == '?') ? optopt : ret;
     1155                int opt = ret;
    10591156                switch (opt)
    10601157                {
     
    11411238                        else if (0 == strcasecmp(optarg, "fileclean"))
    11421239                                pidStyle = kPidStyleFileClean;
     1240                        else {
     1241                                status = 1;
     1242                                LogMessage("Unexpected pid style %s\n", optarg);
     1243                        }
    11431244                        break;
    11441245               
     
    11741275                        DoVersion();
    11751276                        break;
     1277                       
     1278                default:
     1279                        LogMessage("unexpected parameter: %s\n", argv[optind]);
     1280                        status = 1;
     1281                        break;
    11761282                }
    11771283        }
Note: See TracChangeset for help on using the changeset viewer.