[launchd-changes] [23776] trunk/launchd/src

source_changes at macosforge.org source_changes at macosforge.org
Fri Jan 9 16:40:56 PST 2009


Revision: 23776
          http://trac.macosforge.org/projects/launchd/changeset/23776
Author:   dsorresso at apple.com
Date:     2009-01-09 16:40:56 -0800 (Fri, 09 Jan 2009)
Log Message:
-----------
<rdar://problem/6046664> TASK: flatten per-user bootstrap namespaces
<rdar://problem/6241360> Instruments requires SPI for setting environment variables of launchd daemons
Embedded changes.

Modified Paths:
--------------
    trunk/launchd/src/launch_priv.h
    trunk/launchd/src/launchctl.c
    trunk/launchd/src/launchd.c
    trunk/launchd/src/launchd_core_logic.c
    trunk/launchd/src/launchd_core_logic.h
    trunk/launchd/src/launchd_runtime.c
    trunk/launchd/src/launchd_unix_ipc.c
    trunk/launchd/src/libvproc.c
    trunk/launchd/src/protocol_vproc.defs
    trunk/launchd/src/vproc.h
    trunk/launchd/src/vproc_priv.h

Modified: trunk/launchd/src/launch_priv.h
===================================================================
--- trunk/launchd/src/launch_priv.h	2009-01-08 23:44:10 UTC (rev 23775)
+++ trunk/launchd/src/launch_priv.h	2009-01-10 00:40:56 UTC (rev 23776)
@@ -38,7 +38,8 @@
 #define LAUNCH_KEY_SETRESOURCELIMITS					"SetResourceLimits"
 #define LAUNCH_KEY_GETRUSAGESELF						"GetResourceUsageSelf"
 #define LAUNCH_KEY_GETRUSAGECHILDREN					"GetResourceUsageChildren"
-                                                    
+#define LAUNCH_KEY_SETPRIORITYLIST						"SetPriorityList"
+
 #define LAUNCHD_SOCKET_ENV								"LAUNCHD_SOCKET"
 #define LAUNCHD_SOCK_PREFIX								_PATH_VARTMP "launchd"
 #define LAUNCHD_TRUSTED_FD_ENV							"__LAUNCHD_FD"
@@ -46,12 +47,17 @@
 #define LAUNCH_KEY_BATCHCONTROL							"BatchControl"
 #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_JETSAMPRIORITY					"JetsamPriority"
 
 #define LAUNCH_JOBKEY_ENTERKERNELDEBUGGERBEFOREKILL		"EnterKernelDebuggerBeforeKill"
 #define LAUNCH_JOBKEY_PERJOBMACHSERVICES				"PerJobMachServices"

Modified: trunk/launchd/src/launchctl.c
===================================================================
--- trunk/launchd/src/launchctl.c	2009-01-08 23:44:10 UTC (rev 23775)
+++ trunk/launchd/src/launchctl.c	2009-01-10 00:40:56 UTC (rev 23776)
@@ -181,6 +181,7 @@
 static int setenv_cmd(int argc, char *const argv[]);
 static int unsetenv_cmd(int argc, char *const argv[]);
 static int getenv_and_export_cmd(int argc, char *const argv[]);
+static int wait4debugger_cmd(int argc, char *const argv[]);
 
 static int limit_cmd(int argc, char *const argv[]);
 static int stdio_cmd(int argc, char *const argv[]);
@@ -216,6 +217,7 @@
 	{ "unsetenv",	unsetenv_cmd,			"Unset an environmental variable in launchd" },
 	{ "getenv",		getenv_and_export_cmd,	"Get an environmental variable from launchd" },
 	{ "export",		getenv_and_export_cmd,	"Export shell settings from launchd" },
+	{ "debug",		wait4debugger_cmd,		"Set the WaitForDebugger flag for the target job to true." },
 	{ "limit",		limit_cmd,				"View and adjust launchd resource limits" },
 	{ "stdout",		stdio_cmd,				"Redirect launchd's standard out to the given path" },
 	{ "stderr",		stdio_cmd,				"Redirect launchd's standard error to the given path" },
