]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/tests/zero-to-n/zero-to-n.c
xnu-2782.1.97.tar.gz
[apple/xnu.git] / tools / tests / zero-to-n / zero-to-n.c
index 2df39a02ea1643f5848bb0b9cd8faf753122b809..97910a06f64d0a7da7e780a360287b665115eefc 100644 (file)
@@ -29,6 +29,7 @@
 #include <stdio.h>
 #include <math.h>
 #include <sys/wait.h>
+#include <sys/param.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <sys/ptrace.h>
 #include <pthread.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <err.h>
 #include <string.h>
 
+#include <spawn.h>
+#include <spawn_private.h>
+#include <sys/spawn_internal.h>
+#include <mach-o/dyld.h>
+
 #include <libkern/OSAtomic.h>
 
 #include <mach/mach_time.h>
@@ -67,6 +74,7 @@ void                  print_usage();
 int                    thread_setup(int my_id);
 my_policy_type_t       parse_thread_policy(const char *str);
 int                    thread_finish_iteration();
+void                   selfexec_with_apptype(int argc, char *argv[]);
 
 /* Global variables (general) */
 int                    g_numthreads;
@@ -152,7 +160,8 @@ thread_setup(int my_id)
        switch (g_policy) {
                case MY_POLICY_TIMESHARE:
                {
-                       return 0;
+                       res = KERN_SUCCESS;
+                       break;
                }
                case MY_POLICY_REALTIME: 
                {
@@ -270,9 +279,7 @@ child_thread_func(void *arg)
 
        /* Tell main thread when everyone has set up */
        new = OSAtomicIncrement32(&g_done_threads);
-       if (new == g_numthreads) {
-               semaphore_signal(g_main_sem);
-       }
+       semaphore_signal(g_main_sem);
 
        /* For each iteration */
        for (i = 0; i < g_iterations; i++) {
@@ -413,10 +420,11 @@ main(int argc, char **argv)
        uint64_t        max, min;
        uint64_t        traceworthy_latency_ns = TRACEWORTHY_NANOS;
        float           avg, stddev;
+       boolean_t       seen_apptype = FALSE;
 
        srand(time(NULL));
 
-       if (argc < 5 || argc > 9) {
+       if (argc < 5 || argc > 10) {
                print_usage();
                goto fail;
        }
@@ -444,12 +452,18 @@ main(int argc, char **argv)
                        traceworthy_latency_ns = strtoull(argv[++i], NULL, 10);
                } else if (strcmp(argv[i], "-affinity") == 0) {
                        g_do_affinity = TRUE;
+               } else if (strcmp(argv[i], "-switched_apptype") == 0) {
+                       seen_apptype = TRUE;
                } else {
                        print_usage();
                        goto fail;
                }
        }
 
+       if (!seen_apptype) {
+               selfexec_with_apptype(argc, argv);
+       }
+
        mach_timebase_info(&g_mti);
 
 #if MIMIC_DIGI_LEAD_TIME
@@ -496,9 +510,32 @@ main(int argc, char **argv)
                assert(res == 0, fail);
        }
 
+       res = setpriority(PRIO_DARWIN_ROLE, 0, PRIO_DARWIN_ROLE_UI_FOCAL);
+       assert(res == 0, fail);
+       thread_setup(0);
+
+       /* Switching to fixed pri may have stripped our main thread QoS and priority, so re-instate */
+       if (g_policy == MY_POLICY_FIXEDPRI) {
+               thread_precedence_policy_data_t prec;
+               mach_msg_type_number_t count;
+               boolean_t get_default = FALSE;
+               
+               count = THREAD_PRECEDENCE_POLICY_COUNT;
+               res = thread_policy_get(mach_thread_self(), THREAD_PRECEDENCE_POLICY, (thread_policy_t) &prec, &count, &get_default);
+               assert(res == 0, fail);
+               
+               prec.importance += 16; /* 47 - 31 */
+               res = thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY, (thread_policy_t) &prec, THREAD_PRECEDENCE_POLICY_COUNT);
+               assert(res == 0, fail);
+       }
+
        /* Let everyone get settled */
-       semaphore_wait(g_main_sem);
-       sleep(1);
+       for (i = 0; i < g_numthreads; i++) {
+               res = semaphore_wait(g_main_sem);
+               assert(res == 0, fail);
+       }
+       /* Let worker threads get back to sleep... */
+       usleep(g_numthreads * 10);
 
        /* Go! */
        for (i = 0; i < g_iterations; i++) {
@@ -591,3 +628,42 @@ main(int argc, char **argv)
 fail:
        return 1;
 }
+
+/*
+ * WARNING: This is SPI specifically intended for use by launchd to start UI
+ * apps. We use it here for a test tool only to opt into QoS using the same
+ * policies. Do not use this outside xnu or libxpc/launchd.
+ */
+void
+selfexec_with_apptype(int argc, char *argv[])
+{
+       int ret;
+       posix_spawnattr_t attr;
+       extern char **environ;
+       char *new_argv[argc + 1 + 1 /* NULL */];
+       int i;
+       char prog[PATH_MAX];
+       int32_t prog_size = PATH_MAX;
+
+       ret = _NSGetExecutablePath(prog, &prog_size);
+       if (ret != 0) err(1, "_NSGetExecutablePath");
+
+       for (i=0; i < argc; i++) {
+               new_argv[i] = argv[i];
+       }
+
+       new_argv[i]   = "-switched_apptype";
+       new_argv[i+1] = NULL;
+
+       ret = posix_spawnattr_init(&attr);
+       if (ret != 0) errc(1, ret, "posix_spawnattr_init");
+
+       ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC);
+       if (ret != 0) errc(1, ret, "posix_spawnattr_setflags");
+
+       ret = posix_spawnattr_setprocesstype_np(&attr, POSIX_SPAWN_PROC_TYPE_APP_DEFAULT);
+       if (ret != 0) errc(1, ret, "posix_spawnattr_setprocesstype_np");
+
+       ret = posix_spawn(NULL, prog, NULL, &attr, new_argv, environ);
+       if (ret != 0) errc(1, ret, "posix_spawn");
+}