Path: blob/master/src/hotspot/share/runtime/handshake.cpp
40951 views
/*1* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "jvm_io.h"26#include "logging/log.hpp"27#include "logging/logStream.hpp"28#include "memory/resourceArea.hpp"29#include "runtime/atomic.hpp"30#include "runtime/handshake.hpp"31#include "runtime/interfaceSupport.inline.hpp"32#include "runtime/os.hpp"33#include "runtime/osThread.hpp"34#include "runtime/stackWatermarkSet.hpp"35#include "runtime/task.hpp"36#include "runtime/thread.hpp"37#include "runtime/threadSMR.hpp"38#include "runtime/vmThread.hpp"39#include "utilities/formatBuffer.hpp"40#include "utilities/filterQueue.inline.hpp"41#include "utilities/globalDefinitions.hpp"42#include "utilities/preserveException.hpp"4344class HandshakeOperation : public CHeapObj<mtThread> {45friend class HandshakeState;46protected:47HandshakeClosure* _handshake_cl;48// Keeps track of emitted and completed handshake operations.49// Once it reaches zero all handshake operations have been performed.50int32_t _pending_threads;51JavaThread* _target;52Thread* _requester;5354// Must use AsyncHandshakeOperation when using AsyncHandshakeClosure.55HandshakeOperation(AsyncHandshakeClosure* cl, JavaThread* target, Thread* requester) :56_handshake_cl(cl),57_pending_threads(1),58_target(target),59_requester(requester) {}6061public:62HandshakeOperation(HandshakeClosure* cl, JavaThread* target, Thread* requester) :63_handshake_cl(cl),64_pending_threads(1),65_target(target),66_requester(requester) {}67virtual ~HandshakeOperation() {}68void prepare(JavaThread* current_target, Thread* executing_thread);69void do_handshake(JavaThread* thread);70bool is_completed() {71int32_t val = Atomic::load(&_pending_threads);72assert(val >= 0, "_pending_threads=%d cannot be negative", val);73return val == 0;74}75void add_target_count(int count) { Atomic::add(&_pending_threads, count); }76int32_t pending_threads() { return Atomic::load(&_pending_threads); }77const char* name() { return _handshake_cl->name(); }78bool is_async() { return _handshake_cl->is_async(); }79};8081class AsyncHandshakeOperation : public HandshakeOperation {82private:83jlong _start_time_ns;84public:85AsyncHandshakeOperation(AsyncHandshakeClosure* cl, JavaThread* target, jlong start_ns)86: HandshakeOperation(cl, target, NULL), _start_time_ns(start_ns) {}87virtual ~AsyncHandshakeOperation() { delete _handshake_cl; }88jlong start_time() const { return _start_time_ns; }89};9091// Performing handshakes requires a custom yielding strategy because without it92// there is a clear performance regression vs plain spinning. We keep track of93// when we last saw progress by looking at why each targeted thread has not yet94// completed its handshake. After spinning for a while with no progress we will95// yield, but as long as there is progress, we keep spinning. Thus we avoid96// yielding when there is potential work to be done or the handshake is close97// to being finished.98class HandshakeSpinYield : public StackObj {99private:100jlong _start_time_ns;101jlong _last_spin_start_ns;102jlong _spin_time_ns;103104int _result_count[2][HandshakeState::_number_states];105int _prev_result_pos;106107int current_result_pos() { return (_prev_result_pos + 1) & 0x1; }108109void wait_raw(jlong now) {110// We start with fine-grained nanosleeping until a millisecond has111// passed, at which point we resort to plain naked_short_sleep.112if (now - _start_time_ns < NANOSECS_PER_MILLISEC) {113os::naked_short_nanosleep(10 * (NANOUNITS / MICROUNITS));114} else {115os::naked_short_sleep(1);116}117}118119void wait_blocked(JavaThread* self, jlong now) {120ThreadBlockInVM tbivm(self);121wait_raw(now);122}123124bool state_changed() {125for (int i = 0; i < HandshakeState::_number_states; i++) {126if (_result_count[0][i] != _result_count[1][i]) {127return true;128}129}130return false;131}132133void reset_state() {134_prev_result_pos++;135for (int i = 0; i < HandshakeState::_number_states; i++) {136_result_count[current_result_pos()][i] = 0;137}138}139140public:141HandshakeSpinYield(jlong start_time) :142_start_time_ns(start_time), _last_spin_start_ns(start_time),143_spin_time_ns(0), _result_count(), _prev_result_pos(0) {144145const jlong max_spin_time_ns = 100 /* us */ * (NANOUNITS / MICROUNITS);146int free_cpus = os::active_processor_count() - 1;147_spin_time_ns = (5 /* us */ * (NANOUNITS / MICROUNITS)) * free_cpus; // zero on UP148_spin_time_ns = _spin_time_ns > max_spin_time_ns ? max_spin_time_ns : _spin_time_ns;149}150151void add_result(HandshakeState::ProcessResult pr) {152_result_count[current_result_pos()][pr]++;153}154155void process() {156jlong now = os::javaTimeNanos();157if (state_changed()) {158reset_state();159// We spin for x amount of time since last state change.160_last_spin_start_ns = now;161return;162}163jlong wait_target = _last_spin_start_ns + _spin_time_ns;164if (wait_target < now) {165// On UP this is always true.166Thread* self = Thread::current();167if (self->is_Java_thread()) {168wait_blocked(self->as_Java_thread(), now);169} else {170wait_raw(now);171}172_last_spin_start_ns = os::javaTimeNanos();173}174reset_state();175}176};177178static void handle_timeout(HandshakeOperation* op, JavaThread* target) {179JavaThreadIteratorWithHandle jtiwh;180181log_error(handshake)("Handshake timeout: %s(" INTPTR_FORMAT "), pending threads: " INT32_FORMAT,182op->name(), p2i(op), op->pending_threads());183184if (target == NULL) {185for ( ; JavaThread* thr = jtiwh.next(); ) {186if (thr->handshake_state()->operation_pending(op)) {187log_error(handshake)("JavaThread " INTPTR_FORMAT " has not cleared handshake op: " INTPTR_FORMAT, p2i(thr), p2i(op));188// Remember the last one found for more diagnostics below.189target = thr;190}191}192} else {193log_error(handshake)("JavaThread " INTPTR_FORMAT " has not cleared handshake op: " INTPTR_FORMAT, p2i(target), p2i(op));194}195196if (target != NULL) {197if (os::signal_thread(target, SIGILL, "cannot be handshaked")) {198// Give target a chance to report the error and terminate the VM.199os::naked_sleep(3000);200}201} else {202log_error(handshake)("No thread with an unfinished handshake op(" INTPTR_FORMAT ") found.", p2i(op));203}204fatal("Handshake timeout");205}206207static void check_handshake_timeout(jlong start_time, HandshakeOperation* op, JavaThread* target = NULL) {208// Check if handshake operation has timed out209jlong timeout_ns = millis_to_nanos(HandshakeTimeout);210if (timeout_ns > 0) {211if (os::javaTimeNanos() >= (start_time + timeout_ns)) {212handle_timeout(op, target);213}214}215}216217static void log_handshake_info(jlong start_time_ns, const char* name, int targets, int emitted_handshakes_executed, const char* extra = NULL) {218if (log_is_enabled(Info, handshake)) {219jlong completion_time = os::javaTimeNanos() - start_time_ns;220log_info(handshake)("Handshake \"%s\", Targeted threads: %d, Executed by requesting thread: %d, Total completion time: " JLONG_FORMAT " ns%s%s",221name, targets,222emitted_handshakes_executed,223completion_time,224extra != NULL ? ", " : "",225extra != NULL ? extra : "");226}227}228229class VM_HandshakeAllThreads: public VM_Operation {230HandshakeOperation* const _op;231public:232VM_HandshakeAllThreads(HandshakeOperation* op) : _op(op) {}233234bool evaluate_at_safepoint() const { return false; }235236void doit() {237jlong start_time_ns = os::javaTimeNanos();238239JavaThreadIteratorWithHandle jtiwh;240int number_of_threads_issued = 0;241for (JavaThread* thr = jtiwh.next(); thr != NULL; thr = jtiwh.next()) {242thr->handshake_state()->add_operation(_op);243number_of_threads_issued++;244}245246if (number_of_threads_issued < 1) {247log_handshake_info(start_time_ns, _op->name(), 0, 0, "no threads alive");248return;249}250// _op was created with a count == 1 so don't double count.251_op->add_target_count(number_of_threads_issued - 1);252253log_trace(handshake)("Threads signaled, begin processing blocked threads by VMThread");254HandshakeSpinYield hsy(start_time_ns);255// Keeps count on how many of own emitted handshakes256// this thread execute.257int emitted_handshakes_executed = 0;258do {259// Check if handshake operation has timed out260check_handshake_timeout(start_time_ns, _op);261262// Have VM thread perform the handshake operation for blocked threads.263// Observing a blocked state may of course be transient but the processing is guarded264// by mutexes and we optimistically begin by working on the blocked threads265jtiwh.rewind();266for (JavaThread* thr = jtiwh.next(); thr != NULL; thr = jtiwh.next()) {267// A new thread on the ThreadsList will not have an operation,268// hence it is skipped in handshake_try_process.269HandshakeState::ProcessResult pr = thr->handshake_state()->try_process(_op);270hsy.add_result(pr);271if (pr == HandshakeState::_succeeded) {272emitted_handshakes_executed++;273}274}275hsy.process();276} while (!_op->is_completed());277278// This pairs up with the release store in do_handshake(). It prevents future279// loads from floating above the load of _pending_threads in is_completed()280// and thus prevents reading stale data modified in the handshake closure281// by the Handshakee.282OrderAccess::acquire();283284log_handshake_info(start_time_ns, _op->name(), number_of_threads_issued, emitted_handshakes_executed);285}286287VMOp_Type type() const { return VMOp_HandshakeAllThreads; }288};289290void HandshakeOperation::prepare(JavaThread* current_target, Thread* executing_thread) {291if (current_target->is_terminated()) {292// Will never execute any handshakes on this thread.293return;294}295if (current_target != executing_thread) {296// Only when the target is not executing the handshake itself.297StackWatermarkSet::start_processing(current_target, StackWatermarkKind::gc);298}299if (_requester != NULL && _requester != executing_thread && _requester->is_Java_thread()) {300// The handshake closure may contain oop Handles from the _requester.301// We must make sure we can use them.302StackWatermarkSet::start_processing(_requester->as_Java_thread(), StackWatermarkKind::gc);303}304}305306void HandshakeOperation::do_handshake(JavaThread* thread) {307jlong start_time_ns = 0;308if (log_is_enabled(Debug, handshake, task)) {309start_time_ns = os::javaTimeNanos();310}311312// Only actually execute the operation for non terminated threads.313if (!thread->is_terminated()) {314NoSafepointVerifier nsv;315_handshake_cl->do_thread(thread);316}317318if (start_time_ns != 0) {319jlong completion_time = os::javaTimeNanos() - start_time_ns;320log_debug(handshake, task)("Operation: %s for thread " PTR_FORMAT ", is_vm_thread: %s, completed in " JLONG_FORMAT " ns",321name(), p2i(thread), BOOL_TO_STR(Thread::current()->is_VM_thread()), completion_time);322}323324// Inform VMThread/Handshaker that we have completed the operation.325// When this is executed by the Handshakee we need a release store326// here to make sure memory operations executed in the handshake327// closure are visible to the VMThread/Handshaker after it reads328// that the operation has completed.329Atomic::dec(&_pending_threads, memory_order_release);330331// It is no longer safe to refer to 'this' as the VMThread/Handshaker may have destroyed this operation332}333334void Handshake::execute(HandshakeClosure* hs_cl) {335HandshakeOperation cto(hs_cl, NULL, Thread::current());336VM_HandshakeAllThreads handshake(&cto);337VMThread::execute(&handshake);338}339340void Handshake::execute(HandshakeClosure* hs_cl, JavaThread* target) {341JavaThread* self = JavaThread::current();342HandshakeOperation op(hs_cl, target, Thread::current());343344jlong start_time_ns = os::javaTimeNanos();345346ThreadsListHandle tlh;347if (tlh.includes(target)) {348target->handshake_state()->add_operation(&op);349} else {350char buf[128];351jio_snprintf(buf, sizeof(buf), "(thread= " INTPTR_FORMAT " dead)", p2i(target));352log_handshake_info(start_time_ns, op.name(), 0, 0, buf);353return;354}355356// Keeps count on how many of own emitted handshakes357// this thread execute.358int emitted_handshakes_executed = 0;359HandshakeSpinYield hsy(start_time_ns);360while (!op.is_completed()) {361HandshakeState::ProcessResult pr = target->handshake_state()->try_process(&op);362if (pr == HandshakeState::_succeeded) {363emitted_handshakes_executed++;364}365if (op.is_completed()) {366break;367}368369// Check if handshake operation has timed out370check_handshake_timeout(start_time_ns, &op, target);371372hsy.add_result(pr);373// Check for pending handshakes to avoid possible deadlocks where our374// target is trying to handshake us.375if (SafepointMechanism::should_process(self)) {376ThreadBlockInVM tbivm(self);377}378hsy.process();379}380381// This pairs up with the release store in do_handshake(). It prevents future382// loads from floating above the load of _pending_threads in is_completed()383// and thus prevents reading stale data modified in the handshake closure384// by the Handshakee.385OrderAccess::acquire();386387log_handshake_info(start_time_ns, op.name(), 1, emitted_handshakes_executed);388}389390void Handshake::execute(AsyncHandshakeClosure* hs_cl, JavaThread* target) {391jlong start_time_ns = os::javaTimeNanos();392AsyncHandshakeOperation* op = new AsyncHandshakeOperation(hs_cl, target, start_time_ns);393394ThreadsListHandle tlh;395if (tlh.includes(target)) {396target->handshake_state()->add_operation(op);397} else {398log_handshake_info(start_time_ns, op->name(), 0, 0, "(thread dead)");399delete op;400}401}402403HandshakeState::HandshakeState(JavaThread* target) :404_handshakee(target),405_queue(),406_lock(Monitor::leaf, "HandshakeState", Mutex::_allow_vm_block_flag, Monitor::_safepoint_check_never),407_active_handshaker(),408_suspended(false),409_async_suspend_handshake(false)410{411}412413void HandshakeState::add_operation(HandshakeOperation* op) {414// Adds are done lock free and so is arming.415_queue.push(op);416SafepointMechanism::arm_local_poll_release(_handshakee);417}418419bool HandshakeState::operation_pending(HandshakeOperation* op) {420MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);421class MatchOp {422HandshakeOperation* _op;423public:424MatchOp(HandshakeOperation* op) : _op(op) {}425bool operator()(HandshakeOperation* op) {426return op == _op;427}428};429MatchOp mo(op);430return _queue.contains(mo);431}432433HandshakeOperation* HandshakeState::pop_for_self() {434assert(_handshakee == Thread::current(), "Must be called by self");435assert(_lock.owned_by_self(), "Lock must be held");436return _queue.pop();437};438439static bool non_self_queue_filter(HandshakeOperation* op) {440return !op->is_async();441}442443bool HandshakeState::have_non_self_executable_operation() {444assert(_handshakee != Thread::current(), "Must not be called by self");445assert(_lock.owned_by_self(), "Lock must be held");446return _queue.contains(non_self_queue_filter);447}448449HandshakeOperation* HandshakeState::pop() {450assert(_handshakee != Thread::current(), "Must not be called by self");451assert(_lock.owned_by_self(), "Lock must be held");452return _queue.pop(non_self_queue_filter);453};454455bool HandshakeState::process_by_self() {456assert(Thread::current() == _handshakee, "should call from _handshakee");457assert(!_handshakee->is_terminated(), "should not be a terminated thread");458assert(_handshakee->thread_state() != _thread_blocked, "should not be in a blocked state");459assert(_handshakee->thread_state() != _thread_in_native, "should not be in native");460ThreadInVMForHandshake tivm(_handshakee);461{462// Handshakes cannot safely safepoint.463// The exception to this rule is the asynchronous suspension handshake.464// It by-passes the NSV by manually doing the transition.465NoSafepointVerifier nsv;466return process_self_inner();467}468}469470bool HandshakeState::process_self_inner() {471while (should_process()) {472MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);473HandshakeOperation* op = pop_for_self();474if (op != NULL) {475assert(op->_target == NULL || op->_target == Thread::current(), "Wrong thread");476bool async = op->is_async();477log_trace(handshake)("Proc handshake %s " INTPTR_FORMAT " on " INTPTR_FORMAT " by self",478async ? "asynchronous" : "synchronous", p2i(op), p2i(_handshakee));479op->prepare(_handshakee, _handshakee);480if (!async) {481HandleMark hm(_handshakee);482PreserveExceptionMark pem(_handshakee);483op->do_handshake(_handshakee);484} else {485// An asynchronous handshake may put the JavaThread in blocked state (safepoint safe).486// The destructor ~PreserveExceptionMark touches the exception oop so it must not be executed,487// since a safepoint may be in-progress when returning from the async handshake.488op->do_handshake(_handshakee);489log_handshake_info(((AsyncHandshakeOperation*)op)->start_time(), op->name(), 1, 0, "asynchronous");490delete op;491return true; // Must check for safepoints492}493} else {494return false;495}496}497return false;498}499500bool HandshakeState::can_process_handshake() {501// handshake_safe may only be called with polls armed.502// Handshaker controls this by first claiming the handshake via claim_handshake().503return SafepointSynchronize::handshake_safe(_handshakee);504}505506bool HandshakeState::possibly_can_process_handshake() {507// Note that this method is allowed to produce false positives.508if (_handshakee->is_terminated()) {509return true;510}511switch (_handshakee->thread_state()) {512case _thread_in_native:513// native threads are safe if they have no java stack or have walkable stack514return !_handshakee->has_last_Java_frame() || _handshakee->frame_anchor()->walkable();515516case _thread_blocked:517return true;518519default:520return false;521}522}523524bool HandshakeState::claim_handshake() {525if (!_lock.try_lock()) {526return false;527}528// Operations are added lock free and then the poll is armed.529// If all handshake operations for the handshakee are finished and someone530// just adds an operation we may see it here. But if the handshakee is not531// armed yet it is not safe to proceed.532if (have_non_self_executable_operation()) {533if (SafepointMechanism::local_poll_armed(_handshakee)) {534return true;535}536}537_lock.unlock();538return false;539}540541HandshakeState::ProcessResult HandshakeState::try_process(HandshakeOperation* match_op) {542if (!has_operation()) {543// JT has already cleared its handshake544return HandshakeState::_no_operation;545}546547if (!possibly_can_process_handshake()) {548// JT is observed in an unsafe state, it must notice the handshake itself549return HandshakeState::_not_safe;550}551552// Claim the mutex if there still an operation to be executed.553if (!claim_handshake()) {554return HandshakeState::_claim_failed;555}556557// If we own the mutex at this point and while owning the mutex we558// can observe a safe state the thread cannot possibly continue without559// getting caught by the mutex.560if (!can_process_handshake()) {561_lock.unlock();562return HandshakeState::_not_safe;563}564565Thread* current_thread = Thread::current();566567HandshakeState::ProcessResult pr_ret = HandshakeState::_processed;568int executed = 0;569570do {571HandshakeOperation* op = pop();572if (op != NULL) {573assert(SafepointMechanism::local_poll_armed(_handshakee), "Must be");574assert(op->_target == NULL || _handshakee == op->_target, "Wrong thread");575log_trace(handshake)("Processing handshake " INTPTR_FORMAT " by %s(%s)", p2i(op),576op == match_op ? "handshaker" : "cooperative",577current_thread->is_VM_thread() ? "VM Thread" : "JavaThread");578579if (op == match_op) {580pr_ret = HandshakeState::_succeeded;581}582583op->prepare(_handshakee, current_thread);584585_active_handshaker = current_thread;586op->do_handshake(_handshakee);587_active_handshaker = NULL;588589executed++;590}591} while (have_non_self_executable_operation());592593_lock.unlock();594595log_trace(handshake)("%s(" INTPTR_FORMAT ") executed %d ops for JavaThread: " INTPTR_FORMAT " %s target op: " INTPTR_FORMAT,596current_thread->is_VM_thread() ? "VM Thread" : "JavaThread",597p2i(current_thread), executed, p2i(_handshakee),598pr_ret == HandshakeState::_succeeded ? "including" : "excluding", p2i(match_op));599return pr_ret;600}601602void HandshakeState::do_self_suspend() {603assert(Thread::current() == _handshakee, "should call from _handshakee");604assert(_lock.owned_by_self(), "Lock must be held");605assert(!_handshakee->has_last_Java_frame() || _handshakee->frame_anchor()->walkable(), "should have walkable stack");606JavaThreadState jts = _handshakee->thread_state();607while (is_suspended()) {608_handshakee->set_thread_state(_thread_blocked);609log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " suspended", p2i(_handshakee));610_lock.wait_without_safepoint_check();611}612_handshakee->set_thread_state(jts);613set_async_suspend_handshake(false);614log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " resumed", p2i(_handshakee));615}616617// This is the closure that prevents a suspended JavaThread from618// escaping the suspend request.619class ThreadSelfSuspensionHandshake : public AsyncHandshakeClosure {620public:621ThreadSelfSuspensionHandshake() : AsyncHandshakeClosure("ThreadSelfSuspensionHandshake") {}622void do_thread(Thread* thr) {623JavaThread* current = thr->as_Java_thread();624assert(current == Thread::current(), "Must be self executed.");625current->handshake_state()->do_self_suspend();626}627};628629bool HandshakeState::suspend_with_handshake() {630if (_handshakee->is_exiting() ||631_handshakee->threadObj() == NULL) {632log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " exiting", p2i(_handshakee));633return false;634}635if (has_async_suspend_handshake()) {636if (is_suspended()) {637// Target is already suspended.638log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " already suspended", p2i(_handshakee));639return false;640} else {641// Target is going to wake up and leave suspension.642// Let's just stop the thread from doing that.643log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " re-suspended", p2i(_handshakee));644set_suspended(true);645return true;646}647}648// no suspend request649assert(!is_suspended(), "cannot be suspended without a suspend request");650// Thread is safe, so it must execute the request, thus we can count it as suspended651// from this point.652set_suspended(true);653set_async_suspend_handshake(true);654log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " suspended, arming ThreadSuspension", p2i(_handshakee));655ThreadSelfSuspensionHandshake* ts = new ThreadSelfSuspensionHandshake();656Handshake::execute(ts, _handshakee);657return true;658}659660// This is the closure that synchronously honors the suspend request.661class SuspendThreadHandshake : public HandshakeClosure {662bool _did_suspend;663public:664SuspendThreadHandshake() : HandshakeClosure("SuspendThread"), _did_suspend(false) {}665void do_thread(Thread* thr) {666JavaThread* target = thr->as_Java_thread();667_did_suspend = target->handshake_state()->suspend_with_handshake();668}669bool did_suspend() { return _did_suspend; }670};671672bool HandshakeState::suspend() {673SuspendThreadHandshake st;674Handshake::execute(&st, _handshakee);675return st.did_suspend();676}677678bool HandshakeState::resume() {679if (!is_suspended()) {680return false;681}682MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);683if (!is_suspended()) {684assert(!_handshakee->is_suspended(), "cannot be suspended without a suspend request");685return false;686}687// Resume the thread.688set_suspended(false);689_lock.notify();690return true;691}692693694