@@ -527,6 +529,37 @@
 	return 0;
 }
 
+int
+wait4debugger_cmd(int argc, char * const argv[])
+{
+	if( argc != 3 ) {
+		fprintf(stderr, "%s usage: debug <label> <value>\n", argv[0]);
+		return 1;
+	}
+	
+	int result = 1;
+	int64_t inval = 0;
+	if( strncmp(argv[2], "true", sizeof("true")) == 0 ) {
+		inval = 1;
+	} else if( strncmp(argv[2], "false", sizeof("false")) != 0 ) {
+		inval = atoi(argv[2]);
+		inval &= 1;
+	}
+	
+	vproc_t vp = vprocmgr_lookup_vproc(argv[1]);
+	if( vp ) {
+		vproc_err_t verr = vproc_swap_integer(vp, VPROC_GSK_WAITFORDEBUGGER, &inval, NULL);
+		if( verr ) {
+			fprintf(stderr, "Failed to set WaitForDebugger flag on %s.\n", argv[1]);
+		} else {
+			result = 0;
+		}
+		vproc_release(vp);
+	}
+	
+	return result;
+}
+
 void
 unloadjob(launch_data_t job)
 {

Modified: trunk/launchd/src/launchd.c
===================================================================
--- trunk/launchd/src/launchd.c	2009-01-08 23:44:10 UTC (rev 23775)
+++ trunk/launchd/src/launchd.c	2009-01-10 00:40:56 UTC (rev 23776)
@@ -193,6 +193,8 @@
 		if( stat("/var/db/.launchd_flat_per_user_namespace", &sb) == 0 ) {
 			runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "Flat per-user Mach namespaces enabled.");
 		}
+		/* We just wanted to print status about the per-user namespace. PID 1 doesn't have a flat namespace. */
+		g_flat_mach_namespace = false;
 	}
 
 	monitor_networking_state();

Modified: trunk/launchd/src/launchd_core_logic.c
===================================================================
--- trunk/launchd/src/launchd_core_logic.c	2009-01-08 23:44:10 UTC (rev 23775)
+++ trunk/launchd/src/launchd_core_logic.c	2009-01-10 00:40:56 UTC (rev 23776)
@@ -82,7 +82,21 @@
 #if HAVE_QUARANTINE
 #include <quarantine.h>
 #endif
+#if TARGET_OS_EMBEDDED
+#include <sys/kern_memorystatus.h>
+#else
+/* To make my life easier. */
+typedef struct jetsam_priority_entry {
+    pid_t pid;
+    uint32_t flags;
+} jetsam_priority_entry_t;
 
+enum {
+    kJetsamFlagsFrontmost = (1 << 0),
+    kJetsamFlagsKilled =    (1 << 1)
+};
+#endif
+
 #include "launch.h"
 #include "launch_priv.h"
 #include "launch_internal.h"
@@ -110,10 +124,11 @@
  *   If the job hasn't exited in the given number of seconds after sending
  *   it a SIGTERM, SIGKILL it. Can be overriden in the job plist.
  */
-#define LAUNCHD_MIN_JOB_RUN_TIME 10
-#define LAUNCHD_SAMPLE_TIMEOUT 1
-#define LAUNCHD_DEFAULT_EXIT_TIMEOUT 20
-#define LAUNCHD_SIGKILL_TIMER 5
+#define LAUNCHD_MIN_JOB_RUN_TIME		10
+#define LAUNCHD_SAMPLE_TIMEOUT			1
+#define LAUNCHD_DEFAULT_EXIT_TIMEOUT	20
+#define LAUNCHD_SIGKILL_TIMER			5
+#define LAUNCHD_JETSAM_PRIORITY_UNSET	0xdead1eebabell
 
 #define SHUTDOWN_LOG_DIR "/var/log/shutdown"
 
@@ -230,6 +245,7 @@
 
 struct envitem {
 	SLIST_ENTRY(envitem) sle;
+	bool one_shot;
 	char *value;
 	union {
 		const char key[0];
@@ -237,9 +253,10 @@
 	};
 };
 
