tt.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibCore/ArgsParser.h>
  7. #include <errno.h>
  8. #include <pthread.h>
  9. #include <signal_numbers.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <sys/mman.h>
  14. #include <unistd.h>
  15. static int mutex_test();
  16. static int detached_test();
  17. static int priority_test();
  18. static int stack_size_test();
  19. static int staying_alive_test();
  20. static int set_stack_test();
  21. static int kill_test();
  22. int main(int argc, char** argv)
  23. {
  24. const char* test_name = "n";
  25. Core::ArgsParser args_parser;
  26. args_parser.set_general_help(
  27. "Exercise error-handling and edge-case paths of the execution environment "
  28. "(i.e., Kernel or UE) by doing unusual thread-related things.");
  29. 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);
  30. args_parser.parse(argc, argv);
  31. if (*test_name == 'm')
  32. return mutex_test();
  33. if (*test_name == 'd')
  34. return detached_test();
  35. if (*test_name == 'p')
  36. return priority_test();
  37. if (*test_name == 's')
  38. return stack_size_test();
  39. if (*test_name == 't')
  40. return staying_alive_test();
  41. if (*test_name == 'x')
  42. return set_stack_test();
  43. if (*test_name == 'k')
  44. return kill_test();
  45. if (*test_name != 'n') {
  46. args_parser.print_usage(stdout, argv[0]);
  47. return 1;
  48. }
  49. outln("Hello from the first thread!");
  50. pthread_t thread_id;
  51. int rc = pthread_create(
  52. &thread_id, nullptr, [](void*) -> void* {
  53. outln("Hi there, from the second thread!");
  54. pthread_exit((void*)0xDEADBEEF);
  55. },
  56. nullptr);
  57. if (rc < 0) {
  58. perror("pthread_create");
  59. return 1;
  60. }
  61. void* retval;
  62. rc = pthread_join(thread_id, &retval);
  63. if (rc < 0) {
  64. perror("pthread_join");
  65. return 1;
  66. }
  67. outln("Okay, joined and got retval={}", retval);
  68. return 0;
  69. }
  70. static pthread_mutex_t mutex;
  71. int mutex_test()
  72. {
  73. int rc = pthread_mutex_init(&mutex, nullptr);
  74. if (rc < 0) {
  75. perror("pthread_mutex_init");
  76. return 1;
  77. }
  78. pthread_t thread_id;
  79. rc = pthread_create(
  80. &thread_id, nullptr, [](void*) -> void* {
  81. outln("I'm the secondary thread :^)");
  82. for (;;) {
  83. pthread_mutex_lock(&mutex);
  84. outln("Second thread stole mutex");
  85. sleep(1);
  86. outln("Second thread giving back mutex");
  87. pthread_mutex_unlock(&mutex);
  88. sleep(1);
  89. }
  90. },
  91. nullptr);
  92. if (rc < 0) {
  93. perror("pthread_create");
  94. return 1;
  95. }
  96. for (;;) {
  97. pthread_mutex_lock(&mutex);
  98. outln("Obnoxious spam!");
  99. pthread_mutex_unlock(&mutex);
  100. usleep(10000);
  101. }
  102. }
  103. int detached_test()
  104. {
  105. pthread_attr_t attributes;
  106. int rc = pthread_attr_init(&attributes);
  107. if (rc != 0) {
  108. outln("pthread_attr_init: {}", strerror(rc));
  109. return 1;
  110. }
  111. int detach_state = 99; // clearly invalid
  112. rc = pthread_attr_getdetachstate(&attributes, &detach_state);
  113. if (rc != 0) {
  114. outln("pthread_attr_getdetachstate: {}", strerror(rc));
  115. return 2;
  116. }
  117. outln("Default detach state: {}", detach_state == PTHREAD_CREATE_JOINABLE ? "joinable" : "detached");
  118. detach_state = PTHREAD_CREATE_DETACHED;
  119. rc = pthread_attr_setdetachstate(&attributes, detach_state);
  120. if (rc != 0) {
  121. outln("pthread_attr_setdetachstate: {}", strerror(rc));
  122. return 3;
  123. }
  124. outln("Set detach state on new thread to detached");
  125. pthread_t thread_id;
  126. rc = pthread_create(
  127. &thread_id, &attributes, [](void*) -> void* {
  128. outln("I'm the secondary thread :^)");
  129. sleep(1);
  130. pthread_exit((void*)0xDEADBEEF);
  131. },
  132. nullptr);
  133. if (rc != 0) {
  134. outln("pthread_create: {}", strerror(rc));
  135. return 4;
  136. }
  137. void* ret_val;
  138. rc = pthread_join(thread_id, &ret_val);
  139. if (rc != 0 && rc != EINVAL) {
  140. outln("pthread_join: {}", strerror(rc));
  141. return 5;
  142. }
  143. if (rc != EINVAL) {
  144. outln("Expected EINVAL! Thread was joinable?");
  145. return 6;
  146. }
  147. sleep(2);
  148. outln("Thread was created detached. I sure hope it exited on its own.");
  149. rc = pthread_attr_destroy(&attributes);
  150. if (rc != 0) {
  151. outln("pthread_attr_destroy: {}", strerror(rc));
  152. return 7;
  153. }
  154. return 0;
  155. }
  156. int priority_test()
  157. {
  158. pthread_attr_t attributes;
  159. int rc = pthread_attr_init(&attributes);
  160. if (rc != 0) {
  161. outln("pthread_attr_init: {}", strerror(rc));
  162. return 1;
  163. }
  164. struct sched_param sched_params;
  165. rc = pthread_attr_getschedparam(&attributes, &sched_params);
  166. if (rc != 0) {
  167. outln("pthread_attr_getschedparam: {}", strerror(rc));
  168. return 2;
  169. }
  170. outln("Default priority: {}", sched_params.sched_priority);
  171. sched_params.sched_priority = 3;
  172. rc = pthread_attr_setschedparam(&attributes, &sched_params);
  173. if (rc != 0) {
  174. outln("pthread_attr_setschedparam: {}", strerror(rc));
  175. return 3;
  176. }
  177. outln("Set thread priority to 3");
  178. pthread_t thread_id;
  179. rc = pthread_create(
  180. &thread_id, &attributes, [](void*) -> void* {
  181. outln("I'm the secondary thread :^)");
  182. sleep(1);
  183. pthread_exit((void*)0xDEADBEEF);
  184. },
  185. nullptr);
  186. if (rc < 0) {
  187. perror("pthread_create");
  188. return 4;
  189. }
  190. rc = pthread_join(thread_id, nullptr);
  191. if (rc < 0) {
  192. perror("pthread_join");
  193. return 5;
  194. }
  195. rc = pthread_attr_destroy(&attributes);
  196. if (rc != 0) {
  197. outln("pthread_attr_destroy: {}", strerror(rc));
  198. return 6;
  199. }
  200. return 0;
  201. }
  202. int stack_size_test()
  203. {
  204. pthread_attr_t attributes;
  205. int rc = pthread_attr_init(&attributes);
  206. if (rc != 0) {
  207. outln("pthread_attr_init: {}", strerror(rc));
  208. return 1;
  209. }
  210. size_t stack_size;
  211. rc = pthread_attr_getstacksize(&attributes, &stack_size);
  212. if (rc != 0) {
  213. outln("pthread_attr_getstacksize: {}", strerror(rc));
  214. return 2;
  215. }
  216. outln("Default stack size: {}", stack_size);
  217. stack_size = 8 * 1024 * 1024;
  218. rc = pthread_attr_setstacksize(&attributes, stack_size);
  219. if (rc != 0) {
  220. outln("pthread_attr_setstacksize: {}", strerror(rc));
  221. return 3;
  222. }
  223. outln("Set thread stack size to 8 MiB");
  224. pthread_t thread_id;
  225. rc = pthread_create(
  226. &thread_id, &attributes, [](void*) -> void* {
  227. outln("I'm the secondary thread :^)");
  228. sleep(1);
  229. pthread_exit((void*)0xDEADBEEF);
  230. },
  231. nullptr);
  232. if (rc < 0) {
  233. perror("pthread_create");
  234. return 4;
  235. }
  236. rc = pthread_join(thread_id, nullptr);
  237. if (rc < 0) {
  238. perror("pthread_join");
  239. return 5;
  240. }
  241. rc = pthread_attr_destroy(&attributes);
  242. if (rc != 0) {
  243. outln("pthread_attr_destroy: {}", strerror(rc));
  244. return 6;
  245. }
  246. return 0;
  247. }
  248. int staying_alive_test()
  249. {
  250. pthread_t thread_id;
  251. int rc = pthread_create(
  252. &thread_id, nullptr, [](void*) -> void* {
  253. outln("I'm the secondary thread :^)");
  254. sleep(20);
  255. outln("Secondary thread is still alive");
  256. sleep(3520);
  257. outln("Secondary thread exiting");
  258. pthread_exit((void*)0xDEADBEEF);
  259. },
  260. nullptr);
  261. if (rc < 0) {
  262. perror("pthread_create");
  263. return 1;
  264. }
  265. sleep(1);
  266. outln("I'm the main thread :^)");
  267. sleep(3600);
  268. outln("Main thread exiting");
  269. return 0;
  270. }
  271. int set_stack_test()
  272. {
  273. pthread_attr_t attributes;
  274. int rc = pthread_attr_init(&attributes);
  275. if (rc < 0) {
  276. outln("pthread_attr_init: {}", strerror(rc));
  277. return 1;
  278. }
  279. size_t stack_size = 8 * 1024 * 1024;
  280. void* stack_addr = mmap_with_name(nullptr, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 0, 0, "Cool stack");
  281. if (!stack_addr) {
  282. perror("mmap_with_name");
  283. return -1;
  284. }
  285. rc = pthread_attr_setstack(&attributes, stack_addr, stack_size);
  286. if (rc != 0) {
  287. outln("pthread_attr_setstack: {}", strerror(rc));
  288. return 2;
  289. }
  290. outln("Set thread stack to {:p}, size {}", stack_addr, stack_size);
  291. size_t stack_size_verify;
  292. void* stack_addr_verify;
  293. rc = pthread_attr_getstack(&attributes, &stack_addr_verify, &stack_size_verify);
  294. if (rc != 0) {
  295. outln("pthread_attr_getstack: {}", strerror(rc));
  296. return 3;
  297. }
  298. if (stack_addr != stack_addr_verify || stack_size != stack_size_verify) {
  299. outln("Stack address and size don't match! addr: {:p} {:p}, size: {} {}", stack_addr, stack_addr_verify, stack_size, stack_size_verify);
  300. return 4;
  301. }
  302. pthread_t thread_id;
  303. rc = pthread_create(
  304. &thread_id, &attributes, [](void*) -> void* {
  305. outln("I'm the secondary thread :^)");
  306. sleep(1);
  307. pthread_exit((void*)0xDEADBEEF);
  308. },
  309. nullptr);
  310. if (rc < 0) {
  311. perror("pthread_create");
  312. return 5;
  313. }
  314. rc = pthread_join(thread_id, nullptr);
  315. if (rc < 0) {
  316. perror("pthread_join");
  317. return 6;
  318. }
  319. rc = pthread_attr_destroy(&attributes);
  320. if (rc != 0) {
  321. outln("pthread_attr_destroy: {}", strerror(rc));
  322. return 7;
  323. }
  324. return 0;
  325. }
  326. int kill_test()
  327. {
  328. pthread_t thread_id;
  329. int rc = pthread_create(
  330. &thread_id, nullptr, [](void*) -> void* {
  331. outln("I'm the secondary thread :^)");
  332. sleep(100);
  333. outln("Secondary thread is still alive :^(");
  334. pthread_exit((void*)0xDEADBEEF);
  335. },
  336. nullptr);
  337. if (rc < 0) {
  338. perror("pthread_create");
  339. return 1;
  340. }
  341. int result = 0;
  342. sleep(1);
  343. outln("I'm the main thread :^)");
  344. if (pthread_kill(thread_id, 0) != 0) {
  345. perror("pthread_kill");
  346. result = 1;
  347. }
  348. if (pthread_kill(thread_id, SIGKILL) != 0) {
  349. perror("pthread_kill(SIGKILL)");
  350. result = 1;
  351. }
  352. outln("Main thread exiting");
  353. return result;
  354. }