Serenity Operating System
at hosted 350 lines 9.9 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <mman.h> 28#include <pthread.h> 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include <unistd.h> 33 34static int mutex_test(); 35static int detached_test(); 36static int priority_test(); 37static int stack_size_test(); 38static int set_stack_test(); 39 40int main(int argc, char** argv) 41{ 42 if (argc == 2 && *argv[1] == 'm') 43 return mutex_test(); 44 if (argc == 2 && *argv[1] == 'd') 45 return detached_test(); 46 if (argc == 2 && *argv[1] == 'p') 47 return priority_test(); 48 if (argc == 2 && *argv[1] == 's') 49 return stack_size_test(); 50 if (argc == 2 && *argv[1] == 'x') 51 return set_stack_test(); 52 53 printf("Hello from the first thread!\n"); 54 pthread_t thread_id; 55 int rc = pthread_create( 56 &thread_id, nullptr, [](void*) -> void* { 57 printf("Hi there, from the second thread!\n"); 58 pthread_exit((void*)0xDEADBEEF); 59 return nullptr; 60 }, 61 nullptr); 62 if (rc < 0) { 63 perror("pthread_create"); 64 return 1; 65 } 66 void* retval; 67 rc = pthread_join(thread_id, &retval); 68 if (rc < 0) { 69 perror("pthread_join"); 70 return 1; 71 } 72 printf("Okay, joined and got retval=%p\n", retval); 73 return 0; 74} 75 76static pthread_mutex_t mutex; 77 78int mutex_test() 79{ 80 int rc = pthread_mutex_init(&mutex, nullptr); 81 if (rc < 0) { 82 perror("pthread_mutex_init"); 83 return 1; 84 } 85 pthread_t thread_id; 86 rc = pthread_create( 87 &thread_id, nullptr, [](void*) -> void* { 88 printf("I'm the secondary thread :^)\n"); 89 for (;;) { 90 pthread_mutex_lock(&mutex); 91 printf("Second thread stole mutex\n"); 92 sleep(1); 93 printf("Second thread giving back mutex\n"); 94 pthread_mutex_unlock(&mutex); 95 sleep(1); 96 } 97 pthread_exit((void*)0xDEADBEEF); 98 return nullptr; 99 }, 100 nullptr); 101 if (rc < 0) { 102 perror("pthread_create"); 103 return 1; 104 } 105 for (;;) { 106 pthread_mutex_lock(&mutex); 107 printf("Obnoxious spam!\n"); 108 pthread_mutex_unlock(&mutex); 109 usleep(10000); 110 } 111 return 0; 112} 113 114int detached_test() 115{ 116 pthread_attr_t attributes; 117 int rc = pthread_attr_init(&attributes); 118 if (rc != 0) { 119 printf("pthread_attr_setdetachstate: %s\n", strerror(rc)); 120 return 1; 121 } 122 123 int detach_state = 99; // clearly invalid 124 rc = pthread_attr_getdetachstate(&attributes, &detach_state); 125 if (rc != 0) { 126 printf("pthread_attr_setdetachstate: %s\n", strerror(rc)); 127 return 2; 128 } 129 printf("Default detach state: %s\n", detach_state == PTHREAD_CREATE_JOINABLE ? "joinable" : "detached"); 130 131 detach_state = PTHREAD_CREATE_DETACHED; 132 rc = pthread_attr_setdetachstate(&attributes, detach_state); 133 if (rc != 0) { 134 printf("pthread_attr_setdetachstate: %s\n", strerror(rc)); 135 return 3; 136 } 137 printf("Set detach state on new thread to detached\n"); 138 139 pthread_t thread_id; 140 rc = pthread_create( 141 &thread_id, &attributes, [](void*) -> void* { 142 printf("I'm the secondary thread :^)\n"); 143 sleep(1); 144 pthread_exit((void*)0xDEADBEEF); 145 return nullptr; 146 }, 147 nullptr); 148 if (rc < 0) { 149 perror("pthread_create"); 150 return 4; 151 } 152 153 void* ret_val; 154 errno = 0; 155 rc = pthread_join(thread_id, &ret_val); 156 if (rc < 0 && errno != EINVAL) { 157 perror("pthread_join"); 158 return 5; 159 } 160 if (errno != EINVAL) { 161 printf("Expected EINVAL! Thread was joinable?\n"); 162 return 6; 163 } 164 165 sleep(2); 166 printf("Thread was created detached. I sure hope it exited on its own.\n"); 167 168 rc = pthread_attr_destroy(&attributes); 169 if (rc != 0) { 170 printf("pthread_attr_setdetachstate: %s\n", strerror(rc)); 171 return 7; 172 } 173 174 return 0; 175} 176 177int priority_test() 178{ 179 pthread_attr_t attributes; 180 int rc = pthread_attr_init(&attributes); 181 if (rc != 0) { 182 printf("pthread_attr_init: %s\n", strerror(rc)); 183 return 1; 184 } 185 186 struct sched_param sched_params; 187 rc = pthread_attr_getschedparam(&attributes, &sched_params); 188 if (rc != 0) { 189 printf("pthread_attr_getschedparam: %s\n", strerror(rc)); 190 return 2; 191 } 192 printf("Default priority: %d\n", sched_params.sched_priority); 193 194 sched_params.sched_priority = 3; 195 rc = pthread_attr_setschedparam(&attributes, &sched_params); 196 if (rc != 0) { 197 printf("pthread_attr_setschedparam: %s\n", strerror(rc)); 198 return 3; 199 } 200 printf("Set thread priority to 3\n"); 201 202 pthread_t thread_id; 203 rc = pthread_create( 204 &thread_id, &attributes, [](void*) -> void* { 205 printf("I'm the secondary thread :^)\n"); 206 sleep(1); 207 pthread_exit((void*)0xDEADBEEF); 208 return nullptr; 209 }, 210 nullptr); 211 if (rc < 0) { 212 perror("pthread_create"); 213 return 4; 214 } 215 216 rc = pthread_join(thread_id, nullptr); 217 if (rc < 0) { 218 perror("pthread_join"); 219 return 5; 220 } 221 222 rc = pthread_attr_destroy(&attributes); 223 if (rc != 0) { 224 printf("pthread_attr_destroy: %s\n", strerror(rc)); 225 return 6; 226 } 227 228 return 0; 229} 230 231int stack_size_test() 232{ 233 pthread_attr_t attributes; 234 int rc = pthread_attr_init(&attributes); 235 if (rc != 0) { 236 printf("pthread_attr_init: %s\n", strerror(rc)); 237 return 1; 238 } 239 240 size_t stack_size; 241 rc = pthread_attr_getstacksize(&attributes, &stack_size); 242 if (rc != 0) { 243 printf("pthread_attr_getstacksize: %s\n", strerror(rc)); 244 return 2; 245 } 246 printf("Default stack size: %zu\n", stack_size); 247 248 stack_size = 8 * 1024 * 1024; 249 rc = pthread_attr_setstacksize(&attributes, stack_size); 250 if (rc != 0) { 251 printf("pthread_attr_setstacksize: %s\n", strerror(rc)); 252 return 3; 253 } 254 printf("Set thread stack size to 8 MB\n"); 255 256 pthread_t thread_id; 257 rc = pthread_create( 258 &thread_id, &attributes, [](void*) -> void* { 259 printf("I'm the secondary thread :^)\n"); 260 sleep(1); 261 pthread_exit((void*)0xDEADBEEF); 262 return nullptr; 263 }, 264 nullptr); 265 if (rc < 0) { 266 perror("pthread_create"); 267 return 4; 268 } 269 270 rc = pthread_join(thread_id, nullptr); 271 if (rc < 0) { 272 perror("pthread_join"); 273 return 5; 274 } 275 276 rc = pthread_attr_destroy(&attributes); 277 if (rc != 0) { 278 printf("pthread_attr_destroy: %s\n", strerror(rc)); 279 return 6; 280 } 281 282 return 0; 283} 284 285int set_stack_test() 286{ 287 pthread_attr_t attributes; 288 int rc = pthread_attr_init(&attributes); 289 if (rc < 0) { 290 printf("pthread_attr_init: %s\n", strerror(rc)); 291 return 1; 292 } 293 294 size_t stack_size = 8 * 1024 * 1024; 295 void* stack_addr = mmap_with_name(nullptr, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 0, 0, "Cool stack"); 296 297 if (!stack_addr) { 298 perror("mmap_with_name"); 299 return -1; 300 } 301 302 rc = pthread_attr_setstack(&attributes, stack_addr, stack_size); 303 if (rc != 0) { 304 printf("pthread_attr_setstack: %s\n", strerror(rc)); 305 return 2; 306 } 307 printf("Set thread stack to %p, size %zu\n", stack_addr, stack_size); 308 309 size_t stack_size_verify; 310 void* stack_addr_verify; 311 312 rc = pthread_attr_getstack(&attributes, &stack_addr_verify, &stack_size_verify); 313 if (rc != 0) { 314 printf("pthread_attr_getstack: %s\n", strerror(rc)); 315 return 3; 316 } 317 318 if (stack_addr != stack_addr_verify || stack_size != stack_size_verify) { 319 printf("Stack address and size don't match! addr: %p %p, size: %zu %zu\n", stack_addr, stack_addr_verify, stack_size, stack_size_verify); 320 return 4; 321 } 322 323 pthread_t thread_id; 324 rc = pthread_create( 325 &thread_id, &attributes, [](void*) -> void* { 326 printf("I'm the secondary thread :^)\n"); 327 sleep(1); 328 pthread_exit((void*)0xDEADBEEF); 329 return nullptr; 330 }, 331 nullptr); 332 if (rc < 0) { 333 perror("pthread_create"); 334 return 5; 335 } 336 337 rc = pthread_join(thread_id, nullptr); 338 if (rc < 0) { 339 perror("pthread_join"); 340 return 6; 341 } 342 343 rc = pthread_attr_destroy(&attributes); 344 if (rc != 0) { 345 printf("pthread_attr_destroy: %s\n", strerror(rc)); 346 return 7; 347 } 348 349 return 0; 350}