-static bool envitem_new(job_t j, const char *k, const char *v, bool global);
+static bool envitem_new(job_t j, const char *k, const char *v, bool global, bool one_shot);
 static void envitem_delete(job_t j, struct envitem *ei, bool global);
 static void envitem_setup(launch_data_t obj, const char *key, void *context);
+static void envitem_setup_one_shot(launch_data_t obj, const char *key, void *context);
 
 struct limititem {
 	SLIST_ENTRY(limititem) sle;
@@ -306,6 +323,7 @@
 	SLIST_ENTRY(jobmgr_s) sle;
 	SLIST_HEAD(, jobmgr_s) submgrs;
 	LIST_HEAD(, job_s) jobs;
+	LIST_HEAD(, job_s) jetsam_jobs;
 	LIST_HEAD(, job_s) active_jobs[ACTIVE_JOB_HASH_SIZE];
 	LIST_HEAD(, machservice) ms_hash[MACHSERVICE_HASH_SIZE];
 	LIST_HEAD(, job_s) global_env_jobs;
@@ -317,6 +335,7 @@
 	unsigned int global_on_demand_cnt;
 	unsigned int hopefully_first_cnt;
 	unsigned int normal_active_cnt;
+	unsigned int jetsam_jobs_cnt;
 	unsigned int 	sent_stop_to_normal_jobs		:1, 
 					sent_stop_to_hopefully_last_jobs:1, 
 					shutting_down					:1, 
@@ -364,8 +383,9 @@
 #define AUTO_PICK_LEGACY_LABEL (const char *)(~0)
 
 struct job_s {
-	kq_callback kqjob_callback; /* MUST be first element of this structure for benefit of launchd's run loop. */
-	LIST_ENTRY(job_s) sle;
+	kq_callback kqjob_callback;	/* MUST be first element of this structure for benefit of launchd's run loop. */
+	LIST_ENTRY(job_s) sle;								
+	LIST_ENTRY(job_s) jetsam_sle;
 	LIST_ENTRY(job_s) pid_hash_sle;
 	LIST_ENTRY(job_s) label_hash_sle;
 	LIST_ENTRY(job_s) global_env_sle;
@@ -384,7 +404,7 @@
 	cpu_type_t *j_binpref;
 	size_t j_binpref_cnt;
 	mach_port_t j_port;
-	mach_port_t wait_reply_port;	/* we probably should switch to a list of waiters */
+	mach_port_t wait_reply_port; /* we probably should switch to a list of waiters */
 	uid_t mach_uid;
 	jobmgr_t mgr;
 	size_t argc;
@@ -416,6 +436,7 @@
 	int log_redirect_fd;
 	int nice;
 	int stdout_err_fd;
+	long long jetsam_priority;
 	uint32_t timeout;
 	uint32_t exit_timeout;
 	uint64_t sent_signal_time;
@@ -449,6 +470,7 @@
 		    start_pending				:1,	/* an event fired and the job should start, but not necessarily right away */
 		    globargv					:1,	/* man launchd.plist --> EnableGlobbing */
 		    wait4debugger				:1,	/* man launchd.plist --> WaitForDebugger */
+			wait4debugger_oneshot		:1, /* One-shot WaitForDebugger. */
 		    internal_exc_handler		:1,	/* MachExceptionHandler == true */
 		    stall_before_exec			:1,	/* a hack to support an option of spawn_via_launchd() */
 		    only_once 					:1,	/* man launchd.plist --> LaunchOnlyOnce. Note: 5465184 Rename this to "HopefullyNeverExits" */
@@ -476,7 +498,8 @@
 			reap_after_sample			:1,	/* The job exited before sample did, so we should reap it after sample is done. */
 			nosy						:1, /* The job has an OtherJobEnabled KeepAlive criterion. */
 			crashed						:1, /* The job is the default Mach exception handler, and it crashed. */
-			reaped						:1; /* We've received NOTE_EXIT for the job. */
+			reaped						:1, /* We've received NOTE_EXIT for the job. */
+			jetsam_frontmost			:1; /* The job is considered "frontmost" by Jetsam. */
 	mode_t mask;
 	pid_t sample_pid;
 	const char label[0];
@@ -571,6 +594,11 @@
 static void do_unmounts(void);
 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;
@@ -1175,9 +1203,15 @@
 		/* 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 ) {
+		LIST_REMOVE(j, jetsam_sle);
+		j->mgr->jetsam_jobs_cnt--;
+	}
+	
 	kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
-
+	kevent_mod((uintptr_t)j, EVFILT_PROC, EV_DELETE, 0, 0, NULL);
+	
 	LIST_REMOVE(j, sle);
 	LIST_REMOVE(j, label_hash_sle);
 
@@ -1497,7 +1531,8 @@
 	j->currently_ignored = true;
 	j->ondemand = true;
 	j->checkedin = true;
-
+	j->jetsam_priority = LAUNCHD_JETSAM_PRIORITY_UNSET;
+	
 	if (prog) {
 		j->prog = strdup(prog);
 		if (!job_assumes(j, j->prog != NULL)) {
@@ -1836,6 +1871,15 @@
 			}
 		}
 		break;
+	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++;
+		}
+		break;
 	case 'n':
 	case 'N':
 		if (strcasecmp(key, LAUNCH_JOBKEY_NICE) == 0) {
@@ -2345,7 +2389,6 @@
 	struct ldcred *ldc = runtime_get_caller_creds();
 	job_t jr;
 
-
 	jr = job_mig_intran2(root_jobmgr, p, ldc->pid);
 
 	if (!jobmgr_assumes(root_jobmgr, jr != NULL)) {
@@ -2487,6 +2530,8 @@
 		job_mig_swap_integer(j, VPROC_GSK_WEIRD_BOOTSTRAP, 0, 0, &junk);
 	}
 
+	j->wait4debugger_oneshot = false;
+
 	if (j->log_redirect_fd && !j->legacy_LS_job) {
 		job_log_stdouterr(j); /* one last chance */
 
@@ -2633,6 +2678,13 @@
 		}
 	}
 	
