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