From 587e987eefe38fd31fb51b6d52f422eac67bdf8e Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 24 Dec 2009 18:58:16 +0000 Subject: [PATCH] launchd-329.3.tar.gz --- launchd/src/launch_priv.h | 11 +- launchd/src/launchd_core_logic.c | 281 ++++++++++++++++++++----------- launchd/src/launchd_runtime.c | 35 +++- launchd/src/launchd_runtime.h | 4 + 4 files changed, 222 insertions(+), 109 deletions(-) diff --git a/launchd/src/launch_priv.h b/launchd/src/launch_priv.h index 9382370..e19df70 100644 --- a/launchd/src/launch_priv.h +++ b/launchd/src/launch_priv.h @@ -49,18 +49,21 @@ __BEGIN_DECLS #define LAUNCH_KEY_BATCHQUERY "BatchQuery" #define LAUNCHD_DO_APPLE_INTERNAL_LOGGING "__DoAppleInternalLogging__" -#define LAUNCH_KEY_JETSAMLABEL "JetsamLabel" -#define LAUNCH_KEY_JETSAMFRONTMOST "JetsamFrontmost" -#define LAUNCH_KEY_JETSAMPRIORITY "JetsamPriority" - #define LAUNCH_JOBKEY_TRANSACTIONCOUNT "TransactionCount" #define LAUNCH_JOBKEY_QUARANTINEDATA "QuarantineData" #define LAUNCH_JOBKEY_SANDBOXPROFILE "SandboxProfile" #define LAUNCH_JOBKEY_SANDBOXFLAGS "SandboxFlags" #define LAUNCH_JOBKEY_SANDBOX_NAMED "Named" +#define LAUNCH_JOBKEY_JETSAMPROPERTIES "JetsamProperties" #define LAUNCH_JOBKEY_JETSAMPRIORITY "JetsamPriority" +#define LAUNCH_JOBKEY_JETSAMMEMORYLIMIT "JetsamMemoryLimit" #define LAUNCH_JOBKEY_SECURITYSESSIONUUID "SecuritySessionUUID" +#define LAUNCH_KEY_JETSAMLABEL "JetsamLabel" +#define LAUNCH_KEY_JETSAMFRONTMOST "JetsamFrontmost" +#define LAUNCH_KEY_JETSAMPRIORITY LAUNCH_JOBKEY_JETSAMPRIORITY +#define LAUNCH_KEY_JETSAMMEMORYLIMIT LAUNCH_JOBKEY_JETSAMMEMORYLIMIT + #define LAUNCH_JOBKEY_EMBEDDEDPRIVILEGEDISPENSATION "EmbeddedPrivilegeDispensation" #define LAUNCH_JOBKEY_EMBEDDEDMAINTHREADPRIORITY "EmbeddedMainThreadPriority" diff --git a/launchd/src/launchd_core_logic.c b/launchd/src/launchd_core_logic.c index 3a24f37..58f8bd8 100644 --- a/launchd/src/launchd_core_logic.c +++ b/launchd/src/launchd_core_logic.c @@ -16,7 +16,7 @@ * @APPLE_APACHE_LICENSE_HEADER_END@ */ -static const char *const __rcs_file_version__ = "$Revision: 23932 $"; +static const char *const __rcs_file_version__ = "$Revision: 24003 $"; #include "config.h" #include "launchd_core_logic.h" @@ -91,8 +91,12 @@ static const char *const __rcs_file_version__ = "$Revision: 23932 $"; #else /* To make my life easier. */ typedef struct jetsam_priority_entry { - pid_t pid; - uint32_t flags; + pid_t pid; + uint32_t flags; + int32_t hiwat_pages; + int32_t hiwat_reserved1; + int32_t hiwat_reserved2; + int32_t hiwat_reserved3; } jetsam_priority_entry_t; enum { @@ -133,7 +137,6 @@ enum { #define LAUNCHD_DEFAULT_EXIT_TIMEOUT 20 #define LAUNCHD_SIGKILL_TIMER 5 #define LAUNCHD_CLEAN_KILL_TIMER 1 -#define LAUNCHD_JETSAM_PRIORITY_UNSET 0xdead1eebabell #define SHUTDOWN_LOG_DIR "/var/log/shutdown" @@ -276,6 +279,8 @@ static void limititem_setup(launch_data_t obj, const char *key, void *context); static void seatbelt_setup_flags(launch_data_t obj, const char *key, void *context); #endif +static void jetsam_property_setup(launch_data_t obj, const char *key, job_t j); + typedef enum { NETWORK_UP = 1, NETWORK_DOWN, @@ -465,8 +470,9 @@ struct job_s { int log_redirect_fd; int nice; int stdout_err_fd; - long long jetsam_priority; - long long main_thread_priority; + int32_t jetsam_priority; + int32_t jetsam_memlimit; + int32_t main_thread_priority; uint32_t timeout; uint32_t exit_timeout; uint64_t sent_signal_time; @@ -541,7 +547,8 @@ struct job_s { clean_exit_timer_expired :1, /* The job was clean, received SIGKILL and failed to exit after LAUNCHD_CLEAN_KILL_TIMER seconds. */ embedded_special_privileges :1, /* The job runs as a non-root user on embedded but has select privileges of the root user. */ did_exec :1, /* The job exec(2)ed successfully. */ - migratory :1; /* The (anonymous) job called vprocmgr_switch_to_session(). */ + holds_ref :1, /* The (anonymous) job called vprocmgr_switch_to_session(). */ + jetsam_properties :1; /* The job has Jetsam limits in place. */ mode_t mask; pid_t tracing_pid; mach_port_t audit_session; @@ -637,11 +644,6 @@ static void take_sample(job_t j); void eliminate_double_reboot(void); -/* For Jetsam. */ -static void jetsam_priority_from_job(job_t j, bool front, jetsam_priority_entry_t *jp); -static int job_cmp(const job_t *lhs, const job_t *rhs); -int launchd_set_jetsam_priorities(launch_data_t priorities); - /* file local globals */ static size_t total_children; static size_t total_anon_children; @@ -666,6 +668,7 @@ jobmgr_t root_jobmgr; bool g_shutdown_debugging = false; bool g_verbose_boot = false; bool g_embedded_privileged_action = false; +bool g_runtime_busy_time = false; void job_ignore(job_t j) @@ -1199,7 +1202,7 @@ job_remove(job_t j) /* Not a big deal if this fails. It means that the timer's already been freed. */ kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); } - if( j->jetsam_priority != LAUNCHD_JETSAM_PRIORITY_UNSET ) { + if( j->jetsam_properties ) { LIST_REMOVE(j, jetsam_sle); j->mgr->jetsam_jobs_cnt--; } @@ -1415,20 +1418,14 @@ job_new_anonymous(jobmgr_t jm, pid_t anonpid) kp_euid, kp_uid, kp_svuid, kp_egid, kp_gid, kp_svgid, anonpid, kp.kp_proc.p_comm); } - switch (kp.kp_eproc.e_ppid) { - case 0: - /* the kernel */ - break; - case 1: - if (!pid1_magic) { - /* we cannot possibly find a parent job_t that is useful in this function */ - break; - } - /* fall through */ - default: - jp = jobmgr_find_by_pid(jm, kp.kp_eproc.e_ppid, true); - jobmgr_assumes(jm, jp != NULL); - break; + /* "Fix" for a problem that shouldn't even exist. + * See rdar://problem/7264615 for the symptom and rdar://problem/5020256 + * as to why this can happen. + */ + if( !jobmgr_assumes(jm, kp.kp_eproc.e_ppid != anonpid) ) { + jobmgr_log(jm, LOG_WARNING, "Process has become its own parent through ptrace(3). It should find a different way to do whatever it's doing. Setting PPID to 0: %s", kp.kp_proc.p_comm); + errno = EINVAL; + return NULL; } if (jp && !jp->anonymous && unlikely(!(kp.kp_proc.p_flag & P_EXEC))) { @@ -1436,7 +1433,6 @@ job_new_anonymous(jobmgr_t jm, pid_t anonpid) kp.kp_proc.p_pid); } - /* A total hack: Normally, job_new() returns an error during shutdown, but anonymous jobs are special. */ if (unlikely(shutdown_state = jm->shutting_down)) { jm->shutting_down = false; @@ -1469,6 +1465,28 @@ job_new_anonymous(jobmgr_t jm, pid_t anonpid) jm->shutting_down = true; } + /* This is down here to mitigate the effects of rdar://problem/7264615, in which a process + * attaches to its own parent. We need to make sure that the anonymous job has been added + * to the process list so that, if it's used ptrace(3) to cause a cycle in the process + * tree (thereby making it not a tree anymore), we'll find the tracing parent PID of the + * parent process, which is the child, when we go looking for it in jobmgr_find_by_pid(). + */ + switch (kp.kp_eproc.e_ppid) { + case 0: + /* the kernel */ + break; + case 1: + if (!pid1_magic) { + /* we cannot possibly find a parent job_t that is useful in this function */ + break; + } + /* fall through */ + default: + jp = jobmgr_find_by_pid(jm, kp.kp_eproc.e_ppid, true); + jobmgr_assumes(jm, jp != NULL); + break; + } + return jr; } @@ -1531,7 +1549,8 @@ job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *arg j->currently_ignored = true; j->ondemand = true; j->checkedin = true; - j->jetsam_priority = LAUNCHD_JETSAM_PRIORITY_UNSET; + j->jetsam_priority = -1; + j->jetsam_memlimit = -1; uuid_clear(j->expected_audit_uuid); if (prog) { @@ -1897,12 +1916,14 @@ job_import_integer(job_t j, const char *key, long long value) case 'j': case 'J': if( strcasecmp(key, LAUNCH_JOBKEY_JETSAMPRIORITY) == 0 ) { - job_log(j, LOG_DEBUG, "Importing job with priority: %lld", value); - j->jetsam_priority = (typeof(j->jetsam_priority))value; - LIST_INSERT_HEAD(&j->mgr->jetsam_jobs, j, jetsam_sle); - j->mgr->jetsam_jobs_cnt++; + job_log(j, LOG_WARNING | LOG_CONSOLE, "Please change the JetsamPriority key to be in a dictionary named JetsamProperties."); + + launch_data_t pri = launch_data_new_integer(value); + if( job_assumes(j, pri != NULL) ) { + jetsam_property_setup(pri, LAUNCH_JOBKEY_JETSAMPRIORITY, j); + launch_data_free(pri); + } } - break; case 'n': case 'N': if (strcasecmp(key, LAUNCH_JOBKEY_NICE) == 0) { @@ -2051,6 +2072,11 @@ job_import_dictionary(job_t j, const char *key, launch_data_t value) } } break; + case 'j': + case 'J': + if( strcasecmp(key, LAUNCH_JOBKEY_JETSAMPROPERTIES) == 0 ) { + launch_data_dict_iterate(value, (void (*)(launch_data_t, const char *, void *))jetsam_property_setup, j); + } case 'e': case 'E': if (strcasecmp(key, LAUNCH_JOBKEY_ENVIRONMENTVARIABLES) == 0) { @@ -2767,7 +2793,7 @@ job_reap(job_t j) if (j->anonymous) { total_anon_children--; - if( j->migratory ) { + if( j->holds_ref ) { runtime_del_ref(); } } else { @@ -3239,7 +3265,15 @@ job_callback_proc(job_t j, struct kevent *kev) * * Otherwise, we wait for the death of the parent tracer and then reap, just as we * would if a job died while we were sampling it at shutdown. + * + * Note that we foolishly assume that in the process *tree* a node cannot be its + * own parent. Apparently, that is not correct. If this is the case, we forsake + * the process to its own devices. Let it reap itself. */ + if( !job_assumes(j, kp.kp_eproc.e_ppid != (pid_t)kev->ident) ) { + job_log(j, LOG_WARNING, "Job is its own parent and has (somehow) exited. Leaving it to waste away."); + return; + } if( job_assumes(j, kevent_mod(kp.kp_eproc.e_ppid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, j) != -1) ) { j->tracing_pid = kp.kp_eproc.e_ppid; j->reap_after_trace = true; @@ -3447,6 +3481,7 @@ jobmgr_callback(void *obj, struct kevent *kev) case EVFILT_SIGNAL: switch (kev->ident) { case SIGTERM: + jobmgr_log(jm, LOG_DEBUG, "Got SIGTERM. Shutting down."); return launchd_shutdown(); case SIGUSR1: return calendarinterval_callback(); @@ -3489,6 +3524,11 @@ jobmgr_callback(void *obj, struct kevent *kev) jobmgr_still_alive_with_check(jm); } else if( kev->ident == (uintptr_t)&jm->reboot_flags ) { jobmgr_do_garbage_collection(jm); + } else if( kev->ident == (uintptr_t)&g_runtime_busy_time ) { + jobmgr_log(jm, LOG_DEBUG, "Idle exit timer fired. Shutting down."); + if( jobmgr_assumes(jm, runtime_busy_cnt == 0) ) { + return launchd_shutdown(); + } } break; case EVFILT_VNODE: @@ -4181,7 +4221,7 @@ job_setup_attributes(job_t j) } #if !TARGET_OS_EMBEDDED - if( j->jetsam_priority != LAUNCHD_JETSAM_PRIORITY_UNSET ) { + if( j->jetsam_properties ) { job_assumes(j, proc_setpcontrol(PROC_SETPC_TERMINATE) == 0); } #endif @@ -5563,8 +5603,8 @@ jobmgr_do_garbage_collection(jobmgr_t jm) if( phase == JOBMGR_PHASE_HOPEFULLY_EXITS_FIRST && !ji->hopefully_exits_first ) { continue; } else if( phase == JOBMGR_PHASE_NORMAL ) { - if( ji->migratory ) { - /* If we're shutting down, release the hold migratory jobs + if( ji->holds_ref ) { + /* If we're shutting down, release the hold holds_ref jobs * have on us. */ job_remove(ji); @@ -7315,6 +7355,12 @@ job_mig_reboot2(job_t j, uint64_t flags) return 1; } + if( !job_assumes(j, pid_to_log != kp.kp_eproc.e_ppid) ) { + job_log(j, LOG_WARNING, "Job which is its own parent started reboot."); + snprintf(who_started_the_reboot, sizeof(who_started_the_reboot), "%s[%u]->%s[%u]->%s[%u]->...", kp.kp_proc.p_comm, pid_to_log, kp.kp_proc.p_comm, pid_to_log, kp.kp_proc.p_comm, pid_to_log); + break; + } + who_offset = strlen(who_started_the_reboot); snprintf(who_started_the_reboot + who_offset, sizeof(who_started_the_reboot) - who_offset, " %s[%u]%s", kp.kp_proc.p_comm, pid_to_log, kp.kp_eproc.e_ppid ? " ->" : ""); @@ -8140,6 +8186,11 @@ job_mig_move_subset(job_t j, mach_port_t target_subset, name_t session_type, mac j->mgr = jmr; job_set_global_on_demand(j, true); + + if( !j->holds_ref ) { + j->holds_ref = true; + runtime_add_ref(); + } } for (l2l_i = 0; l2l_i < l2l_port_cnt; l2l_i++) { @@ -8308,16 +8359,19 @@ job_mig_switch_to_session(job_t j, mach_port_t requestor_port, name_t session_na } j->mgr = target_jm; - j->migratory = true; - *new_bsport = target_jm->jm_port; - /* Anonymous jobs which move around are particularly interesting to us, so we want to - * stick around while they're still around. - * For example, login calls into the PAM launchd module, which moves the process into - * the StandardIO session by default. So we'll hold a reference on that job to prevent - * ourselves from going away. - */ - runtime_add_ref(); + if( !j->holds_ref ) { + /* Anonymous jobs which move around are particularly interesting to us, so we want to + * stick around while they're still around. + * For example, login calls into the PAM launchd module, which moves the process into + * the StandardIO session by default. So we'll hold a reference on that job to prevent + * ourselves from going away. + */ + j->holds_ref = true; + runtime_add_ref(); + } + + *new_bsport = target_jm->jm_port; return KERN_SUCCESS; } @@ -8497,6 +8551,14 @@ job_mig_subset(job_t j, mach_port_t requestorport, mach_port_t *subsetportp) *subsetportp = jmr->jm_port; jmr->properties |= BOOTSTRAP_PROPERTY_EXPLICITSUBSET; + /* A job could create multiple subsets, so only add a reference the first time + * it does so we don't have to keep a count. + */ + if( j->anonymous && !j->holds_ref ) { + j->holds_ref = true; + runtime_add_ref(); + } + job_log(j, LOG_DEBUG, "Job created a subset named \"%s\"", jmr->name); return BOOTSTRAP_SUCCESS; } @@ -8598,7 +8660,7 @@ job_mig_wait(job_t j, mach_port_t srp, integer_t *waitstatus) job_handle_mpm_wait(NULL, MACH_PORT_NULL, NULL); } struct ldcred *ldc = runtime_get_caller_creds(); - job_t calling_j = job_mig_intran2(j->mgr, MACH_PORT_NULL, ldc->pid); + job_t calling_j = jobmgr_find_by_pid(j->mgr, ldc->pid, true); return job_mig_wait2(calling_j, j, srp, waitstatus, true); #endif @@ -8617,7 +8679,17 @@ job_mig_wait2(job_t j, job_t target_j, mach_port_t srp, integer_t *status, boole return BOOTSTRAP_NO_MEMORY; } - if( target_j->p == 0 ) { + /* See rdar://problem/7084138 for why we do the second part of this check. + * Basically, since Finder, Dock and SystemUIServer are now real launchd + * jobs, they don't get removed after exiting, like legacy LaunchServices + * jobs do. So there's a race. coreservicesd came in asking for the exit + * status after we'd relaunched Finder, so Finder's PID isn't 0. + * + * So we check to make sure the target job isn't a LaunchServices job and + * that the request is coming through the legacy path (mpm_wait()). If so, + * we return the last exit status, regardless of the current PID value. + */ + if( target_j->p == 0 || (!target_j->legacy_LS_job && legacy) ) { *status = target_j->last_exit_status; return BOOTSTRAP_SUCCESS; } @@ -8913,26 +8985,33 @@ simulate_pid1_crash(void) } } -static void -jetsam_priority_from_job(job_t j, bool front, jetsam_priority_entry_t *jp) -{ - jp->pid = j->p; - jp->flags |= front ? kJetsamFlagsFrontmost : 0; -} - -static int -job_cmp(const job_t *lhs, const job_t *rhs) -{ - job_t _lhs = *lhs; - job_t _rhs = *rhs; - /* Sort in descending order. (Priority correlates to the soonishness with which you will be killed.) */ - if( _lhs->jetsam_priority > _rhs->jetsam_priority ) { - return -1; - } else if( _lhs->jetsam_priority < _rhs->jetsam_priority ) { - return 1; +void +jetsam_property_setup(launch_data_t obj, const char *key, job_t j) +{ + job_log(j, LOG_DEBUG, "Setting Jetsam properties for job..."); + if( strcasecmp(key, LAUNCH_JOBKEY_JETSAMPRIORITY) == 0 && launch_data_get_type(obj) == LAUNCH_DATA_INTEGER ) { + j->jetsam_priority = (typeof(j->jetsam_priority))launch_data_get_integer(obj); + job_log(j, LOG_DEBUG, "Priority: %d", j->jetsam_priority); + } else if( strcasecmp(key, LAUNCH_JOBKEY_JETSAMMEMORYLIMIT) == 0 && launch_data_get_type(obj) == LAUNCH_DATA_INTEGER ) { + j->jetsam_memlimit = (typeof(j->jetsam_memlimit))launch_data_get_integer(obj); + job_log(j, LOG_DEBUG, "Memory limit: %d", j->jetsam_memlimit); + } else if( strcasecmp(key, LAUNCH_KEY_JETSAMFRONTMOST) == 0 ) { + /* Ignore. We only recognize this key so we don't complain when we get SpringBoard's request. + * You can't set this in a plist. + */ + } else if( strcasecmp(key, LAUNCH_KEY_JETSAMLABEL) == 0 ) { + /* Ignore. This key is present in SpringBoard's request dictionary, so we don't want to + * complain about it. + */ + } else { + job_log(j, LOG_ERR, "Unknown Jetsam key: %s", key); } - return 0; + if( unlikely(!j->jetsam_properties) ) { + j->jetsam_properties = true; + LIST_INSERT_HEAD(&j->mgr->jetsam_jobs, j, jetsam_sle); + j->mgr->jetsam_jobs_cnt++; + } } int @@ -8941,7 +9020,7 @@ launchd_set_jetsam_priorities(launch_data_t priorities) if( !launchd_assumes(launch_data_get_type(priorities) == LAUNCH_DATA_ARRAY) ) { return EINVAL; } - + jobmgr_t jm = NULL; #if !TARGET_OS_EMBEDDED /* For testing. */ @@ -8978,58 +9057,66 @@ launchd_set_jetsam_priorities(launch_data_t priorities) if( !launchd_assumes(ji != NULL) ) { continue; } - - launch_data_t pri; - long long _pri = 0; - if( !launchd_assumes(pri = launch_data_dict_lookup(ldi, LAUNCH_KEY_JETSAMPRIORITY)) ) { - continue; - } - _pri = launch_data_get_integer(pri); - - if( ji->jetsam_priority == LAUNCHD_JETSAM_PRIORITY_UNSET ) { - LIST_INSERT_HEAD(&ji->mgr->jetsam_jobs, ji, jetsam_sle); - ji->mgr->jetsam_jobs_cnt++; - } - ji->jetsam_priority = _pri; - + + launch_data_dict_iterate(ldi, (void (*)(launch_data_t, const char *, void *))jetsam_property_setup, ji); + launch_data_t frontmost = NULL; - if( !(frontmost = launch_data_dict_lookup(ldi, LAUNCH_KEY_JETSAMFRONTMOST)) ) { - ji->jetsam_frontmost = false; - continue; + if( (frontmost = launch_data_dict_lookup(ldi, LAUNCH_KEY_JETSAMFRONTMOST)) && launch_data_get_type(frontmost) == LAUNCH_DATA_BOOL ) { + ji->jetsam_frontmost = launch_data_get_bool(frontmost); } - ji->jetsam_frontmost = launch_data_get_bool(frontmost); } i = 0; job_t *jobs = (job_t *)calloc(jm->jetsam_jobs_cnt, sizeof(job_t)); - LIST_FOREACH( ji, &jm->jetsam_jobs, jetsam_sle ) { - if( ji->p ) { - jobs[i] = ji; - i++; + if( launchd_assumes(jobs != NULL) ) { + LIST_FOREACH( ji, &jm->jetsam_jobs, jetsam_sle ) { + if( ji->p ) { + jobs[i] = ji; + i++; + } } } + size_t totalpris = i; int result = EINVAL; - if( launchd_assumes(totalpris > 0) ) { - qsort((void *)jobs, totalpris, sizeof(job_t), (int (*)(const void *, const void *))job_cmp); + + /* It is conceivable that there could be no Jetsam jobs running. */ + if( totalpris > 0 ) { + /* Yay blocks! */ + qsort_b((void *)jobs, totalpris, sizeof(job_t), ^ int (const void *lhs, const void *rhs) { + job_t _lhs = *(job_t *)lhs; + job_t _rhs = *(job_t *)rhs; + /* Sort in descending order. (Priority correlates to the soonishness with which you will be killed.) */ + if( _lhs->jetsam_priority > _rhs->jetsam_priority ) { + return -1; + } else if( _lhs->jetsam_priority < _rhs->jetsam_priority ) { + return 1; + } + + return 0; + }); jetsam_priority_entry_t *jpris = (jetsam_priority_entry_t *)calloc(totalpris, sizeof(jetsam_priority_entry_t)); if( !launchd_assumes(jpris != NULL) ) { result = ENOMEM; } else { for( i = 0; i < totalpris; i++ ) { - jetsam_priority_from_job(jobs[i], jobs[i]->jetsam_frontmost, &jpris[i]); + jpris[i].pid = jobs[i]->p; /* Subject to time-of-use vs. time-of-check, obviously. */ + jpris[i].flags |= jobs[i]->jetsam_frontmost ? kJetsamFlagsFrontmost : 0; + jpris[i].hiwat_pages = jobs[i]->jetsam_memlimit; } - int _result = 0; - launchd_assumes((_result = sysctlbyname("kern.memorystatus_priority_list", NULL, NULL, &jpris[0], totalpris * sizeof(jetsam_priority_entry_t))) != -1); - result = _result != 0 ? errno : 0; + launchd_assumes((result = sysctlbyname("kern.memorystatus_priority_list", NULL, NULL, &jpris[0], totalpris * sizeof(jetsam_priority_entry_t))) != -1); + result = result != 0 ? errno : 0; free(jpris); } } - free(jobs); + + if( jobs ) { + free(jobs); + } return result; } diff --git a/launchd/src/launchd_runtime.c b/launchd/src/launchd_runtime.c index 6eb8d40..60d6db0 100644 --- a/launchd/src/launchd_runtime.c +++ b/launchd/src/launchd_runtime.c @@ -18,7 +18,7 @@ * @APPLE_APACHE_LICENSE_HEADER_END@ */ -static const char *const __rcs_file_version__ = "$Revision: 23929 $"; +static const char *const __rcs_file_version__ = "$Revision: 24003 $"; #include "config.h" #include "launchd_runtime.h" @@ -100,10 +100,8 @@ static size_t mig_cb_table_sz; static timeout_callback runtime_idle_callback; static mach_msg_timeout_t runtime_idle_timeout; static struct ldcred ldc; -static size_t runtime_busy_cnt; static size_t runtime_standby_cnt; - static STAILQ_HEAD(, logmsg_s) logmsg_queue = STAILQ_HEAD_INITIALIZER(logmsg_queue); static size_t logmsg_queue_sz; static size_t logmsg_queue_cnt; @@ -141,6 +139,7 @@ bool g_log_pid1_shutdown = false; #endif bool g_log_strict_usage = false; pid_t g_wsp = 0; +size_t runtime_busy_cnt; mach_port_t runtime_get_kernel_port(void) @@ -538,11 +537,11 @@ mportset_callback(void) #if 0 if (launchd_assumes(kev.udata != NULL)) { #endif - log_kevent_struct(LOG_DEBUG, &kev, i); + log_kevent_struct(LOG_DEBUG, &kev, 0); (*((kq_callback *)kev.udata))(kev.udata, &kev); #if 0 } else { - log_kevent_struct(LOG_ERR, &kev, i); + log_kevent_struct(LOG_ERR, &kev, 0); } #endif /* the callback may have tainted our ability to continue this for loop */ @@ -590,7 +589,7 @@ x_handle_kqueue(mach_port_t junk __attribute__((unused)), integer_t fd) if (launchd_assumes((bulk_kev_cnt = kevent(fd, NULL, 0, kev, BULK_KEV_MAX, &ts)) != -1)) { #if 0 for (i = 0; i < bulk_kev_cnt; i++) { - log_kevent_struct(LOG_DEBUG, kev, i); + log_kevent_struct(LOG_DEBUG, &kev[0], i); } #endif for (i = 0; i < bulk_kev_cnt; i++) { @@ -611,7 +610,7 @@ x_handle_kqueue(mach_port_t junk __attribute__((unused)), integer_t fd) runtime_ktrace0(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_END); } else { runtime_syslog(LOG_ERR, "The following kevent had invalid context data."); - log_kevent_struct(LOG_EMERG, kevi, i); + log_kevent_struct(LOG_EMERG, &kev[0], i); } #else runtime_ktrace(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_START, kevi->ident, kevi->filter, kevi->fflags); @@ -863,7 +862,7 @@ kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t for( i = bulk_kev_i + 1; i < bulk_kev_cnt; i++ ) { if( bulk_kev[i].filter == filter && bulk_kev[i].ident == ident ) { runtime_syslog(LOG_DEBUG, "Pruning the following kevent:"); - log_kevent_struct(LOG_DEBUG, &bulk_kev[i], i); + log_kevent_struct(LOG_DEBUG, &bulk_kev[0], i); bulk_kev[i].filter = (short)0; } } @@ -1579,7 +1578,9 @@ runtime_add_ref(void) _vproc_transaction_begin(); #endif } + runtime_busy_cnt++; + runtime_remove_timer(); } void @@ -1595,7 +1596,9 @@ runtime_del_ref(void) _vproc_transaction_end(); #endif } + runtime_busy_cnt--; + runtime_install_timer(); } void @@ -1620,6 +1623,22 @@ runtime_del_weak_ref(void) runtime_standby_cnt--; } +void +runtime_install_timer(void) +{ + if( !pid1_magic && runtime_busy_cnt == 0 ) { + launchd_assumes(kevent_mod((uintptr_t)&g_runtime_busy_time, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, 30, root_jobmgr) != -1); + } +} + +void +runtime_remove_timer(void) +{ + if( !pid1_magic && runtime_busy_cnt > 0 ) { + launchd_assumes(kevent_mod((uintptr_t)&g_runtime_busy_time, EVFILT_TIMER, EV_DELETE, 0, 0, NULL) != -1); + } +} + kern_return_t catch_mach_exception_raise(mach_port_t exception_port __attribute__((unused)), mach_port_t thread, mach_port_t task, exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt) diff --git a/launchd/src/launchd_runtime.h b/launchd/src/launchd_runtime.h index 228e64c..416efde 100644 --- a/launchd/src/launchd_runtime.h +++ b/launchd/src/launchd_runtime.h @@ -108,6 +108,8 @@ extern bool g_use_gmalloc; extern bool g_log_per_user_shutdown; extern bool g_log_strict_usage; extern bool g_embedded_shutdown_log; +extern bool g_runtime_busy_time; +extern size_t runtime_busy_cnt; extern int32_t g_sync_frequency; extern pid_t g_wsp; @@ -118,6 +120,8 @@ void runtime_add_ref(void); void runtime_del_ref(void); void runtime_add_weak_ref(void); void runtime_del_weak_ref(void); +void runtime_install_timer(void); +void runtime_remove_timer(void); void launchd_runtime_init(void); void launchd_runtime_init2(void); -- 2.47.2