+	struct envitem *ei = NULL, *et = NULL;
+	SLIST_FOREACH_SAFE( ei, &j->env, sle, et ) {
+		if( ei->one_shot ) {
+			SLIST_REMOVE(&j->env, ei, envitem, sle);
+		}
+	}
+	
 	if (j->hopefully_exits_first) {
 		j->mgr->hopefully_first_cnt--;
 	} else if (!j->anonymous && !j->hopefully_exits_last) {
@@ -3487,7 +3539,7 @@
 		argv++;
 	}
 
-	if (unlikely(j->wait4debugger)) {
+	if (unlikely(j->wait4debugger || j->wait4debugger_oneshot)) {
 		job_log(j, LOG_WARNING, "Spawned and waiting for the debugger to attach before continuing...");
 		spflags |= POSIX_SPAWN_START_SUSPENDED;
 	}
@@ -4624,7 +4676,7 @@
 }
 
 bool
-envitem_new(job_t j, const char *k, const char *v, bool global)
+envitem_new(job_t j, const char *k, const char *v, bool global, bool one_shot)
 {
 	struct envitem *ei = calloc(1, sizeof(struct envitem) + strlen(k) + 1 + strlen(v) + 1);
 
@@ -4635,6 +4687,7 @@
 	strcpy(ei->key_init, k);
 	ei->value = ei->key_init + strlen(k) + 1;
 	strcpy(ei->value, v);
+	ei->one_shot = one_shot;
 
 	if (global) {
 		if (SLIST_EMPTY(&j->global_env)) {
@@ -4675,12 +4728,28 @@
 	}
 
 	if( strncmp(LAUNCHD_TRUSTED_FD_ENV, key, sizeof(LAUNCHD_TRUSTED_FD_ENV) - 1) != 0 ) {
-		envitem_new(j, key, launch_data_get_string(obj), j->importing_global_env);
+		envitem_new(j, key, launch_data_get_string(obj), j->importing_global_env, false);
 	} else {
 		job_log(j, LOG_WARNING, "Ignoring reserved environmental variable: %s", key);
 	}
 }
 
+void
+envitem_setup_one_shot(launch_data_t obj, const char *key, void *context)
+{
+	job_t j = context;
+	
+	if (launch_data_get_type(obj) != LAUNCH_DATA_STRING) {
+		return;
+	}
+	
+	if( strncmp(LAUNCHD_TRUSTED_FD_ENV, key, sizeof(LAUNCHD_TRUSTED_FD_ENV) - 1) != 0 ) {
+		envitem_new(j, key, launch_data_get_string(obj), j->importing_global_env, true);
+	} else {
+		job_log(j, LOG_WARNING, "Ignoring reserved environmental variable: %s", key);
+	}	
+}
+
 bool
 limititem_update(job_t j, int w, rlim_t r)
 {
@@ -5544,7 +5613,7 @@
 
 		/* <rdar://problem/5042202> launchd-201: can't ssh in with AFP OD account (hangs) */
 		snprintf(buf, sizeof(buf), "0x%X:0:0", getuid());
-		envitem_new(bootstrapper, "__CF_USER_TEXT_ENCODING", buf, false);
+		envitem_new(bootstrapper, "__CF_USER_TEXT_ENCODING", buf, false, false);
 		bootstrapper->weird_bootstrap = true;
 		jobmgr_assumes(jm, job_setup_machport(bootstrapper));
 	} else if( bootstrapper && strncmp(session_type, VPROCMGR_SESSION_SYSTEM, sizeof(VPROCMGR_SESSION_SYSTEM)) == 0 ) {
@@ -6423,7 +6492,7 @@
 		vm_offset_t *outval, mach_msg_type_number_t *outvalCnt) 
 {
 	const char *action;
-	launch_data_t input_obj, output_obj;
+	launch_data_t input_obj = NULL, output_obj = NULL;
 	size_t data_offset = 0;
 	size_t packed_size;
 	struct ldcred *ldc = runtime_get_caller_creds();
@@ -6495,8 +6564,13 @@
 	}
 
 	if (invalCnt) switch (inkey) {
-	case VPROC_GSK_ENVIRONMENT:
-		
+	case VPROC_GSK_ENVIRONMENT:	
+		if( launch_data_get_type(input_obj) == LAUNCH_DATA_DICTIONARY ) {
+			if( j->p ) {
+				job_log(j, LOG_NOTICE, "Setting environment for a currently active job. This environment will take effect on the next invocation of the job.");
+			}
+			launch_data_dict_iterate(input_obj, envitem_setup_one_shot, j);
+		}
 		break;
 	case 0:
 		break;
@@ -6587,6 +6661,9 @@
 		job_log(j, LOG_DEBUG, "Reading transaction model status.");
 		*outval = j->kill_via_shmem;
 		break;
+	case VPROC_GSK_WAITFORDEBUGGER:
+		*outval = j->wait4debugger;
+		break;
 	case 0:
 		*outval = 0;
 		break;
@@ -6660,6 +6737,7 @@
 			j->kill_via_shmem = (bool)inval;
 			job_log(j, LOG_DEBUG, "j->kill_via_shmem = %s", j->kill_via_shmem ? "true" : "false");
 		}
+		break;
 	case VPROC_GSK_WEIRD_BOOTSTRAP:
 		if( job_assumes(j, j->weird_bootstrap) ) {
 			job_log(j, LOG_DEBUG, "Unsetting weird bootstrap.");
@@ -6673,6 +6751,10 @@
 			job_assumes(j, runtime_add_mport(j->mgr->jm_port, protocol_vproc_server, mxmsgsz) == KERN_SUCCESS);
 			j->weird_bootstrap = false;
 		}
+		break;
+	case VPROC_GSK_WAITFORDEBUGGER:
+		j->wait4debugger_oneshot = inval;
+		break;
 	case 0:
 		break;
 	default:
@@ -7349,6 +7431,31 @@
 	return BOOTSTRAP_SUCCESS;
 }
 
