Revision: 23009 http://trac.macosforge.org/projects/launchd/changeset/23009 Author: zarzycki@apple.com Date: 2007-01-11 16:33:20 -0800 (Thu, 11 Jan 2007) Log Message: ----------- <rdar://problem/4911067> KeepAlive with PathState should monitor for file creation state change Modified Paths: -------------- trunk/launchd/src/launchd.c trunk/launchd/src/launchd_core_logic.c trunk/launchd/src/launchd_core_logic.h Modified: trunk/launchd/src/launchd.c =================================================================== --- trunk/launchd/src/launchd.c 2007-01-10 21:58:22 UTC (rev 23008) +++ trunk/launchd/src/launchd.c 2007-01-12 00:33:20 UTC (rev 23009) @@ -645,7 +645,7 @@ if (new_networking_state != network_up) { network_up = new_networking_state; - jobmgr_dispatch_all_other_semaphores(root_jobmgr, NULL); + jobmgr_dispatch_all_semaphores(root_jobmgr); } } Modified: trunk/launchd/src/launchd_core_logic.c =================================================================== --- trunk/launchd/src/launchd_core_logic.c 2007-01-10 21:58:22 UTC (rev 23008) +++ trunk/launchd/src/launchd_core_logic.c 2007-01-12 00:33:20 UTC (rev 23009) @@ -104,8 +104,10 @@ static void machservice_setup_options(launch_data_t obj, const char *key, void *context); static void machservice_resetport(job_t j, struct machservice *ms); static struct machservice *machservice_new(job_t j, const char *name, mach_port_t *serviceport); +static void machservice_ignore(job_t j, struct machservice *ms); +static void machservice_watch(job_t j, struct machservice *ms); static void machservice_delete(struct machservice *); -static void machservice_watch(struct machservice *); +static void machservice_request_notifications(struct machservice *); static mach_port_t machservice_port(struct machservice *); static job_t machservice_job(struct machservice *); static bool machservice_hidden(struct machservice *); @@ -127,19 +129,6 @@ static void socketgroup_callback(job_t j, struct kevent *kev); static void socketgroup_setup(launch_data_t obj, const char *key, void *context); -struct watchpath { - SLIST_ENTRY(watchpath) sle; - int fd; - unsigned int is_qdir:1, __junk:31; - char name[0]; -}; - -static bool watchpath_new(job_t j, const char *name, bool qdir); -static void watchpath_delete(job_t j, struct watchpath *wp); -static void watchpath_watch(job_t j, struct watchpath *wp); -static void watchpath_ignore(job_t j, struct watchpath *wp); -static void watchpath_callback(job_t j, struct kevent *kev); - struct calendarinterval { SLIST_ENTRY(calendarinterval) sle; struct tm when; @@ -178,12 +167,15 @@ FAILED_EXIT, PATH_EXISTS, PATH_MISSING, + PATH_CHANGES, + DIR_NOT_EMPTY, // FILESYSTEMTYPE_IS_MOUNTED, /* for nfsiod, but maybe others */ } semaphore_reason_t; struct semaphoreitem { SLIST_ENTRY(semaphoreitem) sle; semaphore_reason_t why; + int fd; char what[0]; }; @@ -191,6 +183,9 @@ static void semaphoreitem_delete(job_t j, struct semaphoreitem *si); static void semaphoreitem_setup(launch_data_t obj, const char *key, void *context); static void semaphoreitem_setup_paths(launch_data_t obj, const char *key, void *context); +static void semaphoreitem_callback(job_t j, struct kevent *kev); +static void semaphoreitem_watch(job_t j, struct semaphoreitem *si); +static void semaphoreitem_ignore(job_t j, struct semaphoreitem *si); struct jobmgr_s { SLIST_ENTRY(jobmgr_s) sle; @@ -231,7 +226,6 @@ kq_callback kqjob_callback; SLIST_ENTRY(job_s) sle; SLIST_HEAD(, socketgroup) sockets; - SLIST_HEAD(, watchpath) vnodes; SLIST_HEAD(, calendarinterval) cal_intervals; SLIST_HEAD(, envitem) global_env; SLIST_HEAD(, envitem) env; @@ -356,9 +350,9 @@ void job_ignore(job_t j) { + struct semaphoreitem *si; struct socketgroup *sg; struct machservice *ms; - struct watchpath *wp; if (j->currently_ignored) { return; @@ -370,12 +364,12 @@ socketgroup_ignore(j, sg); } - SLIST_FOREACH(wp, &j->vnodes, sle) { - watchpath_ignore(j, wp); + SLIST_FOREACH(ms, &j->machservices, sle) { + machservice_ignore(j, ms); } - SLIST_FOREACH(ms, &j->machservices, sle) { - job_assumes(j, runtime_remove_mport(ms->port) == KERN_SUCCESS); + SLIST_FOREACH(si, &j->semaphores, sle) { + semaphoreitem_ignore(j, si); } } @@ -385,7 +379,6 @@ struct semaphoreitem *si; struct socketgroup *sg; struct machservice *ms; - struct watchpath *wp; if (!j->currently_ignored) { return; @@ -397,19 +390,12 @@ socketgroup_watch(j, sg); } - SLIST_FOREACH(wp, &j->vnodes, sle) { - watchpath_watch(j, wp); - } - SLIST_FOREACH(ms, &j->machservices, sle) { - job_assumes(j, runtime_add_mport(ms->port, NULL, 0) == KERN_SUCCESS); + machservice_watch(j, ms); } SLIST_FOREACH(si, &j->semaphores, sle) { - if (si->why == PATH_EXISTS || si->why == PATH_MISSING) { - /* Maybe another job has the inverse path based semaphore as this job */ - jobmgr_dispatch_all_other_semaphores(root_jobmgr, j); - } + semaphoreitem_watch(j, si); } } @@ -583,7 +569,6 @@ { struct calendarinterval *ci; struct socketgroup *sg; - struct watchpath *wp; struct limititem *li; struct envitem *ei; struct machservice *ms; @@ -627,9 +612,6 @@ while ((sg = SLIST_FIRST(&j->sockets))) { socketgroup_delete(j, sg); } - while ((wp = SLIST_FIRST(&j->vnodes))) { - watchpath_delete(j, wp); - } while ((ci = SLIST_FIRST(&j->cal_intervals))) { calendarinterval_delete(j, ci); } @@ -1299,9 +1281,6 @@ void job_import_array(job_t j, const char *key, launch_data_t value) { - bool is_q_dir = false; - bool is_wp = false; - switch (key[0]) { case 'l': case 'L': @@ -1314,14 +1293,24 @@ case 'q': case 'Q': if (strcasecmp(key, LAUNCH_JOBKEY_QUEUEDIRECTORIES) == 0) { - is_q_dir = true; - is_wp = true; + size_t i, qd_cnt = launch_data_array_get_count(value); + const char *thepath; + for (i = 0; i < qd_cnt; i++) { + thepath = launch_data_get_string(launch_data_array_get_index(value, i)); + semaphoreitem_new(j, DIR_NOT_EMPTY, thepath); + } + } break; case 'w': case 'W': if (strcasecmp(key, LAUNCH_JOBKEY_WATCHPATHS) == 0) { - is_wp = true; + size_t i, wp_cnt = launch_data_array_get_count(value); + const char *thepath; + for (i = 0; i < wp_cnt; i++) { + thepath = launch_data_get_string(launch_data_array_get_index(value, i)); + semaphoreitem_new(j, PATH_CHANGES, thepath); + } } break; case 'b': @@ -1341,15 +1330,6 @@ default: break; } - - if (is_wp) { - size_t i, wp_cnt = launch_data_array_get_count(value); - const char *thepath; - for (i = 0; i < wp_cnt; i++) { - thepath = launch_data_get_string(launch_data_array_get_index(value, i)); - watchpath_new(j, thepath, is_q_dir); - } - } } void @@ -1752,7 +1732,7 @@ } break; case EVFILT_VNODE: - watchpath_callback(j, kev); + semaphoreitem_callback(j, kev); break; case EVFILT_READ: if (kev->ident == (uintptr_t)j->log_redirect_fd) { @@ -2365,111 +2345,82 @@ } } -bool -watchpath_new(job_t j, const char *name, bool qdir) -{ - struct watchpath *wp = calloc(1, sizeof(struct watchpath) + strlen(name) + 1); - - if (!job_assumes(j, wp != NULL)) { - return false; - } - - wp->is_qdir = qdir; - - wp->fd = -1; /* watchpath_watch() will open this */ - - strcpy(wp->name, name); - - SLIST_INSERT_HEAD(&j->vnodes, wp, sle); - - return true; -} - -void -watchpath_delete(job_t j, struct watchpath *wp) -{ - if (wp->fd != -1) { - job_assumes(j, close(wp->fd) != -1); - } - - SLIST_REMOVE(&j->vnodes, wp, watchpath, sle); - - free(wp); -} - void -watchpath_ignore(job_t j, struct watchpath *wp) +semaphoreitem_ignore(job_t j, struct semaphoreitem *si) { - if (wp->fd != -1) { - job_log(j, LOG_DEBUG, "Ignoring Vnode: %d", wp->fd); - job_assumes(j, kevent_mod(wp->fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL) != -1); + if (si->fd != -1) { + job_log(j, LOG_DEBUG, "Ignoring Vnode: %d", si->fd); + job_assumes(j, kevent_mod(si->fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL) != -1); } } void -watchpath_watch(job_t j, struct watchpath *wp) +semaphoreitem_watch(job_t j, struct semaphoreitem *si) { - int fflags = NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK; - int qdir_file_cnt; - - if (!wp->is_qdir) { - fflags |= NOTE_DELETE|NOTE_RENAME|NOTE_REVOKE; + char parentdir_path[PATH_MAX], *which_path = si->what; + int fflags = 0; + + switch (si->why) { + case PATH_EXISTS: + fflags = NOTE_DELETE|NOTE_RENAME|NOTE_REVOKE|NOTE_EXTEND|NOTE_WRITE; + strlcpy(parentdir_path, dirname(si->what), sizeof(parentdir_path)); + which_path = parentdir_path; + break; + case PATH_MISSING: + fflags = NOTE_DELETE|NOTE_RENAME; + break; + case PATH_CHANGES: + fflags = NOTE_DELETE|NOTE_RENAME|NOTE_REVOKE|NOTE_EXTEND|NOTE_WRITE|NOTE_ATTRIB|NOTE_LINK; + break; + default: + return; } - if (wp->fd == -1) { - wp->fd = _fd(open(wp->name, O_EVTONLY|O_NOCTTY|O_NOFOLLOW)); + if (si->fd == -1) { + si->fd = _fd(open(which_path, O_EVTONLY|O_NOCTTY)); } - if (wp->fd == -1) { - return job_log_error(j, LOG_ERR, "Watchpath monitoring failed on \"%s\"", wp->name); + if (si->fd == -1) { + return job_log_error(j, LOG_ERR, "Watchpath monitoring failed on \"%s\"", which_path); } - job_log(j, LOG_DEBUG, "Watching Vnode: %d", wp->fd); - job_assumes(j, kevent_mod(wp->fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, fflags, 0, j) != -1); - - if (!wp->is_qdir) { - return; - } - - if (-1 == (qdir_file_cnt = dir_has_files(j, wp->name))) { - job_log_error(j, LOG_ERR, "dir_has_files(\"%s\", ...)", wp->name); - } else if (qdir_file_cnt > 0) { - job_dispatch(j, true); - } + job_log(j, LOG_DEBUG, "Watching Vnode: %d", si->fd); + job_assumes(j, kevent_mod(si->fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, fflags, 0, j) != -1); } void -watchpath_callback(job_t j, struct kevent *kev) +semaphoreitem_callback(job_t j, struct kevent *kev) { - struct watchpath *wp; - int dir_file_cnt; + struct semaphoreitem *si; - SLIST_FOREACH(wp, &j->vnodes, sle) { - if (wp->fd == (int)kev->ident) { + SLIST_FOREACH(si, &j->semaphores, sle) { + switch (si->why) { + case PATH_CHANGES: + case PATH_EXISTS: + case PATH_MISSING: break; + default: + continue; } + + if (si->fd == (int)kev->ident) { + break; + } } - job_assumes(j, wp != NULL); + if (!job_assumes(j, si != NULL)) { + return; + } if ((NOTE_DELETE|NOTE_RENAME|NOTE_REVOKE) & kev->fflags) { - job_log(j, LOG_DEBUG, "Path invalidated: %s", wp->name); - job_assumes(j, close(wp->fd) == 0); - wp->fd = -1; /* this will get fixed in watchpath_watch() */ - } else if (!wp->is_qdir) { - job_log(j, LOG_DEBUG, "Watch path modified: %s", wp->name); - } else { - job_log(j, LOG_DEBUG, "Queue directory modified: %s", wp->name); - - if (-1 == (dir_file_cnt = dir_has_files(j, wp->name))) { - job_log_error(j, LOG_ERR, "dir_has_files(\"%s\", ...)", wp->name); - } else if (0 == dir_file_cnt) { - job_log(j, LOG_DEBUG, "Spurious wake up, directory is empty again: %s", wp->name); - return; - } + job_log(j, LOG_DEBUG, "Path invalidated: %s", si->what); + job_assumes(j, close(si->fd) == 0); + si->fd = -1; /* this will get fixed in semaphoreitem_watch() */ } - job_dispatch(j, true); + job_log(j, LOG_DEBUG, "Watch path modified: %s", si->what); + + job_dispatch(j, si->why == PATH_CHANGES ? true : false); } bool @@ -2818,6 +2769,8 @@ SLIST_FOREACH(si, &j->semaphores, sle) { bool wanted_state = false; + int qdir_file_cnt; + switch (si->why) { case NETWORK_UP: wanted_state = true; @@ -2843,9 +2796,22 @@ if ((bool)(stat(si->what, &sb) == 0) == wanted_state) { job_log(j, LOG_DEBUG, "KeepAlive check: job configured to run while the following path %s: %s", wanted_state ? "exists" : "is missing", si->what); + if (si->fd != -1) { + job_assumes(j, close(si->fd) == 0); + si->fd = -1; + } return true; } break; + case PATH_CHANGES: + break; + case DIR_NOT_EMPTY: + if (-1 == (qdir_file_cnt = dir_has_files(j, si->what))) { + job_log_error(j, LOG_ERR, "dir_has_files(\"%s\", ...)", si->what); + } else if (qdir_file_cnt > 0) { + return true; + } + break; } } @@ -2928,6 +2894,18 @@ } void +machservice_watch(job_t j, struct machservice *ms) +{ + job_assumes(j, runtime_add_mport(ms->port, NULL, 0) == KERN_SUCCESS); +} + +void +machservice_ignore(job_t j, struct machservice *ms) +{ + job_assumes(j, runtime_remove_mport(ms->port) == KERN_SUCCESS); +} + +void machservice_resetport(job_t j, struct machservice *ms) { job_assumes(j, launchd_mport_close_recv(ms->port) == KERN_SUCCESS); @@ -3347,7 +3325,7 @@ } void -machservice_watch(struct machservice *ms) +machservice_request_notifications(struct machservice *ms) { mach_msg_id_t which = MACH_NOTIFY_DEAD_NAME; @@ -3521,6 +3499,7 @@ return false; } + si->fd = -1; si->why = why; if (what) { @@ -3533,11 +3512,15 @@ } void -semaphoreitem_delete(job_t j, struct semaphoreitem *ri) +semaphoreitem_delete(job_t j, struct semaphoreitem *si) { - SLIST_REMOVE(&j->semaphores, ri, semaphoreitem, sle); + SLIST_REMOVE(&j->semaphores, si, semaphoreitem, sle); - free(ri); + if (si->fd != -1) { + job_assumes(j, close(si->fd) != -1); + } + + free(si); } void @@ -3571,18 +3554,18 @@ } void -jobmgr_dispatch_all_other_semaphores(jobmgr_t jm, job_t nj) +jobmgr_dispatch_all_semaphores(jobmgr_t jm) { jobmgr_t jmi; job_t ji, jn; SLIST_FOREACH(jmi, &jm->submgrs, sle) { - jobmgr_dispatch_all_other_semaphores(jmi, nj); + jobmgr_dispatch_all_semaphores(jmi); } SLIST_FOREACH_SAFE(ji, &jm->jobs, sle, jn) { - if (ji != nj && !SLIST_EMPTY(&ji->semaphores)) { + if (!SLIST_EMPTY(&ji->semaphores)) { job_dispatch(ji, false); } } @@ -3979,7 +3962,7 @@ return BOOTSTRAP_SERVICE_ACTIVE; } - machservice_watch(ms); + machservice_request_notifications(ms); job_log(j, LOG_INFO, "Check-in of service: %s", servicename); @@ -4034,7 +4017,7 @@ if (serviceport != MACH_PORT_NULL) { if ((ms = machservice_new(j, servicename, &serviceport))) { - machservice_watch(ms); + machservice_request_notifications(ms); } else { return BOOTSTRAP_NO_MEMORY; } @@ -4228,7 +4211,7 @@ struct machservice *ms; if ((ms = machservice_new(jmr->anonj, l2l_names[l2l_i], &l2l_ports[l2l_i]))) { - machservice_watch(ms); + machservice_request_notifications(ms); } } Modified: trunk/launchd/src/launchd_core_logic.h =================================================================== --- trunk/launchd/src/launchd_core_logic.h 2007-01-10 21:58:22 UTC (rev 23008) +++ trunk/launchd/src/launchd_core_logic.h 2007-01-12 00:33:20 UTC (rev 23009) @@ -33,7 +33,7 @@ void jobmgr_set_stderr(jobmgr_t jm, const char *what); bool jobmgr_is_idle(jobmgr_t jm); void jobmgr_remove_all_inactive(jobmgr_t jm); -void jobmgr_dispatch_all_other_semaphores(jobmgr_t jm, job_t nj); +void jobmgr_dispatch_all_semaphores(jobmgr_t jm); job_t jobmgr_find(jobmgr_t jm, const char *label); void jobmgr_delete_anything_with_port(jobmgr_t jm, mach_port_t port); bool jobmgr_ack_port_destruction(jobmgr_t jm, mach_port_t p);
participants (1)
-
source_changes@macosforge.org