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