+kern_return_t
+job_mig_port_for_label(job_t j __attribute__((unused)), name_t label, mach_port_t *mp)
+{
+	struct ldcred *ldc = runtime_get_caller_creds();
+	kern_return_t kr = BOOTSTRAP_NOT_PRIVILEGED;
+	
+	mach_port_t _mp = MACH_PORT_NULL;
+	if( ldc->euid == 0 || ldc->euid == geteuid() ) {
+		job_t target_j = job_find(label);
+		if( jobmgr_assumes(root_jobmgr, target_j != NULL) ) {
+			if( target_j->j_port == MACH_PORT_NULL ) {
+				job_assumes(target_j, job_setup_machport(target_j) == true);
+			}
+			
+			_mp = target_j->j_port;
+			kr = _mp != MACH_PORT_NULL ? BOOTSTRAP_SUCCESS : BOOTSTRAP_NO_MEMORY;
+		} else {
+			kr = BOOTSTRAP_NO_MEMORY;
+		}
+	}
+
+	*mp = _mp;
+	return kr;
+}
+
 jobmgr_t 
 jobmgr_find_by_name(jobmgr_t jm, const char *where)
 {
@@ -8189,3 +8296,120 @@
 		}
 	}
 }
+
+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;
+	}
+	
+	return 0;
+}
+
+int
+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. */
+	jm = jobmgr_find_by_name(root_jobmgr, VPROCMGR_SESSION_AQUA);
+	if( !launchd_assumes(jm != NULL) ) {
+		return EINVAL;
+	}
+#else
+	/* Since this is for embedded, we can assume that the root job manager holds the Jetsam jobs. */
+	jm = root_jobmgr;
+#endif
+		
+	size_t npris = launch_data_array_get_count(priorities);
+
+	job_t ji = NULL;
+	size_t i = 0;
+	for( i = 0; i < npris; i++ ) {
+		launch_data_t ldi = launch_data_array_get_index(priorities, i);
+		if( !launchd_assumes(launch_data_get_type(ldi) == LAUNCH_DATA_DICTIONARY) ) {
+			continue;
+		}
+		
+		launch_data_t label = NULL;
+		if( !launchd_assumes(label = launch_data_dict_lookup(ldi, LAUNCH_KEY_JETSAMLABEL)) ) {
+			continue;
+		}
+		const char *_label = launch_data_get_string(label);
+		
+		ji = job_find(_label);
+		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_t frontmost = NULL;
+		if( !(frontmost = launch_data_dict_lookup(ldi, LAUNCH_KEY_JETSAMFRONTMOST)) ) {
+			ji->jetsam_frontmost = false;
+			continue;
+		}
+		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++;
+		}
+	}
+	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);
+		
+		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]);
+			}
+			
+			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;
+			
+			free(jpris);
+		}
+	}
+	free(jobs);
+	
+	return result;
+}

