123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- /*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <LibCore/ArgsParser.h>
- #include <errno.h>
- #include <pthread.h>
- #include <signal_numbers.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/mman.h>
- #include <unistd.h>
- static int mutex_test();
- static int detached_test();
- static int priority_test();
- static int stack_size_test();
- static int staying_alive_test();
- static int set_stack_test();
- static int kill_test();
- int main(int argc, char** argv)
- {
- const char* test_name = "n";
- Core::ArgsParser args_parser;
- args_parser.set_general_help(
- "Exercise error-handling and edge-case paths of the execution environment "
- "(i.e., Kernel or UE) by doing unusual thread-related things.");
- args_parser.add_positional_argument(test_name, "Test to run (m = mutex, d = detached, p = priority, s = stack size, t = simple thread test, x = set stack, k = kill, nothing = join race)", "test-name", Core::ArgsParser::Required::No);
- args_parser.parse(argc, argv);
- if (*test_name == 'm')
- return mutex_test();
- if (*test_name == 'd')
- return detached_test();
- if (*test_name == 'p')
- return priority_test();
- if (*test_name == 's')
- return stack_size_test();
- if (*test_name == 't')
- return staying_alive_test();
- if (*test_name == 'x')
- return set_stack_test();
- if (*test_name == 'k')
- return kill_test();
- if (*test_name != 'n') {
- args_parser.print_usage(stdout, argv[0]);
- return 1;
- }
- outln("Hello from the first thread!");
- pthread_t thread_id;
- int rc = pthread_create(
- &thread_id, nullptr, [](void*) -> void* {
- outln("Hi there, from the second thread!");
- pthread_exit((void*)0xDEADBEEF);
- },
- nullptr);
- if (rc < 0) {
- perror("pthread_create");
- return 1;
- }
- void* retval;
- rc = pthread_join(thread_id, &retval);
- if (rc < 0) {
- perror("pthread_join");
- return 1;
- }
- outln("Okay, joined and got retval={}", retval);
- return 0;
- }
- static pthread_mutex_t mutex;
- int mutex_test()
- {
- int rc = pthread_mutex_init(&mutex, nullptr);
- if (rc < 0) {
- perror("pthread_mutex_init");
- return 1;
- }
- pthread_t thread_id;
- rc = pthread_create(
- &thread_id, nullptr, [](void*) -> void* {
- outln("I'm the secondary thread :^)");
- for (;;) {
- pthread_mutex_lock(&mutex);
- outln("Second thread stole mutex");
- sleep(1);
- outln("Second thread giving back mutex");
- pthread_mutex_unlock(&mutex);
- sleep(1);
- }
- },
- nullptr);
- if (rc < 0) {
- perror("pthread_create");
- return 1;
- }
- for (;;) {
- pthread_mutex_lock(&mutex);
- outln("Obnoxious spam!");
- pthread_mutex_unlock(&mutex);
- usleep(10000);
- }
- }
- int detached_test()
- {
- pthread_attr_t attributes;
- int rc = pthread_attr_init(&attributes);
- if (rc != 0) {
- outln("pthread_attr_init: {}", strerror(rc));
- return 1;
- }
- int detach_state = 99; // clearly invalid
- rc = pthread_attr_getdetachstate(&attributes, &detach_state);
- if (rc != 0) {
- outln("pthread_attr_getdetachstate: {}", strerror(rc));
- return 2;
- }
- outln("Default detach state: {}", detach_state == PTHREAD_CREATE_JOINABLE ? "joinable" : "detached");
- detach_state = PTHREAD_CREATE_DETACHED;
- rc = pthread_attr_setdetachstate(&attributes, detach_state);
- if (rc != 0) {
- outln("pthread_attr_setdetachstate: {}", strerror(rc));
- return 3;
- }
- outln("Set detach state on new thread to detached");
- pthread_t thread_id;
- rc = pthread_create(
- &thread_id, &attributes, [](void*) -> void* {
- outln("I'm the secondary thread :^)");
- sleep(1);
- pthread_exit((void*)0xDEADBEEF);
- },
- nullptr);
- if (rc != 0) {
- outln("pthread_create: {}", strerror(rc));
- return 4;
- }
- void* ret_val;
- rc = pthread_join(thread_id, &ret_val);
- if (rc != 0 && rc != EINVAL) {
- outln("pthread_join: {}", strerror(rc));
- return 5;
- }
- if (rc != EINVAL) {
- outln("Expected EINVAL! Thread was joinable?");
- return 6;
- }
- sleep(2);
- outln("Thread was created detached. I sure hope it exited on its own.");
- rc = pthread_attr_destroy(&attributes);
- if (rc != 0) {
- outln("pthread_attr_destroy: {}", strerror(rc));
- return 7;
- }
- return 0;
- }
- int priority_test()
- {
- pthread_attr_t attributes;
- int rc = pthread_attr_init(&attributes);
- if (rc != 0) {
- outln("pthread_attr_init: {}", strerror(rc));
- return 1;
- }
- struct sched_param sched_params;
- rc = pthread_attr_getschedparam(&attributes, &sched_params);
- if (rc != 0) {
- outln("pthread_attr_getschedparam: {}", strerror(rc));
- return 2;
- }
- outln("Default priority: {}", sched_params.sched_priority);
- sched_params.sched_priority = 3;
- rc = pthread_attr_setschedparam(&attributes, &sched_params);
- if (rc != 0) {
- outln("pthread_attr_setschedparam: {}", strerror(rc));
- return 3;
- }
- outln("Set thread priority to 3");
- pthread_t thread_id;
- rc = pthread_create(
- &thread_id, &attributes, [](void*) -> void* {
- outln("I'm the secondary thread :^)");
- sleep(1);
- pthread_exit((void*)0xDEADBEEF);
- },
- nullptr);
- if (rc < 0) {
- perror("pthread_create");
- return 4;
- }
- rc = pthread_join(thread_id, nullptr);
- if (rc < 0) {
- perror("pthread_join");
- return 5;
- }
- rc = pthread_attr_destroy(&attributes);
- if (rc != 0) {
- outln("pthread_attr_destroy: {}", strerror(rc));
- return 6;
- }
- return 0;
- }
- int stack_size_test()
- {
- pthread_attr_t attributes;
- int rc = pthread_attr_init(&attributes);
- if (rc != 0) {
- outln("pthread_attr_init: {}", strerror(rc));
- return 1;
- }
- size_t stack_size;
- rc = pthread_attr_getstacksize(&attributes, &stack_size);
- if (rc != 0) {
- outln("pthread_attr_getstacksize: {}", strerror(rc));
- return 2;
- }
- outln("Default stack size: {}", stack_size);
- stack_size = 8 * 1024 * 1024;
- rc = pthread_attr_setstacksize(&attributes, stack_size);
- if (rc != 0) {
- outln("pthread_attr_setstacksize: {}", strerror(rc));
- return 3;
- }
- outln("Set thread stack size to 8 MiB");
- pthread_t thread_id;
- rc = pthread_create(
- &thread_id, &attributes, [](void*) -> void* {
- outln("I'm the secondary thread :^)");
- sleep(1);
- pthread_exit((void*)0xDEADBEEF);
- },
- nullptr);
- if (rc < 0) {
- perror("pthread_create");
- return 4;
- }
- rc = pthread_join(thread_id, nullptr);
- if (rc < 0) {
- perror("pthread_join");
- return 5;
- }
- rc = pthread_attr_destroy(&attributes);
- if (rc != 0) {
- outln("pthread_attr_destroy: {}", strerror(rc));
- return 6;
- }
- return 0;
- }
- int staying_alive_test()
- {
- pthread_t thread_id;
- int rc = pthread_create(
- &thread_id, nullptr, [](void*) -> void* {
- outln("I'm the secondary thread :^)");
- sleep(20);
- outln("Secondary thread is still alive");
- sleep(3520);
- outln("Secondary thread exiting");
- pthread_exit((void*)0xDEADBEEF);
- },
- nullptr);
- if (rc < 0) {
- perror("pthread_create");
- return 1;
- }
- sleep(1);
- outln("I'm the main thread :^)");
- sleep(3600);
- outln("Main thread exiting");
- return 0;
- }
- int set_stack_test()
- {
- pthread_attr_t attributes;
- int rc = pthread_attr_init(&attributes);
- if (rc < 0) {
- outln("pthread_attr_init: {}", strerror(rc));
- return 1;
- }
- size_t stack_size = 8 * 1024 * 1024;
- void* stack_addr = mmap_with_name(nullptr, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 0, 0, "Cool stack");
- if (!stack_addr) {
- perror("mmap_with_name");
- return -1;
- }
- rc = pthread_attr_setstack(&attributes, stack_addr, stack_size);
- if (rc != 0) {
- outln("pthread_attr_setstack: {}", strerror(rc));
- return 2;
- }
- outln("Set thread stack to {:p}, size {}", stack_addr, stack_size);
- size_t stack_size_verify;
- void* stack_addr_verify;
- rc = pthread_attr_getstack(&attributes, &stack_addr_verify, &stack_size_verify);
- if (rc != 0) {
- outln("pthread_attr_getstack: {}", strerror(rc));
- return 3;
- }
- if (stack_addr != stack_addr_verify || stack_size != stack_size_verify) {
- outln("Stack address and size don't match! addr: {:p} {:p}, size: {} {}", stack_addr, stack_addr_verify, stack_size, stack_size_verify);
- return 4;
- }
- pthread_t thread_id;
- rc = pthread_create(
- &thread_id, &attributes, [](void*) -> void* {
- outln("I'm the secondary thread :^)");
- sleep(1);
- pthread_exit((void*)0xDEADBEEF);
- },
- nullptr);
- if (rc < 0) {
- perror("pthread_create");
- return 5;
- }
- rc = pthread_join(thread_id, nullptr);
- if (rc < 0) {
- perror("pthread_join");
- return 6;
- }
- rc = pthread_attr_destroy(&attributes);
- if (rc != 0) {
- outln("pthread_attr_destroy: {}", strerror(rc));
- return 7;
- }
- return 0;
- }
- int kill_test()
- {
- pthread_t thread_id;
- int rc = pthread_create(
- &thread_id, nullptr, [](void*) -> void* {
- outln("I'm the secondary thread :^)");
- sleep(100);
- outln("Secondary thread is still alive :^(");
- pthread_exit((void*)0xDEADBEEF);
- },
- nullptr);
- if (rc < 0) {
- perror("pthread_create");
- return 1;
- }
- int result = 0;
- sleep(1);
- outln("I'm the main thread :^)");
- if (pthread_kill(thread_id, 0) != 0) {
- perror("pthread_kill");
- result = 1;
- }
- if (pthread_kill(thread_id, SIGKILL) != 0) {
- perror("pthread_kill(SIGKILL)");
- result = 1;
- }
- outln("Main thread exiting");
- return result;
- }
|