1 /* 2 * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 * 6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 10 11 /*! Threading routines */ 12 13 14 #include <thread.h> 15 16 #include <errno.h> 17 #include <malloc.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <sys/resource.h> 22 23 #include <algorithm> 24 25 #include <OS.h> 26 27 #include <util/AutoLock.h> 28 29 #include <arch/debug.h> 30 #include <boot/kernel_args.h> 31 #include <condition_variable.h> 32 #include <cpu.h> 33 #include <int.h> 34 #include <kimage.h> 35 #include <kscheduler.h> 36 #include <ksignal.h> 37 #include <Notifications.h> 38 #include <real_time_clock.h> 39 #include <slab/Slab.h> 40 #include <smp.h> 41 #include <syscalls.h> 42 #include <syscall_restart.h> 43 #include <team.h> 44 #include <tls.h> 45 #include <user_runtime.h> 46 #include <user_thread.h> 47 #include <vfs.h> 48 #include <vm/vm.h> 49 #include <vm/VMAddressSpace.h> 50 #include <wait_for_objects.h> 51 52 #include "TeamThreadTables.h" 53 54 55 //#define TRACE_THREAD 56 #ifdef TRACE_THREAD 57 # define TRACE(x) dprintf x 58 #else 59 # define TRACE(x) ; 60 #endif 61 62 63 #define THREAD_MAX_MESSAGE_SIZE 65536 64 65 66 // #pragma mark - ThreadHashTable 67 68 69 typedef BKernel::TeamThreadTable<Thread> ThreadHashTable; 70 71 72 // thread list 73 static Thread sIdleThreads[B_MAX_CPU_COUNT]; 74 static ThreadHashTable sThreadHash; 75 static spinlock sThreadHashLock = B_SPINLOCK_INITIALIZER; 76 static thread_id sNextThreadID = 2; 77 // ID 1 is allocated for the kernel by Team::Team() behind our back 78 79 // some arbitrarily chosen limits -- should probably depend on the available 80 // memory (the limit is not yet enforced) 81 static int32 sMaxThreads = 4096; 82 static int32 sUsedThreads = 0; 83 84 85 struct UndertakerEntry : DoublyLinkedListLinkImpl<UndertakerEntry> { 86 Thread* thread; 87 team_id teamID; 88 89 UndertakerEntry(Thread* thread, team_id teamID) 90 : 91 thread(thread), 92 teamID(teamID) 93 { 94 } 95 }; 96 97 98 struct ThreadEntryArguments { 99 status_t (*kernelFunction)(void* argument); 100 void* argument; 101 bool enterUserland; 102 }; 103 104 struct UserThreadEntryArguments : ThreadEntryArguments { 105 addr_t userlandEntry; 106 void* userlandArgument1; 107 void* userlandArgument2; 108 pthread_t pthread; 109 arch_fork_arg* forkArgs; 110 uint32 flags; 111 }; 112 113 114 class ThreadNotificationService : public DefaultNotificationService { 115 public: 116 ThreadNotificationService() 117 : DefaultNotificationService("threads") 118 { 119 } 120 121 void Notify(uint32 eventCode, team_id teamID, thread_id threadID, 122 Thread* thread = NULL) 123 { 124 char eventBuffer[128]; 125 KMessage event; 126 event.SetTo(eventBuffer, sizeof(eventBuffer), THREAD_MONITOR); 127 event.AddInt32("event", eventCode); 128 event.AddInt32("team", teamID); 129 event.AddInt32("thread", threadID); 130 if (thread != NULL) 131 event.AddPointer("threadStruct", thread); 132 133 DefaultNotificationService::Notify(event, eventCode); 134 } 135 136 void Notify(uint32 eventCode, Thread* thread) 137 { 138 return Notify(eventCode, thread->id, thread->team->id, thread); 139 } 140 }; 141 142 143 static DoublyLinkedList<UndertakerEntry> sUndertakerEntries; 144 static ConditionVariable sUndertakerCondition; 145 static ThreadNotificationService sNotificationService; 146 147 148 // object cache to allocate thread structures from 149 static object_cache* sThreadCache; 150 151 152 // #pragma mark - Thread 153 154 155 /*! Constructs a thread. 156 157 \param name The thread's name. 158 \param threadID The ID to be assigned to the new thread. If 159 \code < 0 \endcode a fresh one is allocated. 160 \param cpu The CPU the thread shall be assigned. 161 */ 162 Thread::Thread(const char* name, thread_id threadID, struct cpu_ent* cpu) 163 : 164 flags(0), 165 serial_number(-1), 166 hash_next(NULL), 167 team_next(NULL), 168 queue_next(NULL), 169 priority(-1), 170 next_priority(-1), 171 io_priority(-1), 172 cpu(cpu), 173 previous_cpu(NULL), 174 pinned_to_cpu(0), 175 sig_block_mask(0), 176 sigsuspend_original_unblocked_mask(0), 177 user_signal_context(NULL), 178 signal_stack_base(0), 179 signal_stack_size(0), 180 signal_stack_enabled(false), 181 in_kernel(true), 182 was_yielded(false), 183 user_thread(NULL), 184 fault_handler(0), 185 page_faults_allowed(1), 186 team(NULL), 187 select_infos(NULL), 188 kernel_stack_area(-1), 189 kernel_stack_base(0), 190 user_stack_area(-1), 191 user_stack_base(0), 192 user_local_storage(0), 193 kernel_errno(0), 194 user_time(0), 195 kernel_time(0), 196 last_time(0), 197 cpu_clock_offset(0), 198 post_interrupt_callback(NULL), 199 post_interrupt_data(NULL) 200 { 201 id = threadID >= 0 ? threadID : allocate_thread_id(); 202 visible = false; 203 204 // init locks 205 char lockName[32]; 206 snprintf(lockName, sizeof(lockName), "Thread:%" B_PRId32, id); 207 mutex_init_etc(&fLock, lockName, MUTEX_FLAG_CLONE_NAME); 208 209 B_INITIALIZE_SPINLOCK(&time_lock); 210 211 // init name 212 if (name != NULL) 213 strlcpy(this->name, name, B_OS_NAME_LENGTH); 214 else 215 strcpy(this->name, "unnamed thread"); 216 217 alarm.period = 0; 218 219 exit.status = 0; 220 221 list_init(&exit.waiters); 222 223 exit.sem = -1; 224 msg.write_sem = -1; 225 msg.read_sem = -1; 226 227 // add to thread table -- yet invisible 228 InterruptsSpinLocker threadHashLocker(sThreadHashLock); 229 sThreadHash.Insert(this); 230 } 231 232 233 Thread::~Thread() 234 { 235 // Delete resources that should actually be deleted by the thread itself, 236 // when it exited, but that might still exist, if the thread was never run. 237 238 if (user_stack_area >= 0) 239 delete_area(user_stack_area); 240 241 DeleteUserTimers(false); 242 243 // delete the resources, that may remain in either case 244 245 if (kernel_stack_area >= 0) 246 delete_area(kernel_stack_area); 247 248 fPendingSignals.Clear(); 249 250 if (exit.sem >= 0) 251 delete_sem(exit.sem); 252 if (msg.write_sem >= 0) 253 delete_sem(msg.write_sem); 254 if (msg.read_sem >= 0) 255 delete_sem(msg.read_sem); 256 257 scheduler_on_thread_destroy(this); 258 259 mutex_destroy(&fLock); 260 261 // remove from thread table 262 InterruptsSpinLocker threadHashLocker(sThreadHashLock); 263 sThreadHash.Remove(this); 264 } 265 266 267 /*static*/ status_t 268 Thread::Create(const char* name, Thread*& _thread) 269 { 270 Thread* thread = new Thread(name, -1, NULL); 271 if (thread == NULL) 272 return B_NO_MEMORY; 273 274 status_t error = thread->Init(false); 275 if (error != B_OK) { 276 delete thread; 277 return error; 278 } 279 280 _thread = thread; 281 return B_OK; 282 } 283 284 285 /*static*/ Thread* 286 Thread::Get(thread_id id) 287 { 288 InterruptsSpinLocker threadHashLocker(sThreadHashLock); 289 Thread* thread = sThreadHash.Lookup(id); 290 if (thread != NULL) 291 thread->AcquireReference(); 292 return thread; 293 } 294 295 296 /*static*/ Thread* 297 Thread::GetAndLock(thread_id id) 298 { 299 // look it up and acquire a reference 300 InterruptsSpinLocker threadHashLocker(sThreadHashLock); 301 Thread* thread = sThreadHash.Lookup(id); 302 if (thread == NULL) 303 return NULL; 304 305 thread->AcquireReference(); 306 threadHashLocker.Unlock(); 307 308 // lock and check, if it is still in the hash table 309 thread->Lock(); 310 threadHashLocker.Lock(); 311 312 if (sThreadHash.Lookup(id) == thread) 313 return thread; 314 315 threadHashLocker.Unlock(); 316 317 // nope, the thread is no longer in the hash table 318 thread->UnlockAndReleaseReference(); 319 320 return NULL; 321 } 322 323 324 /*static*/ Thread* 325 Thread::GetDebug(thread_id id) 326 { 327 return sThreadHash.Lookup(id, false); 328 } 329 330 331 /*static*/ bool 332 Thread::IsAlive(thread_id id) 333 { 334 InterruptsSpinLocker threadHashLocker(sThreadHashLock); 335 return sThreadHash.Lookup(id) != NULL; 336 } 337 338 339 void* 340 Thread::operator new(size_t size) 341 { 342 return object_cache_alloc(sThreadCache, 0); 343 } 344 345 346 void* 347 Thread::operator new(size_t, void* pointer) 348 { 349 return pointer; 350 } 351 352 353 void 354 Thread::operator delete(void* pointer, size_t size) 355 { 356 object_cache_free(sThreadCache, pointer, 0); 357 } 358 359 360 status_t 361 Thread::Init(bool idleThread) 362 { 363 status_t error = scheduler_on_thread_create(this, idleThread); 364 if (error != B_OK) 365 return error; 366 367 char temp[64]; 368 sprintf(temp, "thread_%ld_retcode_sem", id); 369 exit.sem = create_sem(0, temp); 370 if (exit.sem < 0) 371 return exit.sem; 372 373 sprintf(temp, "%s send", name); 374 msg.write_sem = create_sem(1, temp); 375 if (msg.write_sem < 0) 376 return msg.write_sem; 377 378 sprintf(temp, "%s receive", name); 379 msg.read_sem = create_sem(0, temp); 380 if (msg.read_sem < 0) 381 return msg.read_sem; 382 383 error = arch_thread_init_thread_struct(this); 384 if (error != B_OK) 385 return error; 386 387 return B_OK; 388 } 389 390 391 /*! Checks whether the thread is still in the thread hash table. 392 */ 393 bool 394 Thread::IsAlive() const 395 { 396 InterruptsSpinLocker threadHashLocker(sThreadHashLock); 397 398 return sThreadHash.Lookup(id) != NULL; 399 } 400 401 402 void 403 Thread::ResetSignalsOnExec() 404 { 405 // We are supposed keep the pending signals and the signal mask. Only the 406 // signal stack, if set, shall be unset. 407 408 sigsuspend_original_unblocked_mask = 0; 409 user_signal_context = NULL; 410 signal_stack_base = 0; 411 signal_stack_size = 0; 412 signal_stack_enabled = false; 413 } 414 415 416 /*! Adds the given user timer to the thread and, if user-defined, assigns it an 417 ID. 418 419 The caller must hold the thread's lock. 420 421 \param timer The timer to be added. If it doesn't have an ID yet, it is 422 considered user-defined and will be assigned an ID. 423 \return \c B_OK, if the timer was added successfully, another error code 424 otherwise. 425 */ 426 status_t 427 Thread::AddUserTimer(UserTimer* timer) 428 { 429 // If the timer is user-defined, check timer limit and increment 430 // user-defined count. 431 if (timer->ID() < 0 && !team->CheckAddUserDefinedTimer()) 432 return EAGAIN; 433 434 fUserTimers.AddTimer(timer); 435 436 return B_OK; 437 } 438 439 440 /*! Removes the given user timer from the thread. 441 442 The caller must hold the thread's lock. 443 444 \param timer The timer to be removed. 445 446 */ 447 void 448 Thread::RemoveUserTimer(UserTimer* timer) 449 { 450 fUserTimers.RemoveTimer(timer); 451 452 if (timer->ID() >= USER_TIMER_FIRST_USER_DEFINED_ID) 453 team->UserDefinedTimersRemoved(1); 454 } 455 456 457 /*! Deletes all (or all user-defined) user timers of the thread. 458 459 The caller must hold the thread's lock. 460 461 \param userDefinedOnly If \c true, only the user-defined timers are deleted, 462 otherwise all timers are deleted. 463 */ 464 void 465 Thread::DeleteUserTimers(bool userDefinedOnly) 466 { 467 int32 count = fUserTimers.DeleteTimers(userDefinedOnly); 468 team->UserDefinedTimersRemoved(count); 469 } 470 471 472 void 473 Thread::DeactivateCPUTimeUserTimers() 474 { 475 while (ThreadTimeUserTimer* timer = fCPUTimeUserTimers.Head()) 476 timer->Deactivate(); 477 } 478 479 480 // #pragma mark - ThreadListIterator 481 482 483 ThreadListIterator::ThreadListIterator() 484 { 485 // queue the entry 486 InterruptsSpinLocker locker(sThreadHashLock); 487 sThreadHash.InsertIteratorEntry(&fEntry); 488 } 489 490 491 ThreadListIterator::~ThreadListIterator() 492 { 493 // remove the entry 494 InterruptsSpinLocker locker(sThreadHashLock); 495 sThreadHash.RemoveIteratorEntry(&fEntry); 496 } 497 498 499 Thread* 500 ThreadListIterator::Next() 501 { 502 // get the next team -- if there is one, get reference for it 503 InterruptsSpinLocker locker(sThreadHashLock); 504 Thread* thread = sThreadHash.NextElement(&fEntry); 505 if (thread != NULL) 506 thread->AcquireReference(); 507 508 return thread; 509 } 510 511 512 // #pragma mark - ThreadCreationAttributes 513 514 515 ThreadCreationAttributes::ThreadCreationAttributes(thread_func function, 516 const char* name, int32 priority, void* arg, team_id team, 517 Thread* thread) 518 { 519 this->entry = NULL; 520 this->name = name; 521 this->priority = priority; 522 this->args1 = NULL; 523 this->args2 = NULL; 524 this->stack_address = NULL; 525 this->stack_size = 0; 526 this->pthread = NULL; 527 this->flags = 0; 528 this->team = team >= 0 ? team : team_get_kernel_team()->id; 529 this->thread = thread; 530 this->signal_mask = 0; 531 this->additional_stack_size = 0; 532 this->kernelEntry = function; 533 this->kernelArgument = arg; 534 this->forkArgs = NULL; 535 } 536 537 538 /*! Initializes the structure from a userland structure. 539 \param userAttributes The userland structure (must be a userland address). 540 \param nameBuffer A character array of at least size B_OS_NAME_LENGTH, 541 which will be used for the \c name field, if the userland structure has 542 a name. The buffer must remain valid as long as this structure is in 543 use afterwards (or until it is reinitialized). 544 \return \c B_OK, if the initialization went fine, another error code 545 otherwise. 546 */ 547 status_t 548 ThreadCreationAttributes::InitFromUserAttributes( 549 const thread_creation_attributes* userAttributes, char* nameBuffer) 550 { 551 if (userAttributes == NULL || !IS_USER_ADDRESS(userAttributes) 552 || user_memcpy((thread_creation_attributes*)this, userAttributes, 553 sizeof(thread_creation_attributes)) != B_OK) { 554 return B_BAD_ADDRESS; 555 } 556 557 if (stack_size != 0 558 && (stack_size < MIN_USER_STACK_SIZE 559 || stack_size > MAX_USER_STACK_SIZE)) { 560 return B_BAD_VALUE; 561 } 562 563 if (entry == NULL || !IS_USER_ADDRESS(entry) 564 || (stack_address != NULL && !IS_USER_ADDRESS(stack_address)) 565 || (name != NULL && (!IS_USER_ADDRESS(name) 566 || user_strlcpy(nameBuffer, name, B_OS_NAME_LENGTH) < 0))) { 567 return B_BAD_ADDRESS; 568 } 569 570 name = name != NULL ? nameBuffer : "user thread"; 571 572 // kernel only attributes (not in thread_creation_attributes): 573 Thread* currentThread = thread_get_current_thread(); 574 team = currentThread->team->id; 575 thread = NULL; 576 signal_mask = currentThread->sig_block_mask; 577 // inherit the current thread's signal mask 578 additional_stack_size = 0; 579 kernelEntry = NULL; 580 kernelArgument = NULL; 581 forkArgs = NULL; 582 583 return B_OK; 584 } 585 586 587 // #pragma mark - private functions 588 589 590 /*! Inserts a thread into a team. 591 The caller must hold the team's lock, the thread's lock, and the scheduler 592 lock. 593 */ 594 static void 595 insert_thread_into_team(Team *team, Thread *thread) 596 { 597 thread->team_next = team->thread_list; 598 team->thread_list = thread; 599 team->num_threads++; 600 601 if (team->num_threads == 1) { 602 // this was the first thread 603 team->main_thread = thread; 604 } 605 thread->team = team; 606 } 607 608 609 /*! Removes a thread from a team. 610 The caller must hold the team's lock, the thread's lock, and the scheduler 611 lock. 612 */ 613 static void 614 remove_thread_from_team(Team *team, Thread *thread) 615 { 616 Thread *temp, *last = NULL; 617 618 for (temp = team->thread_list; temp != NULL; temp = temp->team_next) { 619 if (temp == thread) { 620 if (last == NULL) 621 team->thread_list = temp->team_next; 622 else 623 last->team_next = temp->team_next; 624 625 team->num_threads--; 626 break; 627 } 628 last = temp; 629 } 630 } 631 632 633 static status_t 634 enter_userspace(Thread* thread, UserThreadEntryArguments* args) 635 { 636 status_t error = arch_thread_init_tls(thread); 637 if (error != B_OK) { 638 dprintf("Failed to init TLS for new userland thread \"%s\" (%" B_PRId32 639 ")\n", thread->name, thread->id); 640 free(args->forkArgs); 641 return error; 642 } 643 644 user_debug_update_new_thread_flags(thread); 645 646 // init the thread's user_thread 647 user_thread* userThread = thread->user_thread; 648 userThread->pthread = args->pthread; 649 userThread->flags = 0; 650 userThread->wait_status = B_OK; 651 userThread->defer_signals 652 = (args->flags & THREAD_CREATION_FLAG_DEFER_SIGNALS) != 0 ? 1 : 0; 653 userThread->pending_signals = 0; 654 655 if (args->forkArgs != NULL) { 656 // This is a fork()ed thread. Copy the fork args onto the stack and 657 // free them. 658 arch_fork_arg archArgs = *args->forkArgs; 659 free(args->forkArgs); 660 661 arch_restore_fork_frame(&archArgs); 662 // this one won't return here 663 return B_ERROR; 664 } 665 666 // Jump to the entry point in user space. Only returns, if something fails. 667 return arch_thread_enter_userspace(thread, args->userlandEntry, 668 args->userlandArgument1, args->userlandArgument2); 669 } 670 671 672 status_t 673 thread_enter_userspace_new_team(Thread* thread, addr_t entryFunction, 674 void* argument1, void* argument2) 675 { 676 UserThreadEntryArguments entryArgs; 677 entryArgs.kernelFunction = NULL; 678 entryArgs.argument = NULL; 679 entryArgs.enterUserland = true; 680 entryArgs.userlandEntry = (addr_t)entryFunction; 681 entryArgs.userlandArgument1 = argument1; 682 entryArgs.userlandArgument2 = argument2; 683 entryArgs.pthread = NULL; 684 entryArgs.forkArgs = NULL; 685 entryArgs.flags = 0; 686 687 return enter_userspace(thread, &entryArgs); 688 } 689 690 691 static void 692 common_thread_entry(void* _args) 693 { 694 Thread* thread = thread_get_current_thread(); 695 696 // The thread is new and has been scheduled the first time. 697 698 // start CPU time based user timers 699 if (thread->HasActiveCPUTimeUserTimers() 700 || thread->team->HasActiveCPUTimeUserTimers()) { 701 user_timer_continue_cpu_timers(thread, thread->cpu->previous_thread); 702 } 703 704 // notify the user debugger code 705 if ((thread->flags & THREAD_FLAGS_DEBUGGER_INSTALLED) != 0) 706 user_debug_thread_scheduled(thread); 707 708 // start tracking time 709 thread->last_time = system_time(); 710 711 // unlock the scheduler lock and enable interrupts 712 release_spinlock(&gSchedulerLock); 713 enable_interrupts(); 714 715 // call the kernel function, if any 716 ThreadEntryArguments* args = (ThreadEntryArguments*)_args; 717 if (args->kernelFunction != NULL) 718 args->kernelFunction(args->argument); 719 720 // If requested, enter userland, now. 721 if (args->enterUserland) { 722 enter_userspace(thread, (UserThreadEntryArguments*)args); 723 // only returns or error 724 725 // If that's the team's main thread, init the team exit info. 726 if (thread == thread->team->main_thread) 727 team_init_exit_info_on_error(thread->team); 728 } 729 730 // we're done 731 thread_exit(); 732 } 733 734 735 /*! Prepares the given thread's kernel stack for executing its entry function. 736 737 The data pointed to by \a data of size \a dataSize are copied to the 738 thread's kernel stack. A pointer to the copy's data is passed to the entry 739 function. The entry function is common_thread_entry(). 740 741 \param thread The thread. 742 \param data Pointer to data to be copied to the thread's stack and passed 743 to the entry function. 744 \param dataSize The size of \a data. 745 */ 746 static void 747 init_thread_kernel_stack(Thread* thread, const void* data, size_t dataSize) 748 { 749 uint8* stack = (uint8*)thread->kernel_stack_base; 750 uint8* stackTop = (uint8*)thread->kernel_stack_top; 751 752 // clear (or rather invalidate) the kernel stack contents, if compiled with 753 // debugging 754 #if KDEBUG > 0 755 # if defined(DEBUG_KERNEL_STACKS) && defined(STACK_GROWS_DOWNWARDS) 756 memset((void*)(stack + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE), 0xcc, 757 KERNEL_STACK_SIZE); 758 # else 759 memset(stack, 0xcc, KERNEL_STACK_SIZE); 760 # endif 761 #endif 762 763 // copy the data onto the stack, with 16-byte alignment to be on the safe 764 // side 765 void* clonedData; 766 #ifdef STACK_GROWS_DOWNWARDS 767 clonedData = (void*)ROUNDDOWN((addr_t)stackTop - dataSize, 16); 768 stackTop = (uint8*)clonedData; 769 #else 770 clonedData = (void*)ROUNDUP((addr_t)stack, 16); 771 stack = (uint8*)clonedData + ROUNDUP(dataSize, 16); 772 #endif 773 774 memcpy(clonedData, data, dataSize); 775 776 arch_thread_init_kthread_stack(thread, stack, stackTop, 777 &common_thread_entry, clonedData); 778 } 779 780 781 static status_t 782 create_thread_user_stack(Team* team, Thread* thread, void* _stackBase, 783 size_t stackSize, size_t additionalSize, char* nameBuffer) 784 { 785 area_id stackArea = -1; 786 uint8* stackBase = (uint8*)_stackBase; 787 788 if (stackBase != NULL) { 789 // A stack has been specified. It must be large enough to hold the 790 // TLS space at least. 791 STATIC_ASSERT(TLS_SIZE < MIN_USER_STACK_SIZE); 792 if (stackSize < MIN_USER_STACK_SIZE) 793 return B_BAD_VALUE; 794 795 stackBase -= TLS_SIZE; 796 } 797 798 if (stackBase == NULL) { 799 // No user-defined stack -- allocate one. For non-main threads the stack 800 // will be between USER_STACK_REGION and the main thread stack area. For 801 // a main thread the position is fixed. 802 803 if (stackSize == 0) { 804 // Use the default size (a different one for a main thread). 805 stackSize = thread->id == team->id 806 ? USER_MAIN_THREAD_STACK_SIZE : USER_STACK_SIZE; 807 } else { 808 // Verify that the given stack size is large enough. 809 if (stackSize < MIN_USER_STACK_SIZE - TLS_SIZE) 810 return B_BAD_VALUE; 811 812 stackSize = PAGE_ALIGN(stackSize); 813 } 814 stackSize += USER_STACK_GUARD_PAGES * B_PAGE_SIZE; 815 816 size_t areaSize = PAGE_ALIGN(stackSize + TLS_SIZE + additionalSize); 817 818 snprintf(nameBuffer, B_OS_NAME_LENGTH, "%s_%ld_stack", thread->name, 819 thread->id); 820 821 virtual_address_restrictions virtualRestrictions = {}; 822 if (thread->id == team->id) { 823 // The main thread gets a fixed position at the top of the stack 824 // address range. 825 stackBase = (uint8*)(USER_STACK_REGION + USER_STACK_REGION_SIZE 826 - areaSize); 827 virtualRestrictions.address_specification = B_EXACT_ADDRESS; 828 829 } else { 830 // not a main thread 831 stackBase = (uint8*)(addr_t)USER_STACK_REGION; 832 virtualRestrictions.address_specification = B_BASE_ADDRESS; 833 } 834 virtualRestrictions.address = (void*)stackBase; 835 836 physical_address_restrictions physicalRestrictions = {}; 837 838 stackArea = create_area_etc(team->id, nameBuffer, 839 areaSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA | B_STACK_AREA, 840 0, &virtualRestrictions, &physicalRestrictions, 841 (void**)&stackBase); 842 if (stackArea < 0) 843 return stackArea; 844 } 845 846 // set the stack 847 ThreadLocker threadLocker(thread); 848 thread->user_stack_base = (addr_t)stackBase; 849 thread->user_stack_size = stackSize; 850 thread->user_stack_area = stackArea; 851 852 return B_OK; 853 } 854 855 856 status_t 857 thread_create_user_stack(Team* team, Thread* thread, void* stackBase, 858 size_t stackSize, size_t additionalSize) 859 { 860 char nameBuffer[B_OS_NAME_LENGTH]; 861 return create_thread_user_stack(team, thread, stackBase, stackSize, 862 additionalSize, nameBuffer); 863 } 864 865 866 /*! Creates a new thread. 867 868 \param attributes The thread creation attributes, specifying the team in 869 which to create the thread, as well as a whole bunch of other arguments. 870 \param kernel \c true, if a kernel-only thread shall be created, \c false, 871 if the thread shall also be able to run in userland. 872 \return The ID of the newly created thread (>= 0) or an error code on 873 failure. 874 */ 875 thread_id 876 thread_create_thread(const ThreadCreationAttributes& attributes, bool kernel) 877 { 878 status_t status = B_OK; 879 880 TRACE(("thread_create_thread(%s, thread = %p, %s)\n", attributes.name, 881 attributes.thread, kernel ? "kernel" : "user")); 882 883 // get the team 884 Team* team = Team::Get(attributes.team); 885 if (team == NULL) 886 return B_BAD_TEAM_ID; 887 BReference<Team> teamReference(team, true); 888 889 // If a thread object is given, acquire a reference to it, otherwise create 890 // a new thread object with the given attributes. 891 Thread* thread = attributes.thread; 892 if (thread != NULL) { 893 thread->AcquireReference(); 894 } else { 895 status = Thread::Create(attributes.name, thread); 896 if (status != B_OK) 897 return status; 898 } 899 BReference<Thread> threadReference(thread, true); 900 901 thread->team = team; 902 // set already, so, if something goes wrong, the team pointer is 903 // available for deinitialization 904 thread->priority = attributes.priority == -1 905 ? B_NORMAL_PRIORITY : attributes.priority; 906 thread->next_priority = thread->priority; 907 thread->state = B_THREAD_SUSPENDED; 908 thread->next_state = B_THREAD_SUSPENDED; 909 910 thread->sig_block_mask = attributes.signal_mask; 911 912 // init debug structure 913 init_thread_debug_info(&thread->debug_info); 914 915 // create the kernel stack 916 char stackName[B_OS_NAME_LENGTH]; 917 snprintf(stackName, B_OS_NAME_LENGTH, "%s_%ld_kstack", thread->name, 918 thread->id); 919 thread->kernel_stack_area = create_area(stackName, 920 (void **)&thread->kernel_stack_base, B_ANY_KERNEL_ADDRESS, 921 KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE, 922 B_FULL_LOCK, 923 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_KERNEL_STACK_AREA); 924 925 if (thread->kernel_stack_area < 0) { 926 // we're not yet part of a team, so we can just bail out 927 status = thread->kernel_stack_area; 928 929 dprintf("create_thread: error creating kernel stack: %s!\n", 930 strerror(status)); 931 932 return status; 933 } 934 935 thread->kernel_stack_top = thread->kernel_stack_base + KERNEL_STACK_SIZE 936 + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE; 937 938 if (kernel) { 939 // Init the thread's kernel stack. It will start executing 940 // common_thread_entry() with the arguments we prepare here. 941 ThreadEntryArguments entryArgs; 942 entryArgs.kernelFunction = attributes.kernelEntry; 943 entryArgs.argument = attributes.kernelArgument; 944 entryArgs.enterUserland = false; 945 946 init_thread_kernel_stack(thread, &entryArgs, sizeof(entryArgs)); 947 } else { 948 // create the userland stack, if the thread doesn't have one yet 949 if (thread->user_stack_base == 0) { 950 status = create_thread_user_stack(team, thread, 951 attributes.stack_address, attributes.stack_size, 952 attributes.additional_stack_size, stackName); 953 if (status != B_OK) 954 return status; 955 } 956 957 // Init the thread's kernel stack. It will start executing 958 // common_thread_entry() with the arguments we prepare here. 959 UserThreadEntryArguments entryArgs; 960 entryArgs.kernelFunction = attributes.kernelEntry; 961 entryArgs.argument = attributes.kernelArgument; 962 entryArgs.enterUserland = true; 963 entryArgs.userlandEntry = (addr_t)attributes.entry; 964 entryArgs.userlandArgument1 = attributes.args1; 965 entryArgs.userlandArgument2 = attributes.args2; 966 entryArgs.pthread = attributes.pthread; 967 entryArgs.forkArgs = attributes.forkArgs; 968 entryArgs.flags = attributes.flags; 969 970 init_thread_kernel_stack(thread, &entryArgs, sizeof(entryArgs)); 971 972 // create the pre-defined thread timers 973 status = user_timer_create_thread_timers(team, thread); 974 if (status != B_OK) 975 return status; 976 } 977 978 // lock the team and see, if it is still alive 979 TeamLocker teamLocker(team); 980 if (team->state >= TEAM_STATE_SHUTDOWN) 981 return B_BAD_TEAM_ID; 982 983 bool debugNewThread = false; 984 if (!kernel) { 985 // allocate the user_thread structure, if not already allocated 986 if (thread->user_thread == NULL) { 987 thread->user_thread = team_allocate_user_thread(team); 988 if (thread->user_thread == NULL) 989 return B_NO_MEMORY; 990 } 991 992 // If the new thread belongs to the same team as the current thread, it 993 // may inherit some of the thread debug flags. 994 Thread* currentThread = thread_get_current_thread(); 995 if (currentThread != NULL && currentThread->team == team) { 996 // inherit all user flags... 997 int32 debugFlags = atomic_get(¤tThread->debug_info.flags) 998 & B_THREAD_DEBUG_USER_FLAG_MASK; 999 1000 // ... save the syscall tracing flags, unless explicitely specified 1001 if (!(debugFlags & B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS)) { 1002 debugFlags &= ~(B_THREAD_DEBUG_PRE_SYSCALL 1003 | B_THREAD_DEBUG_POST_SYSCALL); 1004 } 1005 1006 thread->debug_info.flags = debugFlags; 1007 1008 // stop the new thread, if desired 1009 debugNewThread = debugFlags & B_THREAD_DEBUG_STOP_CHILD_THREADS; 1010 } 1011 } 1012 1013 // We're going to make the thread live, now. The thread itself will take 1014 // over a reference to its Thread object. We acquire another reference for 1015 // our own use (and threadReference remains armed). 1016 thread->AcquireReference(); 1017 1018 ThreadLocker threadLocker(thread); 1019 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 1020 SpinLocker threadHashLocker(sThreadHashLock); 1021 1022 // make thread visible in global hash/list 1023 thread->visible = true; 1024 sUsedThreads++; 1025 scheduler_on_thread_init(thread); 1026 1027 // Debug the new thread, if the parent thread required that (see above), 1028 // or the respective global team debug flag is set. But only, if a 1029 // debugger is installed for the team. 1030 if (!kernel) { 1031 int32 teamDebugFlags = atomic_get(&team->debug_info.flags); 1032 debugNewThread |= (teamDebugFlags & B_TEAM_DEBUG_STOP_NEW_THREADS) != 0; 1033 if (debugNewThread 1034 && (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) != 0) { 1035 thread->debug_info.flags |= B_THREAD_DEBUG_STOP; 1036 } 1037 } 1038 1039 // insert thread into team 1040 insert_thread_into_team(team, thread); 1041 1042 threadHashLocker.Unlock(); 1043 schedulerLocker.Unlock(); 1044 threadLocker.Unlock(); 1045 teamLocker.Unlock(); 1046 1047 // notify listeners 1048 sNotificationService.Notify(THREAD_ADDED, thread); 1049 1050 return thread->id; 1051 } 1052 1053 1054 static status_t 1055 undertaker(void* /*args*/) 1056 { 1057 while (true) { 1058 // wait for a thread to bury 1059 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 1060 1061 while (sUndertakerEntries.IsEmpty()) { 1062 ConditionVariableEntry conditionEntry; 1063 sUndertakerCondition.Add(&conditionEntry); 1064 schedulerLocker.Unlock(); 1065 1066 conditionEntry.Wait(); 1067 1068 schedulerLocker.Lock(); 1069 } 1070 1071 UndertakerEntry* _entry = sUndertakerEntries.RemoveHead(); 1072 schedulerLocker.Unlock(); 1073 1074 UndertakerEntry entry = *_entry; 1075 // we need a copy, since the original entry is on the thread's stack 1076 1077 // we've got an entry 1078 Thread* thread = entry.thread; 1079 1080 // remove this thread from from the kernel team -- this makes it 1081 // unaccessible 1082 Team* kernelTeam = team_get_kernel_team(); 1083 TeamLocker kernelTeamLocker(kernelTeam); 1084 thread->Lock(); 1085 schedulerLocker.Lock(); 1086 1087 remove_thread_from_team(kernelTeam, thread); 1088 1089 schedulerLocker.Unlock(); 1090 kernelTeamLocker.Unlock(); 1091 1092 // free the thread structure 1093 thread->UnlockAndReleaseReference(); 1094 } 1095 1096 // can never get here 1097 return B_OK; 1098 } 1099 1100 1101 /*! Returns the semaphore the thread is currently waiting on. 1102 1103 The return value is purely informative. 1104 The caller must hold the scheduler lock. 1105 1106 \param thread The thread. 1107 \return The ID of the semaphore the thread is currently waiting on or \c -1, 1108 if it isn't waiting on a semaphore. 1109 */ 1110 static sem_id 1111 get_thread_wait_sem(Thread* thread) 1112 { 1113 if (thread->state == B_THREAD_WAITING 1114 && thread->wait.type == THREAD_BLOCK_TYPE_SEMAPHORE) { 1115 return (sem_id)(addr_t)thread->wait.object; 1116 } 1117 return -1; 1118 } 1119 1120 1121 /*! Fills the thread_info structure with information from the specified thread. 1122 The caller must hold the thread's lock and the scheduler lock. 1123 */ 1124 static void 1125 fill_thread_info(Thread *thread, thread_info *info, size_t size) 1126 { 1127 info->thread = thread->id; 1128 info->team = thread->team->id; 1129 1130 strlcpy(info->name, thread->name, B_OS_NAME_LENGTH); 1131 1132 info->sem = -1; 1133 1134 if (thread->state == B_THREAD_WAITING) { 1135 info->state = B_THREAD_WAITING; 1136 1137 switch (thread->wait.type) { 1138 case THREAD_BLOCK_TYPE_SNOOZE: 1139 info->state = B_THREAD_ASLEEP; 1140 break; 1141 1142 case THREAD_BLOCK_TYPE_SEMAPHORE: 1143 { 1144 sem_id sem = (sem_id)(addr_t)thread->wait.object; 1145 if (sem == thread->msg.read_sem) 1146 info->state = B_THREAD_RECEIVING; 1147 else 1148 info->sem = sem; 1149 break; 1150 } 1151 1152 case THREAD_BLOCK_TYPE_CONDITION_VARIABLE: 1153 default: 1154 break; 1155 } 1156 } else 1157 info->state = (thread_state)thread->state; 1158 1159 info->priority = thread->priority; 1160 info->stack_base = (void *)thread->user_stack_base; 1161 info->stack_end = (void *)(thread->user_stack_base 1162 + thread->user_stack_size); 1163 1164 InterruptsSpinLocker threadTimeLocker(thread->time_lock); 1165 info->user_time = thread->user_time; 1166 info->kernel_time = thread->kernel_time; 1167 } 1168 1169 1170 static status_t 1171 send_data_etc(thread_id id, int32 code, const void *buffer, size_t bufferSize, 1172 int32 flags) 1173 { 1174 // get the thread 1175 Thread *target = Thread::Get(id); 1176 if (target == NULL) 1177 return B_BAD_THREAD_ID; 1178 BReference<Thread> targetReference(target, true); 1179 1180 // get the write semaphore 1181 ThreadLocker targetLocker(target); 1182 sem_id cachedSem = target->msg.write_sem; 1183 targetLocker.Unlock(); 1184 1185 if (bufferSize > THREAD_MAX_MESSAGE_SIZE) 1186 return B_NO_MEMORY; 1187 1188 status_t status = acquire_sem_etc(cachedSem, 1, flags, 0); 1189 if (status == B_INTERRUPTED) { 1190 // we got interrupted by a signal 1191 return status; 1192 } 1193 if (status != B_OK) { 1194 // Any other acquisition problems may be due to thread deletion 1195 return B_BAD_THREAD_ID; 1196 } 1197 1198 void* data; 1199 if (bufferSize > 0) { 1200 data = malloc(bufferSize); 1201 if (data == NULL) 1202 return B_NO_MEMORY; 1203 if (user_memcpy(data, buffer, bufferSize) != B_OK) { 1204 free(data); 1205 return B_BAD_DATA; 1206 } 1207 } else 1208 data = NULL; 1209 1210 targetLocker.Lock(); 1211 1212 // The target thread could have been deleted at this point. 1213 if (!target->IsAlive()) { 1214 targetLocker.Unlock(); 1215 free(data); 1216 return B_BAD_THREAD_ID; 1217 } 1218 1219 // Save message informations 1220 target->msg.sender = thread_get_current_thread()->id; 1221 target->msg.code = code; 1222 target->msg.size = bufferSize; 1223 target->msg.buffer = data; 1224 cachedSem = target->msg.read_sem; 1225 1226 targetLocker.Unlock(); 1227 1228 release_sem(cachedSem); 1229 return B_OK; 1230 } 1231 1232 1233 static int32 1234 receive_data_etc(thread_id *_sender, void *buffer, size_t bufferSize, 1235 int32 flags) 1236 { 1237 Thread *thread = thread_get_current_thread(); 1238 size_t size; 1239 int32 code; 1240 1241 status_t status = acquire_sem_etc(thread->msg.read_sem, 1, flags, 0); 1242 if (status != B_OK) { 1243 // Actually, we're not supposed to return error codes 1244 // but since the only reason this can fail is that we 1245 // were killed, it's probably okay to do so (but also 1246 // meaningless). 1247 return status; 1248 } 1249 1250 if (buffer != NULL && bufferSize != 0 && thread->msg.buffer != NULL) { 1251 size = min_c(bufferSize, thread->msg.size); 1252 status = user_memcpy(buffer, thread->msg.buffer, size); 1253 if (status != B_OK) { 1254 free(thread->msg.buffer); 1255 release_sem(thread->msg.write_sem); 1256 return status; 1257 } 1258 } 1259 1260 *_sender = thread->msg.sender; 1261 code = thread->msg.code; 1262 1263 free(thread->msg.buffer); 1264 release_sem(thread->msg.write_sem); 1265 1266 return code; 1267 } 1268 1269 1270 static status_t 1271 common_getrlimit(int resource, struct rlimit * rlp) 1272 { 1273 if (!rlp) 1274 return B_BAD_ADDRESS; 1275 1276 switch (resource) { 1277 case RLIMIT_NOFILE: 1278 case RLIMIT_NOVMON: 1279 return vfs_getrlimit(resource, rlp); 1280 1281 case RLIMIT_CORE: 1282 rlp->rlim_cur = 0; 1283 rlp->rlim_max = 0; 1284 return B_OK; 1285 1286 case RLIMIT_STACK: 1287 { 1288 Thread *thread = thread_get_current_thread(); 1289 rlp->rlim_cur = thread->user_stack_size; 1290 rlp->rlim_max = thread->user_stack_size; 1291 return B_OK; 1292 } 1293 1294 default: 1295 return EINVAL; 1296 } 1297 1298 return B_OK; 1299 } 1300 1301 1302 static status_t 1303 common_setrlimit(int resource, const struct rlimit * rlp) 1304 { 1305 if (!rlp) 1306 return B_BAD_ADDRESS; 1307 1308 switch (resource) { 1309 case RLIMIT_NOFILE: 1310 case RLIMIT_NOVMON: 1311 return vfs_setrlimit(resource, rlp); 1312 1313 case RLIMIT_CORE: 1314 // We don't support core file, so allow settings to 0/0 only. 1315 if (rlp->rlim_cur != 0 || rlp->rlim_max != 0) 1316 return EINVAL; 1317 return B_OK; 1318 1319 default: 1320 return EINVAL; 1321 } 1322 1323 return B_OK; 1324 } 1325 1326 1327 static status_t 1328 common_snooze_etc(bigtime_t timeout, clockid_t clockID, uint32 flags, 1329 bigtime_t* _remainingTime) 1330 { 1331 switch (clockID) { 1332 case CLOCK_REALTIME: 1333 // make sure the B_TIMEOUT_REAL_TIME_BASE flag is set and fall 1334 // through 1335 flags |= B_TIMEOUT_REAL_TIME_BASE; 1336 case CLOCK_MONOTONIC: 1337 { 1338 // Store the start time, for the case that we get interrupted and 1339 // need to return the remaining time. For absolute timeouts we can 1340 // still get he time later, if needed. 1341 bigtime_t startTime 1342 = _remainingTime != NULL && (flags & B_RELATIVE_TIMEOUT) != 0 1343 ? system_time() : 0; 1344 1345 Thread* thread = thread_get_current_thread(); 1346 1347 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 1348 1349 thread_prepare_to_block(thread, flags, THREAD_BLOCK_TYPE_SNOOZE, 1350 NULL); 1351 status_t status = thread_block_with_timeout_locked(flags, timeout); 1352 1353 if (status == B_TIMED_OUT || status == B_WOULD_BLOCK) 1354 return B_OK; 1355 1356 // If interrupted, compute the remaining time, if requested. 1357 if (status == B_INTERRUPTED && _remainingTime != NULL) { 1358 if ((flags & B_RELATIVE_TIMEOUT) != 0) { 1359 *_remainingTime = std::max( 1360 startTime + timeout - system_time(), (bigtime_t)0); 1361 } else { 1362 bigtime_t now = (flags & B_TIMEOUT_REAL_TIME_BASE) != 0 1363 ? real_time_clock_usecs() : system_time(); 1364 *_remainingTime = std::max(timeout - now, (bigtime_t)0); 1365 } 1366 } 1367 1368 return status; 1369 } 1370 1371 case CLOCK_THREAD_CPUTIME_ID: 1372 // Waiting for ourselves to do something isn't particularly 1373 // productive. 1374 return B_BAD_VALUE; 1375 1376 case CLOCK_PROCESS_CPUTIME_ID: 1377 default: 1378 // We don't have to support those, but we are allowed to. Could be 1379 // done be creating a UserTimer on the fly with a custom UserEvent 1380 // that would just wake us up. 1381 return ENOTSUP; 1382 } 1383 } 1384 1385 1386 // #pragma mark - debugger calls 1387 1388 1389 static int 1390 make_thread_unreal(int argc, char **argv) 1391 { 1392 int32 id = -1; 1393 1394 if (argc > 2) { 1395 print_debugger_command_usage(argv[0]); 1396 return 0; 1397 } 1398 1399 if (argc > 1) 1400 id = strtoul(argv[1], NULL, 0); 1401 1402 for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); 1403 Thread* thread = it.Next();) { 1404 if (id != -1 && thread->id != id) 1405 continue; 1406 1407 if (thread->priority > B_DISPLAY_PRIORITY) { 1408 thread->priority = thread->next_priority = B_NORMAL_PRIORITY; 1409 kprintf("thread %ld made unreal\n", thread->id); 1410 } 1411 } 1412 1413 return 0; 1414 } 1415 1416 1417 static int 1418 set_thread_prio(int argc, char **argv) 1419 { 1420 int32 id; 1421 int32 prio; 1422 1423 if (argc > 3 || argc < 2) { 1424 print_debugger_command_usage(argv[0]); 1425 return 0; 1426 } 1427 1428 prio = strtoul(argv[1], NULL, 0); 1429 if (prio > THREAD_MAX_SET_PRIORITY) 1430 prio = THREAD_MAX_SET_PRIORITY; 1431 if (prio < THREAD_MIN_SET_PRIORITY) 1432 prio = THREAD_MIN_SET_PRIORITY; 1433 1434 if (argc > 2) 1435 id = strtoul(argv[2], NULL, 0); 1436 else 1437 id = thread_get_current_thread()->id; 1438 1439 bool found = false; 1440 for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); 1441 Thread* thread = it.Next();) { 1442 if (thread->id != id) 1443 continue; 1444 thread->priority = thread->next_priority = prio; 1445 kprintf("thread %ld set to priority %ld\n", id, prio); 1446 found = true; 1447 break; 1448 } 1449 if (!found) 1450 kprintf("thread %ld (%#lx) not found\n", id, id); 1451 1452 return 0; 1453 } 1454 1455 1456 static int 1457 make_thread_suspended(int argc, char **argv) 1458 { 1459 int32 id; 1460 1461 if (argc > 2) { 1462 print_debugger_command_usage(argv[0]); 1463 return 0; 1464 } 1465 1466 if (argc == 1) 1467 id = thread_get_current_thread()->id; 1468 else 1469 id = strtoul(argv[1], NULL, 0); 1470 1471 bool found = false; 1472 for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); 1473 Thread* thread = it.Next();) { 1474 if (thread->id != id) 1475 continue; 1476 1477 thread->next_state = B_THREAD_SUSPENDED; 1478 kprintf("thread %ld suspended\n", id); 1479 found = true; 1480 break; 1481 } 1482 if (!found) 1483 kprintf("thread %ld (%#lx) not found\n", id, id); 1484 1485 return 0; 1486 } 1487 1488 1489 static int 1490 make_thread_resumed(int argc, char **argv) 1491 { 1492 int32 id; 1493 1494 if (argc != 2) { 1495 print_debugger_command_usage(argv[0]); 1496 return 0; 1497 } 1498 1499 // force user to enter a thread id, as using 1500 // the current thread is usually not intended 1501 id = strtoul(argv[1], NULL, 0); 1502 1503 bool found = false; 1504 for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); 1505 Thread* thread = it.Next();) { 1506 if (thread->id != id) 1507 continue; 1508 1509 if (thread->state == B_THREAD_SUSPENDED) { 1510 scheduler_enqueue_in_run_queue(thread); 1511 kprintf("thread %ld resumed\n", thread->id); 1512 } 1513 found = true; 1514 break; 1515 } 1516 if (!found) 1517 kprintf("thread %ld (%#lx) not found\n", id, id); 1518 1519 return 0; 1520 } 1521 1522 1523 static int 1524 drop_into_debugger(int argc, char **argv) 1525 { 1526 status_t err; 1527 int32 id; 1528 1529 if (argc > 2) { 1530 print_debugger_command_usage(argv[0]); 1531 return 0; 1532 } 1533 1534 if (argc == 1) 1535 id = thread_get_current_thread()->id; 1536 else 1537 id = strtoul(argv[1], NULL, 0); 1538 1539 err = _user_debug_thread(id); 1540 // TODO: This is a non-trivial syscall doing some locking, so this is 1541 // really nasty and may go seriously wrong. 1542 if (err) 1543 kprintf("drop failed\n"); 1544 else 1545 kprintf("thread %ld dropped into user debugger\n", id); 1546 1547 return 0; 1548 } 1549 1550 1551 /*! Returns a user-readable string for a thread state. 1552 Only for use in the kernel debugger. 1553 */ 1554 static const char * 1555 state_to_text(Thread *thread, int32 state) 1556 { 1557 switch (state) { 1558 case B_THREAD_READY: 1559 return "ready"; 1560 1561 case B_THREAD_RUNNING: 1562 return "running"; 1563 1564 case B_THREAD_WAITING: 1565 { 1566 if (thread != NULL) { 1567 switch (thread->wait.type) { 1568 case THREAD_BLOCK_TYPE_SNOOZE: 1569 return "zzz"; 1570 1571 case THREAD_BLOCK_TYPE_SEMAPHORE: 1572 { 1573 sem_id sem = (sem_id)(addr_t)thread->wait.object; 1574 if (sem == thread->msg.read_sem) 1575 return "receive"; 1576 break; 1577 } 1578 } 1579 } 1580 1581 return "waiting"; 1582 } 1583 1584 case B_THREAD_SUSPENDED: 1585 return "suspended"; 1586 1587 case THREAD_STATE_FREE_ON_RESCHED: 1588 return "death"; 1589 1590 default: 1591 return "UNKNOWN"; 1592 } 1593 } 1594 1595 1596 static void 1597 print_thread_list_table_head() 1598 { 1599 kprintf("thread id state wait for object cpu pri stack " 1600 " team name\n"); 1601 } 1602 1603 1604 static void 1605 _dump_thread_info(Thread *thread, bool shortInfo) 1606 { 1607 if (shortInfo) { 1608 kprintf("%p %6ld %-10s", thread, thread->id, state_to_text(thread, 1609 thread->state)); 1610 1611 // does it block on a semaphore or a condition variable? 1612 if (thread->state == B_THREAD_WAITING) { 1613 switch (thread->wait.type) { 1614 case THREAD_BLOCK_TYPE_SEMAPHORE: 1615 { 1616 sem_id sem = (sem_id)(addr_t)thread->wait.object; 1617 if (sem == thread->msg.read_sem) 1618 kprintf(" "); 1619 else 1620 kprintf("sem %12ld ", sem); 1621 break; 1622 } 1623 1624 case THREAD_BLOCK_TYPE_CONDITION_VARIABLE: 1625 kprintf("cvar %p ", thread->wait.object); 1626 break; 1627 1628 case THREAD_BLOCK_TYPE_SNOOZE: 1629 kprintf(" "); 1630 break; 1631 1632 case THREAD_BLOCK_TYPE_SIGNAL: 1633 kprintf("signal "); 1634 break; 1635 1636 case THREAD_BLOCK_TYPE_MUTEX: 1637 kprintf("mutex %p ", thread->wait.object); 1638 break; 1639 1640 case THREAD_BLOCK_TYPE_RW_LOCK: 1641 kprintf("rwlock %p ", thread->wait.object); 1642 break; 1643 1644 case THREAD_BLOCK_TYPE_OTHER: 1645 kprintf("other "); 1646 break; 1647 1648 default: 1649 kprintf("??? %p ", thread->wait.object); 1650 break; 1651 } 1652 } else 1653 kprintf(" - "); 1654 1655 // on which CPU does it run? 1656 if (thread->cpu) 1657 kprintf("%2d", thread->cpu->cpu_num); 1658 else 1659 kprintf(" -"); 1660 1661 kprintf("%4ld %p%5ld %s\n", thread->priority, 1662 (void *)thread->kernel_stack_base, thread->team->id, 1663 thread->name != NULL ? thread->name : "<NULL>"); 1664 1665 return; 1666 } 1667 1668 // print the long info 1669 1670 struct thread_death_entry *death = NULL; 1671 1672 kprintf("THREAD: %p\n", thread); 1673 kprintf("id: %ld (%#lx)\n", thread->id, thread->id); 1674 kprintf("serial_number: %" B_PRId64 "\n", thread->serial_number); 1675 kprintf("name: \"%s\"\n", thread->name); 1676 kprintf("hash_next: %p\nteam_next: %p\nq_next: %p\n", 1677 thread->hash_next, thread->team_next, thread->queue_next); 1678 kprintf("priority: %ld (next %ld, I/O: %ld)\n", thread->priority, 1679 thread->next_priority, thread->io_priority); 1680 kprintf("state: %s\n", state_to_text(thread, thread->state)); 1681 kprintf("next_state: %s\n", state_to_text(thread, thread->next_state)); 1682 kprintf("cpu: %p ", thread->cpu); 1683 if (thread->cpu) 1684 kprintf("(%d)\n", thread->cpu->cpu_num); 1685 else 1686 kprintf("\n"); 1687 kprintf("sig_pending: %#llx (blocked: %#llx" 1688 ", before sigsuspend(): %#llx)\n", 1689 (long long)thread->ThreadPendingSignals(), 1690 (long long)thread->sig_block_mask, 1691 (long long)thread->sigsuspend_original_unblocked_mask); 1692 kprintf("in_kernel: %d\n", thread->in_kernel); 1693 1694 if (thread->state == B_THREAD_WAITING) { 1695 kprintf("waiting for: "); 1696 1697 switch (thread->wait.type) { 1698 case THREAD_BLOCK_TYPE_SEMAPHORE: 1699 { 1700 sem_id sem = (sem_id)(addr_t)thread->wait.object; 1701 if (sem == thread->msg.read_sem) 1702 kprintf("data\n"); 1703 else 1704 kprintf("semaphore %ld\n", sem); 1705 break; 1706 } 1707 1708 case THREAD_BLOCK_TYPE_CONDITION_VARIABLE: 1709 kprintf("condition variable %p\n", thread->wait.object); 1710 break; 1711 1712 case THREAD_BLOCK_TYPE_SNOOZE: 1713 kprintf("snooze()\n"); 1714 break; 1715 1716 case THREAD_BLOCK_TYPE_SIGNAL: 1717 kprintf("signal\n"); 1718 break; 1719 1720 case THREAD_BLOCK_TYPE_MUTEX: 1721 kprintf("mutex %p\n", thread->wait.object); 1722 break; 1723 1724 case THREAD_BLOCK_TYPE_RW_LOCK: 1725 kprintf("rwlock %p\n", thread->wait.object); 1726 break; 1727 1728 case THREAD_BLOCK_TYPE_OTHER: 1729 kprintf("other (%s)\n", (char*)thread->wait.object); 1730 break; 1731 1732 default: 1733 kprintf("unknown (%p)\n", thread->wait.object); 1734 break; 1735 } 1736 } 1737 1738 kprintf("fault_handler: %p\n", (void *)thread->fault_handler); 1739 kprintf("team: %p, \"%s\"\n", thread->team, 1740 thread->team->Name()); 1741 kprintf(" exit.sem: %ld\n", thread->exit.sem); 1742 kprintf(" exit.status: %#lx (%s)\n", thread->exit.status, strerror(thread->exit.status)); 1743 kprintf(" exit.waiters:\n"); 1744 while ((death = (struct thread_death_entry*)list_get_next_item( 1745 &thread->exit.waiters, death)) != NULL) { 1746 kprintf("\t%p (thread %ld)\n", death, death->thread); 1747 } 1748 1749 kprintf("kernel_stack_area: %ld\n", thread->kernel_stack_area); 1750 kprintf("kernel_stack_base: %p\n", (void *)thread->kernel_stack_base); 1751 kprintf("user_stack_area: %ld\n", thread->user_stack_area); 1752 kprintf("user_stack_base: %p\n", (void *)thread->user_stack_base); 1753 kprintf("user_local_storage: %p\n", (void *)thread->user_local_storage); 1754 kprintf("user_thread: %p\n", (void *)thread->user_thread); 1755 kprintf("kernel_errno: %#x (%s)\n", thread->kernel_errno, 1756 strerror(thread->kernel_errno)); 1757 kprintf("kernel_time: %Ld\n", thread->kernel_time); 1758 kprintf("user_time: %Ld\n", thread->user_time); 1759 kprintf("flags: 0x%lx\n", thread->flags); 1760 kprintf("architecture dependant section:\n"); 1761 arch_thread_dump_info(&thread->arch_info); 1762 } 1763 1764 1765 static int 1766 dump_thread_info(int argc, char **argv) 1767 { 1768 bool shortInfo = false; 1769 int argi = 1; 1770 if (argi < argc && strcmp(argv[argi], "-s") == 0) { 1771 shortInfo = true; 1772 print_thread_list_table_head(); 1773 argi++; 1774 } 1775 1776 if (argi == argc) { 1777 _dump_thread_info(thread_get_current_thread(), shortInfo); 1778 return 0; 1779 } 1780 1781 for (; argi < argc; argi++) { 1782 const char *name = argv[argi]; 1783 int32 id = strtoul(name, NULL, 0); 1784 1785 if (IS_KERNEL_ADDRESS(id)) { 1786 // semi-hack 1787 _dump_thread_info((Thread *)id, shortInfo); 1788 continue; 1789 } 1790 1791 // walk through the thread list, trying to match name or id 1792 bool found = false; 1793 for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); 1794 Thread* thread = it.Next();) { 1795 if (!strcmp(name, thread->name) || thread->id == id) { 1796 _dump_thread_info(thread, shortInfo); 1797 found = true; 1798 break; 1799 } 1800 } 1801 1802 if (!found) 1803 kprintf("thread \"%s\" (%ld) doesn't exist!\n", name, id); 1804 } 1805 1806 return 0; 1807 } 1808 1809 1810 static int 1811 dump_thread_list(int argc, char **argv) 1812 { 1813 bool realTimeOnly = false; 1814 bool calling = false; 1815 const char *callSymbol = NULL; 1816 addr_t callStart = 0; 1817 addr_t callEnd = 0; 1818 int32 requiredState = 0; 1819 team_id team = -1; 1820 sem_id sem = -1; 1821 1822 if (!strcmp(argv[0], "realtime")) 1823 realTimeOnly = true; 1824 else if (!strcmp(argv[0], "ready")) 1825 requiredState = B_THREAD_READY; 1826 else if (!strcmp(argv[0], "running")) 1827 requiredState = B_THREAD_RUNNING; 1828 else if (!strcmp(argv[0], "waiting")) { 1829 requiredState = B_THREAD_WAITING; 1830 1831 if (argc > 1) { 1832 sem = strtoul(argv[1], NULL, 0); 1833 if (sem == 0) 1834 kprintf("ignoring invalid semaphore argument.\n"); 1835 } 1836 } else if (!strcmp(argv[0], "calling")) { 1837 if (argc < 2) { 1838 kprintf("Need to give a symbol name or start and end arguments.\n"); 1839 return 0; 1840 } else if (argc == 3) { 1841 callStart = parse_expression(argv[1]); 1842 callEnd = parse_expression(argv[2]); 1843 } else 1844 callSymbol = argv[1]; 1845 1846 calling = true; 1847 } else if (argc > 1) { 1848 team = strtoul(argv[1], NULL, 0); 1849 if (team == 0) 1850 kprintf("ignoring invalid team argument.\n"); 1851 } 1852 1853 print_thread_list_table_head(); 1854 1855 for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); 1856 Thread* thread = it.Next();) { 1857 // filter out threads not matching the search criteria 1858 if ((requiredState && thread->state != requiredState) 1859 || (calling && !arch_debug_contains_call(thread, callSymbol, 1860 callStart, callEnd)) 1861 || (sem > 0 && get_thread_wait_sem(thread) != sem) 1862 || (team > 0 && thread->team->id != team) 1863 || (realTimeOnly && thread->priority < B_REAL_TIME_DISPLAY_PRIORITY)) 1864 continue; 1865 1866 _dump_thread_info(thread, true); 1867 } 1868 return 0; 1869 } 1870 1871 1872 // #pragma mark - private kernel API 1873 1874 1875 void 1876 thread_exit(void) 1877 { 1878 cpu_status state; 1879 Thread* thread = thread_get_current_thread(); 1880 Team* team = thread->team; 1881 Team* kernelTeam = team_get_kernel_team(); 1882 thread_id parentID = -1; 1883 status_t status; 1884 struct thread_debug_info debugInfo; 1885 team_id teamID = team->id; 1886 1887 TRACE(("thread %ld exiting w/return code %#lx\n", thread->id, 1888 thread->exit.status)); 1889 1890 if (!are_interrupts_enabled()) 1891 panic("thread_exit() called with interrupts disabled!\n"); 1892 1893 // boost our priority to get this over with 1894 thread->priority = thread->next_priority = B_URGENT_DISPLAY_PRIORITY; 1895 1896 if (team != kernelTeam) { 1897 // Cancel previously installed alarm timer, if any. Hold the scheduler 1898 // lock to make sure that when cancel_timer() returns, the alarm timer 1899 // hook will not be invoked anymore (since 1900 // B_TIMER_ACQUIRE_SCHEDULER_LOCK is used). 1901 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 1902 cancel_timer(&thread->alarm); 1903 schedulerLocker.Unlock(); 1904 1905 // Delete all user timers associated with the thread. 1906 ThreadLocker threadLocker(thread); 1907 thread->DeleteUserTimers(false); 1908 1909 // detach the thread's user thread 1910 user_thread* userThread = thread->user_thread; 1911 thread->user_thread = NULL; 1912 1913 threadLocker.Unlock(); 1914 1915 // Delete the thread's user thread, if it's not the main thread. If it 1916 // is, we can save the work, since it will be deleted with the team's 1917 // address space. 1918 if (thread != team->main_thread) 1919 team_free_user_thread(team, userThread); 1920 } 1921 1922 // remember the user stack area -- we will delete it below 1923 area_id userStackArea = -1; 1924 if (team->address_space != NULL && thread->user_stack_area >= 0) { 1925 userStackArea = thread->user_stack_area; 1926 thread->user_stack_area = -1; 1927 } 1928 1929 struct job_control_entry *death = NULL; 1930 struct thread_death_entry* threadDeathEntry = NULL; 1931 bool deleteTeam = false; 1932 port_id debuggerPort = -1; 1933 1934 if (team != kernelTeam) { 1935 user_debug_thread_exiting(thread); 1936 1937 if (team->main_thread == thread) { 1938 // The main thread is exiting. Shut down the whole team. 1939 deleteTeam = true; 1940 1941 // kill off all other threads and the user debugger facilities 1942 debuggerPort = team_shutdown_team(team); 1943 1944 // acquire necessary locks, which are: process group lock, kernel 1945 // team lock, parent team lock, and the team lock 1946 team->LockProcessGroup(); 1947 kernelTeam->Lock(); 1948 team->LockTeamAndParent(true); 1949 } else { 1950 threadDeathEntry 1951 = (thread_death_entry*)malloc(sizeof(thread_death_entry)); 1952 1953 // acquire necessary locks, which are: kernel team lock and the team 1954 // lock 1955 kernelTeam->Lock(); 1956 team->Lock(); 1957 } 1958 1959 ThreadLocker threadLocker(thread); 1960 1961 state = disable_interrupts(); 1962 1963 // swap address spaces, to make sure we're running on the kernel's pgdir 1964 vm_swap_address_space(team->address_space, VMAddressSpace::Kernel()); 1965 1966 SpinLocker schedulerLocker(gSchedulerLock); 1967 // removing the thread and putting its death entry to the parent 1968 // team needs to be an atomic operation 1969 1970 // remember how long this thread lasted 1971 bigtime_t now = system_time(); 1972 InterruptsSpinLocker threadTimeLocker(thread->time_lock); 1973 thread->kernel_time += now - thread->last_time; 1974 thread->last_time = now; 1975 threadTimeLocker.Unlock(); 1976 1977 team->dead_threads_kernel_time += thread->kernel_time; 1978 team->dead_threads_user_time += thread->user_time; 1979 1980 // stop/update thread/team CPU time user timers 1981 if (thread->HasActiveCPUTimeUserTimers() 1982 || team->HasActiveCPUTimeUserTimers()) { 1983 user_timer_stop_cpu_timers(thread, NULL); 1984 } 1985 1986 // deactivate CPU time user timers for the thread 1987 if (thread->HasActiveCPUTimeUserTimers()) 1988 thread->DeactivateCPUTimeUserTimers(); 1989 1990 // put the thread into the kernel team until it dies 1991 remove_thread_from_team(team, thread); 1992 insert_thread_into_team(kernelTeam, thread); 1993 1994 if (team->death_entry != NULL) { 1995 if (--team->death_entry->remaining_threads == 0) 1996 team->death_entry->condition.NotifyOne(true, B_OK); 1997 } 1998 1999 if (deleteTeam) { 2000 Team* parent = team->parent; 2001 2002 // remember who our parent was so we can send a signal 2003 parentID = parent->id; 2004 2005 // Set the team job control state to "dead" and detach the job 2006 // control entry from our team struct. 2007 team_set_job_control_state(team, JOB_CONTROL_STATE_DEAD, NULL, 2008 true); 2009 death = team->job_control_entry; 2010 team->job_control_entry = NULL; 2011 2012 if (death != NULL) { 2013 death->InitDeadState(); 2014 2015 // team_set_job_control_state() already moved our entry 2016 // into the parent's list. We just check the soft limit of 2017 // death entries. 2018 if (parent->dead_children.count > MAX_DEAD_CHILDREN) { 2019 death = parent->dead_children.entries.RemoveHead(); 2020 parent->dead_children.count--; 2021 } else 2022 death = NULL; 2023 } 2024 2025 schedulerLocker.Unlock(); 2026 restore_interrupts(state); 2027 2028 threadLocker.Unlock(); 2029 2030 // Get a temporary reference to the team's process group 2031 // -- team_remove_team() removes the team from the group, which 2032 // might destroy it otherwise and we wouldn't be able to unlock it. 2033 ProcessGroup* group = team->group; 2034 group->AcquireReference(); 2035 2036 pid_t foregroundGroupToSignal; 2037 team_remove_team(team, foregroundGroupToSignal); 2038 2039 // unlock everything but the parent team 2040 team->Unlock(); 2041 if (parent != kernelTeam) 2042 kernelTeam->Unlock(); 2043 group->Unlock(); 2044 group->ReleaseReference(); 2045 2046 // Send SIGCHLD to the parent as long as we still have its lock. 2047 // This makes job control state change + signalling atomic. 2048 Signal childSignal(SIGCHLD, team->exit.reason, B_OK, team->id); 2049 if (team->exit.reason == CLD_EXITED) { 2050 childSignal.SetStatus(team->exit.status); 2051 } else { 2052 childSignal.SetStatus(team->exit.signal); 2053 childSignal.SetSendingUser(team->exit.signaling_user); 2054 } 2055 send_signal_to_team(parent, childSignal, B_DO_NOT_RESCHEDULE); 2056 2057 // also unlock the parent 2058 parent->Unlock(); 2059 2060 // If the team was a session leader with controlling TTY, we have 2061 // to send SIGHUP to the foreground process group. 2062 if (foregroundGroupToSignal >= 0) { 2063 Signal groupSignal(SIGHUP, SI_USER, B_OK, team->id); 2064 send_signal_to_process_group(foregroundGroupToSignal, 2065 groupSignal, B_DO_NOT_RESCHEDULE); 2066 } 2067 } else { 2068 // The thread is not the main thread. We store a thread death entry 2069 // for it, unless someone is already waiting for it. 2070 if (threadDeathEntry != NULL 2071 && list_is_empty(&thread->exit.waiters)) { 2072 threadDeathEntry->thread = thread->id; 2073 threadDeathEntry->status = thread->exit.status; 2074 2075 // add entry -- remove an old one, if we hit the limit 2076 list_add_item(&team->dead_threads, threadDeathEntry); 2077 team->dead_threads_count++; 2078 threadDeathEntry = NULL; 2079 2080 if (team->dead_threads_count > MAX_DEAD_THREADS) { 2081 threadDeathEntry 2082 = (thread_death_entry*)list_remove_head_item( 2083 &team->dead_threads); 2084 team->dead_threads_count--; 2085 } 2086 } 2087 2088 schedulerLocker.Unlock(); 2089 restore_interrupts(state); 2090 2091 threadLocker.Unlock(); 2092 team->Unlock(); 2093 kernelTeam->Unlock(); 2094 } 2095 2096 TRACE(("thread_exit: thread %ld now a kernel thread!\n", thread->id)); 2097 } 2098 2099 free(threadDeathEntry); 2100 2101 // delete the team if we're its main thread 2102 if (deleteTeam) { 2103 team_delete_team(team, debuggerPort); 2104 2105 // we need to delete any death entry that made it to here 2106 delete death; 2107 } 2108 2109 ThreadLocker threadLocker(thread); 2110 2111 state = disable_interrupts(); 2112 SpinLocker schedulerLocker(gSchedulerLock); 2113 2114 // mark invisible in global hash/list, so it's no longer accessible 2115 SpinLocker threadHashLocker(sThreadHashLock); 2116 thread->visible = false; 2117 sUsedThreads--; 2118 threadHashLocker.Unlock(); 2119 2120 // Stop debugging for this thread 2121 SpinLocker threadDebugInfoLocker(thread->debug_info.lock); 2122 debugInfo = thread->debug_info; 2123 clear_thread_debug_info(&thread->debug_info, true); 2124 threadDebugInfoLocker.Unlock(); 2125 2126 // Remove the select infos. We notify them a little later. 2127 select_info* selectInfos = thread->select_infos; 2128 thread->select_infos = NULL; 2129 2130 schedulerLocker.Unlock(); 2131 restore_interrupts(state); 2132 2133 threadLocker.Unlock(); 2134 2135 destroy_thread_debug_info(&debugInfo); 2136 2137 // notify select infos 2138 select_info* info = selectInfos; 2139 while (info != NULL) { 2140 select_sync* sync = info->sync; 2141 2142 notify_select_events(info, B_EVENT_INVALID); 2143 info = info->next; 2144 put_select_sync(sync); 2145 } 2146 2147 // notify listeners 2148 sNotificationService.Notify(THREAD_REMOVED, thread); 2149 2150 // shutdown the thread messaging 2151 2152 status = acquire_sem_etc(thread->msg.write_sem, 1, B_RELATIVE_TIMEOUT, 0); 2153 if (status == B_WOULD_BLOCK) { 2154 // there is data waiting for us, so let us eat it 2155 thread_id sender; 2156 2157 delete_sem(thread->msg.write_sem); 2158 // first, let's remove all possibly waiting writers 2159 receive_data_etc(&sender, NULL, 0, B_RELATIVE_TIMEOUT); 2160 } else { 2161 // we probably own the semaphore here, and we're the last to do so 2162 delete_sem(thread->msg.write_sem); 2163 } 2164 // now we can safely remove the msg.read_sem 2165 delete_sem(thread->msg.read_sem); 2166 2167 // fill all death entries and delete the sem that others will use to wait 2168 // for us 2169 { 2170 sem_id cachedExitSem = thread->exit.sem; 2171 2172 ThreadLocker threadLocker(thread); 2173 2174 // make sure no one will grab this semaphore again 2175 thread->exit.sem = -1; 2176 2177 // fill all death entries 2178 thread_death_entry* entry = NULL; 2179 while ((entry = (thread_death_entry*)list_get_next_item( 2180 &thread->exit.waiters, entry)) != NULL) { 2181 entry->status = thread->exit.status; 2182 } 2183 2184 threadLocker.Unlock(); 2185 2186 delete_sem(cachedExitSem); 2187 } 2188 2189 // delete the user stack, if this was a user thread 2190 if (!deleteTeam && userStackArea >= 0) { 2191 // We postponed deleting the user stack until now, since this way all 2192 // notifications for the thread's death are out already and all other 2193 // threads waiting for this thread's death and some object on its stack 2194 // will wake up before we (try to) delete the stack area. Of most 2195 // relevance is probably the case where this is the main thread and 2196 // other threads use objects on its stack -- so we want them terminated 2197 // first. 2198 // When the team is deleted, all areas are deleted anyway, so we don't 2199 // need to do that explicitly in that case. 2200 vm_delete_area(teamID, userStackArea, true); 2201 } 2202 2203 // notify the debugger 2204 if (teamID != kernelTeam->id) 2205 user_debug_thread_deleted(teamID, thread->id); 2206 2207 // enqueue in the undertaker list and reschedule for the last time 2208 UndertakerEntry undertakerEntry(thread, teamID); 2209 2210 disable_interrupts(); 2211 schedulerLocker.Lock(); 2212 2213 sUndertakerEntries.Add(&undertakerEntry); 2214 sUndertakerCondition.NotifyOne(true); 2215 2216 thread->next_state = THREAD_STATE_FREE_ON_RESCHED; 2217 scheduler_reschedule(); 2218 2219 panic("never can get here\n"); 2220 } 2221 2222 2223 /*! Called in the interrupt handler code when a thread enters 2224 the kernel for any reason. 2225 Only tracks time for now. 2226 Interrupts are disabled. 2227 */ 2228 void 2229 thread_at_kernel_entry(bigtime_t now) 2230 { 2231 Thread *thread = thread_get_current_thread(); 2232 2233 TRACE(("thread_at_kernel_entry: entry thread %ld\n", thread->id)); 2234 2235 // track user time 2236 SpinLocker threadTimeLocker(thread->time_lock); 2237 thread->user_time += now - thread->last_time; 2238 thread->last_time = now; 2239 thread->in_kernel = true; 2240 threadTimeLocker.Unlock(); 2241 } 2242 2243 2244 /*! Called whenever a thread exits kernel space to user space. 2245 Tracks time, handles signals, ... 2246 Interrupts must be enabled. When the function returns, interrupts will be 2247 disabled. 2248 The function may not return. This e.g. happens when the thread has received 2249 a deadly signal. 2250 */ 2251 void 2252 thread_at_kernel_exit(void) 2253 { 2254 Thread *thread = thread_get_current_thread(); 2255 2256 TRACE(("thread_at_kernel_exit: exit thread %ld\n", thread->id)); 2257 2258 handle_signals(thread); 2259 2260 disable_interrupts(); 2261 2262 // track kernel time 2263 bigtime_t now = system_time(); 2264 SpinLocker threadTimeLocker(thread->time_lock); 2265 thread->in_kernel = false; 2266 thread->kernel_time += now - thread->last_time; 2267 thread->last_time = now; 2268 } 2269 2270 2271 /*! The quick version of thread_kernel_exit(), in case no signals are pending 2272 and no debugging shall be done. 2273 Interrupts must be disabled. 2274 */ 2275 void 2276 thread_at_kernel_exit_no_signals(void) 2277 { 2278 Thread *thread = thread_get_current_thread(); 2279 2280 TRACE(("thread_at_kernel_exit_no_signals: exit thread %ld\n", thread->id)); 2281 2282 // track kernel time 2283 bigtime_t now = system_time(); 2284 SpinLocker threadTimeLocker(thread->time_lock); 2285 thread->in_kernel = false; 2286 thread->kernel_time += now - thread->last_time; 2287 thread->last_time = now; 2288 } 2289 2290 2291 void 2292 thread_reset_for_exec(void) 2293 { 2294 Thread* thread = thread_get_current_thread(); 2295 2296 ThreadLocker threadLocker(thread); 2297 2298 // delete user-defined timers 2299 thread->DeleteUserTimers(true); 2300 2301 // cancel pre-defined timer 2302 if (UserTimer* timer = thread->UserTimerFor(USER_TIMER_REAL_TIME_ID)) 2303 timer->Cancel(); 2304 2305 // reset user_thread and user stack 2306 thread->user_thread = NULL; 2307 thread->user_stack_area = -1; 2308 thread->user_stack_base = 0; 2309 thread->user_stack_size = 0; 2310 2311 // reset signals 2312 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 2313 2314 thread->ResetSignalsOnExec(); 2315 2316 // reset thread CPU time clock 2317 thread->cpu_clock_offset = -thread->CPUTime(false); 2318 2319 // Note: We don't cancel an alarm. It is supposed to survive exec*(). 2320 } 2321 2322 2323 /*! Insert a thread to the tail of a queue */ 2324 void 2325 thread_enqueue(Thread *thread, struct thread_queue *queue) 2326 { 2327 thread->queue_next = NULL; 2328 if (queue->head == NULL) { 2329 queue->head = thread; 2330 queue->tail = thread; 2331 } else { 2332 queue->tail->queue_next = thread; 2333 queue->tail = thread; 2334 } 2335 } 2336 2337 2338 Thread * 2339 thread_lookat_queue(struct thread_queue *queue) 2340 { 2341 return queue->head; 2342 } 2343 2344 2345 Thread * 2346 thread_dequeue(struct thread_queue *queue) 2347 { 2348 Thread *thread = queue->head; 2349 2350 if (thread != NULL) { 2351 queue->head = thread->queue_next; 2352 if (queue->tail == thread) 2353 queue->tail = NULL; 2354 } 2355 return thread; 2356 } 2357 2358 2359 Thread * 2360 thread_dequeue_id(struct thread_queue *q, thread_id id) 2361 { 2362 Thread *thread; 2363 Thread *last = NULL; 2364 2365 thread = q->head; 2366 while (thread != NULL) { 2367 if (thread->id == id) { 2368 if (last == NULL) 2369 q->head = thread->queue_next; 2370 else 2371 last->queue_next = thread->queue_next; 2372 2373 if (q->tail == thread) 2374 q->tail = last; 2375 break; 2376 } 2377 last = thread; 2378 thread = thread->queue_next; 2379 } 2380 return thread; 2381 } 2382 2383 2384 thread_id 2385 allocate_thread_id() 2386 { 2387 InterruptsSpinLocker threadHashLocker(sThreadHashLock); 2388 2389 // find the next unused ID 2390 thread_id id; 2391 do { 2392 id = sNextThreadID++; 2393 2394 // deal with integer overflow 2395 if (sNextThreadID < 0) 2396 sNextThreadID = 2; 2397 2398 // check whether the ID is already in use 2399 } while (sThreadHash.Lookup(id, false) != NULL); 2400 2401 return id; 2402 } 2403 2404 2405 thread_id 2406 peek_next_thread_id() 2407 { 2408 InterruptsSpinLocker threadHashLocker(sThreadHashLock); 2409 return sNextThreadID; 2410 } 2411 2412 2413 /*! Yield the CPU to other threads. 2414 If \a force is \c true, the thread will almost guaranteedly be unscheduled. 2415 If \c false, it will continue to run, if there's no other thread in ready 2416 state, and if it has a higher priority than the other ready threads, it 2417 still has a good chance to continue. 2418 */ 2419 void 2420 thread_yield(bool force) 2421 { 2422 if (force) { 2423 // snooze for roughly 3 thread quantums 2424 snooze_etc(9000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT); 2425 #if 0 2426 cpu_status state; 2427 2428 Thread *thread = thread_get_current_thread(); 2429 if (thread == NULL) 2430 return; 2431 2432 InterruptsSpinLocker _(gSchedulerLock); 2433 2434 // mark the thread as yielded, so it will not be scheduled next 2435 //thread->was_yielded = true; 2436 thread->next_priority = B_LOWEST_ACTIVE_PRIORITY; 2437 scheduler_reschedule(); 2438 #endif 2439 } else { 2440 Thread *thread = thread_get_current_thread(); 2441 if (thread == NULL) 2442 return; 2443 2444 // Don't force the thread off the CPU, just reschedule. 2445 InterruptsSpinLocker _(gSchedulerLock); 2446 scheduler_reschedule(); 2447 } 2448 } 2449 2450 2451 /*! Kernel private thread creation function. 2452 */ 2453 thread_id 2454 spawn_kernel_thread_etc(thread_func function, const char *name, int32 priority, 2455 void *arg, team_id team) 2456 { 2457 return thread_create_thread( 2458 ThreadCreationAttributes(function, name, priority, arg, team), 2459 true); 2460 } 2461 2462 2463 status_t 2464 wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout, 2465 status_t *_returnCode) 2466 { 2467 job_control_entry* freeDeath = NULL; 2468 status_t status = B_OK; 2469 2470 if (id < B_OK) 2471 return B_BAD_THREAD_ID; 2472 2473 // get the thread, queue our death entry, and fetch the semaphore we have to 2474 // wait on 2475 sem_id exitSem = B_BAD_THREAD_ID; 2476 struct thread_death_entry death; 2477 2478 Thread* thread = Thread::GetAndLock(id); 2479 if (thread != NULL) { 2480 // remember the semaphore we have to wait on and place our death entry 2481 exitSem = thread->exit.sem; 2482 list_add_link_to_head(&thread->exit.waiters, &death); 2483 2484 thread->UnlockAndReleaseReference(); 2485 // Note: We mustn't dereference the pointer afterwards, only check 2486 // it. 2487 } 2488 2489 thread_death_entry* threadDeathEntry = NULL; 2490 2491 if (thread == NULL) { 2492 // we couldn't find this thread -- maybe it's already gone, and we'll 2493 // find its death entry in our team 2494 Team* team = thread_get_current_thread()->team; 2495 TeamLocker teamLocker(team); 2496 2497 // check the child death entries first (i.e. main threads of child 2498 // teams) 2499 bool deleteEntry; 2500 freeDeath = team_get_death_entry(team, id, &deleteEntry); 2501 if (freeDeath != NULL) { 2502 death.status = freeDeath->status; 2503 if (!deleteEntry) 2504 freeDeath = NULL; 2505 } else { 2506 // check the thread death entries of the team (non-main threads) 2507 while ((threadDeathEntry = (thread_death_entry*)list_get_next_item( 2508 &team->dead_threads, threadDeathEntry)) != NULL) { 2509 if (threadDeathEntry->thread == id) { 2510 list_remove_item(&team->dead_threads, threadDeathEntry); 2511 team->dead_threads_count--; 2512 death.status = threadDeathEntry->status; 2513 break; 2514 } 2515 } 2516 2517 if (threadDeathEntry == NULL) 2518 status = B_BAD_THREAD_ID; 2519 } 2520 } 2521 2522 if (thread == NULL && status == B_OK) { 2523 // we found the thread's death entry in our team 2524 if (_returnCode) 2525 *_returnCode = death.status; 2526 2527 delete freeDeath; 2528 free(threadDeathEntry); 2529 return B_OK; 2530 } 2531 2532 // we need to wait for the death of the thread 2533 2534 if (exitSem < 0) 2535 return B_BAD_THREAD_ID; 2536 2537 resume_thread(id); 2538 // make sure we don't wait forever on a suspended thread 2539 2540 status = acquire_sem_etc(exitSem, 1, flags, timeout); 2541 2542 if (status == B_OK) { 2543 // this should never happen as the thread deletes the semaphore on exit 2544 panic("could acquire exit_sem for thread %ld\n", id); 2545 } else if (status == B_BAD_SEM_ID) { 2546 // this is the way the thread normally exits 2547 status = B_OK; 2548 2549 if (_returnCode) 2550 *_returnCode = death.status; 2551 } else { 2552 // We were probably interrupted or the timeout occurred; we need to 2553 // remove our death entry now. 2554 thread = Thread::GetAndLock(id); 2555 if (thread != NULL) { 2556 list_remove_link(&death); 2557 thread->UnlockAndReleaseReference(); 2558 } else { 2559 // The thread is already gone, so we need to wait uninterruptibly 2560 // for its exit semaphore to make sure our death entry stays valid. 2561 // It won't take long, since the thread is apparently already in the 2562 // middle of the cleanup. 2563 acquire_sem(exitSem); 2564 status = B_OK; 2565 } 2566 } 2567 2568 return status; 2569 } 2570 2571 2572 status_t 2573 select_thread(int32 id, struct select_info* info, bool kernel) 2574 { 2575 // get and lock the thread 2576 Thread* thread = Thread::GetAndLock(id); 2577 if (thread == NULL) 2578 return B_BAD_THREAD_ID; 2579 BReference<Thread> threadReference(thread, true); 2580 ThreadLocker threadLocker(thread, true); 2581 2582 // We support only B_EVENT_INVALID at the moment. 2583 info->selected_events &= B_EVENT_INVALID; 2584 2585 // add info to list 2586 if (info->selected_events != 0) { 2587 info->next = thread->select_infos; 2588 thread->select_infos = info; 2589 2590 // we need a sync reference 2591 atomic_add(&info->sync->ref_count, 1); 2592 } 2593 2594 return B_OK; 2595 } 2596 2597 2598 status_t 2599 deselect_thread(int32 id, struct select_info* info, bool kernel) 2600 { 2601 // get and lock the thread 2602 Thread* thread = Thread::GetAndLock(id); 2603 if (thread == NULL) 2604 return B_BAD_THREAD_ID; 2605 BReference<Thread> threadReference(thread, true); 2606 ThreadLocker threadLocker(thread, true); 2607 2608 // remove info from list 2609 select_info** infoLocation = &thread->select_infos; 2610 while (*infoLocation != NULL && *infoLocation != info) 2611 infoLocation = &(*infoLocation)->next; 2612 2613 if (*infoLocation != info) 2614 return B_OK; 2615 2616 *infoLocation = info->next; 2617 2618 threadLocker.Unlock(); 2619 2620 // surrender sync reference 2621 put_select_sync(info->sync); 2622 2623 return B_OK; 2624 } 2625 2626 2627 int32 2628 thread_max_threads(void) 2629 { 2630 return sMaxThreads; 2631 } 2632 2633 2634 int32 2635 thread_used_threads(void) 2636 { 2637 InterruptsSpinLocker threadHashLocker(sThreadHashLock); 2638 return sUsedThreads; 2639 } 2640 2641 2642 /*! Returns a user-readable string for a thread state. 2643 Only for use in the kernel debugger. 2644 */ 2645 const char* 2646 thread_state_to_text(Thread* thread, int32 state) 2647 { 2648 return state_to_text(thread, state); 2649 } 2650 2651 2652 int32 2653 thread_get_io_priority(thread_id id) 2654 { 2655 Thread* thread = Thread::GetAndLock(id); 2656 if (thread == NULL) 2657 return B_BAD_THREAD_ID; 2658 BReference<Thread> threadReference(thread, true); 2659 ThreadLocker threadLocker(thread, true); 2660 2661 int32 priority = thread->io_priority; 2662 if (priority < 0) { 2663 // negative I/O priority means using the (CPU) priority 2664 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 2665 priority = thread->priority; 2666 } 2667 2668 return priority; 2669 } 2670 2671 2672 void 2673 thread_set_io_priority(int32 priority) 2674 { 2675 Thread* thread = thread_get_current_thread(); 2676 ThreadLocker threadLocker(thread); 2677 2678 thread->io_priority = priority; 2679 } 2680 2681 2682 status_t 2683 thread_init(kernel_args *args) 2684 { 2685 TRACE(("thread_init: entry\n")); 2686 2687 // create the thread hash table 2688 new(&sThreadHash) ThreadHashTable(); 2689 if (sThreadHash.Init(128) != B_OK) 2690 panic("thread_init(): failed to init thread hash table!"); 2691 2692 // create the thread structure object cache 2693 sThreadCache = create_object_cache("threads", sizeof(Thread), 16, NULL, 2694 NULL, NULL); 2695 // Note: The x86 port requires 16 byte alignment of thread structures. 2696 if (sThreadCache == NULL) 2697 panic("thread_init(): failed to allocate thread object cache!"); 2698 2699 if (arch_thread_init(args) < B_OK) 2700 panic("arch_thread_init() failed!\n"); 2701 2702 // skip all thread IDs including B_SYSTEM_TEAM, which is reserved 2703 sNextThreadID = B_SYSTEM_TEAM + 1; 2704 2705 // create an idle thread for each cpu 2706 for (uint32 i = 0; i < args->num_cpus; i++) { 2707 Thread *thread; 2708 area_info info; 2709 char name[64]; 2710 2711 sprintf(name, "idle thread %lu", i + 1); 2712 thread = new(&sIdleThreads[i]) Thread(name, 2713 i == 0 ? team_get_kernel_team_id() : -1, &gCPU[i]); 2714 if (thread == NULL || thread->Init(true) != B_OK) { 2715 panic("error creating idle thread struct\n"); 2716 return B_NO_MEMORY; 2717 } 2718 2719 gCPU[i].running_thread = thread; 2720 2721 thread->team = team_get_kernel_team(); 2722 thread->priority = thread->next_priority = B_IDLE_PRIORITY; 2723 thread->state = B_THREAD_RUNNING; 2724 thread->next_state = B_THREAD_READY; 2725 sprintf(name, "idle thread %lu kstack", i + 1); 2726 thread->kernel_stack_area = find_area(name); 2727 2728 if (get_area_info(thread->kernel_stack_area, &info) != B_OK) 2729 panic("error finding idle kstack area\n"); 2730 2731 thread->kernel_stack_base = (addr_t)info.address; 2732 thread->kernel_stack_top = thread->kernel_stack_base + info.size; 2733 2734 thread->visible = true; 2735 insert_thread_into_team(thread->team, thread); 2736 } 2737 sUsedThreads = args->num_cpus; 2738 2739 // init the notification service 2740 new(&sNotificationService) ThreadNotificationService(); 2741 2742 // start the undertaker thread 2743 new(&sUndertakerEntries) DoublyLinkedList<UndertakerEntry>(); 2744 sUndertakerCondition.Init(&sUndertakerEntries, "undertaker entries"); 2745 2746 thread_id undertakerThread = spawn_kernel_thread(&undertaker, "undertaker", 2747 B_DISPLAY_PRIORITY, NULL); 2748 if (undertakerThread < 0) 2749 panic("Failed to create undertaker thread!"); 2750 resume_thread(undertakerThread); 2751 2752 // set up some debugger commands 2753 add_debugger_command_etc("threads", &dump_thread_list, "List all threads", 2754 "[ <team> ]\n" 2755 "Prints a list of all existing threads, or, if a team ID is given,\n" 2756 "all threads of the specified team.\n" 2757 " <team> - The ID of the team whose threads shall be listed.\n", 0); 2758 add_debugger_command_etc("ready", &dump_thread_list, 2759 "List all ready threads", 2760 "\n" 2761 "Prints a list of all threads in ready state.\n", 0); 2762 add_debugger_command_etc("running", &dump_thread_list, 2763 "List all running threads", 2764 "\n" 2765 "Prints a list of all threads in running state.\n", 0); 2766 add_debugger_command_etc("waiting", &dump_thread_list, 2767 "List all waiting threads (optionally for a specific semaphore)", 2768 "[ <sem> ]\n" 2769 "Prints a list of all threads in waiting state. If a semaphore is\n" 2770 "specified, only the threads waiting on that semaphore are listed.\n" 2771 " <sem> - ID of the semaphore.\n", 0); 2772 add_debugger_command_etc("realtime", &dump_thread_list, 2773 "List all realtime threads", 2774 "\n" 2775 "Prints a list of all threads with realtime priority.\n", 0); 2776 add_debugger_command_etc("thread", &dump_thread_info, 2777 "Dump info about a particular thread", 2778 "[ -s ] ( <id> | <address> | <name> )*\n" 2779 "Prints information about the specified thread. If no argument is\n" 2780 "given the current thread is selected.\n" 2781 " -s - Print info in compact table form (like \"threads\").\n" 2782 " <id> - The ID of the thread.\n" 2783 " <address> - The address of the thread structure.\n" 2784 " <name> - The thread's name.\n", 0); 2785 add_debugger_command_etc("calling", &dump_thread_list, 2786 "Show all threads that have a specific address in their call chain", 2787 "{ <symbol-pattern> | <start> <end> }\n", 0); 2788 add_debugger_command_etc("unreal", &make_thread_unreal, 2789 "Set realtime priority threads to normal priority", 2790 "[ <id> ]\n" 2791 "Sets the priority of all realtime threads or, if given, the one\n" 2792 "with the specified ID to \"normal\" priority.\n" 2793 " <id> - The ID of the thread.\n", 0); 2794 add_debugger_command_etc("suspend", &make_thread_suspended, 2795 "Suspend a thread", 2796 "[ <id> ]\n" 2797 "Suspends the thread with the given ID. If no ID argument is given\n" 2798 "the current thread is selected.\n" 2799 " <id> - The ID of the thread.\n", 0); 2800 add_debugger_command_etc("resume", &make_thread_resumed, "Resume a thread", 2801 "<id>\n" 2802 "Resumes the specified thread, if it is currently suspended.\n" 2803 " <id> - The ID of the thread.\n", 0); 2804 add_debugger_command_etc("drop", &drop_into_debugger, 2805 "Drop a thread into the userland debugger", 2806 "<id>\n" 2807 "Drops the specified (userland) thread into the userland debugger\n" 2808 "after leaving the kernel debugger.\n" 2809 " <id> - The ID of the thread.\n", 0); 2810 add_debugger_command_etc("priority", &set_thread_prio, 2811 "Set a thread's priority", 2812 "<priority> [ <id> ]\n" 2813 "Sets the priority of the thread with the specified ID to the given\n" 2814 "priority. If no thread ID is given, the current thread is selected.\n" 2815 " <priority> - The thread's new priority (0 - 120)\n" 2816 " <id> - The ID of the thread.\n", 0); 2817 2818 return B_OK; 2819 } 2820 2821 2822 status_t 2823 thread_preboot_init_percpu(struct kernel_args *args, int32 cpuNum) 2824 { 2825 // set up the cpu pointer in the not yet initialized per-cpu idle thread 2826 // so that get_current_cpu and friends will work, which is crucial for 2827 // a lot of low level routines 2828 sIdleThreads[cpuNum].cpu = &gCPU[cpuNum]; 2829 arch_thread_set_current_thread(&sIdleThreads[cpuNum]); 2830 return B_OK; 2831 } 2832 2833 2834 // #pragma mark - thread blocking API 2835 2836 2837 static status_t 2838 thread_block_timeout(timer* timer) 2839 { 2840 // The timer has been installed with B_TIMER_ACQUIRE_SCHEDULER_LOCK, so 2841 // we're holding the scheduler lock already. This makes things comfortably 2842 // easy. 2843 2844 Thread* thread = (Thread*)timer->user_data; 2845 thread_unblock_locked(thread, B_TIMED_OUT); 2846 2847 return B_HANDLED_INTERRUPT; 2848 } 2849 2850 2851 /*! Blocks the current thread. 2852 2853 The function acquires the scheduler lock and calls thread_block_locked(). 2854 See there for more information. 2855 */ 2856 status_t 2857 thread_block() 2858 { 2859 InterruptsSpinLocker _(gSchedulerLock); 2860 return thread_block_locked(thread_get_current_thread()); 2861 } 2862 2863 2864 /*! Blocks the current thread with a timeout. 2865 2866 Acquires the scheduler lock and calls thread_block_with_timeout_locked(). 2867 See there for more information. 2868 */ 2869 status_t 2870 thread_block_with_timeout(uint32 timeoutFlags, bigtime_t timeout) 2871 { 2872 InterruptsSpinLocker _(gSchedulerLock); 2873 return thread_block_with_timeout_locked(timeoutFlags, timeout); 2874 } 2875 2876 2877 /*! Blocks the current thread with a timeout. 2878 2879 The thread is blocked until someone else unblock it or the specified timeout 2880 occurs. Must be called after a call to thread_prepare_to_block(). If the 2881 thread has already been unblocked after the previous call to 2882 thread_prepare_to_block(), this function will return immediately. See 2883 thread_prepare_to_block() for more details. 2884 2885 The caller must hold the scheduler lock. 2886 2887 \param thread The current thread. 2888 \param timeoutFlags The standard timeout flags: 2889 - \c B_RELATIVE_TIMEOUT: \a timeout specifies the time to wait. 2890 - \c B_ABSOLUTE_TIMEOUT: \a timeout specifies the absolute end time when 2891 the timeout shall occur. 2892 - \c B_TIMEOUT_REAL_TIME_BASE: Only relevant when \c B_ABSOLUTE_TIMEOUT 2893 is specified, too. Specifies that \a timeout is a real time, not a 2894 system time. 2895 If neither \c B_RELATIVE_TIMEOUT nor \c B_ABSOLUTE_TIMEOUT are 2896 specified, an infinite timeout is implied and the function behaves like 2897 thread_block_locked(). 2898 \return The error code passed to the unblocking function. thread_interrupt() 2899 uses \c B_INTERRUPTED. When the timeout occurred, \c B_TIMED_OUT is 2900 returned. By convention \c B_OK means that the wait was successful while 2901 another error code indicates a failure (what that means depends on the 2902 client code). 2903 */ 2904 status_t 2905 thread_block_with_timeout_locked(uint32 timeoutFlags, bigtime_t timeout) 2906 { 2907 Thread* thread = thread_get_current_thread(); 2908 2909 if (thread->wait.status != 1) 2910 return thread->wait.status; 2911 2912 bool useTimer = (timeoutFlags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) 2913 && timeout != B_INFINITE_TIMEOUT; 2914 2915 if (useTimer) { 2916 // Timer flags: absolute/relative + "acquire thread lock". The latter 2917 // avoids nasty race conditions and deadlock problems that could 2918 // otherwise occur between our cancel_timer() and a concurrently 2919 // executing thread_block_timeout(). 2920 uint32 timerFlags; 2921 if ((timeoutFlags & B_RELATIVE_TIMEOUT) != 0) { 2922 timerFlags = B_ONE_SHOT_RELATIVE_TIMER; 2923 } else { 2924 timerFlags = B_ONE_SHOT_ABSOLUTE_TIMER; 2925 if ((timeoutFlags & B_TIMEOUT_REAL_TIME_BASE) != 0) 2926 timerFlags |= B_TIMER_REAL_TIME_BASE; 2927 } 2928 timerFlags |= B_TIMER_ACQUIRE_SCHEDULER_LOCK; 2929 2930 // install the timer 2931 thread->wait.unblock_timer.user_data = thread; 2932 add_timer(&thread->wait.unblock_timer, &thread_block_timeout, timeout, 2933 timerFlags); 2934 } 2935 2936 // block 2937 status_t error = thread_block_locked(thread); 2938 2939 // cancel timer, if it didn't fire 2940 if (error != B_TIMED_OUT && useTimer) 2941 cancel_timer(&thread->wait.unblock_timer); 2942 2943 return error; 2944 } 2945 2946 2947 /*! Unblocks a userland-blocked thread. 2948 The caller must not hold any locks. 2949 */ 2950 static status_t 2951 user_unblock_thread(thread_id threadID, status_t status) 2952 { 2953 // get the thread 2954 Thread* thread = Thread::GetAndLock(threadID); 2955 if (thread == NULL) 2956 return B_BAD_THREAD_ID; 2957 BReference<Thread> threadReference(thread, true); 2958 ThreadLocker threadLocker(thread, true); 2959 2960 if (thread->user_thread == NULL) 2961 return B_NOT_ALLOWED; 2962 2963 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 2964 2965 if (thread->user_thread->wait_status > 0) { 2966 thread->user_thread->wait_status = status; 2967 thread_unblock_locked(thread, status); 2968 } 2969 2970 return B_OK; 2971 } 2972 2973 2974 // #pragma mark - public kernel API 2975 2976 2977 void 2978 exit_thread(status_t returnValue) 2979 { 2980 Thread *thread = thread_get_current_thread(); 2981 Team* team = thread->team; 2982 2983 thread->exit.status = returnValue; 2984 2985 // if called from a kernel thread, we don't deliver the signal, 2986 // we just exit directly to keep the user space behaviour of 2987 // this function 2988 if (team != team_get_kernel_team()) { 2989 // If this is its main thread, set the team's exit status. 2990 if (thread == team->main_thread) { 2991 TeamLocker teamLocker(team); 2992 2993 if (!team->exit.initialized) { 2994 team->exit.reason = CLD_EXITED; 2995 team->exit.signal = 0; 2996 team->exit.signaling_user = 0; 2997 team->exit.status = returnValue; 2998 team->exit.initialized = true; 2999 } 3000 3001 teamLocker.Unlock(); 3002 } 3003 3004 Signal signal(SIGKILLTHR, SI_USER, B_OK, team->id); 3005 send_signal_to_thread(thread, signal, B_DO_NOT_RESCHEDULE); 3006 } else 3007 thread_exit(); 3008 } 3009 3010 3011 status_t 3012 kill_thread(thread_id id) 3013 { 3014 if (id <= 0) 3015 return B_BAD_VALUE; 3016 3017 Thread* currentThread = thread_get_current_thread(); 3018 3019 Signal signal(SIGKILLTHR, SI_USER, B_OK, currentThread->team->id); 3020 return send_signal_to_thread_id(id, signal, 0); 3021 } 3022 3023 3024 status_t 3025 send_data(thread_id thread, int32 code, const void *buffer, size_t bufferSize) 3026 { 3027 return send_data_etc(thread, code, buffer, bufferSize, 0); 3028 } 3029 3030 3031 int32 3032 receive_data(thread_id *sender, void *buffer, size_t bufferSize) 3033 { 3034 return receive_data_etc(sender, buffer, bufferSize, 0); 3035 } 3036 3037 3038 bool 3039 has_data(thread_id thread) 3040 { 3041 // TODO: The thread argument is ignored. 3042 int32 count; 3043 3044 if (get_sem_count(thread_get_current_thread()->msg.read_sem, 3045 &count) != B_OK) 3046 return false; 3047 3048 return count == 0 ? false : true; 3049 } 3050 3051 3052 status_t 3053 _get_thread_info(thread_id id, thread_info *info, size_t size) 3054 { 3055 if (info == NULL || size != sizeof(thread_info) || id < B_OK) 3056 return B_BAD_VALUE; 3057 3058 // get the thread 3059 Thread* thread = Thread::GetAndLock(id); 3060 if (thread == NULL) 3061 return B_BAD_THREAD_ID; 3062 BReference<Thread> threadReference(thread, true); 3063 ThreadLocker threadLocker(thread, true); 3064 3065 // fill the info -- also requires the scheduler lock to be held 3066 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 3067 3068 fill_thread_info(thread, info, size); 3069 3070 return B_OK; 3071 } 3072 3073 3074 status_t 3075 _get_next_thread_info(team_id teamID, int32 *_cookie, thread_info *info, 3076 size_t size) 3077 { 3078 if (info == NULL || size != sizeof(thread_info) || teamID < 0) 3079 return B_BAD_VALUE; 3080 3081 int32 lastID = *_cookie; 3082 3083 // get the team 3084 Team* team = Team::GetAndLock(teamID); 3085 if (team == NULL) 3086 return B_BAD_VALUE; 3087 BReference<Team> teamReference(team, true); 3088 TeamLocker teamLocker(team, true); 3089 3090 Thread* thread = NULL; 3091 3092 if (lastID == 0) { 3093 // We start with the main thread 3094 thread = team->main_thread; 3095 } else { 3096 // Find the one thread with an ID greater than ours (as long as the IDs 3097 // don't wrap they are always sorted from highest to lowest). 3098 // TODO: That is broken not only when the IDs wrap, but also for the 3099 // kernel team, to which threads are added when they are dying. 3100 for (Thread* next = team->thread_list; next != NULL; 3101 next = next->team_next) { 3102 if (next->id <= lastID) 3103 break; 3104 3105 thread = next; 3106 } 3107 } 3108 3109 if (thread == NULL) 3110 return B_BAD_VALUE; 3111 3112 lastID = thread->id; 3113 *_cookie = lastID; 3114 3115 ThreadLocker threadLocker(thread); 3116 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 3117 3118 fill_thread_info(thread, info, size); 3119 3120 return B_OK; 3121 } 3122 3123 3124 thread_id 3125 find_thread(const char* name) 3126 { 3127 if (name == NULL) 3128 return thread_get_current_thread_id(); 3129 3130 InterruptsSpinLocker threadHashLocker(sThreadHashLock); 3131 3132 // TODO: Scanning the whole hash with the thread hash lock held isn't 3133 // exactly cheap -- although this function is probably used very rarely. 3134 3135 for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); 3136 Thread* thread = it.Next();) { 3137 if (!thread->visible) 3138 continue; 3139 3140 if (strcmp(thread->name, name) == 0) 3141 return thread->id; 3142 } 3143 3144 return B_NAME_NOT_FOUND; 3145 } 3146 3147 3148 status_t 3149 rename_thread(thread_id id, const char* name) 3150 { 3151 if (name == NULL) 3152 return B_BAD_VALUE; 3153 3154 // get the thread 3155 Thread* thread = Thread::GetAndLock(id); 3156 if (thread == NULL) 3157 return B_BAD_THREAD_ID; 3158 BReference<Thread> threadReference(thread, true); 3159 ThreadLocker threadLocker(thread, true); 3160 3161 // check whether the operation is allowed 3162 if (thread->team != thread_get_current_thread()->team) 3163 return B_NOT_ALLOWED; 3164 3165 strlcpy(thread->name, name, B_OS_NAME_LENGTH); 3166 3167 team_id teamID = thread->team->id; 3168 3169 threadLocker.Unlock(); 3170 3171 // notify listeners 3172 sNotificationService.Notify(THREAD_NAME_CHANGED, teamID, id); 3173 // don't pass the thread structure, as it's unsafe, if it isn't ours 3174 3175 return B_OK; 3176 } 3177 3178 3179 status_t 3180 set_thread_priority(thread_id id, int32 priority) 3181 { 3182 int32 oldPriority; 3183 3184 // make sure the passed in priority is within bounds 3185 if (priority > THREAD_MAX_SET_PRIORITY) 3186 priority = THREAD_MAX_SET_PRIORITY; 3187 if (priority < THREAD_MIN_SET_PRIORITY) 3188 priority = THREAD_MIN_SET_PRIORITY; 3189 3190 // get the thread 3191 Thread* thread = Thread::GetAndLock(id); 3192 if (thread == NULL) 3193 return B_BAD_THREAD_ID; 3194 BReference<Thread> threadReference(thread, true); 3195 ThreadLocker threadLocker(thread, true); 3196 3197 // check whether the change is allowed 3198 if (thread_is_idle_thread(thread)) 3199 return B_NOT_ALLOWED; 3200 3201 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 3202 3203 if (thread == thread_get_current_thread()) { 3204 // It's ourself, so we know we aren't in the run queue, and we can 3205 // manipulate our structure directly. 3206 oldPriority = thread->priority; 3207 thread->priority = thread->next_priority = priority; 3208 } else { 3209 oldPriority = thread->priority; 3210 scheduler_set_thread_priority(thread, priority); 3211 } 3212 3213 return oldPriority; 3214 } 3215 3216 3217 status_t 3218 snooze_etc(bigtime_t timeout, int timebase, uint32 flags) 3219 { 3220 return common_snooze_etc(timeout, timebase, flags, NULL); 3221 } 3222 3223 3224 /*! snooze() for internal kernel use only; doesn't interrupt on signals. */ 3225 status_t 3226 snooze(bigtime_t timeout) 3227 { 3228 return snooze_etc(timeout, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); 3229 } 3230 3231 3232 /*! snooze_until() for internal kernel use only; doesn't interrupt on 3233 signals. 3234 */ 3235 status_t 3236 snooze_until(bigtime_t timeout, int timebase) 3237 { 3238 return snooze_etc(timeout, timebase, B_ABSOLUTE_TIMEOUT); 3239 } 3240 3241 3242 status_t 3243 wait_for_thread(thread_id thread, status_t *_returnCode) 3244 { 3245 return wait_for_thread_etc(thread, 0, 0, _returnCode); 3246 } 3247 3248 3249 status_t 3250 suspend_thread(thread_id id) 3251 { 3252 if (id <= 0) 3253 return B_BAD_VALUE; 3254 3255 Thread* currentThread = thread_get_current_thread(); 3256 3257 Signal signal(SIGSTOP, SI_USER, B_OK, currentThread->team->id); 3258 return send_signal_to_thread_id(id, signal, 0); 3259 } 3260 3261 3262 status_t 3263 resume_thread(thread_id id) 3264 { 3265 if (id <= 0) 3266 return B_BAD_VALUE; 3267 3268 Thread* currentThread = thread_get_current_thread(); 3269 3270 // Using the kernel internal SIGNAL_CONTINUE_THREAD signal retains 3271 // compatibility to BeOS which documents the combination of suspend_thread() 3272 // and resume_thread() to interrupt threads waiting on semaphores. 3273 Signal signal(SIGNAL_CONTINUE_THREAD, SI_USER, B_OK, 3274 currentThread->team->id); 3275 return send_signal_to_thread_id(id, signal, 0); 3276 } 3277 3278 3279 thread_id 3280 spawn_kernel_thread(thread_func function, const char *name, int32 priority, 3281 void *arg) 3282 { 3283 return thread_create_thread( 3284 ThreadCreationAttributes(function, name, priority, arg), 3285 true); 3286 } 3287 3288 3289 int 3290 getrlimit(int resource, struct rlimit * rlp) 3291 { 3292 status_t error = common_getrlimit(resource, rlp); 3293 if (error != B_OK) { 3294 errno = error; 3295 return -1; 3296 } 3297 3298 return 0; 3299 } 3300 3301 3302 int 3303 setrlimit(int resource, const struct rlimit * rlp) 3304 { 3305 status_t error = common_setrlimit(resource, rlp); 3306 if (error != B_OK) { 3307 errno = error; 3308 return -1; 3309 } 3310 3311 return 0; 3312 } 3313 3314 3315 // #pragma mark - syscalls 3316 3317 3318 void 3319 _user_exit_thread(status_t returnValue) 3320 { 3321 exit_thread(returnValue); 3322 } 3323 3324 3325 status_t 3326 _user_kill_thread(thread_id thread) 3327 { 3328 // TODO: Don't allow kernel threads to be killed! 3329 return kill_thread(thread); 3330 } 3331 3332 3333 status_t 3334 _user_cancel_thread(thread_id threadID, void (*cancelFunction)(int)) 3335 { 3336 // check the cancel function 3337 if (cancelFunction == NULL || !IS_USER_ADDRESS(cancelFunction)) 3338 return B_BAD_VALUE; 3339 3340 // get and lock the thread 3341 Thread* thread = Thread::GetAndLock(threadID); 3342 if (thread == NULL) 3343 return B_BAD_THREAD_ID; 3344 BReference<Thread> threadReference(thread, true); 3345 ThreadLocker threadLocker(thread, true); 3346 3347 // only threads of the same team can be canceled 3348 if (thread->team != thread_get_current_thread()->team) 3349 return B_NOT_ALLOWED; 3350 3351 // set the cancel function 3352 thread->cancel_function = cancelFunction; 3353 3354 // send the cancellation signal to the thread 3355 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 3356 return send_signal_to_thread_locked(thread, SIGNAL_CANCEL_THREAD, NULL, 0); 3357 } 3358 3359 3360 status_t 3361 _user_resume_thread(thread_id thread) 3362 { 3363 // TODO: Don't allow kernel threads to be resumed! 3364 return resume_thread(thread); 3365 } 3366 3367 3368 status_t 3369 _user_suspend_thread(thread_id thread) 3370 { 3371 // TODO: Don't allow kernel threads to be suspended! 3372 return suspend_thread(thread); 3373 } 3374 3375 3376 status_t 3377 _user_rename_thread(thread_id thread, const char *userName) 3378 { 3379 char name[B_OS_NAME_LENGTH]; 3380 3381 if (!IS_USER_ADDRESS(userName) 3382 || userName == NULL 3383 || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK) 3384 return B_BAD_ADDRESS; 3385 3386 // TODO: Don't allow kernel threads to be renamed! 3387 return rename_thread(thread, name); 3388 } 3389 3390 3391 int32 3392 _user_set_thread_priority(thread_id thread, int32 newPriority) 3393 { 3394 // TODO: Don't allow setting priority of kernel threads! 3395 return set_thread_priority(thread, newPriority); 3396 } 3397 3398 3399 thread_id 3400 _user_spawn_thread(thread_creation_attributes* userAttributes) 3401 { 3402 // copy the userland structure to the kernel 3403 char nameBuffer[B_OS_NAME_LENGTH]; 3404 ThreadCreationAttributes attributes; 3405 status_t error = attributes.InitFromUserAttributes(userAttributes, 3406 nameBuffer); 3407 if (error != B_OK) 3408 return error; 3409 3410 // create the thread 3411 thread_id threadID = thread_create_thread(attributes, false); 3412 3413 if (threadID >= 0) 3414 user_debug_thread_created(threadID); 3415 3416 return threadID; 3417 } 3418 3419 3420 status_t 3421 _user_snooze_etc(bigtime_t timeout, int timebase, uint32 flags, 3422 bigtime_t* userRemainingTime) 3423 { 3424 // We need to store more syscall restart parameters than usual and need a 3425 // somewhat different handling. Hence we can't use 3426 // syscall_restart_handle_timeout_pre() but do the job ourselves. 3427 struct restart_parameters { 3428 bigtime_t timeout; 3429 clockid_t timebase; 3430 uint32 flags; 3431 }; 3432 3433 Thread* thread = thread_get_current_thread(); 3434 3435 if ((thread->flags & THREAD_FLAGS_SYSCALL_RESTARTED) != 0) { 3436 // The syscall was restarted. Fetch the parameters from the stored 3437 // restart parameters. 3438 restart_parameters* restartParameters 3439 = (restart_parameters*)thread->syscall_restart.parameters; 3440 timeout = restartParameters->timeout; 3441 timebase = restartParameters->timebase; 3442 flags = restartParameters->flags; 3443 } else { 3444 // convert relative timeouts to absolute ones 3445 if ((flags & B_RELATIVE_TIMEOUT) != 0) { 3446 // not restarted yet and the flags indicate a relative timeout 3447 3448 // Make sure we use the system time base, so real-time clock changes 3449 // won't affect our wait. 3450 flags &= ~(uint32)B_TIMEOUT_REAL_TIME_BASE; 3451 if (timebase == CLOCK_REALTIME) 3452 timebase = CLOCK_MONOTONIC; 3453 3454 // get the current time and make the timeout absolute 3455 bigtime_t now; 3456 status_t error = user_timer_get_clock(timebase, now); 3457 if (error != B_OK) 3458 return error; 3459 3460 timeout += now; 3461 3462 // deal with overflow 3463 if (timeout < 0) 3464 timeout = B_INFINITE_TIMEOUT; 3465 3466 flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT; 3467 } else 3468 flags |= B_ABSOLUTE_TIMEOUT; 3469 } 3470 3471 // snooze 3472 bigtime_t remainingTime; 3473 status_t error = common_snooze_etc(timeout, timebase, 3474 flags | B_CAN_INTERRUPT | B_CHECK_PERMISSION, 3475 userRemainingTime != NULL ? &remainingTime : NULL); 3476 3477 // If interrupted, copy the remaining time back to userland and prepare the 3478 // syscall restart. 3479 if (error == B_INTERRUPTED) { 3480 if (userRemainingTime != NULL 3481 && (!IS_USER_ADDRESS(userRemainingTime) 3482 || user_memcpy(userRemainingTime, &remainingTime, 3483 sizeof(remainingTime)) != B_OK)) { 3484 return B_BAD_ADDRESS; 3485 } 3486 3487 // store the normalized values in the restart parameters 3488 restart_parameters* restartParameters 3489 = (restart_parameters*)thread->syscall_restart.parameters; 3490 restartParameters->timeout = timeout; 3491 restartParameters->timebase = timebase; 3492 restartParameters->flags = flags; 3493 3494 // restart the syscall, if possible 3495 atomic_or(&thread->flags, THREAD_FLAGS_RESTART_SYSCALL); 3496 } 3497 3498 return error; 3499 } 3500 3501 3502 void 3503 _user_thread_yield(void) 3504 { 3505 thread_yield(true); 3506 } 3507 3508 3509 status_t 3510 _user_get_thread_info(thread_id id, thread_info *userInfo) 3511 { 3512 thread_info info; 3513 status_t status; 3514 3515 if (!IS_USER_ADDRESS(userInfo)) 3516 return B_BAD_ADDRESS; 3517 3518 status = _get_thread_info(id, &info, sizeof(thread_info)); 3519 3520 if (status >= B_OK 3521 && user_memcpy(userInfo, &info, sizeof(thread_info)) < B_OK) 3522 return B_BAD_ADDRESS; 3523 3524 return status; 3525 } 3526 3527 3528 status_t 3529 _user_get_next_thread_info(team_id team, int32 *userCookie, 3530 thread_info *userInfo) 3531 { 3532 status_t status; 3533 thread_info info; 3534 int32 cookie; 3535 3536 if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo) 3537 || user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK) 3538 return B_BAD_ADDRESS; 3539 3540 status = _get_next_thread_info(team, &cookie, &info, sizeof(thread_info)); 3541 if (status < B_OK) 3542 return status; 3543 3544 if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK 3545 || user_memcpy(userInfo, &info, sizeof(thread_info)) < B_OK) 3546 return B_BAD_ADDRESS; 3547 3548 return status; 3549 } 3550 3551 3552 thread_id 3553 _user_find_thread(const char *userName) 3554 { 3555 char name[B_OS_NAME_LENGTH]; 3556 3557 if (userName == NULL) 3558 return find_thread(NULL); 3559 3560 if (!IS_USER_ADDRESS(userName) 3561 || user_strlcpy(name, userName, sizeof(name)) < B_OK) 3562 return B_BAD_ADDRESS; 3563 3564 return find_thread(name); 3565 } 3566 3567 3568 status_t 3569 _user_wait_for_thread(thread_id id, status_t *userReturnCode) 3570 { 3571 status_t returnCode; 3572 status_t status; 3573 3574 if (userReturnCode != NULL && !IS_USER_ADDRESS(userReturnCode)) 3575 return B_BAD_ADDRESS; 3576 3577 status = wait_for_thread_etc(id, B_CAN_INTERRUPT, 0, &returnCode); 3578 3579 if (status == B_OK && userReturnCode != NULL 3580 && user_memcpy(userReturnCode, &returnCode, sizeof(status_t)) < B_OK) { 3581 return B_BAD_ADDRESS; 3582 } 3583 3584 return syscall_restart_handle_post(status); 3585 } 3586 3587 3588 bool 3589 _user_has_data(thread_id thread) 3590 { 3591 return has_data(thread); 3592 } 3593 3594 3595 status_t 3596 _user_send_data(thread_id thread, int32 code, const void *buffer, 3597 size_t bufferSize) 3598 { 3599 if (!IS_USER_ADDRESS(buffer)) 3600 return B_BAD_ADDRESS; 3601 3602 return send_data_etc(thread, code, buffer, bufferSize, 3603 B_KILL_CAN_INTERRUPT); 3604 // supports userland buffers 3605 } 3606 3607 3608 status_t 3609 _user_receive_data(thread_id *_userSender, void *buffer, size_t bufferSize) 3610 { 3611 thread_id sender; 3612 status_t code; 3613 3614 if ((!IS_USER_ADDRESS(_userSender) && _userSender != NULL) 3615 || !IS_USER_ADDRESS(buffer)) 3616 return B_BAD_ADDRESS; 3617 3618 code = receive_data_etc(&sender, buffer, bufferSize, B_KILL_CAN_INTERRUPT); 3619 // supports userland buffers 3620 3621 if (_userSender != NULL) 3622 if (user_memcpy(_userSender, &sender, sizeof(thread_id)) < B_OK) 3623 return B_BAD_ADDRESS; 3624 3625 return code; 3626 } 3627 3628 3629 status_t 3630 _user_block_thread(uint32 flags, bigtime_t timeout) 3631 { 3632 syscall_restart_handle_timeout_pre(flags, timeout); 3633 flags |= B_CAN_INTERRUPT; 3634 3635 Thread* thread = thread_get_current_thread(); 3636 ThreadLocker threadLocker(thread); 3637 3638 // check, if already done 3639 if (thread->user_thread->wait_status <= 0) 3640 return thread->user_thread->wait_status; 3641 3642 // nope, so wait 3643 thread_prepare_to_block(thread, flags, THREAD_BLOCK_TYPE_OTHER, "user"); 3644 3645 threadLocker.Unlock(); 3646 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 3647 3648 status_t status = thread_block_with_timeout_locked(flags, timeout); 3649 3650 schedulerLocker.Unlock(); 3651 threadLocker.Lock(); 3652 3653 // Interruptions or timeouts can race with other threads unblocking us. 3654 // Favor a wake-up by another thread, i.e. if someone changed the wait 3655 // status, use that. 3656 status_t oldStatus = thread->user_thread->wait_status; 3657 if (oldStatus > 0) 3658 thread->user_thread->wait_status = status; 3659 else 3660 status = oldStatus; 3661 3662 threadLocker.Unlock(); 3663 3664 return syscall_restart_handle_timeout_post(status, timeout); 3665 } 3666 3667 3668 status_t 3669 _user_unblock_thread(thread_id threadID, status_t status) 3670 { 3671 status_t error = user_unblock_thread(threadID, status); 3672 3673 if (error == B_OK) 3674 scheduler_reschedule_if_necessary(); 3675 3676 return error; 3677 } 3678 3679 3680 status_t 3681 _user_unblock_threads(thread_id* userThreads, uint32 count, status_t status) 3682 { 3683 enum { 3684 MAX_USER_THREADS_TO_UNBLOCK = 128 3685 }; 3686 3687 if (userThreads == NULL || !IS_USER_ADDRESS(userThreads)) 3688 return B_BAD_ADDRESS; 3689 if (count > MAX_USER_THREADS_TO_UNBLOCK) 3690 return B_BAD_VALUE; 3691 3692 thread_id threads[MAX_USER_THREADS_TO_UNBLOCK]; 3693 if (user_memcpy(threads, userThreads, count * sizeof(thread_id)) != B_OK) 3694 return B_BAD_ADDRESS; 3695 3696 for (uint32 i = 0; i < count; i++) 3697 user_unblock_thread(threads[i], status); 3698 3699 scheduler_reschedule_if_necessary(); 3700 3701 return B_OK; 3702 } 3703 3704 3705 // TODO: the following two functions don't belong here 3706 3707 3708 int 3709 _user_getrlimit(int resource, struct rlimit *urlp) 3710 { 3711 struct rlimit rl; 3712 int ret; 3713 3714 if (urlp == NULL) 3715 return EINVAL; 3716 3717 if (!IS_USER_ADDRESS(urlp)) 3718 return B_BAD_ADDRESS; 3719 3720 ret = common_getrlimit(resource, &rl); 3721 3722 if (ret == 0) { 3723 ret = user_memcpy(urlp, &rl, sizeof(struct rlimit)); 3724 if (ret < 0) 3725 return ret; 3726 3727 return 0; 3728 } 3729 3730 return ret; 3731 } 3732 3733 3734 int 3735 _user_setrlimit(int resource, const struct rlimit *userResourceLimit) 3736 { 3737 struct rlimit resourceLimit; 3738 3739 if (userResourceLimit == NULL) 3740 return EINVAL; 3741 3742 if (!IS_USER_ADDRESS(userResourceLimit) 3743 || user_memcpy(&resourceLimit, userResourceLimit, 3744 sizeof(struct rlimit)) < B_OK) 3745 return B_BAD_ADDRESS; 3746 3747 return common_setrlimit(resource, &resourceLimit); 3748 } 3749