Modified: trunk/launchd/src/launchd_core_logic.h
===================================================================
--- trunk/launchd/src/launchd_core_logic.h	2009-01-08 23:44:10 UTC (rev 23775)
+++ trunk/launchd/src/launchd_core_logic.h	2009-01-10 00:40:56 UTC (rev 23776)
@@ -56,4 +56,6 @@
 void job_log(job_t j, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4)));
 void job_set_pid_crashed(pid_t p);
 
+int launchd_set_jetsam_priorities(launch_data_t priorities);
+
 #endif

Modified: trunk/launchd/src/launchd_runtime.c
===================================================================
--- trunk/launchd/src/launchd_runtime.c	2009-01-08 23:44:10 UTC (rev 23775)
+++ trunk/launchd/src/launchd_runtime.c	2009-01-10 00:40:56 UTC (rev 23776)
@@ -131,7 +131,7 @@
 bool do_apple_internal_logging;
 bool low_level_debug;
 bool g_force_old_kill_path = false;
-bool g_flat_mach_namespace = false;
+bool g_flat_mach_namespace = true;
 
 mach_port_t
 runtime_get_kernel_port(void)
@@ -1743,7 +1743,7 @@
 		g_force_old_kill_path = true;
 	}
 	
-	if( !pid1_magic && stat("/var/db/.launchd_flat_per_user_namespace", &sb) == 0 ) {
-		g_flat_mach_namespace = true;
+	if( !pid1_magic && stat("/var/db/.launchd_no_flat_per_user_namespace", &sb) == 0 ) {
+		g_flat_mach_namespace = false;
 	}
 }

