1/** 2 * \file 3 * \brief Threads implementation. 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <stdlib.h> 16#include <stdio.h> 17#include <string.h> 18#include <barrelfish/barrelfish.h> 19#include <barrelfish/dispatch.h> 20#include <barrelfish/dispatcher_arch.h> 21#include <barrelfish/debug.h> 22#include <barrelfish/slab.h> 23#include <barrelfish/caddr.h> 24#include <barrelfish/curdispatcher_arch.h> 25#include <barrelfish/vspace_mmu_aware.h> 26#include <barrelfish_kpi/cpu_arch.h> 27#include <barrelfish_kpi/domain_params.h> 28#include <arch/registers.h> 29#include <trace/trace.h> 30 31#include <trace_definitions/trace_defs.h> 32 33#include "arch/threads.h" 34#include "threads_priv.h" 35#include "init.h" 36 37#if defined(__x86_64__) 38# include "arch/ldt.h" 39#endif 40 41 42/// Maximum number of threads in a domain, used to size VM region for thread structures 43// there is no point having MAX_THREADS > LDT_NENTRIES on x86 (see ldt.c) 44#define MAX_THREADS 256 45 46/// Static stack and storage for a bootstrap/cleanup thread 47// XXX: 16-byte aligned for x86-64 48static uintptr_t staticstack[THREADS_DEFAULT_STACK_BYTES / sizeof(uintptr_t)] 49__attribute__((aligned(STACK_ALIGNMENT))); 50 51static struct thread staticthread __attribute__((aligned(THREAD_ALIGNMENT))) = { 52 .stack = staticstack, 53 .stack_top = (char *)staticstack + sizeof(staticstack) 54}; 55static struct thread_mutex staticthread_lock = THREAD_MUTEX_INITIALIZER; 56 57/// Storage metadata for thread structures (and TLS data) 58static struct slab_allocator thread_slabs; 59static struct vspace_mmu_aware thread_slabs_vm; 60 61// XXX: mutex and spinlock protecting thread slabs in spanned domains 62/* This ought to be just a mutex. However, thread_create() is called on the 63 * inter-disp message handler thread, and if it blocks in a mutex, there is no 64 * way to wake it up and we will deadlock. This is a quick-fix workaround: 65 * The spinlock protects the data structure 66 * The mutex avoids unneccessary spinning (it is acquired first when safe) 67 */ 68static spinlock_t thread_slabs_spinlock; 69static struct thread_mutex thread_slabs_mutex = THREAD_MUTEX_INITIALIZER; 70 71/// Base and size of the original ("pristine") thread-local storage init data 72static void *tls_block_init_base; 73static size_t tls_block_init_len; 74static size_t tls_block_total_len; 75 76/// Warning already issued about RSP usage. (Prevent repeated warnings 77/// from the same domain -- e.g., when using THC whose stacks appear 78/// invalid here). 79__attribute__((unused)) static bool stack_warned=0; 80 81/// Wrapper function for most threads, runs given function then deletes itself 82static void thread_entry(thread_func_t start_func, void *start_data) 83{ 84 assert((lvaddr_t)start_func >= BASE_PAGE_SIZE); 85 int retval = start_func(start_data); 86 thread_exit(retval); 87 assert(!"thread_exit returned"); 88} 89 90/// int counter for assigning initial thread ids 91static uintptr_t threadid = 0; 92 93#ifndef NDEBUG 94/// Debugging assertions on thread queues 95static void check_queue(struct thread *queue) 96{ 97 if (queue == NULL) { 98 return; 99 } 100 struct thread *q = queue; 101 int i = 0; 102 103 do { 104 assert_disabled(q != NULL); 105 106 // check for NULL next and prev pointers 107 assert_disabled((lvaddr_t)q->next > BASE_PAGE_SIZE); 108 assert_disabled((lvaddr_t)q->prev > BASE_PAGE_SIZE); 109 110 // check that next and prev pointers are sane 111 assert_disabled(q->next->prev == q); 112 assert_disabled(q->prev->next == q); 113 114 // advance to next elem 115 q = q->next; 116 i++; 117 assert_disabled(i < MAX_THREADS); 118 } while (q != queue); 119} 120#else /* NDEBUG version */ 121static inline void check_queue(struct thread *queue) {} 122#endif 123 124/** 125 * \brief Enqueue a thread in the given queue 126 * 127 * For safety, should only happen while disabled. 128 */ 129void thread_enqueue(struct thread *thread, struct thread **queue) 130{ 131 assert_disabled(thread != NULL); 132 assert_disabled(queue != NULL); 133 check_queue(*queue); 134 if (*queue == NULL) { 135 *queue = thread->prev = thread->next = thread; 136 } else { 137 assert_disabled((*queue)->prev != NULL); 138 thread->prev = (*queue)->prev; 139 thread->next = *queue; 140 (*queue)->prev = thread; 141 assert_disabled(thread->prev != NULL); 142 thread->prev->next = thread; 143 } 144 145 check_queue(*queue); 146} 147 148/** 149 * \brief Dequeue the first thread on the given queue 150 * 151 * For safety, should only happen while disabled. 152 * 153 * \returns Pointer to thread that was dequeued 154 */ 155struct thread *thread_dequeue(struct thread **queue) 156{ 157 assert_disabled(queue != NULL); 158 struct thread *thread = *queue; 159 assert_disabled(thread != NULL); 160 check_queue(thread); 161 if (thread->prev == thread) { 162 assert_disabled(thread->next == thread); 163 *queue = NULL; 164 } else { 165 thread->prev->next = thread->next; 166 thread->next->prev = thread->prev; 167 *queue = thread->next; 168 } 169 check_queue(*queue); 170#ifndef NDEBUG 171 thread->prev = thread->next = NULL; 172#endif 173 return thread; 174} 175 176/** 177 * \brief Remove a specific thread from a queue 178 * 179 * Does not check that the thread is in the given queue, which it must be. 180 * For safety, should only happen while disabled. 181 */ 182void thread_remove_from_queue(struct thread **queue, struct thread *thread) 183{ 184 assert_disabled(queue != NULL); 185 assert_disabled(thread != NULL); 186 check_queue(*queue); 187 if (thread->prev == thread) { 188 assert_disabled(thread->next == thread); 189 assert_disabled(*queue == thread); 190 *queue = NULL; 191 } else { 192 thread->prev->next = thread->next; 193 thread->next->prev = thread->prev; 194 if (*queue == thread) { 195 *queue = thread->next; 196 } 197 } 198 check_queue(*queue); 199#ifndef NDEBUG 200 thread->prev = thread->next = NULL; 201#endif 202} 203 204/// Refill backing storage for thread region 205static errval_t refill_thread_slabs(struct slab_allocator *slabs) 206{ 207 assert(slabs == &thread_slabs); 208 209 size_t size; 210 void *buf; 211 errval_t err; 212 213 size_t blocksize = sizeof(struct thread) + tls_block_total_len; 214 err = vspace_mmu_aware_map(&thread_slabs_vm, blocksize, &buf, &size); 215 if (err_is_fail(err)) { 216 return err_push(err, LIB_ERR_VSPACE_MMU_AWARE_MAP); 217 } 218 219 slab_grow(slabs, buf, size); 220 221 return SYS_ERR_OK; 222} 223 224/// Initialise the state of a new thread structure 225static void thread_init(dispatcher_handle_t disp, struct thread *newthread) 226{ 227 newthread->self = newthread; 228#ifndef NDEBUG 229 newthread->next = newthread->prev = NULL; 230#endif 231 newthread->tls_dtv = NULL; 232 newthread->disp = disp; 233 newthread->coreid = get_dispatcher_generic(disp)->core_id; 234 newthread->userptr = NULL; 235 memset(newthread->userptrs, 0, sizeof(newthread->userptrs)); 236 newthread->yield_epoch = 0; 237 newthread->wakeup_reason = NULL; 238 newthread->return_value = 0; 239 thread_cond_init(&newthread->exit_condition); 240 thread_mutex_init(&newthread->exit_lock); 241 newthread->state = THREAD_STATE_RUNNABLE; 242 newthread->detached = false; 243 newthread->joining = false; 244 newthread->in_exception = false; 245 newthread->paused = false; 246 newthread->slab = NULL; 247 newthread->token = 0; 248 newthread->token_number = 1; 249 250 newthread->rpc_in_progress = false; 251 newthread->async_error = SYS_ERR_OK; 252 newthread->local_trigger = NULL; 253} 254 255/** 256 * \brief Returns false if the stack pointer is out of bounds. 257 */ 258static bool thread_check_stack_bounds(struct thread *thread, 259 arch_registers_state_t *archregs) { 260 lvaddr_t sp = (lvaddr_t) registers_get_sp(archregs); 261 return sp > (lvaddr_t)thread->stack || 262 sp <= (lvaddr_t)thread->stack_top; 263} 264 265/** 266 * \brief Schedule and run the next active thread, or yield the dispatcher. 267 * 268 * This may only be called from the dispatcher (on its stack and while 269 * disabled!). 270 * 271 * \param disp Dispatcher pointer 272 */ 273void thread_run_disabled(dispatcher_handle_t handle) 274{ 275 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 276 struct dispatcher_shared_generic *disp = 277 get_dispatcher_shared_generic(handle); 278 arch_registers_state_t *enabled_area = 279 dispatcher_get_enabled_save_area(handle); 280 281 if (disp_gen->current != NULL) { 282 assert_disabled(disp_gen->runq != NULL); 283 284 // check stack bounds 285 warn_disabled(&stack_warned, 286 thread_check_stack_bounds(disp_gen->current, enabled_area)); 287 288 struct thread *next = disp_gen->current->next; 289 assert_disabled(next != NULL); 290 if (next != disp_gen->current) { 291 // save previous thread's state 292 arch_registers_state_t *cur_regs = &disp_gen->current->regs; 293 memcpy(cur_regs, enabled_area, sizeof(arch_registers_state_t)); 294 disp_gen->current = next; 295 disp_resume(handle, &next->regs); 296 } else { 297 // same thread as before 298 disp_resume(handle, enabled_area); 299 } 300 } else if (disp_gen->runq != NULL) { 301 disp_gen->current = disp_gen->runq; 302 disp->haswork = true; 303 disp_resume(handle, &disp_gen->runq->regs); 304 } else { 305 // kernel gave us the CPU when we have nothing to do. block! 306 disp->haswork = havework_disabled(handle); 307 disp_gen->current = NULL; 308 disp_yield_disabled(handle); 309 } 310} 311 312/** Free all heap/slab-allocated state associated with a thread */ 313static void free_thread(struct thread *thread) 314{ 315#if defined(__x86_64__) // XXX: gungy segment selector stuff 316 assert(thread->thread_seg_selector != 0); 317 uint16_t fs; 318 __asm("mov %%fs, %0" : "=r" (fs)); 319 if (thread->thread_seg_selector == fs) { 320 assert(thread->disp == curdispatcher()); 321 struct dispatcher_x86_64 *disp_priv = get_dispatcher_x86_64(thread->disp); 322 // we're freeing the current thread; make sure we reload a valid segment 323 // selector so that curdispatcher() keeps working! 324 __asm volatile("mov %%ax, %%fs" 325 : /* No outputs */ 326 : "a" (disp_priv->disp_seg_selector)); 327 } 328 ldt_free_segment(thread->thread_seg_selector); 329#endif 330 331 free(thread->stack); 332 if (thread->tls_dtv != NULL) { 333 free(thread->tls_dtv); 334 } 335 336 thread_mutex_lock(&thread_slabs_mutex); 337 acquire_spinlock(&thread_slabs_spinlock); 338 slab_free(&thread_slabs, thread->slab); // frees thread itself 339 release_spinlock(&thread_slabs_spinlock); 340 thread_mutex_unlock(&thread_slabs_mutex); 341} 342 343#define ALIGN_PTR(ptr, alignment) ((((uintptr_t)(ptr)) + (alignment) - 1) & ~((alignment) - 1)) 344 345/** 346 * \brief Creates a new thread that will not be runnable 347 * 348 * \param start_func Function to run on the new thread 349 * \param arg Argument to pass to function 350 * \param stacksize Size of stack, in bytes 351 * 352 * \returns Thread pointer on success, NULL on failure 353 */ 354struct thread *thread_create_unrunnable(thread_func_t start_func, void *arg, 355 size_t stacksize) 356{ 357 // allocate stack 358 assert((stacksize % sizeof(uintptr_t)) == 0); 359 void *stack = malloc(stacksize); 360 if (stack == NULL) { 361 return NULL; 362 } 363 364 // allocate space for TCB + initial TLS data 365 // no mutex as it may deadlock: see comment for thread_slabs_spinlock 366 // thread_mutex_lock(&thread_slabs_mutex); 367 acquire_spinlock(&thread_slabs_spinlock); 368 void *space = slab_alloc(&thread_slabs); 369 release_spinlock(&thread_slabs_spinlock); 370 // thread_mutex_unlock(&thread_slabs_mutex); 371 if (space == NULL) { 372 free(stack); 373 return NULL; 374 } 375 376 // split space into TLS data followed by TCB 377 // XXX: this layout is specific to the x86 ABIs! once other (saner) 378 // architectures support TLS, we'll need to break out the logic. 379 void *tls_data = space; 380 struct thread *newthread = (void *)ALIGN_PTR((uintptr_t)space + tls_block_total_len, THREAD_ALIGNMENT); 381 382 // init thread 383 thread_init(curdispatcher(), newthread); 384 newthread->slab = space; 385 386 if (tls_block_total_len > 0) { 387 // populate initial TLS data from pristine copy 388 assert(tls_block_init_len <= tls_block_total_len); 389 memcpy(tls_data, tls_block_init_base, tls_block_init_len); 390 391 // zero-fill remainder 392 memset((char *)tls_data + tls_block_init_len, 0, 393 tls_block_total_len - tls_block_init_len); 394 395 // create a TLS thread vector 396 struct tls_dtv *dtv = malloc(sizeof(struct tls_dtv) + 1 * sizeof(void *)); 397 assert(dtv != NULL); 398 399 dtv->gen = 0; 400 dtv->dtv[0] = tls_data; 401 newthread->tls_dtv = dtv; 402 } 403 404 // FIXME: make arch-specific 405#if defined(__x86_64__) || defined(__k1om__) 406 // create segment for TCB 407 errval_t err = ldt_alloc_segment(newthread, &newthread->thread_seg_selector); 408 if (err_is_fail(err)) { 409 DEBUG_ERR(err, "error allocating LDT segment for new thread"); 410 free_thread(newthread); 411 free(stack); 412 return NULL; 413 } 414#endif 415 416 // init stack 417 newthread->stack = stack; 418 newthread->stack_top = (char *)stack + stacksize; 419 420 // waste space for alignment, if malloc gave us an unaligned stack 421 newthread->stack_top = (char *)newthread->stack_top 422 - (lvaddr_t)newthread->stack_top % STACK_ALIGNMENT; 423 424 // set thread's ID 425 newthread->id = threadid++; 426 427 // init registers 428 registers_set_initial(&newthread->regs, newthread, (lvaddr_t)thread_entry, 429 (lvaddr_t)newthread->stack_top, 430 (lvaddr_t)start_func, (lvaddr_t)arg, 0, 0); 431 432 return newthread; 433} 434 435/** 436 * \brief Creates a new thread, and makes it runnable 437 * 438 * \param start_func Function to run on the new thread 439 * \param arg Argument to pass to function 440 * \param stacksize Size of stack, in bytes 441 * 442 * \returns Thread pointer on success, NULL on failure 443 */ 444struct thread *thread_create_varstack(thread_func_t start_func, void *arg, 445 size_t stacksize) 446{ 447 struct thread *newthread = thread_create_unrunnable(start_func, arg, stacksize); 448 if (newthread) { 449 // enqueue on runq 450 dispatcher_handle_t handle = disp_disable(); 451 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 452 newthread->disp = handle; 453 thread_enqueue(newthread, &disp_gen->runq); 454 disp_enable(handle); 455 } 456 return newthread; 457} 458 459/** 460 * \brief Creates a new thread, and makes it runnable 461 * 462 * \param start_func Function to run on the new thread 463 * \param arg Argument to pass to function 464 * 465 * \returns Thread pointer on success, NULL on failure 466 */ 467struct thread *thread_create(thread_func_t start_func, void *arg) 468{ 469 return thread_create_varstack(start_func, arg, THREADS_DEFAULT_STACK_BYTES); 470} 471 472/** 473 * \brief Wait for termination of another thread 474 * 475 * \param thread Pointer to thread to wait for 476 * \param retval Pointer to variable to hold return value of thread, or NULL 477 * 478 * \returns SYS_ERR_OK on success, error code on error. 479 */ 480errval_t thread_join(struct thread *thread, int *retval) 481{ 482 assert(thread != NULL); 483 // this function should only be called for threads on same core 484 assert(thread->coreid == disp_get_core_id()); 485 486 thread_mutex_lock(&thread->exit_lock); 487 if(thread->detached) { 488 // Thread is detached and thus not joinable 489 thread_mutex_unlock(&thread->exit_lock); 490 return LIB_ERR_THREAD_JOIN_DETACHED; 491 } 492 493 if(thread->joining) { 494 // Someone else already joins, that's an error 495 thread_mutex_unlock(&thread->exit_lock); 496 return LIB_ERR_THREAD_JOIN; 497 } 498 499 thread->joining = true; 500 if(thread->state != THREAD_STATE_EXITED) { // Possibly wait for thread exit 501 thread_cond_wait(&thread->exit_condition, &thread->exit_lock); 502 } 503 504 if(retval != NULL) { 505 *retval = thread->return_value; 506 } 507 508 thread_mutex_unlock(&thread->exit_lock); // Not really needed 509 free_thread(thread); 510 511 return SYS_ERR_OK; 512} 513 514bool thread_exited(struct thread *thread) { 515 return thread->state == THREAD_STATE_EXITED; 516} 517 518 519/** 520 * \brief Detach a thread. Free its state when it terminates. 521 * 522 * \param thread Pointer to thread to detach 523 * 524 * \return SYS_ERR_OK on success. 525 */ 526errval_t thread_detach(struct thread *thread) 527{ 528 assert(thread != NULL); 529 thread_mutex_lock(&thread->exit_lock); 530 531 if(thread->joining) { 532 // Someone else already joins, that's an error 533 thread_mutex_unlock(&thread->exit_lock); 534 return LIB_ERR_THREAD_JOIN; 535 } 536 537 if(!thread->detached) { 538 thread->detached = true; 539 } else { 540 // Detaching more than once is an error 541 thread_mutex_unlock(&thread->exit_lock); 542 return LIB_ERR_THREAD_DETACHED; 543 } 544 545 if(thread->state == THREAD_STATE_EXITED) { 546 // Thread already exited before we detached, clean it up 547 free_thread(thread); 548 return SYS_ERR_OK; 549 } 550 551 thread_mutex_unlock(&thread->exit_lock); 552 return SYS_ERR_OK; 553} 554 555/** 556 * \brief Returns the thread pointer to the currently-running thread 557 */ 558struct thread *thread_self(void) 559{ 560 struct thread *me; 561#if defined(__x86_64__) // XXX: AB's silly little arch-specific optimisation 562 __asm("movq %%fs:0, %0" : "=r" (me)); 563#else 564 // it's not necessary to disable, but might be once we do migration 565 bool was_enabled; 566 dispatcher_handle_t handle = disp_try_disable(&was_enabled); 567 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 568 me = disp_gen->current; 569 if (was_enabled) 570 disp_enable(handle); 571#endif 572 return me; 573} 574 575struct thread *thread_self_disabled(void) 576{ 577 dispatcher_handle_t handle = curdispatcher(); 578 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 579 return disp_gen->current; 580} 581 582uintptr_t thread_id(void) 583{ 584 return thread_self()->id; 585} 586 587uintptr_t thread_get_id(struct thread *t) 588{ 589 return t->id; 590} 591 592void thread_set_id(uintptr_t id) 593{ 594 struct thread *me = thread_self(); 595 me->id = id; 596} 597 598uint32_t thread_set_token(struct waitset_chanstate *channel) 599{ 600 struct thread *me = thread_self(); 601 // generate new token 602 uint32_t outgoing_token = (uint32_t)((me->id << 16) | 603 (me->coreid << 24) | ((me->token_number & 255) << 8)) | 1; 604 assert(me->token == 0); 605 me->token_number++; 606 if (!(me->token_number & 255)) 607 me->token_number = 1; 608 me->token = outgoing_token & ~1; // wait for this token 609 me->channel = channel; // on that channel 610 return outgoing_token; 611} 612 613void thread_clear_token(struct waitset_chanstate *channel) 614{ 615 struct thread *me = thread_self(); 616 617 me->token = 0; // don't wait anymore 618 me->channel = NULL; 619} 620 621uint32_t thread_current_token(void) 622{ 623 return thread_self()->token; 624} 625 626void thread_set_outgoing_token(uint32_t token) 627{ 628 struct thread *me = thread_self(); 629 630 assert(!me->outgoing_token); 631 me->outgoing_token = token; 632} 633 634void thread_get_outgoing_token(uint32_t *token) 635{ 636 struct thread *me = thread_self(); 637 // if thread's outgoing token is set, get it 638 if (me->outgoing_token) { 639 *token = me->outgoing_token; 640 me->outgoing_token = 0; 641 } 642} 643 644void thread_set_local_trigger(struct waitset_chanstate *trigger) 645{ 646 struct thread *me = thread_self(); 647 me->local_trigger = trigger; 648} 649 650struct waitset_chanstate * thread_get_local_trigger(void) 651{ 652 struct thread *me = thread_self(); 653 return me->local_trigger; 654} 655 656void thread_set_rpc_in_progress(bool v) 657{ 658 thread_self()->rpc_in_progress = v; 659} 660 661bool thread_get_rpc_in_progress(void) 662{ 663 return thread_self()->rpc_in_progress; 664} 665 666void thread_set_async_error(errval_t e) 667{ 668 thread_self()->async_error = e; 669} 670 671errval_t thread_get_async_error(void) 672{ 673 return thread_self()->async_error; 674} 675 676/** 677 * \brief Store receive slot provided by rpc 678 */ 679 680void thread_store_recv_slot(struct capref recv_slot) 681{ 682 dispatcher_handle_t handle = disp_disable(); 683 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 684 685 assert(disp_gen->recv_slot_count < MAX_RECV_SLOTS); 686 assert(disp_gen->recv_slot_count >= 0); 687 disp_gen->recv_slots[disp_gen->recv_slot_count++] = recv_slot; 688 689 disp_enable(handle); 690} 691 692struct capref thread_get_next_recv_slot(void) 693{ 694 dispatcher_handle_t handle = disp_disable(); 695 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 696 struct capref retcap; 697 698 // HERE: recv_slot_count is > 0 if we have one+ caps stored 699 if (disp_gen->recv_slot_count <= 0) { 700 retcap = NULL_CAP; 701 } else { 702 retcap = disp_gen->recv_slots[--disp_gen->recv_slot_count]; 703 } 704 disp_enable(handle); 705 return retcap; 706} 707 708void thread_set_status(int status) { 709 struct thread *me = thread_self(); 710 me->return_value = status; 711} 712 713void *thread_get_stack_top(void) { 714 return thread_self()->stack_top; 715} 716 717/** 718 * \brief Yield the calling thread 719 * 720 * Switches to the next runnable thread in this dispatcher, or if none is 721 * available, yields the dispatcher. 722 */ 723void thread_yield(void) 724{ 725 dispatcher_handle_t handle = disp_disable(); 726 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 727 struct dispatcher_shared_generic *disp = 728 get_dispatcher_shared_generic(handle); 729 arch_registers_state_t *enabled_area = 730 dispatcher_get_enabled_save_area(handle); 731 732 struct thread *me = disp_gen->current; 733 struct thread *next = me; 734 me->yield_epoch = disp_gen->timeslice; 735 736 do { 737 assert_disabled(next != NULL); 738 next = next->next; 739 if (next == me) { 740 break; // Everybody yielded this timeslice 741 } 742 } while(next->yield_epoch == disp_gen->timeslice); 743 744 poll_channels_disabled(handle); 745 746 if (next != me) { 747 disp_gen->current = next; 748 disp_switch(handle, &me->regs, &next->regs); 749 } else { 750 assert_disabled(disp_gen->runq != NULL); 751 assert_disabled(disp->haswork); 752 trace_event(TRACE_SUBSYS_THREADS, TRACE_EVENT_THREADS_C_DISP_SAVE, 3); 753 disp_save(handle, enabled_area, true, CPTR_NULL); 754 } 755} 756 757/** 758 * \brief Yield both the calling thread, and the dispatcher to another domain 759 * 760 * \param endpoint Endpoint cap to which we wish to yield, or #CAP_NULL 761 * for an undirected yield 762 * 763 * Yields the dispatcher, optionally to another specified dispatcher. 764 */ 765void thread_yield_dispatcher(struct capref endpoint) 766{ 767 dispatcher_handle_t handle = disp_disable(); 768 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 769 struct dispatcher_shared_generic *disp = 770 get_dispatcher_shared_generic(handle); 771 arch_registers_state_t *enabled_area = 772 dispatcher_get_enabled_save_area(handle); 773 774 assert_disabled(disp_gen->runq != NULL); 775 assert_disabled(disp->haswork); 776 777 trace_event(TRACE_SUBSYS_THREADS, TRACE_EVENT_THREADS_C_DISP_SAVE, 1); 778 disp_save(handle, enabled_area, true, get_cap_addr(endpoint)); 779} 780 781/// Function that runs on the static thread/stack to clean up a "real" (alloced) thread 782static int cleanup_thread(void *arg) 783{ 784 struct thread *thread = arg; 785 786 // free old thread and its stack 787 if (thread != NULL) { 788 free_thread(thread); 789 } 790 791 // disable and release static thread 792 dispatcher_handle_t handle = disp_disable(); 793 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 794 struct dispatcher_shared_generic *disp = 795 get_dispatcher_shared_generic(handle); 796 struct thread *me = disp_gen->current; 797 struct thread *ft = 798 thread_mutex_unlock_disabled(handle, &disp_gen->cleanupthread_lock); 799 assert(ft == NULL); 800 801 // run the next thread, if any 802 struct thread *next = me->next; 803 thread_remove_from_queue(&disp_gen->runq, me); 804 if (next != me) { 805 disp_gen->current = next; 806 disp_resume(handle, &next->regs); 807 } else { 808 disp_gen->current = NULL; 809 disp->haswork = havework_disabled(handle); 810 disp_yield_disabled(handle); 811 } 812 813 return 0; 814} 815 816/** 817 * \brief Terminate the calling thread 818 */ 819void thread_exit(int status) 820{ 821 struct thread *me = thread_self(); 822 823 thread_mutex_lock(&me->exit_lock); 824 825 // if this is the static thread, we don't need to do anything but cleanup 826 if (me == &staticthread) { 827 assert(me->detached); 828 // disable and release static thread 829 dispatcher_handle_t handle = disp_disable(); 830 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 831 struct dispatcher_shared_generic *disp = 832 get_dispatcher_shared_generic(handle); 833 assert_disabled(me == &staticthread); 834 assert_disabled(me->stack == staticstack); 835 struct thread *ft = 836 thread_mutex_unlock_disabled(handle, &staticthread_lock); 837 assert(ft == NULL); 838 839 // run the next thread, if any 840 struct thread *next = me->next; 841 thread_remove_from_queue(&disp_gen->runq, me); 842 if (next != me) { 843 disp_gen->current = next; 844 disp_resume(handle, &next->regs); 845 } else { 846 disp_gen->current = NULL; 847 disp->haswork = havework_disabled(handle); 848 disp_yield_disabled(handle); 849 } 850 } 851 852 if (me->detached) { 853 // otherwise, we use a dispatcher-local thread to perform cleanup 854 struct dispatcher_generic *dg = get_dispatcher_generic(curdispatcher()); 855 thread_mutex_lock(&dg->cleanupthread_lock); 856 if(dg->cleanupthread == NULL) { 857 dg->cleanupthread = 858 thread_create_unrunnable(cleanup_thread, me, 859 THREADS_DEFAULT_STACK_BYTES); 860 } 861 thread_init(curdispatcher(), dg->cleanupthread); 862 863 registers_set_initial(&dg->cleanupthread->regs, dg->cleanupthread, 864 (lvaddr_t)cleanup_thread, 865 (lvaddr_t)dg->cleanupthread->stack_top, (lvaddr_t)me, 866 0, 0, 0); 867 868 // Switch to it (on this dispatcher) 869 dispatcher_handle_t handle = disp_disable(); 870 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 871 872 thread_remove_from_queue(&disp_gen->runq, me); 873 thread_enqueue(dg->cleanupthread, &disp_gen->runq); 874 disp_gen->cleanupthread->disp = handle; 875 disp_gen->current = dg->cleanupthread; 876 disp_resume(handle, &dg->cleanupthread->regs); 877 } else { 878 // We're not detached -- wakeup joiner 879 me->return_value = status; 880 me->state = THREAD_STATE_EXITED; 881 thread_cond_signal(&me->exit_condition); 882 883 // Disable and unlock exit lock 884 dispatcher_handle_t handle = disp_disable(); 885 struct thread *wakeup = 886 thread_mutex_unlock_disabled(handle, &me->exit_lock); 887 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 888 struct dispatcher_shared_generic *disp = 889 get_dispatcher_shared_generic(handle); 890 891 assert_disabled(wakeup == NULL); 892 893 // run the next thread, if any 894 struct thread *next = me->next; 895 thread_remove_from_queue(&disp_gen->runq, me); 896 if (next != me) { 897 disp_gen->current = next; 898 disp_resume(handle, &next->regs); 899 } else { 900 disp_gen->current = NULL; 901 disp->haswork = havework_disabled(handle); 902 disp_yield_disabled(handle); 903 } 904 } 905 906 USER_PANIC("should never be reached"); 907} 908 909/** 910 * \brief Block the caller, and optionally release a spinlock, while disabled 911 * 912 * The caller is unconditionally blocked, and placed into the given queue 913 * pending a call that will unblock it. After manipulating the queues, and 914 * before switching threds, the given spinlock, if specified, is unlocked. 915 * This function must only be called while disabled. 916 * 917 * This function is intended for use by multi-processor thread synchronisation 918 * functions. 919 * 920 * \param disp Dispatcher pointer 921 * \param queue (Optional) Queue of threads in which to place caller 922 * \param spinlock (Optional) pointer to spinlock 923 * 924 * \returns Argument passed to thread_unblock, when unblocked 925 */ 926void *thread_block_and_release_spinlock_disabled(dispatcher_handle_t handle, 927 struct thread **queue, 928 spinlock_t *spinlock) 929{ 930 struct dispatcher_shared_generic *disp = 931 get_dispatcher_shared_generic(handle); 932 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 933 struct thread *me = disp_gen->current; 934 struct thread *next = me->next; 935 assert_disabled(next != NULL); 936 937 assert_disabled(me->state == THREAD_STATE_RUNNABLE); 938 me->state = THREAD_STATE_BLOCKED; 939 940 thread_remove_from_queue(&disp_gen->runq, me); 941 if (queue != NULL) { 942 thread_enqueue(me, queue); 943 } 944 945 if (spinlock != NULL) { 946 release_spinlock(spinlock); 947 } 948 949 if (next != me) { 950 assert_disabled(disp_gen->runq != NULL); 951 disp_gen->current = next; 952 disp_switch(handle, &me->regs, &next->regs); 953 } else { 954 assert_disabled(disp_gen->runq == NULL); 955 disp_gen->current = NULL; 956 disp->haswork = havework_disabled(handle); 957 trace_event(TRACE_SUBSYS_THREADS, TRACE_EVENT_THREADS_C_DISP_SAVE, 2); 958 disp_save(handle, &me->regs, true, CPTR_NULL); 959 } 960 961 assert(me->disp == handle); // didn't migrate while asleep 962 return me->wakeup_reason; 963} 964 965/** 966 * \brief Block the calling thread, while disabled 967 * 968 * The caller is unconditionally blocked, and placed into the given queue 969 * pending a call that will unblock it. 970 * This function must only be called while disabled. 971 * 972 * \param disp Dispatcher pointer 973 * \param queue Queue of threads in which to place caller 974 * 975 * \returns Argument passed to thread_unblock, when unblocked 976 */ 977void *thread_block_disabled(dispatcher_handle_t disp, struct thread **queue) 978{ 979 return thread_block_and_release_spinlock_disabled(disp, queue, NULL); 980} 981 982/** 983 * \brief Block the calling thread, while enabled 984 * 985 * The caller is unconditionally blocked, and placed into the given queue 986 * pending a call that will unblock it. 987 * This function must only be called while enabled. 988 * 989 * \param queue Queue of threads in which to place caller 990 * 991 * \returns Argument passed to thread_unblock, when unblocked 992 */ 993void *thread_block(struct thread **queue) 994{ 995 return thread_block_disabled(disp_disable(), queue); 996} 997 998/** 999 * \brief Unblock a single thread from a given queue, while disabled 1000 * 1001 * A single thread is removed from the queue of blocked threads, and awoken. 1002 * This function must only be called while disabled. 1003 * 1004 * \param disp Dispatcher pointer 1005 * \param queue Queue of threads from which to unblock one 1006 * \param reason Value to be returned from thread_block() 1007 * 1008 * \returns Pointer to thread to be woken on a foreign dispatcher 1009 */ 1010struct thread *thread_unblock_one_disabled(dispatcher_handle_t handle, 1011 struct thread **queue, 1012 void *reason) 1013{ 1014 assert_disabled(queue != NULL); 1015 1016 // Any threads in queue? 1017 if (*queue == NULL) { 1018 return NULL; 1019 } 1020 1021 // Wakeup one waiting thread 1022 struct thread *wakeup = thread_dequeue(queue); 1023 wakeup->wakeup_reason = reason; 1024 assert_disabled(wakeup->state == THREAD_STATE_BLOCKED); 1025 wakeup->state = THREAD_STATE_RUNNABLE; 1026 1027 /* enqueue on run queue if it's "our" thread, and not paused */ 1028 if (wakeup->disp == handle) { 1029 if (!wakeup->paused) { 1030 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 1031 thread_enqueue(wakeup, &disp_gen->runq); 1032 } 1033 return NULL; 1034 } else { 1035 return wakeup; 1036 } 1037} 1038 1039/** 1040 * \brief Unblock a single thread from a given queue, while enabled 1041 * 1042 * A single thread is removed from the queue of blocked threads, and awoken. 1043 * This function must only be called while enabled. 1044 * 1045 * \param queue Queue of threads from which to unblock one 1046 * \param reason Value to be returned from thread_block() 1047 * 1048 * \returns Pointer to thread to be woken on a foreign dispatcher 1049 */ 1050struct thread *thread_unblock_one(struct thread **queue, void *reason) 1051{ 1052 struct thread *thread; 1053 1054 dispatcher_handle_t handle = disp_disable(); 1055 thread = thread_unblock_one_disabled(handle, queue, reason); 1056 disp_enable(handle); 1057 return thread; 1058} 1059 1060/** 1061 * \brief Unblock all threads on a given queue, while disabled 1062 * 1063 * All threads on the queue of blocked threads are awoken. 1064 * This function must only be called while disabled. 1065 * 1066 * \param disp Dispatcher pointer 1067 * \param queue Queue of threads to unblock 1068 * \param reason Value to be returned from thread_block() 1069 * 1070 * \returns Pointer to list of threads to be woken on a foreign dispatcher 1071 */ 1072struct thread *thread_unblock_all_disabled(dispatcher_handle_t handle, 1073 struct thread **queue, void *reason) 1074{ 1075 assert_disabled(queue != NULL); 1076 struct thread *wakeupq = NULL; 1077 1078 // Wakeup all waiting threads 1079 while (*queue != NULL) { 1080 struct thread *wakeup = thread_unblock_one_disabled(handle, queue, reason); 1081 if (wakeup != NULL) { 1082 wakeup->next = wakeupq; 1083 wakeupq = wakeup; 1084 } 1085 } 1086 1087 return wakeupq; 1088} 1089 1090extern int _main(int argc, const char *argv[]); 1091 1092/// Thread created in new domain that runs main() 1093static int main_thread(void *params) 1094{ 1095 struct spawn_domain_params *p = params; 1096 exit(_main(p->argc, p->argv)); 1097 return EXIT_FAILURE; 1098} 1099 1100static bool init_domain_global; // XXX 1101 1102/// Thread created on static stack in new domain that runs init code 1103static int bootstrap_thread(struct spawn_domain_params *params) 1104//int bootstrap_thread(struct spawn_domain_params *params); 1105//int bootstrap_thread(struct spawn_domain_params *params) 1106{ 1107 errval_t err; 1108 1109 // Set libc function pointers 1110 barrelfish_libc_glue_init(); 1111 1112 if (params == NULL) { 1113 printf("%s: error in creating a thread, NULL parameters given\n", 1114 disp_name()); 1115 } 1116 assert(params != NULL); 1117 1118 // Do we have TLS data? 1119 tls_block_init_base = params->tls_init_base; 1120 tls_block_init_len = params->tls_init_len; 1121 tls_block_total_len = params->tls_total_len; 1122 1123 // Initialize subsystems 1124 err = barrelfish_init_onthread(params); 1125 if (err_is_fail(err)) { 1126 DEBUG_ERR(err, "error during libbarrelfish init"); 1127 exit(EXIT_FAILURE); 1128 assert(!"exit returned!"); 1129 } 1130 1131 // Allocate storage region for real threads 1132 size_t blocksize = sizeof(struct thread) + tls_block_total_len + THREAD_ALIGNMENT; 1133 err = vspace_mmu_aware_init(&thread_slabs_vm, MAX_THREADS * blocksize); 1134 if (err_is_fail(err)) { 1135 USER_PANIC_ERR(err, "vspace_mmu_aware_init for thread region failed\n"); 1136 } 1137 // XXX: do this nicer, but we need struct threads to be in Vspace < 4GB so 1138 // we can set the thread segment register. -SG, 2017-02-28. 1139 // We can't use the assertion yet, as the init domain has it's thread 1140 // slabs above 4G. 1141 //assert(vregion_get_base_addr(&thread_slabs_vm.vregion) + vregion_get_size(&thread_slabs_vm.vregion) < 1ul << 32); 1142 slab_init(&thread_slabs, blocksize, refill_thread_slabs); 1143 1144 if (init_domain_global) { 1145 // run main() on this thread, since we can't allocate 1146 if (tls_block_total_len > 0) { 1147 USER_PANIC("unsupported: use of TLS data in bootstrap domain\n"); 1148 } 1149 main_thread(params); 1150 } else { 1151 // Start real thread to run main() 1152 struct thread *thread = thread_create(main_thread, params); 1153 assert(thread != NULL); 1154 } 1155 1156 return 0; // ignored 1157} 1158 1159/** 1160 * \brief Initialise thread system while still disabled 1161 * 1162 * This function initialises the thread system while the dispatcher is still 1163 * disabled, before enabling the dispatcher, running the general initialisation 1164 * code, and calling main(). 1165 * 1166 * \param disp Dispatcher pointer 1167 * \param init_domain True if we are a bootstrap domain 1168 */ 1169void thread_init_disabled(dispatcher_handle_t handle, bool init_domain) 1170{ 1171 struct dispatcher_shared_generic *disp = 1172 get_dispatcher_shared_generic(handle); 1173 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 1174 arch_registers_state_t *enabled_area = 1175 dispatcher_get_enabled_save_area(handle); 1176 1177 init_domain_global = init_domain; 1178 1179 // Create the first thread manually 1180 struct thread *thread = &staticthread; 1181 staticthread_lock.locked = true; // XXX: safe while disabled 1182 1183 // waste space for alignment, if unaligned 1184 thread->stack_top = (char *)thread->stack_top 1185 - (lvaddr_t)thread->stack_top % STACK_ALIGNMENT; 1186 1187 // Initialise the first (static) thread 1188 thread_init(handle, thread); 1189 thread->detached = true; 1190 1191#if defined(__x86_64__) 1192 // create segment for TCB 1193 errval_t err = ldt_alloc_segment_disabled(handle, thread, 1194 &thread->thread_seg_selector); 1195 if (err_is_fail(err)) { 1196 USER_PANIC_ERR(err, "error allocating LDT segment for first thread"); 1197 } 1198#endif 1199 1200 uintptr_t param; 1201 registers_get_param(enabled_area, ¶m); 1202 1203 registers_set_initial(&thread->regs, thread, (lvaddr_t)thread_entry, 1204 /* TODO: pass stack base and limit, choose in arch 1205 * code (possibly setting up other hints on stack) */ 1206 (lvaddr_t)thread->stack_top, 1207 (lvaddr_t)bootstrap_thread, param, 0, 0); 1208 1209 // Switch to it (always on this dispatcher) 1210 thread->disp = handle; 1211 thread_enqueue(thread, &disp_gen->runq); 1212 disp_gen->current = thread; 1213 disp->haswork = true; 1214 disp_resume(handle, &thread->regs); 1215} 1216 1217/** 1218 * \brief Called on the remote core when spanning a domain across cores 1219 * 1220 * Runs the provided thread after enqueuing it and enabling the dispatcher 1221 */ 1222void thread_init_remote(dispatcher_handle_t handle, struct thread *thread) 1223{ 1224 struct dispatcher_shared_generic *disp = 1225 get_dispatcher_shared_generic(handle); 1226 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 1227 thread_enqueue(thread, &disp_gen->runq); 1228 disp_gen->current = thread; 1229 disp->haswork = true; 1230 disp_resume(handle, &thread->regs); 1231} 1232 1233/** 1234 * \brief Prepare to span the current domain 1235 * 1236 * This is a kludge. It is called from domain.c when creating a new dispatcher, 1237 * and is responsible for pre-allocating all the storage that might be needed 1238 * for thread metadata in the slab allocator. It can go away once we sanely 1239 * manage the vspace across multiple dispatchers in a domain. 1240 */ 1241void threads_prepare_to_span(dispatcher_handle_t newdh) 1242{ 1243 static bool called; 1244 1245 if (!called) { 1246 called = true; 1247 1248 thread_mutex_lock(&thread_slabs_mutex); 1249 acquire_spinlock(&thread_slabs_spinlock); 1250 1251 while (slab_freecount(&thread_slabs) < MAX_THREADS - 1) { 1252 size_t size; 1253 void *buf; 1254 errval_t err; 1255 1256 size_t blocksize = sizeof(struct thread) + tls_block_total_len; 1257 err = vspace_mmu_aware_map(&thread_slabs_vm, 64 * blocksize, 1258 &buf, &size); 1259 if (err_is_fail(err)) { 1260 if (err_no(err) == LIB_ERR_VSPACE_MMU_AWARE_NO_SPACE) { 1261 // we've wasted space with fragmentation 1262 // cross our fingers and hope for the best... 1263 break; 1264 } 1265 USER_PANIC_ERR(err, "in vspace_mmu_aware_map while prefilling " 1266 "thread slabs\n"); 1267 } 1268 1269 slab_grow(&thread_slabs, buf, size); 1270 } 1271 1272 release_spinlock(&thread_slabs_spinlock); 1273 thread_mutex_unlock(&thread_slabs_mutex); 1274 } 1275} 1276 1277/** 1278 * \brief Pause (suspend execution of) the given thread, and optionally capture its register state 1279 * 1280 * The thread will not be run, until a subsequent call to thread_resume() 1281 */ 1282void thread_pause_and_capture_state(struct thread *thread, 1283 arch_registers_state_t **ret_regs) 1284{ 1285 assert(thread != NULL); 1286 dispatcher_handle_t dh = disp_disable(); 1287 struct dispatcher_generic *disp = get_dispatcher_generic(dh); 1288 if (thread->disp == dh) { 1289 if (!thread->paused) { 1290 thread->paused = true; 1291 if (thread == disp->current) { // doesn't make much sense... 1292 sys_print("Warning: pausing current thread!\n",100); 1293 assert_disabled(thread->state == THREAD_STATE_RUNNABLE); 1294 thread_block_disabled(dh, NULL); 1295 } else if (thread->state == THREAD_STATE_RUNNABLE) { 1296 thread_remove_from_queue(&disp->runq, thread); 1297 } 1298 } 1299 if (ret_regs != NULL) { 1300 *ret_regs = &thread->regs; 1301 } 1302 } else { 1303 USER_PANIC("NYI: remote dispatcher thread_pause()"); 1304 } 1305 disp_enable(dh); 1306} 1307 1308/** 1309 * \brief Pause (suspend execution of) the given thread 1310 * 1311 * The thread will not be run, until a subsequent call to thread_resume() 1312 */ 1313void thread_pause(struct thread *thread) 1314{ 1315 thread_pause_and_capture_state(thread, NULL); 1316} 1317 1318/** 1319 * \brief Resume execution of a thread previously suspended by thread_pause() 1320 */ 1321void thread_resume(struct thread *thread) 1322{ 1323 assert(thread != NULL); 1324 dispatcher_handle_t dh = disp_disable(); 1325 struct dispatcher_generic *disp = get_dispatcher_generic(dh); 1326 if (thread->disp == dh) { 1327 if (thread->paused) { 1328 thread->paused = false; 1329 if (thread->state == THREAD_STATE_RUNNABLE) { 1330 thread_enqueue(thread, &disp->runq); 1331 } 1332 } 1333 } else { 1334 USER_PANIC("NYI: remote dispatcher thread_resume()"); 1335 } 1336 disp_enable(dh); 1337} 1338 1339/** 1340 * \brief Set old-style thread-local storage pointer. 1341 * \param p User's pointer 1342 */ 1343void thread_set_tls(void *p) 1344{ 1345 struct thread *me = thread_self(); 1346 me->userptr = p; 1347} 1348 1349void thread_set_tls_key(int key, void *p) 1350{ 1351 struct thread *me = thread_self(); 1352 me->userptrs[key] = p; 1353} 1354 1355/** 1356 * \brief Return old-style thread-local storage pointer. 1357 * \return User's pointer, previously passed to thread_set_tls() 1358 */ 1359void *thread_get_tls(void) 1360{ 1361 struct thread *me = thread_self(); 1362 return me->userptr; 1363} 1364 1365void *thread_get_tls_key(int key) 1366{ 1367 struct thread *me = thread_self(); 1368 return me->userptrs[key]; 1369} 1370 1371/** 1372 * \brief Set the exception handler function for the current thread. 1373 * Optionally also change its stack, and return the old values. 1374 * 1375 * \param newhandler New exception handler. Pass NULL to disable an existing handler. 1376 * \param oldhandler If non-NULL, returns previous exception handler 1377 * \param new_stack_base If non-NULL, sets a new exception handler stack (base) 1378 * \param new_stack_top If non-NULL, sets a new exception handler stack (top) 1379 * \param old_stack_base If non-NULL, returns previous stack base 1380 * \param old_stack_top If non-NULL, returns previous stack top 1381 */ 1382errval_t thread_set_exception_handler(exception_handler_fn newhandler, 1383 exception_handler_fn *oldhandler, 1384 void *new_stack_base, void *new_stack_top, 1385 void **old_stack_base, void **old_stack_top) 1386{ 1387 struct thread *me = thread_self(); 1388 1389 if (oldhandler != NULL) { 1390 *oldhandler = me->exception_handler; 1391 } 1392 1393 if (old_stack_base != NULL) { 1394 *old_stack_base = me->exception_stack; 1395 } 1396 1397 if (old_stack_top != NULL) { 1398 *old_stack_top = me->exception_stack_top; 1399 } 1400 1401 me->exception_handler = newhandler; 1402 1403 if (new_stack_base != NULL && new_stack_top != NULL) { 1404 me->exception_stack = new_stack_base; 1405 me->exception_stack_top = new_stack_top; 1406 } 1407 1408 return SYS_ERR_OK; 1409} 1410 1411static void exception_handler_wrapper(arch_registers_state_t *cpuframe, 1412 uintptr_t hack_arg, void *addr) 1413{ 1414 struct thread *me = thread_self(); 1415 1416 assert(me->in_exception); 1417 assert(me->exception_handler != NULL); 1418 1419 // XXX: unpack hack arg 1420 enum exception_type type = hack_arg >> 16; 1421 int subtype = hack_arg & 0xffff; 1422 1423 // run handler 1424 me->exception_handler(type, subtype, addr, cpuframe); 1425 1426 // resume state 1427 dispatcher_handle_t dh = disp_disable(); 1428 struct dispatcher_generic *disp_gen = get_dispatcher_generic(dh); 1429 //memcpy(&me->regs, cpuframe, sizeof(arch_registers_state_t)); 1430 1431 assert_disabled(me->in_exception); 1432 me->in_exception = false; 1433 1434 assert_disabled(disp_gen->current == me); 1435 disp_resume(dh, cpuframe); 1436} 1437 1438#if 0 1439void thread_debug_regs(struct thread *t); 1440void thread_debug_regs(struct thread *t) 1441{ 1442 printf("%d: RIP = %lx, RSP = %lx\n", disp_get_domain_id(), 1443 t->regs.rip, t->regs.rsp); 1444 uint64_t *stack = (uint64_t *)t->regs.rsp; 1445 printf("%d: ", disp_get_domain_id()); 1446 for(int i = 0; i < 30; i++) { 1447 printf("%lx ", stack[i]); 1448 } 1449 printf("\n"); 1450} 1451#endif 1452 1453/** 1454 * \brief Deliver an exception to the current thread, and resume. 1455 * 1456 * This may only be called from the dispatcher (on its stack and while 1457 * disabled!). 1458 * 1459 * \param handle Dispatcher handle 1460 * \param type Exception type 1461 * \param subtype Exception subtype 1462 * \param addr Exception address 1463 * \param regs CPU register state at time of exception 1464 */ 1465void thread_deliver_exception_disabled(dispatcher_handle_t handle, 1466 enum exception_type type, int subtype, 1467 void *addr, arch_registers_state_t *regs) 1468{ 1469 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 1470 struct dispatcher_shared_generic *disp =get_dispatcher_shared_generic(handle); 1471 struct thread *thread = disp_gen->current; 1472 assert_disabled(thread != NULL); 1473 assert_disabled(disp_gen->runq != NULL); 1474 1475 char str[256]; 1476 1477 // can we deliver the exception? 1478 if (thread->exception_handler == NULL || thread->exception_stack_top == NULL 1479 || thread->in_exception) { 1480 if (thread->in_exception) { 1481 snprintf(str, sizeof(str), 1482 "%s.%d: Can't deliver exception to thread: already in handler\n", 1483 disp->name, disp_get_core_id()); 1484 sys_print(str, sizeof(str)); 1485 } else { 1486 snprintf(str, sizeof(str), 1487 "%s.%d: Can't deliver exception to thread: handler not set\n", 1488 disp->name, disp_get_core_id()); 1489 sys_print(str, sizeof(str)); 1490 } 1491 1492 // warn on stack overflow. 1493 lvaddr_t sp = (lvaddr_t) registers_get_sp(regs); 1494 lvaddr_t ip = (lvaddr_t) registers_get_ip(regs); 1495 1496 snprintf(str, sizeof(str), "%.*s.%d: Thread interrupted at IP %"PRIxLVADDR"\n", 1497 DISP_NAME_LEN, disp->name, disp_get_core_id(), (lvaddr_t)ip); 1498 sys_print(str, sizeof(str)); 1499 1500 if (sp < (lvaddr_t)thread->stack || 1501 sp > (lvaddr_t)thread->stack_top) { 1502 snprintf(str, sizeof(str), "Error: stack bounds exceeded: sp = 0x%" 1503 PRIxPTR " but [bottom, top] = [0x%" PRIxPTR ", 0x%" 1504 PRIxPTR "]\n", (lvaddr_t) sp, (lvaddr_t) thread->stack, 1505 (lvaddr_t) thread->stack_top); 1506 sys_print(str, sizeof(str)); 1507 } 1508 1509 // TODO: actually delete the thread! 1510 disp_gen->current = NULL; 1511 thread_remove_from_queue(&disp_gen->runq, thread); 1512 return; 1513 } 1514 1515 thread->in_exception = true; 1516 1517 lvaddr_t stack_top = (lvaddr_t)thread->exception_stack_top; 1518 1519 // save thread's state at time of fault on top of exception stack 1520 stack_top -= sizeof(arch_registers_state_t); 1521 // Make sure we store the state at an aligned position 1522 stack_top -= stack_top % STACK_ALIGNMENT; 1523 arch_registers_state_t *cpuframe = (void *)stack_top; 1524 memcpy(cpuframe, regs, sizeof(arch_registers_state_t)); 1525 1526 // XXX: sanity-check to ensure we have a sensible amount of exception stack left 1527 assert_disabled(stack_top > (lvaddr_t)thread->exception_stack + 8192); 1528 1529 // XXX: pack two small ints together to fit into a single register 1530 uintptr_t hack_arg = (uintptr_t)type << 16 | (subtype & 0xffff); 1531 1532 registers_set_initial(&thread->regs, thread, 1533 (lvaddr_t)exception_handler_wrapper, 1534 stack_top, (lvaddr_t)cpuframe, 1535 hack_arg, (lvaddr_t)addr, 0); 1536 1537 disp_resume(handle, &thread->regs); 1538} 1539