File thread_entry.cpp¶
File List > cubrid > src > thread > thread_entry.cpp
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* thread_entry - implementation for thread contextual cache.
*/
#include "thread_entry.hpp"
#include "critical_section.h" // for INF_WAIT
#include "critical_section_tracker.hpp"
#include "error_manager.h"
#include "fault_injection.h"
#include "list_file.h"
#include "lock_free.h"
#include "lockfree_transaction_system.hpp"
#include "log_compress.h"
#include "log_system_tran.hpp"
#include "memory_alloc.h"
#include "page_buffer.h"
#include "resource_tracker.hpp"
#include <cstring>
#include <sstream>
#if !defined (WINDOWS)
#include <pthread.h>
#endif // WINDOWS
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
namespace cubthread
{
// resource tracker dedicated section
// todo - normally each tracker should be moved to its own module
// enable trackers in SERVER_MODE && debug
static const bool ENABLE_TRACKERS =
#if !defined (NDEBUG) && defined (SERVER_MODE)
true;
#else // RELEASE or !SERVER_MODE
false;
#endif // RELEASE or !SERVER_MODE
// tracker constants
// alloc
const char *ALLOC_TRACK_NAME = "Virtual Memory";
const char *ALLOC_TRACK_RES_NAME = "res_ptr";
const std::size_t ALLOC_TRACK_MAX_ITEMS = 32767;
// page buffer
const char *PGBUF_TRACK_NAME = "Page Buffer";
const char *PGBUF_TRACK_RES_NAME = "pgptr";
const std::size_t PGBUF_TRACK_MAX_ITEMS = 1024;
const unsigned PGBUF_TRACK_MAX_AMOUNT = 16; // re-fix is possible... how many to accept is debatable
// entry implementation
entry::entry ()
// public:
: index (-1)
, type (TT_NONE)
, emulate_tid ()
, client_id (-1)
, tran_index (NULL_TRAN_INDEX)
, private_lru_index (-1)
, tran_index_lock ()
, rid (0)
, m_status (status::TS_DEAD)
, th_entry_lock ()
, wakeup_cond ()
, private_heap_id (0)
, conn_entry (NULL)
, xasl_unpack_info_ptr (NULL)
, xasl_errcode (0)
, xasl_recursion_depth (0)
, rand_seed (0)
, rand_buf ()
, resume_status (THREAD_RESUME_NONE)
, request_latch_mode (PGBUF_NO_LATCH)
, request_fix_count (0)
, victim_request_fail (false)
, interrupted (false)
, shutdown (false)
, check_interrupt (true)
, wait_for_latch_promote (false)
, next_wait_thrd (NULL)
, lockwait (NULL)
, lockwait_stime (0)
, lockwait_msecs (0)
, lockwait_state (-1)
, query_entry (NULL)
, tran_next_wait (NULL)
, worker_thrd_list (NULL)
, log_zip_undo (NULL)
, log_zip_redo (NULL)
, log_data_ptr (NULL)
, log_data_length (0)
, no_logging (false)
, net_request_index (-1)
, vacuum_worker (NULL)
, sort_stats_active (false)
, event_stats ()
, trace_format (0)
, on_trace (false)
, clear_trace (false)
, tran_entries ()
, no_supplemental_log (false)
, trigger_involved (false)
, is_cdc_daemon (false)
#if !defined (NDEBUG)
, fi_test_array (NULL)
, count_private_allocators (0)
#endif /* DEBUG */
, m_qlist_count (0)
, read_ovfl_pages_count (0) // For Vacuum only.
, m_loaddb_driver (NULL)
, m_px_lock_mutex ()
, m_px_stats_mutex ()
, m_px_stats (NULL)
, m_px_orig_thread_entry (NULL)
, m_uses_px_stats (false)
, m_is_private_lru_enabled (false)
, m_holder_anchor (NULL)
// private:
, m_id ()
, m_error ()
, m_cleared (false)
, m_alloc_tracker (*new cubbase::alloc_tracker (ALLOC_TRACK_NAME, ENABLE_TRACKERS, ALLOC_TRACK_MAX_ITEMS,
ALLOC_TRACK_RES_NAME))
, m_pgbuf_tracker (*new cubbase::pgbuf_tracker (PGBUF_TRACK_NAME, ENABLE_TRACKERS, PGBUF_TRACK_MAX_ITEMS,
PGBUF_TRACK_RES_NAME, PGBUF_TRACK_MAX_AMOUNT))
, m_csect_tracker (*new cubsync::critical_section_tracker (ENABLE_TRACKERS))
, m_systdes (NULL)
, m_lf_tran_index (lockfree::tran::INVALID_INDEX)
{
if (pthread_mutex_init (&tran_index_lock, NULL) != 0)
{
// cannot recover from this
assert (false);
}
if (pthread_mutex_init (&th_entry_lock, NULL) != 0)
{
// cannot recover from this
assert (false);
}
if (pthread_cond_init (&wakeup_cond, NULL) != 0)
{
// cannot recover from this
assert (false);
}
if (pthread_mutex_init (&m_px_lock_mutex, NULL) != 0)
{
// cannot recover from this
assert (false);
}
if (pthread_mutex_init (&m_px_stats_mutex, NULL) != 0)
{
// cannot recover from this
assert (false);
}
private_heap_id = db_create_private_heap ();
struct timeval t;
gettimeofday (&t, NULL);
rand_seed = (unsigned int) t.tv_usec;
srand48_r ((long) t.tv_usec, &rand_buf);
std::memset (&event_stats, 0, sizeof (event_stats));
/* lock-free transaction entries */
tran_entries[THREAD_TS_SPAGE_SAVING] = NULL;
tran_entries[THREAD_TS_OBJ_LOCK_RES] = NULL;
tran_entries[THREAD_TS_OBJ_LOCK_ENT] = NULL;
tran_entries[THREAD_TS_CATALOG] = NULL;
tran_entries[THREAD_TS_SESSIONS] = NULL;
tran_entries[THREAD_TS_FREE_SORT_LIST] = NULL;
tran_entries[THREAD_TS_GLOBAL_UNIQUE_STATS] = NULL;
tran_entries[THREAD_TS_HFID_TABLE] = NULL;
tran_entries[THREAD_TS_XCACHE] = NULL;
tran_entries[THREAD_TS_FPCACHE] = NULL;
_unload_cnt_parallel_process = NO_UNLOAD_PARALLEL_PROCESSIING;
_unload_parallel_process_idx = NO_UNLOAD_PARALLEL_PROCESSIING;
#if !defined (NDEBUG)
fi_thread_init (this);
#endif /* DEBUG */
}
entry::~entry (void)
{
clear_resources ();
delete &m_alloc_tracker;
delete &m_pgbuf_tracker;
delete &m_csect_tracker;
}
void
entry::request_lock_free_transactions (void)
{
/* lock-free transaction entries */
tran_entries[THREAD_TS_SPAGE_SAVING] = lf_tran_request_entry (&spage_saving_Ts);
tran_entries[THREAD_TS_OBJ_LOCK_RES] = lf_tran_request_entry (&obj_lock_res_Ts);
tran_entries[THREAD_TS_OBJ_LOCK_ENT] = lf_tran_request_entry (&obj_lock_ent_Ts);
tran_entries[THREAD_TS_CATALOG] = lf_tran_request_entry (&catalog_Ts);
tran_entries[THREAD_TS_SESSIONS] = lf_tran_request_entry (&sessions_Ts);
tran_entries[THREAD_TS_FREE_SORT_LIST] = lf_tran_request_entry (&free_sort_list_Ts);
tran_entries[THREAD_TS_GLOBAL_UNIQUE_STATS] = lf_tran_request_entry (&global_unique_stats_Ts);
tran_entries[THREAD_TS_HFID_TABLE] = lf_tran_request_entry (&hfid_table_Ts);
tran_entries[THREAD_TS_XCACHE] = lf_tran_request_entry (&xcache_Ts);
tran_entries[THREAD_TS_FPCACHE] = lf_tran_request_entry (&fpcache_Ts);
tran_entries[THREAD_TS_DWB_SLOTS] = lf_tran_request_entry (&dwb_slots_Ts);
}
void
entry::clear_resources (void)
{
if (m_cleared)
{
return;
}
if (pthread_mutex_destroy (&tran_index_lock) != 0)
{
assert (false);
}
if (pthread_mutex_destroy (&th_entry_lock) != 0)
{
assert (false);
}
if (pthread_cond_destroy (&wakeup_cond) != 0)
{
assert (false);
}
if (pthread_mutex_destroy (&m_px_lock_mutex) != 0)
{
// cannot recover from this
assert (false);
}
if (pthread_mutex_destroy (&m_px_stats_mutex) != 0)
{
// cannot recover from this
assert (false);
}
if (log_zip_undo != NULL)
{
log_zip_free ((LOG_ZIP *) log_zip_undo);
}
if (log_zip_redo != NULL)
{
log_zip_free ((LOG_ZIP *) log_zip_redo);
}
if (log_data_ptr != NULL)
{
free (log_data_ptr);
}
no_logging = false;
no_supplemental_log = false;
trigger_involved = false;
is_cdc_daemon = false;
end_resource_tracks ();
db_destroy_private_heap (this, private_heap_id);
#if !defined (NDEBUG)
for (int i = 0; i < THREAD_TS_COUNT; i++)
{
assert (tran_entries[i] == NULL);
}
#endif // DEBUG
#if !defined (NDEBUG)
fi_thread_final (this);
#endif // DEBUG
assert (m_systdes == NULL);
m_cleared = true;
}
thread_id_t
entry::get_id ()
{
return m_id;
}
pthread_t
entry::get_posix_id ()
{
pthread_t thread_id = 0;
if (m_id != thread_id_t ())
{
std::ostringstream oss;
oss << m_id;
thread_id = (pthread_t) std::stoul (oss.str ());
}
return thread_id;
}
void
entry::register_id ()
{
m_id = std::this_thread::get_id ();
#if defined (SERVER_MODE)
// native thread identifier must be equal to identifier of std::this_thread
assert (get_posix_id () == pthread_self ());
#endif /* SERVER_MODE */
}
void
entry::unregister_id ()
{
m_id = thread_id_t ();
}
bool
entry::is_on_current_thread () const
{
return m_id == std::this_thread::get_id ();
}
void
entry::return_lock_free_transaction_entries (void)
{
for (std::size_t i = 0; i < THREAD_TS_COUNT; i++)
{
if (tran_entries[i] != NULL)
{
lf_tran_return_entry (tran_entries[i]);
tran_entries[i] = NULL;
}
}
}
void
entry::release_packet (void *buffer)
{
conn_entry->release_packet (buffer);
}
void
entry::lock (void)
{
pthread_mutex_lock (&th_entry_lock);
}
void
entry::unlock (void)
{
pthread_mutex_unlock (&th_entry_lock);
}
void
entry::end_resource_tracks (void)
{
if (!ENABLE_TRACKERS)
{
// all trackers are activated by this flag
return;
}
m_alloc_tracker.clear_all ();
m_pgbuf_tracker.clear_all ();
m_csect_tracker.clear_all ();
m_qlist_count = 0;
}
void
entry::push_resource_tracks (void)
{
if (!ENABLE_TRACKERS)
{
// all trackers are activated by this flag
return;
}
m_alloc_tracker.push_track ();
m_pgbuf_tracker.push_track ();
m_csect_tracker.start ();
}
void
entry::pop_resource_tracks (void)
{
if (!ENABLE_TRACKERS)
{
// all trackers are activated by this flag
return;
}
m_alloc_tracker.pop_track ();
m_pgbuf_tracker.pop_track ();
m_csect_tracker.stop ();
}
void
entry::claim_system_worker ()
{
assert (m_systdes == NULL);
m_systdes = new log_system_tdes ();
tran_index = LOG_SYSTEM_TRAN_INDEX;
}
void
entry::retire_system_worker ()
{
delete m_systdes;
m_systdes = NULL;
tran_index = NULL_TRAN_INDEX;
}
void
entry::assign_lf_tran_index (lockfree::tran::index idx)
{
m_lf_tran_index = idx;
}
lockfree::tran::index
entry::pull_lf_tran_index ()
{
lockfree::tran::index ret = m_lf_tran_index;
m_lf_tran_index = lockfree::tran::INVALID_INDEX;
return ret;
}
lockfree::tran::index
entry::get_lf_tran_index ()
{
return m_lf_tran_index;
}
} // namespace cubthread
// legacy C functions
using thread_clock_type = std::chrono::system_clock;
static void thread_wakeup_internal (cubthread::entry *thread_p, thread_resume_suspend_status resume_reason,
bool had_mutex);
static void thread_check_suspend_reason_and_wakeup_internal (cubthread::entry *thread_p,
thread_resume_suspend_status resume_reason,
thread_resume_suspend_status suspend_reason,
bool had_mutex);
// todo - remove timeval and use std::chrono
static void
thread_timeval_add_usec (const std::chrono::microseconds &usec, struct timeval &tv)
{
const long ratio = 1000000;
// add all usecs to tv_usec
tv.tv_usec += (long) usec.count ();
// move seconds from tv_usec to tv_sec
tv.tv_sec += tv.tv_usec / ratio;
tv.tv_usec = tv.tv_usec % ratio;
}
/*
* thread_suspend_wakeup_and_unlock_entry() -
* return:
* thread_p(in):
* suspended_reason(in):
*
* Note: this function must be called by current thread also, the lock must have already been acquired.
*/
void
thread_suspend_wakeup_and_unlock_entry (cubthread::entry *thread_p, thread_resume_suspend_status suspended_reason)
{
cubthread::entry::status old_status;
thread_clock_type::time_point start_time_pt;
std::chrono::microseconds usecs;
assert (thread_p->m_status == cubthread::entry::status::TS_RUN
|| thread_p->m_status == cubthread::entry::status::TS_CHECK);
old_status = thread_p->m_status;
thread_p->m_status = cubthread::entry::status::TS_WAIT;
thread_p->resume_status = suspended_reason;
if (thread_p->event_stats.trace_slow_query == true)
{
start_time_pt = thread_clock_type::now ();
}
pthread_cond_wait (&thread_p->wakeup_cond, &thread_p->th_entry_lock);
if (thread_p->event_stats.trace_slow_query == true)
{
usecs = std::chrono::duration_cast<std::chrono::microseconds> (thread_clock_type::now () - start_time_pt);
if (suspended_reason == THREAD_LOCK_SUSPENDED)
{
thread_timeval_add_usec (usecs, thread_p->event_stats.lock_waits);
}
else if (suspended_reason == THREAD_PGBUF_SUSPENDED)
{
thread_timeval_add_usec (usecs, thread_p->event_stats.latch_waits);
}
}
thread_p->m_status = old_status;
pthread_mutex_unlock (&thread_p->th_entry_lock);
}
/*
* thread_suspend_timeout_wakeup_and_unlock_entry() -
* return:
* thread_p(in):
* time_p(in):
* suspended_reason(in):
*/
int
thread_suspend_timeout_wakeup_and_unlock_entry (cubthread::entry *thread_p, struct timespec *time_p,
thread_resume_suspend_status suspended_reason)
{
int r;
cubthread::entry::status old_status;
thread_clock_type::time_point start_time_pt;
std::chrono::microseconds usecs;
int error = NO_ERROR;
assert (thread_p->m_status == cubthread::entry::status::TS_RUN
|| thread_p->m_status == cubthread::entry::status::TS_CHECK);
old_status = thread_p->m_status;
thread_p->m_status = cubthread::entry::status::TS_WAIT;
thread_p->resume_status = suspended_reason;
if (thread_p->event_stats.trace_slow_query == true && suspended_reason == THREAD_PGBUF_SUSPENDED)
{
start_time_pt = thread_clock_type::now ();
}
r = pthread_cond_timedwait (&thread_p->wakeup_cond, &thread_p->th_entry_lock, time_p);
if (thread_p->event_stats.trace_slow_query == true && suspended_reason == THREAD_PGBUF_SUSPENDED)
{
usecs = std::chrono::duration_cast < std::chrono::microseconds > (thread_clock_type::now () - start_time_pt);
thread_timeval_add_usec (usecs, thread_p->event_stats.latch_waits);
}
if (r != 0 && r != ETIMEDOUT)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CSS_PTHREAD_COND_TIMEDWAIT, 0);
return ER_CSS_PTHREAD_COND_TIMEDWAIT;
}
if (r == ETIMEDOUT)
{
error = ER_CSS_PTHREAD_COND_TIMEDOUT;
}
thread_p->m_status = old_status;
pthread_mutex_unlock (&thread_p->th_entry_lock);
return error;
}
/*
* thread_wakeup_internal () -
* return:
* thread_p(in/out):
* resume_reason:
*/
static void
thread_wakeup_internal (cubthread::entry *thread_p, thread_resume_suspend_status resume_reason, bool had_mutex)
{
if (had_mutex == false)
{
thread_lock_entry (thread_p);
}
pthread_cond_signal (&thread_p->wakeup_cond);
thread_p->resume_status = resume_reason;
if (had_mutex == false)
{
thread_unlock_entry (thread_p);
}
}
/*
* thread_check_suspend_reason_and_wakeup_internal () -
* return:
* thread_p(in):
* resume_reason:
* suspend_reason:
* had_mutex:
*/
static void
thread_check_suspend_reason_and_wakeup_internal (cubthread::entry *thread_p,
thread_resume_suspend_status resume_reason,
thread_resume_suspend_status suspend_reason, bool had_mutex)
{
if (had_mutex == false)
{
thread_lock_entry (thread_p);
}
if (thread_p->resume_status != suspend_reason)
{
thread_unlock_entry (thread_p);
return;
}
pthread_cond_signal (&thread_p->wakeup_cond);
thread_p->resume_status = resume_reason;
thread_unlock_entry (thread_p);
}
/*
* thread_wakeup () -
* return:
* thread_p(in/out):
* resume_reason:
*/
void
thread_wakeup (cubthread::entry *thread_p, thread_resume_suspend_status resume_reason)
{
thread_wakeup_internal (thread_p, resume_reason, false);
}
void
thread_check_suspend_reason_and_wakeup (cubthread::entry *thread_p, thread_resume_suspend_status resume_reason,
thread_resume_suspend_status suspend_reason)
{
thread_check_suspend_reason_and_wakeup_internal (thread_p, resume_reason, suspend_reason, false);
}
/*
* thread_wakeup_already_had_mutex () -
* return:
* thread_p(in/out):
* resume_reason:
*/
void
thread_wakeup_already_had_mutex (cubthread::entry *thread_p, thread_resume_suspend_status resume_reason)
{
thread_wakeup_internal (thread_p, resume_reason, true);
}
/*
* thread_suspend_with_other_mutex() -
* return: 0 if no error, or error code
* thread_p(in):
* mutex_p():
* timeout(in):
* to(in):
* suspended_reason(in):
*/
int
thread_suspend_with_other_mutex (cubthread::entry *thread_p, pthread_mutex_t *mutex_p, int timeout,
struct timespec *to, thread_resume_suspend_status suspended_reason)
{
int r = 0;
cubthread::entry::status old_status;
int error = NO_ERROR;
assert (thread_p != NULL);
old_status = thread_p->m_status;
pthread_mutex_lock (&thread_p->th_entry_lock);
thread_p->m_status = cubthread::entry::status::TS_WAIT;
thread_p->resume_status = suspended_reason;
pthread_mutex_unlock (&thread_p->th_entry_lock);
if (timeout == INF_WAIT)
{
pthread_cond_wait (&thread_p->wakeup_cond, mutex_p);
}
else
{
r = pthread_cond_timedwait (&thread_p->wakeup_cond, mutex_p, to);
}
/* we should restore thread's status */
if (r != NO_ERROR)
{
error = (r == ETIMEDOUT) ? ER_CSS_PTHREAD_COND_TIMEDOUT : ER_CSS_PTHREAD_COND_WAIT;
if (timeout == INF_WAIT || r != ETIMEDOUT)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
}
}
pthread_mutex_lock (&thread_p->th_entry_lock);
thread_p->m_status = old_status;
pthread_mutex_unlock (&thread_p->th_entry_lock);
assert (error == NO_ERROR || error == ER_CSS_PTHREAD_COND_TIMEDOUT);
return error;
}
/*
* thread_type_to_string () - Translate thread type into string
* representation
* return:
* type(in): thread type
*/
const char *
thread_type_to_string (thread_type type)
{
switch (type)
{
case TT_MASTER:
return "MASTER";
case TT_SERVER:
return "SERVER";
case TT_WORKER:
return "WORKER";
case TT_DAEMON:
return "DAEMON";
case TT_LOADDB:
return "LOADDB";
case TT_VACUUM_MASTER:
return "VACUUM_MASTER";
case TT_VACUUM_WORKER:
return "VACUUM_WORKER";
case TT_RECOVERY:
return "RECOVERY";
case TT_NONE:
return "NONE";
}
return "UNKNOWN";
}
/*
* thread_status_to_string () - Translate thread status into string
* representation
* return:
* type(in): thread type
*/
const char *
thread_status_to_string (cubthread::entry::status status)
{
switch (status)
{
case cubthread::entry::status::TS_DEAD:
return "DEAD";
case cubthread::entry::status::TS_FREE:
return "FREE";
case cubthread::entry::status::TS_RUN:
return "RUN";
case cubthread::entry::status::TS_WAIT:
return "WAIT";
case cubthread::entry::status::TS_CHECK:
return "CHECK";
}
return "UNKNOWN";
}
/*
* thread_resume_status_to_string () - Translate thread resume status into
* string representation
* return:
* type(in): thread type
*/
const char *
thread_resume_status_to_string (thread_resume_suspend_status resume_status)
{
switch (resume_status)
{
case THREAD_RESUME_NONE:
return "RESUME_NONE";
case THREAD_RESUME_DUE_TO_INTERRUPT:
return "RESUME_DUE_TO_INTERRUPT";
case THREAD_RESUME_DUE_TO_SHUTDOWN:
return "RESUME_DUE_TO_SHUTDOWN";
case THREAD_PGBUF_SUSPENDED:
return "PGBUF_SUSPENDED";
case THREAD_PGBUF_RESUMED:
return "PGBUF_RESUMED";
case THREAD_JOB_QUEUE_SUSPENDED:
return "JOB_QUEUE_SUSPENDED";
case THREAD_JOB_QUEUE_RESUMED:
return "JOB_QUEUE_RESUMED";
case THREAD_CSECT_READER_SUSPENDED:
return "CSECT_READER_SUSPENDED";
case THREAD_CSECT_READER_RESUMED:
return "CSECT_READER_RESUMED";
case THREAD_CSECT_WRITER_SUSPENDED:
return "CSECT_WRITER_SUSPENDED";
case THREAD_CSECT_WRITER_RESUMED:
return "CSECT_WRITER_RESUMED";
case THREAD_CSECT_PROMOTER_SUSPENDED:
return "CSECT_PROMOTER_SUSPENDED";
case THREAD_CSECT_PROMOTER_RESUMED:
return "CSECT_PROMOTER_RESUMED";
case THREAD_CSS_QUEUE_SUSPENDED:
return "CSS_QUEUE_SUSPENDED";
case THREAD_CSS_QUEUE_RESUMED:
return "CSS_QUEUE_RESUMED";
case THREAD_HEAP_CLSREPR_SUSPENDED:
return "HEAP_CLSREPR_SUSPENDED";
case THREAD_HEAP_CLSREPR_RESUMED:
return "HEAP_CLSREPR_RESUMED";
case THREAD_LOCK_SUSPENDED:
return "LOCK_SUSPENDED";
case THREAD_LOCK_RESUMED:
return "LOCK_RESUMED";
case THREAD_LOGWR_SUSPENDED:
return "LOGWR_SUSPENDED";
case THREAD_LOGWR_RESUMED:
return "LOGWR_RESUMED";
case THREAD_ALLOC_BCB_SUSPENDED:
return "ALLOC_BCB_SUSPENDED";
case THREAD_ALLOC_BCB_RESUMED:
return "ALLOC_BCB_RESUMED";
case THREAD_DWB_QUEUE_SUSPENDED:
return "DWB_BLOCK_QUEUE_SUSPENDED";
case THREAD_DWB_QUEUE_RESUMED:
return "DWB_BLOCK_QUEUE_RESUMED";
}
return "UNKNOWN";
}