Modified: trunk/launchd/src/launchd_unix_ipc.c
===================================================================
--- trunk/launchd/src/launchd_unix_ipc.c	2009-01-08 23:44:10 UTC (rev 23775)
+++ trunk/launchd/src/launchd_unix_ipc.c	2009-01-10 00:40:56 UTC (rev 23776)
@@ -415,6 +415,8 @@
 			resp = job_export(j);
 			ipc_revoke_fds(resp);
 		}
+	} else if( !strcmp(cmd, LAUNCH_KEY_SETPRIORITYLIST) ) {
+		resp = launch_data_new_errno(launchd_set_jetsam_priorities(data));
 	}
 
 	rmc->resp = resp;

Modified: trunk/launchd/src/libvproc.c
===================================================================
--- trunk/launchd/src/libvproc.c	2009-01-08 23:44:10 UTC (rev 23775)
+++ trunk/launchd/src/libvproc.c	2009-01-10 00:40:56 UTC (rev 23776)
@@ -34,6 +34,8 @@
 #include <pthread.h>
 #include <signal.h>
 #include <assert.h>
+#include <libkern/OSAtomic.h>
+
 #if HAVE_QUARANTINE
 #include <quarantine.h>
 #endif
@@ -59,6 +61,55 @@
 static pthread_once_t shmem_inited = PTHREAD_ONCE_INIT;
 static uint64_t s_cached_transactions_enabled = 0;
 
+struct vproc_s {
+	int32_t refcount;
+	mach_port_t j_port;
+};
+
+vproc_t vprocmgr_lookup_vproc(const char *label)
+{
+	struct vproc_s *vp = NULL;
+	
+	mach_port_t mp = MACH_PORT_NULL;
+	kern_return_t kr = vproc_mig_port_for_label(bootstrap_port, (char *)label, &mp);
+	if( kr == BOOTSTRAP_SUCCESS ) {
+		vp = (struct vproc_s *)calloc(1, sizeof(struct vproc_s));
+		if( vp ) {
+			vp->refcount = 1;
+			mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_SEND, 1);
+			vp->j_port = mp;
+		}
+		mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_SEND, -1);
+	}
+	
+	return vp;
+}
+
+vproc_t vproc_retain(vproc_t vp)
+{
+	int32_t orig = OSAtomicAdd32(1, &vp->refcount) - 1;	
+	if( orig <= 0 ) {
+		/* We've gone from 0 to 1, which means that this object was due to be freed. */
+		__crashreporter_info__ = "Under-retain / over-release of vproc_t.";
+		abort();
+	}
+	
+	return vp;
+}
+
+void vproc_release(vproc_t vp)
+{
+	int32_t newval = OSAtomicAdd32(-1, &vp->refcount);
+	if( newval < 0 ) {
+		/* We're in negative numbers, which is bad. */
+		__crashreporter_info__ = "Over-release of vproc_t.";
+		abort();
+	} else if( newval == 0 ) {
+		mach_port_deallocate(mach_task_self(), vp->j_port);
+		free(vp);
+	}
+}
+
 static void
 vproc_shmem_init(void)
 {
@@ -746,7 +797,7 @@
 }
 
 vproc_err_t
-vproc_swap_integer(vproc_t vp __attribute__((unused)), vproc_gsk_t key, int64_t *inval, int64_t *outval)
+vproc_swap_integer(vproc_t vp, vproc_gsk_t key, int64_t *inval, int64_t *outval)
 {
 	static int64_t cached_is_managed = -1;
 	int64_t dummyval = 0;
@@ -785,7 +836,8 @@
 		break;
 	}
 
