static void * outer_thread (void *closure) { pthread_t *threads = xcalloc (sizeof (*threads), inner_thread_count); while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED)) { pthread_barrier_t barrier; xpthread_barrier_init (&barrier, NULL, inner_thread_count + 1); for (int i = 0; i < inner_thread_count; ++i) { void *(*func) (void *); if ((i % 2) == 0) func = malloc_first_thread; else func = wait_first_thread; threads[i] = xpthread_create (NULL, func, &barrier); } xpthread_barrier_wait (&barrier); for (int i = 0; i < inner_thread_count; ++i) xpthread_join (threads[i]); xpthread_barrier_destroy (&barrier); } free (threads); return NULL; }
/* * The accept thread's job is easy. * Accept a new connection and pass it off to a work thread. Repeat. */ void * accept_thread(void *arg) { config_t *config = (config_t *) arg; int s; struct sockaddr_un sa; socklen_t salen = sizeof(sa); mlog(LOG_DEBUG2, "%s: tid=%lu", __func__, (unsigned long) pthread_self()); for (;;) { s = accept(config->s, (struct sockaddr *) &sa, &salen); if (s == -1) { mlog(LOG_ERR, "%s: plugin accept: %s", __func__, strerror(errno)); /* not much else we can do */ continue; } mlog(LOG_DEBUG, "%s: plugin accept fd=%d", __func__, s); /* * start a work thread (1:1 model) */ { pthread_t tid; config_t *inst; inst = xmalloc(sizeof(*config)); (void) memcpy(inst, config, sizeof(*config)); inst->s = s; xpthread_create(&tid, &attr_detached, work_thread, inst); } } /* for (;;) */ }
int do_test (void) { xpthread_rwlockattr_init (&mylock_attr); xpthread_rwlockattr_setkind_np (&mylock_attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); xpthread_rwlock_init (&mylock, &mylock_attr); for (int n = 0; n < LOOPS; n++) { pthread_t tids[NTHREADS]; do_exit = 0; for (int i = 0; i < NTHREADS; i++) tids[i] = xpthread_create (NULL, run_loop, NULL); /* Let the threads run for some time. */ sleep (1); printf ("Exiting..."); fflush (stdout); do_exit = 1; for (int i = 0; i < NTHREADS; i++) xpthread_join (tids[i]); printf ("done.\n"); } pthread_rwlock_destroy (&mylock); pthread_rwlockattr_destroy (&mylock_attr); return 0; }
static void benchmark(void) { int i; long sum = 0; long min_ms = LONG_MAX, max_ms = 0, avg_ms; pthread_t *tid; struct benchmark_thread_data *data; #ifdef CHUNKD_BENCHMARK stc_init(); #endif tid = xmalloc(sizeof(tid[0]) * threads); data = xmalloc(sizeof(data[0]) * threads); for (i = 0; i < threads; i++) { data[i].id = i; xpthread_create(&tid[i], NULL, benchmark_thread, &data[i]); } wait_threads(tid, threads); #define _MIN(a, b) ((a) < (b) ? (a) : (b)) #define _MAX(a, b) ((a) < (b) ? (b) : (a)) for (i = 0; i < threads; i++) { long ms = data[i].time_ms; sum += ms; min_ms = _MIN(min_ms, ms); max_ms = _MAX(max_ms, ms); } avg_ms = sum / threads; printf("%d %ld.%03ld %ld.%03ld %ld.%03ld\n", threads, avg_ms / 1000, avg_ms % 1000, min_ms / 1000, min_ms % 1000, max_ms / 1000, max_ms % 1000); if (verbose) { unsigned long long total_bytes; unsigned long long bytes_per_msec; total_bytes = value_length; total_bytes *= threads; total_bytes *= requests; bytes_per_msec = total_bytes / avg_ms; printf("Throughput: %llu KB/sec\n", bytes_per_msec * 1000UL / 1024UL); } free(data); free(tid); }
static int do_test (void) { /* Limit the size of the process, so that memory allocation will fail without impacting the entire system. */ { struct rlimit limit; if (getrlimit (RLIMIT_AS, &limit) != 0) { printf ("FAIL: getrlimit (RLIMIT_AS) failed: %m\n"); return 1; } /* This limit, 800MB, is just a heuristic. Any value can be picked. */ long target = 800 * 1024 * 1024; if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > target) { limit.rlim_cur = target; if (setrlimit (RLIMIT_AS, &limit) != 0) { printf ("FAIL: setrlimit (RLIMIT_AS) failed: %m\n"); return 1; } } } xpthread_attr_init (&detached); xpthread_attr_setdetachstate (&detached, PTHREAD_CREATE_DETACHED); /* A large thread stack seems beneficial for reproducing a race condition in detached thread creation. The goal is to reach the limit of the runtime thread stack cache such that the detached thread's stack is unmapped after exit and causes a segfault when the parent reads the thread descriptor data stored on the the unmapped stack. */ xpthread_attr_setstacksize (&detached, 16 * 1024 * 1024); xpthread_barrier_init (&barrier, NULL, creator_threads); pthread_t threads[creator_threads]; for (int i = 0; i < creator_threads; ++i) threads[i] = xpthread_create (NULL, creator_thread, NULL); for (int i = 0; i < creator_threads; ++i) xpthread_join (threads[i]); xpthread_attr_destroy (&detached); xpthread_barrier_destroy (&barrier); return 0; }
static struct worker_info *create_workers(struct benchmark_config *config, int thnum, const char *command, struct work_queue *in_queue, struct work_queue *out_queue) { struct worker_info *data = xmalloc(sizeof(*data) * thnum); int i; for (i = 0; i < thnum; i++) { data[i].db = config->ops.open_db(config); data[i].config = config; data[i].command = command; data[i].in_queue = in_queue; data[i].out_queue = out_queue; } for (i = 0; i < thnum; i++) xpthread_create(&data[i].tid, benchmark_thread, &data[i]); return data; }
static int do_test (void) { xpthread_barrier_init (&barrier, NULL, thread_count + 1); pthread_t threads[thread_count]; for (size_t i = 0; i < array_length (threads); ++i) threads[i] = xpthread_create (NULL, allocation_thread_function, NULL); xpthread_barrier_wait (&barrier); puts ("info: After allocation:"); malloc_info (0, stdout); xpthread_barrier_wait (&barrier); for (size_t i = 0; i < array_length (threads); ++i) xpthread_join (threads[i]); puts ("\ninfo: After deallocation:"); malloc_info (0, stdout); return 0; }
static int do_test (void) { unsigned int i; printf ("Starting %d threads to run %lld iterations.\n", thread_count, iteration_count); pthread_t *threads = xmalloc (thread_count * sizeof (pthread_t)); xpthread_barrier_init (&barrier, NULL, thread_count); xpthread_mutex_init (&mutex, NULL); for (i = 0; i < thread_count; i++) threads[i] = xpthread_create (NULL, thr_func, (void *) (uintptr_t) i); for (i = 0; i < thread_count; i++) xpthread_join (threads[i]); xpthread_barrier_destroy (&barrier); free (threads); return EXIT_SUCCESS; }
static int do_test (void) { /* The number of threads should be smaller than the number of arenas, so that there will be some free arenas to add to the arena free list. */ enum { outer_thread_count = 2 }; if (mallopt (M_ARENA_MAX, 8) == 0) { printf ("error: mallopt (M_ARENA_MAX) failed\n"); return 1; } /* Leave some room for shutting down all threads gracefully. */ int timeout = 3; if (timeout > DEFAULT_TIMEOUT) timeout = DEFAULT_TIMEOUT - 1; pthread_t *threads = xcalloc (sizeof (*threads), outer_thread_count); for (long i = 0; i < outer_thread_count; ++i) threads[i] = xpthread_create (NULL, outer_thread, NULL); struct timespec ts = {timeout, 0}; if (nanosleep (&ts, NULL)) { printf ("error: error: nanosleep: %m\n"); abort (); } __atomic_store_n (&termination_requested, true, __ATOMIC_RELAXED); for (long i = 0; i < outer_thread_count; ++i) xpthread_join (threads[i]); free (threads); return 0; }
static int do_test (void) { /* The test basically pipe a 'echo $$' created by a thread with a cancellation pending. It then checks if the thread is not cancelled, the process is created and if the output is the expected one. */ if (pipe (pipefd) != 0) { puts ("error: pipe failed"); exit (1); } /* Not interested in knowing when the pipe is closed. */ if (sigignore (SIGPIPE) != 0) { puts ("error: sigignore failed"); exit (1); } /* To synchronize with the thread. */ if (pthread_barrier_init (&b, NULL, 2) != 0) { puts ("error: pthread_barrier_init failed"); exit (1); } pthread_t th = xpthread_create (NULL, &tf, NULL); if (pthread_cancel (th) != 0) { puts ("error: pthread_cancel failed"); return 1; } xpthread_barrier_wait (&b); if (xpthread_join (th) == PTHREAD_CANCELED) { puts ("error: thread cancelled"); exit (1); } close (pipefd[1]); /* The global 'pid' should be set by thread posix_spawn calling. Check below if it was executed correctly and with expected output. */ char buf[64]; ssize_t n; bool seen_pid = false; while (TEMP_FAILURE_RETRY ((n = read (pipefd[0], buf, sizeof (buf)))) > 0) { /* We only expect to read the PID. */ char *endp; long int rpid = strtol (buf, &endp, 10); if (*endp != '\n') { printf ("error: didn't parse whole line: \"%s\"\n", buf); exit (1); } if (endp == buf) { puts ("error: read empty line"); exit (1); } if (rpid != pid) { printf ("error: found \"%s\", expected PID %ld\n", buf, (long int) pid); exit (1); } if (seen_pid) { puts ("error: found more than one PID line"); exit (1); } seen_pid = true; } close (pipefd[0]); int status; int err = waitpid (pid, &status, 0); if (err != pid) { puts ("errnor: waitpid failed"); exit (1); } if (!seen_pid) { puts ("error: didn't get PID"); exit (1); } return 0; }
void start_daemon(int client) { // Launch the daemon, create new session, set proper context if (getuid() != UID_ROOT || getgid() != UID_ROOT) { fprintf(stderr, "Starting daemon requires root: %s\n", strerror(errno)); PLOGE("start daemon"); } switch (fork()) { case -1: PLOGE("fork"); case 0: break; default: return; } // First close the client, it's useless for us close(client); xsetsid(); setcon("u:r:su:s0"); umask(022); int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC); xdup2(fd, STDIN_FILENO); xdup2(fd, STDOUT_FILENO); xdup2(fd, STDERR_FILENO); close(fd); // Patch selinux with medium patch before we do anything load_policydb(SELINUX_POLICY); sepol_med_rules(); dump_policydb(SELINUX_LOAD); // Continue the larger patch in another thread, we will join later pthread_create(&sepol_patch, NULL, large_sepol_patch, NULL); struct sockaddr_un sun; fd = setup_socket(&sun); xbind(fd, (struct sockaddr*) &sun, sizeof(sun)); xlisten(fd, 10); // Change process name strcpy(argv0, "magisk_daemon"); // The root daemon should not do anything if an error occurs // It should stay intact under any circumstances err_handler = do_nothing; LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") daemon started\n"); // Unlock all blocks for rw unlock_blocks(); // Setup links under /sbin xmount(NULL, "/", NULL, MS_REMOUNT, NULL); create_links(NULL, "/sbin"); xchmod("/sbin", 0755); xmkdir("/magisk", 0755); xchmod("/magisk", 0755); xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL); // Loop forever to listen for requests while(1) { int *client = xmalloc(sizeof(int)); *client = xaccept4(fd, NULL, NULL, SOCK_CLOEXEC); pthread_t thread; xpthread_create(&thread, NULL, request_handler, client); // Detach the thread, we will never join it pthread_detach(thread); } }