| 745 | } |
| 746 | |
| 747 | void SaveStateManager::stopThisThread(int signum) |
| 748 | { |
| 749 | GlobalNative gn; |
| 750 | |
| 751 | ThreadInfo *current_thread = ThreadManager::getCurrentThread(); |
| 752 | |
| 753 | if (current_thread->state == ThreadInfo::ST_TERMINATED) { |
| 754 | pthread_exit(nullptr); |
| 755 | } |
| 756 | |
| 757 | if (current_thread->state == ThreadInfo::ST_CKPNTHREAD) { |
| 758 | return; |
| 759 | } |
| 760 | |
| 761 | /* Make sure we don't get called twice for same thread */ |
| 762 | if (ThreadManager::updateState(current_thread, ThreadInfo::ST_SUSPINPROG, ThreadInfo::ST_SIGNALED)) { |
| 763 | |
| 764 | /* Set up our restart point, ie, we get jumped to here after a restore */ |
| 765 | |
| 766 | ThreadLocalStorage::saveTLSState(¤t_thread->tlsInfo); // save thread local storage |
| 767 | MYASSERT(getcontext(¤t_thread->savctx) == 0) |
| 768 | |
| 769 | /* We save the current stack pointer, so that we can use the remaining |
| 770 | * space in the stack as a stack segment for the clone() call if the current |
| 771 | * thread has to be created */ |
| 772 | save_sp(¤t_thread->saved_sp); |
| 773 | |
| 774 | if (!restoreInProgress) { |
| 775 | |
| 776 | /* Both state saving and state loading operations go here first, to |
| 777 | * suspend the thread. */ |
| 778 | |
| 779 | /* Tell the checkpoint thread that we're all saved away */ |
| 780 | MYASSERT(ThreadManager::updateState(current_thread, ThreadInfo::ST_SUSPENDED, ThreadInfo::ST_SUSPINPROG)) |
| 781 | sem_post(&semNotifyCkptThread); |
| 782 | |
| 783 | /* Then wait for the ckpt thread to write the ckpt file then wake us up */ |
| 784 | LOG(LL_DEBUG, LCF_CHECKPOINT, "Thread suspended"); |
| 785 | |
| 786 | /* Before suspending, we must position the stack pointer so that it |
| 787 | * always takes the same value. Because the stack pointer may not be |
| 788 | * the same between saving and loading the thread, and so returning |
| 789 | * after the `pthread_mutex_lock()` will cause a crash. |
| 790 | * To do that, we allocate on the stack a big array so that we reach |
| 791 | * near the end of the stack. */ |
| 792 | ptrdiff_t free_space = reinterpret_cast<ptrdiff_t>(current_thread->saved_sp) |
| 793 | - reinterpret_cast<ptrdiff_t>(current_thread->stack_addr); |
| 794 | free_space -= 4096*4; // Arbitrary size left to run the remaining code |
| 795 | |
| 796 | LOG(LL_DEBUG, LCF_CHECKPOINT, "Current stack pointer %p and base stack %p size %zu, allocate %td bytes", current_thread->saved_sp, current_thread->stack_addr, current_thread->stack_size, free_space); |
| 797 | if (free_space < 0) { |
| 798 | LOG(LL_WARN, LCF_CHECKPOINT, "We don't have enough space left in the stack to pad"); |
| 799 | } |
| 800 | else { |
| 801 | uintptr_t *pad = static_cast<uintptr_t*>(alloca(free_space)); |
| 802 | pad[0] = reinterpret_cast<uintptr_t>(pad); // to hopefully prevent optimization |
| 803 | } |
| 804 |
nothing calls this directly
no test coverage detected