-	if (vproc_mig_swap_integer(bootstrap_port, inval ? key : 0, outval ? key : 0, inval ? *inval : 0, outval ? outval : &dummyval) == 0) {
+	mach_port_t mp = vp ? vp->j_port : bootstrap_port;
+	if (vproc_mig_swap_integer(mp, inval ? key : 0, outval ? key : 0, inval ? *inval : 0, outval ? outval : &dummyval) == 0) {
 		switch (key) {
 		case VPROC_GSK_MGR_PID:
 			cached_pid = outval ? *outval : dummyval;
@@ -832,7 +884,7 @@
 }
 
 vproc_err_t
-vproc_swap_complex(vproc_t vp __attribute__((unused)), vproc_gsk_t key, launch_data_t inval, launch_data_t *outval)
+vproc_swap_complex(vproc_t vp, vproc_gsk_t key, launch_data_t inval, launch_data_t *outval)
 {
 	size_t data_offset = 0, good_enough_size = 10*1024*1024;
 	mach_msg_type_number_t indata_cnt = 0, outdata_cnt;
@@ -853,7 +905,8 @@
 		indata = (vm_offset_t)buf;
 	}
 
-	if (vproc_mig_swap_complex(bootstrap_port, inval ? key : 0, outval ? key : 0, indata, indata_cnt, &outdata, &outdata_cnt) != 0) {
+	mach_port_t mp = vp ? vp->j_port : bootstrap_port;
+	if (vproc_mig_swap_complex(mp, inval ? key : 0, outval ? key : 0, indata, indata_cnt, &outdata, &outdata_cnt) != 0) {
 		goto out;
 	}
 

Modified: trunk/launchd/src/protocol_vproc.defs
===================================================================
--- trunk/launchd/src/protocol_vproc.defs	2009-01-08 23:44:10 UTC (rev 23775)
+++ trunk/launchd/src/protocol_vproc.defs	2009-01-10 00:40:56 UTC (rev 23776)
@@ -199,3 +199,7 @@
 				__pid				: pid_t;
 out				__managed			: boolean_t);
 
+routine port_for_label(
+				__bs_port			: job_t;
+				__label				: name_t;
+out				__mp				: mach_port_make_send_t);

Modified: trunk/launchd/src/vproc.h
===================================================================
--- trunk/launchd/src/vproc.h	2009-01-08 23:44:10 UTC (rev 23775)
+++ trunk/launchd/src/vproc.h	2009-01-10 00:40:56 UTC (rev 23776)
@@ -34,7 +34,7 @@
 
 typedef void * vproc_err_t;
 
-typedef void * vproc_t;
+typedef struct vproc_s * vproc_t;
 typedef void * vprocmgr_t;
 
 const char *vproc_strerror(vproc_err_t r);

Modified: trunk/launchd/src/vproc_priv.h
===================================================================
--- trunk/launchd/src/vproc_priv.h	2009-01-08 23:44:10 UTC (rev 23775)
+++ trunk/launchd/src/vproc_priv.h	2009-01-10 00:40:56 UTC (rev 23776)
@@ -59,12 +59,17 @@
 	VPROC_GSK_ABANDON_PROCESS_GROUP,
 	VPROC_GSK_TRANSACTIONS_ENABLED,
 	VPROC_GSK_WEIRD_BOOTSTRAP,
+	VPROC_GSK_WAITFORDEBUGGER,
 } vproc_gsk_t;
 
 typedef unsigned int vproc_flags_t;
 /* For _vproc_kickstart_by_label() -- instructs launchd to kickstart the job to stall before exec(2). */
 #define VPROCFLAG_STALL_JOB_EXEC	1 << 1
 
+vproc_t vprocmgr_lookup_vproc(const char *label);
+vproc_t vproc_retain(vproc_t vp);
+void vproc_release(vproc_t vp);
+
 vproc_err_t vproc_swap_integer(vproc_t vp, vproc_gsk_t key, int64_t *inval, int64_t *outval);
 vproc_err_t vproc_swap_complex(vproc_t vp, vproc_gsk_t key, launch_data_t inval, launch_data_t *outval);
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/launchd-changes/attachments/20090109/6a474945/attachment-0001.html>


More information about the launchd-changes mailing list